GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/dhcpd/udpsock.c Lines: 0 87 0.0 %
Date: 2017-11-07 Branches: 0 30 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: udpsock.c,v 1.10 2017/02/13 22:33:39 krw Exp $	*/
2
3
/*
4
 * Copyright (c) 2014 YASUOKA Masahiko <yasuoka@openbsd.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
#include <sys/ioctl.h>
21
#include <sys/socket.h>
22
23
#include <arpa/inet.h>
24
25
#include <net/if.h>
26
#include <net/if_dl.h>
27
28
#include <netinet/in.h>
29
30
#include <ctype.h>
31
#include <errno.h>
32
#include <stdio.h>
33
#include <stdlib.h>
34
#include <string.h>
35
#include <unistd.h>
36
37
#include "dhcp.h"
38
#include "tree.h"
39
#include "dhcpd.h"
40
#include "log.h"
41
42
void	 udpsock_handler (struct protocol *);
43
ssize_t	 udpsock_send_packet(struct interface_info *, struct dhcp_packet *,
44
    size_t, struct in_addr, struct sockaddr_in *, struct hardware *);
45
46
struct udpsock {
47
	int	 sock;
48
};
49
50
void
51
udpsock_startup(struct in_addr bindaddr)
52
{
53
	int			 sock, onoff;
54
	struct sockaddr_in	 sin4;
55
	struct udpsock		*udpsock;
56
57
	if ((udpsock = calloc(1, sizeof(struct udpsock))) == NULL)
58
		fatal("could not create udpsock");
59
60
	memset(&sin4, 0, sizeof(sin4));
61
	if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
62
		fatal("creating a socket failed for udp");
63
64
	onoff = 1;
65
	if (setsockopt(sock, IPPROTO_IP, IP_RECVIF, &onoff, sizeof(onoff)) !=
66
	    0)
67
		fatal("setsocketopt IP_RECVIF failed for udp");
68
69
	sin4.sin_family = AF_INET;
70
	sin4.sin_len = sizeof(sin4);
71
	sin4.sin_addr = bindaddr;
72
	sin4.sin_port = server_port;
73
74
	if (bind(sock, (struct sockaddr *)&sin4, sizeof(sin4)) != 0)
75
		fatal("bind failed for udp");
76
77
	add_protocol("udp", sock, udpsock_handler, (void *)(intptr_t)udpsock);
78
	log_info("Listening on %s:%d/udp.", inet_ntoa(sin4.sin_addr),
79
	    ntohs(server_port));
80
81
	udpsock->sock = sock;
82
}
83
84
void
85
udpsock_handler(struct protocol *protocol)
86
{
87
	int			 sockio;
88
	char			 cbuf[256], ifname[IF_NAMESIZE];
89
	ssize_t			 len;
90
	struct udpsock		*udpsock = protocol->local;
91
	struct msghdr		 m;
92
	struct cmsghdr		*cm;
93
	struct iovec		 iov[1];
94
	struct sockaddr_storage	 ss;
95
	struct sockaddr_in	*sin4;
96
	struct sockaddr_dl	*sdl = NULL;
97
	struct interface_info	 iface;
98
	struct iaddr		 from, addr;
99
	unsigned char		 packetbuf[4095];
100
	struct dhcp_packet	*packet = (struct dhcp_packet *)packetbuf;
101
	struct hardware		 hw;
102
	struct ifreq		 ifr;
103
	struct subnet		*subnet;
104
105
	memset(&hw, 0, sizeof(hw));
106
107
	iov[0].iov_base = packetbuf;
108
	iov[0].iov_len = sizeof(packetbuf);
109
	memset(&m, 0, sizeof(m));
110
	m.msg_name = &ss;
111
	m.msg_namelen = sizeof(ss);
112
	m.msg_iov = iov;
113
	m.msg_iovlen = 1;
114
	m.msg_control = cbuf;
115
	m.msg_controllen = sizeof(cbuf);
116
117
	memset(&iface, 0, sizeof(iface));
118
	if ((len = recvmsg(udpsock->sock, &m, 0)) < 0) {
119
		log_warn("receiving a DHCP message failed");
120
		return;
121
	}
122
	if (ss.ss_family != AF_INET) {
123
		log_warnx("received DHCP message is not AF_INET");
124
		return;
125
	}
126
	sin4 = (struct sockaddr_in *)&ss;
127
	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m);
128
	    m.msg_controllen != 0 && cm;
129
	    cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) {
130
		if (cm->cmsg_level == IPPROTO_IP &&
131
		    cm->cmsg_type == IP_RECVIF)
132
			sdl = (struct sockaddr_dl *)CMSG_DATA(cm);
133
	}
134
	if (sdl == NULL) {
135
		log_warnx("could not get the received interface by IP_RECVIF");
136
		return;
137
	}
138
	if_indextoname(sdl->sdl_index, ifname);
139
140
	if ((sockio = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
141
		log_warn("socket creation failed");
142
		return;
143
	}
144
	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
145
	if (ioctl(sockio, SIOCGIFADDR, &ifr, sizeof(ifr)) != 0) {
146
		log_warn("Failed to get address for %s", ifname);
147
		close(sockio);
148
		return;
149
	}
150
	close(sockio);
151
152
	if (ifr.ifr_addr.sa_family != AF_INET)
153
		return;
154
155
	iface.is_udpsock = 1;
156
	iface.send_packet = udpsock_send_packet;
157
	iface.wfdesc = udpsock->sock;
158
	iface.ifp = &ifr;
159
	iface.index = sdl->sdl_index;
160
	iface.primary_address =
161
	    ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
162
	strlcpy(iface.name, ifname, sizeof(iface.name));
163
164
	addr.len = 4;
165
	memcpy(&addr.iabuf, &iface.primary_address, addr.len);
166
167
	if ((subnet = find_subnet(addr)) == NULL)
168
		return;
169
	iface.shared_network = subnet->shared_network ;
170
	from.len = 4;
171
	memcpy(&from.iabuf, &sin4->sin_addr, from.len);
172
	do_packet(&iface, packet, len, sin4->sin_port, from, &hw);
173
}
174
175
ssize_t
176
udpsock_send_packet(struct interface_info *interface, struct dhcp_packet *raw,
177
    size_t len, struct in_addr from, struct sockaddr_in *to,
178
    struct hardware *hto)
179
{
180
	return (sendto(interface->wfdesc, raw, len, 0, (struct sockaddr *)to,
181
	    sizeof(struct sockaddr_in)));
182
}