1 /*
2  * dhcpcd - DHCP client daemon
3  * Copyright (c) 2013 Antti Kantee <pooka@iki.fi>
4  * Copyright (c) 2006-2010 Roy Marples <roy@marples.name>
5  * All rights reserved
6 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/param.h>
30 #include <sys/cprng.h>
31 #include <sys/ioctl.h>
32 #include <sys/kmem.h>
33 #include <sys/param.h>
34 #include <sys/socket.h>
35 #include <sys/time.h>
36 
37 #include <net/if.h>
38 #include <net/if_arp.h>
39 #include <net/if_dl.h>
40 #include <net/if_types.h>
41 #include <netinet/in_systm.h>
42 #include <netinet/in.h>
43 #include <netinet/ip.h>
44 #include <netinet/udp.h>
45 #include <net/if_media.h>
46 
47 #include "dhcp_common.h"
48 #include "dhcp_dhcp.h"
49 #include "dhcp_if-options.h"
50 #include "dhcp_net.h"
51 
52 static char hwaddr_buffer[(HWADDR_LEN * 3) + 1];
53 
54 struct socket *socket_afnet;
55 
56 int
inet_ntocidr(struct in_addr address)57 inet_ntocidr(struct in_addr address)
58 {
59 	int cidr = 0;
60 	uint32_t mask = htonl(address.s_addr);
61 
62 	while (mask) {
63 		cidr++;
64 		mask <<= 1;
65 	}
66 	return cidr;
67 }
68 
69 int
inet_cidrtoaddr(int cidr,struct in_addr * addr)70 inet_cidrtoaddr(int cidr, struct in_addr *addr)
71 {
72 	int ocets;
73 
74 	if (cidr < 1 || cidr > 32) {
75 		return EINVAL;
76 	}
77 	ocets = (cidr + 7) / 8;
78 
79 	addr->s_addr = 0;
80 	if (ocets > 0) {
81 		memset(&addr->s_addr, 255, (size_t)ocets - 1);
82 		memset((unsigned char *)&addr->s_addr + (ocets - 1),
83 		    (256 - (1 << (32 - cidr) % 8)), 1);
84 	}
85 
86 	return 0;
87 }
88 
89 uint32_t
get_netmask(uint32_t addr)90 get_netmask(uint32_t addr)
91 {
92 	uint32_t dst;
93 
94 	if (addr == 0)
95 		return 0;
96 
97 	dst = htonl(addr);
98 	if (IN_CLASSA(dst))
99 		return ntohl(IN_CLASSA_NET);
100 	if (IN_CLASSB(dst))
101 		return ntohl(IN_CLASSB_NET);
102 	if (IN_CLASSC(dst))
103 		return ntohl(IN_CLASSC_NET);
104 
105 	return 0;
106 }
107 
108 char *
hwaddr_ntoa(const unsigned char * hwaddr,size_t hwlen)109 hwaddr_ntoa(const unsigned char *hwaddr, size_t hwlen)
110 {
111 	char *p = hwaddr_buffer;
112 	size_t i;
113 
114 	for (i = 0; i < hwlen && i < HWADDR_LEN; i++) {
115 		if (i > 0)
116 			*p ++= ':';
117 		p += snprintf(p, 3, "%.2x", hwaddr[i]);
118 	}
119 
120 	*p ++= '\0';
121 
122 	return hwaddr_buffer;
123 }
124 
125 size_t
hwaddr_aton(unsigned char * buffer,const char * addr)126 hwaddr_aton(unsigned char *buffer, const char *addr)
127 {
128 	char c[3];
129 	const char *p = addr;
130 	unsigned char *bp = buffer;
131 	size_t len = 0;
132 
133 	c[2] = '\0';
134 	while (*p) {
135 		c[0] = *p++;
136 		c[1] = *p++;
137 		/* Ensure that digits are hex */
138 		if (isxdigit((unsigned char)c[0]) == 0 ||
139 		    isxdigit((unsigned char)c[1]) == 0)
140 		{
141 			return EINVAL;
142 		}
143 		/* We should have at least two entries 00:01 */
144 		if (len == 0 && *p == '\0') {
145 			return EINVAL;
146 		}
147 		/* Ensure that next data is EOL or a seperator with data */
148 		if (!(*p == '\0' || (*p == ':' && *(p + 1) != '\0'))) {
149 			return EINVAL;
150 		}
151 		if (*p)
152 			p++;
153 		if (bp)
154 			*bp++ = (unsigned char)strtoll(c, NULL, 16);
155 		len++;
156 	}
157 	return len;
158 }
159 
160 int
init_interface(const char * ifname,struct interface ** ifacep)161 init_interface(const char *ifname, struct interface **ifacep)
162 {
163 	struct ifnet *ifp;
164 	struct ifreq ifr;
165 	struct interface *iface = NULL;
166 	int error;
167 
168 	ifp = ifunit(ifname);
169 	if (!ifp)
170 		return EXDEV;
171 
172 	memset(&ifr, 0, sizeof(ifr));
173 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
174 	if ((error = ifioctl(socket_afnet, SIOCGIFFLAGS, &ifr, curlwp)) != 0)
175 		goto eexit;
176 
177 	iface = kmem_zalloc(sizeof(*iface), KM_SLEEP);
178 	strlcpy(iface->name, ifname, sizeof(iface->name));
179 	iface->ifp = ifp;
180 	iface->flags = ifr.ifr_flags;
181 	/* We reserve the 100 range for virtual interfaces, if and when
182 	 * we can work them out. */
183 	iface->metric = 200 + iface->ifp->if_index;
184 	if (getifssid(ifname, iface->ssid) == 0) {
185 		iface->wireless = 1;
186 		iface->metric += 100;
187 	}
188 
189 	if (ifioctl(socket_afnet, SIOCGIFMTU, &ifr, curlwp) != 0)
190 		goto eexit;
191 	/* Ensure that the MTU is big enough for DHCP */
192 	if (ifr.ifr_mtu < MTU_MIN) {
193 		ifr.ifr_mtu = MTU_MIN;
194 		strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
195 		if ((error = ifioctl(socket_afnet,
196 		    SIOCSIFMTU, &ifr, curlwp)) != 0)
197 			goto eexit;
198 	}
199 
200 	/* 0 is a valid fd, so init to -1 */
201 	iface->raw_fd = -1;
202 	iface->udp_fd = -1;
203 	iface->arp_fd = -1;
204 
205  eexit:
206 	if (error) {
207 		kmem_free(iface, sizeof(*iface));
208 		iface = NULL;
209 	}
210 
211 	*ifacep = iface;
212 	return error;
213 }
214 
215 int
carrier_status(struct interface * iface)216 carrier_status(struct interface *iface)
217 {
218 	int ret;
219 	struct ifreq ifr;
220 	struct ifmediareq ifmr;
221 
222 	memset(&ifr, 0, sizeof(ifr));
223 	strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
224 
225 	if ((ret = ifioctl(socket_afnet, SIOCGIFFLAGS, &ifr, curlwp)) != 0)
226 		return ret;
227 	iface->flags = ifr.ifr_flags;
228 
229 	ret = -1;
230 	memset(&ifmr, 0, sizeof(ifmr));
231 	strlcpy(ifmr.ifm_name, iface->name, sizeof(ifmr.ifm_name));
232 	if (ifioctl(socket_afnet, SIOCGIFMEDIA, &ifmr, curlwp) == 0 &&
233 	    ifmr.ifm_status & IFM_AVALID)
234 		ret = (ifmr.ifm_status & IFM_ACTIVE) ? 1 : 0;
235 	if (ret != 0)
236 		ret = (ifr.ifr_flags & IFF_RUNNING) ? 1 : 0;
237 	return ret;
238 }
239 
240 void
up_interface(struct interface * iface)241 up_interface(struct interface *iface)
242 {
243 
244 	if_up(iface->ifp);
245 }
246 
247 int
do_address(const char * ifname,struct in_addr * addr,struct in_addr * net,struct in_addr * dst,int act)248 do_address(const char *ifname,
249     struct in_addr *addr, struct in_addr *net, struct in_addr *dst, int act)
250 {
251 	const struct sockaddr_in *a, *n, *d;
252 	struct ifnet *ifp = ifunit(ifname);
253 	struct ifaddr *ifa;
254 	int retval;
255 
256 	if (ifp == NULL)
257 		return 0;
258 
259 	retval = 0;
260 	IFADDR_FOREACH(ifa, ifp) {
261 		if (ifa->ifa_addr->sa_family != AF_INET)
262 			continue;
263 
264 		a = (const struct sockaddr_in *)(void *)ifa->ifa_addr;
265 		n = (const struct sockaddr_in *)(void *)ifa->ifa_netmask;
266 		if (ifa->ifa_flags & IFF_POINTOPOINT)
267 			d = (const struct sockaddr_in *)(void *)
268 			    ifa->ifa_dstaddr;
269 		else
270 			d = NULL;
271 		if (act == 1) {
272 			addr->s_addr = a->sin_addr.s_addr;
273 			net->s_addr = n->sin_addr.s_addr;
274 			if (dst) {
275 				if (ifa->ifa_flags & IFF_POINTOPOINT)
276 					dst->s_addr = d->sin_addr.s_addr;
277 				else
278 					dst->s_addr = INADDR_ANY;
279 			}
280 			retval = 1;
281 			break;
282 		}
283 		if (addr->s_addr == a->sin_addr.s_addr &&
284 		    (net == NULL || net->s_addr == n->sin_addr.s_addr))
285 		{
286 			retval = 1;
287 			break;
288 		}
289 	}
290 
291 	return retval;
292 }
293 
294 int
do_mtu(const char * ifname,short int mtu)295 do_mtu(const char *ifname, short int mtu)
296 {
297 	struct ifreq ifr;
298 
299 	memset(&ifr, 0, sizeof(ifr));
300 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
301 	ifr.ifr_mtu = mtu;
302 	if (ifioctl(socket_afnet, mtu ? SIOCSIFMTU : SIOCGIFMTU, &ifr, curlwp))
303 		return -1;
304 	return ifr.ifr_mtu;
305 }
306 
307 void
free_routes(struct rt * routes)308 free_routes(struct rt *routes)
309 {
310 	struct rt *r;
311 
312 	while (routes) {
313 		r = routes->next;
314 		kmem_free(routes, sizeof(*r));
315 		routes = r;
316 	}
317 }
318 
319 struct udp_dhcp_packet
320 {
321 	struct ip ip;
322 	struct udphdr udp;
323 	struct dhcp_message dhcp;
324 };
325 const size_t udp_dhcp_len = sizeof(struct udp_dhcp_packet);
326 
327 static uint16_t
checksum(const void * data,uint16_t len)328 checksum(const void *data, uint16_t len)
329 {
330 	const uint8_t *addr = data;
331 	uint32_t sum = 0;
332 
333 	while (len > 1) {
334 		sum += addr[0] * 256 + addr[1];
335 		addr += 2;
336 		len -= 2;
337 	}
338 
339 	if (len == 1)
340 		sum += *addr * 256;
341 
342 	sum = (sum >> 16) + (sum & 0xffff);
343 	sum += (sum >> 16);
344 
345 	sum = htons(sum);
346 
347 	return ~sum;
348 }
349 
350 ssize_t
make_udp_packet(uint8_t ** packet,const uint8_t * data,size_t length,struct in_addr source,struct in_addr dest)351 make_udp_packet(uint8_t **packet, const uint8_t *data, size_t length,
352     struct in_addr source, struct in_addr dest)
353 {
354 	struct udp_dhcp_packet *udpp;
355 	struct ip *ip;
356 	struct udphdr *udp;
357 
358 	udpp = kmem_zalloc(sizeof(*udpp), KM_SLEEP);
359 	ip = &udpp->ip;
360 	udp = &udpp->udp;
361 
362 	/* OK, this is important :)
363 	 * We copy the data to our packet and then create a small part of the
364 	 * ip structure and an invalid ip_len (basically udp length).
365 	 * We then fill the udp structure and put the checksum
366 	 * of the whole packet into the udp checksum.
367 	 * Finally we complete the ip structure and ip checksum.
368 	 * If we don't do the ordering like so then the udp checksum will be
369 	 * broken, so find another way of doing it! */
370 
371 	memcpy(&udpp->dhcp, data, length);
372 
373 	ip->ip_p = IPPROTO_UDP;
374 	ip->ip_src.s_addr = source.s_addr;
375 	if (dest.s_addr == 0)
376 		ip->ip_dst.s_addr = INADDR_BROADCAST;
377 	else
378 		ip->ip_dst.s_addr = dest.s_addr;
379 
380 	udp->uh_sport = htons(DHCP_CLIENT_PORT);
381 	udp->uh_dport = htons(DHCP_SERVER_PORT);
382 	udp->uh_ulen = htons(sizeof(*udp) + length);
383 	ip->ip_len = udp->uh_ulen;
384 	udp->uh_sum = checksum(udpp, sizeof(*udpp));
385 
386 	ip->ip_v = IPVERSION;
387 	ip->ip_hl = sizeof(*ip) >> 2;
388 	ip->ip_id = cprng_fast32() & UINT16_MAX;
389 	ip->ip_ttl = IPDEFTTL;
390 	ip->ip_len = htons(sizeof(*ip) + sizeof(*udp) + length);
391 	ip->ip_sum = checksum(ip, sizeof(*ip));
392 
393 	*packet = (uint8_t *)udpp;
394 	return sizeof(*ip) + sizeof(*udp) + length;
395 }
396 
397 ssize_t
get_udp_data(const uint8_t ** data,const uint8_t * udp)398 get_udp_data(const uint8_t **data, const uint8_t *udp)
399 {
400 	struct udp_dhcp_packet packet;
401 
402 	memcpy(&packet, udp, sizeof(packet));
403 	*data = udp + offsetof(struct udp_dhcp_packet, dhcp);
404 	return ntohs(packet.ip.ip_len) -
405 	    sizeof(packet.ip) -
406 	    sizeof(packet.udp);
407 }
408 
409 int
valid_udp_packet(const uint8_t * data,size_t data_len,struct in_addr * from)410 valid_udp_packet(const uint8_t *data, size_t data_len, struct in_addr *from)
411 {
412 	struct udp_dhcp_packet packet;
413 	uint16_t bytes, udpsum;
414 
415 	if (data_len < sizeof(packet.ip)) {
416 		if (from)
417 			from->s_addr = INADDR_ANY;
418 		return EINVAL;
419 	}
420 	memcpy(&packet, data, MIN(data_len, sizeof(packet)));
421 	if (from)
422 		from->s_addr = packet.ip.ip_src.s_addr;
423 	if (data_len > sizeof(packet)) {
424 		return EINVAL;
425 	}
426 	if (checksum(&packet.ip, sizeof(packet.ip)) != 0) {
427 		return EINVAL;
428 	}
429 
430 	bytes = ntohs(packet.ip.ip_len);
431 	if (data_len < bytes) {
432 		return EINVAL;
433 	}
434 	udpsum = packet.udp.uh_sum;
435 	packet.udp.uh_sum = 0;
436 	packet.ip.ip_hl = 0;
437 	packet.ip.ip_v = 0;
438 	packet.ip.ip_tos = 0;
439 	packet.ip.ip_len = packet.udp.uh_ulen;
440 	packet.ip.ip_id = 0;
441 	packet.ip.ip_off = 0;
442 	packet.ip.ip_ttl = 0;
443 	packet.ip.ip_sum = 0;
444 	if (udpsum && checksum(&packet, bytes) != udpsum) {
445 		return EINVAL;
446 	}
447 
448 	return 0;
449 }
450