1/*
2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2010 Roy Marples <roy@marples.name>
4 * All rights reserved
5
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/types.h>
29#include <sys/ioctl.h>
30#include <sys/param.h>
31#include <sys/socket.h>
32#include <sys/time.h>
33
34#include <arpa/inet.h>
35#include <net/if.h>
36#include <net/if_arp.h>
37#ifdef AF_LINK
38#  include <net/if_dl.h>
39#  include <net/if_types.h>
40#endif
41#include <netinet/in_systm.h>
42#include <netinet/in.h>
43#include <netinet/ip.h>
44#define __FAVOR_BSD /* Nasty glibc hack so we can use BSD semantics for UDP */
45#include <netinet/udp.h>
46#undef __FAVOR_BSD
47#ifdef AF_PACKET
48#  include <netpacket/packet.h>
49#endif
50#ifdef SIOCGIFMEDIA
51#  include <net/if_media.h>
52#endif
53
54#include <ctype.h>
55#include <errno.h>
56#include <ifaddrs.h>
57#include <fnmatch.h>
58#include <stddef.h>
59#include <stdio.h>
60#include <stdlib.h>
61#include <string.h>
62#include <syslog.h>
63#include <unistd.h>
64
65#include "config.h"
66#include "common.h"
67#include "dhcp.h"
68#include "if-options.h"
69#include "net.h"
70#include "signals.h"
71
72static char hwaddr_buffer[(HWADDR_LEN * 3) + 1];
73
74int socket_afnet = -1;
75
76int
77inet_ntocidr(struct in_addr address)
78{
79	int cidr = 0;
80	uint32_t mask = htonl(address.s_addr);
81
82	while (mask) {
83		cidr++;
84		mask <<= 1;
85	}
86	return cidr;
87}
88
89int
90inet_cidrtoaddr(int cidr, struct in_addr *addr)
91{
92	int ocets;
93
94	if (cidr < 1 || cidr > 32) {
95		errno = EINVAL;
96		return -1;
97	}
98	ocets = (cidr + 7) / 8;
99
100	addr->s_addr = 0;
101	if (ocets > 0) {
102		memset(&addr->s_addr, 255, (size_t)ocets - 1);
103		memset((unsigned char *)&addr->s_addr + (ocets - 1),
104		    (256 - (1 << (32 - cidr) % 8)), 1);
105	}
106
107	return 0;
108}
109
110uint32_t
111get_netmask(uint32_t addr)
112{
113	uint32_t dst;
114
115	if (addr == 0)
116		return 0;
117
118	dst = htonl(addr);
119	if (IN_CLASSA(dst))
120		return ntohl(IN_CLASSA_NET);
121	if (IN_CLASSB(dst))
122		return ntohl(IN_CLASSB_NET);
123	if (IN_CLASSC(dst))
124		return ntohl(IN_CLASSC_NET);
125
126	return 0;
127}
128
129char *
130hwaddr_ntoa(const unsigned char *hwaddr, size_t hwlen)
131{
132	char *p = hwaddr_buffer;
133	size_t i;
134
135	for (i = 0; i < hwlen && i < HWADDR_LEN; i++) {
136		if (i > 0)
137			*p ++= ':';
138		p += snprintf(p, 3, "%.2x", hwaddr[i]);
139	}
140
141	*p ++= '\0';
142
143	return hwaddr_buffer;
144}
145
146size_t
147hwaddr_aton(unsigned char *buffer, const char *addr)
148{
149	char c[3];
150	const char *p = addr;
151	unsigned char *bp = buffer;
152	size_t len = 0;
153
154	c[2] = '\0';
155	while (*p) {
156		c[0] = *p++;
157		c[1] = *p++;
158		/* Ensure that digits are hex */
159		if (isxdigit((unsigned char)c[0]) == 0 ||
160		    isxdigit((unsigned char)c[1]) == 0)
161		{
162			errno = EINVAL;
163			return 0;
164		}
165		/* We should have at least two entries 00:01 */
166		if (len == 0 && *p == '\0') {
167			errno = EINVAL;
168			return 0;
169		}
170		/* Ensure that next data is EOL or a seperator with data */
171		if (!(*p == '\0' || (*p == ':' && *(p + 1) != '\0'))) {
172			errno = EINVAL;
173			return 0;
174		}
175		if (*p)
176			p++;
177		if (bp)
178			*bp++ = (unsigned char)strtol(c, NULL, 16);
179		len++;
180	}
181	return len;
182}
183
184struct interface *
185init_interface(const char *ifname)
186{
187	struct ifreq ifr;
188	struct interface *iface = NULL;
189
190	memset(&ifr, 0, sizeof(ifr));
191	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
192	if (ioctl(socket_afnet, SIOCGIFFLAGS, &ifr) == -1)
193		goto eexit;
194
195	iface = xzalloc(sizeof(*iface));
196	strlcpy(iface->name, ifname, sizeof(iface->name));
197	iface->flags = ifr.ifr_flags;
198	/* We reserve the 100 range for virtual interfaces, if and when
199	 * we can work them out. */
200	iface->metric = 200 + if_nametoindex(iface->name);
201	if (getifssid(ifname, iface->ssid) != -1) {
202		iface->wireless = 1;
203		iface->metric += 100;
204	}
205
206	if (ioctl(socket_afnet, SIOCGIFMTU, &ifr) == -1)
207		goto eexit;
208	/* Ensure that the MTU is big enough for DHCP */
209	if (ifr.ifr_mtu < MTU_MIN) {
210		ifr.ifr_mtu = MTU_MIN;
211		strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
212		if (ioctl(socket_afnet, SIOCSIFMTU, &ifr) == -1)
213			goto eexit;
214	}
215
216	snprintf(iface->leasefile, sizeof(iface->leasefile),
217	    LEASEFILE, ifname);
218	/* 0 is a valid fd, so init to -1 */
219	iface->raw_fd = -1;
220	iface->udp_fd = -1;
221	iface->arp_fd = -1;
222	goto exit;
223
224eexit:
225	free(iface);
226	iface = NULL;
227exit:
228	return iface;
229}
230
231void
232free_interface(struct interface *iface)
233{
234	if (!iface)
235		return;
236	if (iface->state) {
237		free_options(iface->state->options);
238		free(iface->state->old);
239		free(iface->state->new);
240		free(iface->state->offer);
241		free(iface->state);
242	}
243	free(iface->clientid);
244	free(iface);
245}
246
247int
248carrier_status(struct interface *iface)
249{
250	int ret;
251	struct ifreq ifr;
252#ifdef SIOCGIFMEDIA
253	struct ifmediareq ifmr;
254#endif
255#ifdef __linux__
256	char *p;
257#endif
258
259	memset(&ifr, 0, sizeof(ifr));
260	strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
261#ifdef __linux__
262	/* We can only test the real interface up */
263	if ((p = strchr(ifr.ifr_name, ':')))
264		*p = '\0';
265#endif
266
267	if (ioctl(socket_afnet, SIOCGIFFLAGS, &ifr) == -1)
268		return -1;
269	iface->flags = ifr.ifr_flags;
270
271	ret = -1;
272#ifdef SIOCGIFMEDIA
273	memset(&ifmr, 0, sizeof(ifmr));
274	strlcpy(ifmr.ifm_name, iface->name, sizeof(ifmr.ifm_name));
275	if (ioctl(socket_afnet, SIOCGIFMEDIA, &ifmr) != -1 &&
276	    ifmr.ifm_status & IFM_AVALID)
277		ret = (ifmr.ifm_status & IFM_ACTIVE) ? 1 : 0;
278#endif
279	if (ret == -1)
280		ret = (ifr.ifr_flags & IFF_RUNNING) ? 1 : 0;
281	return ret;
282}
283
284int
285up_interface(struct interface *iface)
286{
287	struct ifreq ifr;
288	int retval = -1;
289#ifdef __linux__
290	char *p;
291#endif
292
293	memset(&ifr, 0, sizeof(ifr));
294	strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
295#ifdef __linux__
296	/* We can only bring the real interface up */
297	if ((p = strchr(ifr.ifr_name, ':')))
298		*p = '\0';
299#endif
300	if (ioctl(socket_afnet, SIOCGIFFLAGS, &ifr) == 0) {
301		if ((ifr.ifr_flags & IFF_UP))
302			retval = 0;
303		else {
304			ifr.ifr_flags |= IFF_UP;
305			if (ioctl(socket_afnet, SIOCSIFFLAGS, &ifr) == 0)
306				retval = 0;
307		}
308		iface->flags = ifr.ifr_flags;
309	}
310	return retval;
311}
312
313struct interface *
314discover_interfaces(int argc, char * const *argv)
315{
316	struct ifaddrs *ifaddrs, *ifa;
317	char *p;
318	int i;
319	struct interface *ifp, *ifs, *ifl;
320#ifdef __linux__
321	char ifn[IF_NAMESIZE];
322#endif
323#ifdef AF_LINK
324	const struct sockaddr_dl *sdl;
325#ifdef IFLR_ACTIVE
326	struct if_laddrreq iflr;
327	int socket_aflink;
328
329	socket_aflink = socket(AF_LINK, SOCK_DGRAM, 0);
330	if (socket_aflink == -1)
331		return NULL;
332	memset(&iflr, 0, sizeof(iflr));
333#endif
334#elif AF_PACKET
335	const struct sockaddr_ll *sll;
336#endif
337
338	if (getifaddrs(&ifaddrs) == -1)
339		return NULL;
340
341	ifs = ifl = NULL;
342	for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
343		if (ifa->ifa_addr != NULL) {
344#ifdef AF_LINK
345			if (ifa->ifa_addr->sa_family != AF_LINK)
346				continue;
347#elif AF_PACKET
348			if (ifa->ifa_addr->sa_family != AF_PACKET)
349				continue;
350#endif
351		}
352
353		/* It's possible for an interface to have >1 AF_LINK.
354		 * For our purposes, we use the first one. */
355		for (ifp = ifs; ifp; ifp = ifp->next)
356			if (strcmp(ifp->name, ifa->ifa_name) == 0)
357				break;
358		if (ifp)
359			continue;
360		if (argc > 0) {
361			for (i = 0; i < argc; i++) {
362#ifdef __linux__
363				/* Check the real interface name */
364				strlcpy(ifn, argv[i], sizeof(ifn));
365				p = strchr(ifn, ':');
366				if (p)
367					*p = '\0';
368				if (strcmp(ifn, ifa->ifa_name) == 0)
369					break;
370#else
371				if (strcmp(argv[i], ifa->ifa_name) == 0)
372					break;
373#endif
374			}
375			if (i == argc)
376				continue;
377			p = argv[i];
378		} else {
379			/* -1 means we're discovering against a specific
380			 * interface, but we still need the below rules
381			 * to apply. */
382			if (argc == -1 && strcmp(argv[0], ifa->ifa_name) != 0)
383				continue;
384			for (i = 0; i < ifdc; i++)
385				if (!fnmatch(ifdv[i], ifa->ifa_name, 0))
386					break;
387			if (i < ifdc)
388				continue;
389			for (i = 0; i < ifac; i++)
390				if (!fnmatch(ifav[i], ifa->ifa_name, 0))
391					break;
392			if (ifac && i == ifac)
393				continue;
394			p = ifa->ifa_name;
395		}
396		if ((ifp = init_interface(p)) == NULL)
397			continue;
398
399		/* Bring the interface up if not already */
400		if (!(ifp->flags & IFF_UP)
401#ifdef SIOCGIFMEDIA
402		    && carrier_status(ifp) != -1
403#endif
404		   )
405		{
406			if (up_interface(ifp) == 0)
407				options |= DHCPCD_WAITUP;
408			else
409				syslog(LOG_ERR, "%s: up_interface: %m", ifp->name);
410		}
411
412		/* Don't allow loopback unless explicit */
413		if (ifp->flags & IFF_LOOPBACK) {
414			if (argc == 0 && ifac == 0) {
415				free_interface(ifp);
416				continue;
417			}
418		} else if (ifa->ifa_addr != NULL) {
419#ifdef AF_LINK
420			sdl = (const struct sockaddr_dl *)(void *)ifa->ifa_addr;
421
422#ifdef IFLR_ACTIVE
423			/* We need to check for active address */
424			strlcpy(iflr.iflr_name, ifp->name,
425			    sizeof(iflr.iflr_name));
426			memcpy(&iflr.addr, ifa->ifa_addr,
427			    MIN(ifa->ifa_addr->sa_len, sizeof(iflr.addr)));
428			iflr.flags = IFLR_PREFIX;
429			iflr.prefixlen = sdl->sdl_alen * NBBY;
430			if (ioctl(socket_aflink, SIOCGLIFADDR, &iflr) == -1 ||
431			    !(iflr.flags & IFLR_ACTIVE))
432			{
433				free_interface(ifp);
434				continue;
435			}
436#endif
437
438			switch(sdl->sdl_type) {
439			case IFT_ETHER:
440				ifp->family = ARPHRD_ETHER;
441				break;
442			case IFT_IEEE1394:
443				ifp->family = ARPHRD_IEEE1394;
444				break;
445			}
446			ifp->hwlen = sdl->sdl_alen;
447#ifndef CLLADDR
448#  define CLLADDR(s) ((const char *)((s)->sdl_data + (s)->sdl_nlen))
449#endif
450			memcpy(ifp->hwaddr, CLLADDR(sdl), ifp->hwlen);
451#elif AF_PACKET
452			sll = (const struct sockaddr_ll *)(void *)ifa->ifa_addr;
453			ifp->family = sll->sll_hatype;
454			ifp->hwlen = sll->sll_halen;
455			if (ifp->hwlen != 0)
456				memcpy(ifp->hwaddr, sll->sll_addr, ifp->hwlen);
457#endif
458		}
459
460		/* We only work on ethernet by default */
461		if (!(ifp->flags & IFF_POINTOPOINT) &&
462		    ifp->family != ARPHRD_ETHER)
463		{
464			if (argc == 0 && ifac == 0) {
465				free_interface(ifp);
466				continue;
467			}
468			switch (ifp->family) {
469			case ARPHRD_IEEE1394: /* FALLTHROUGH */
470			case ARPHRD_INFINIBAND:
471				/* We don't warn for supported families */
472				break;
473			default:
474				syslog(LOG_WARNING,
475				    "%s: unknown hardware family", p);
476			}
477		}
478
479		/* Handle any platform init for the interface */
480		if (if_init(ifp) == -1) {
481			syslog(LOG_ERR, "%s: if_init: %m", p);
482			free_interface(ifp);
483			continue;
484		}
485
486		if (ifl)
487			ifl->next = ifp;
488		else
489			ifs = ifp;
490		ifl = ifp;
491	}
492	freeifaddrs(ifaddrs);
493
494#ifdef IFLR_ACTIVE
495	close(socket_aflink);
496#endif
497
498	return ifs;
499}
500
501int
502do_address(const char *ifname,
503    struct in_addr *addr, struct in_addr *net, struct in_addr *dst, int act)
504{
505	struct ifaddrs *ifaddrs, *ifa;
506	const struct sockaddr_in *a, *n, *d;
507	int retval;
508
509	if (getifaddrs(&ifaddrs) == -1)
510		return -1;
511
512	retval = 0;
513	for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
514		if (ifa->ifa_addr == NULL ||
515		    ifa->ifa_addr->sa_family != AF_INET ||
516		    strcmp(ifa->ifa_name, ifname) != 0)
517			continue;
518		a = (const struct sockaddr_in *)(void *)ifa->ifa_addr;
519		n = (const struct sockaddr_in *)(void *)ifa->ifa_netmask;
520		if (ifa->ifa_flags & IFF_POINTOPOINT)
521			d = (const struct sockaddr_in *)(void *)
522			    ifa->ifa_dstaddr;
523		else
524			d = NULL;
525		if (act == 1) {
526			addr->s_addr = a->sin_addr.s_addr;
527			net->s_addr = n->sin_addr.s_addr;
528			if (dst) {
529				/* TODO: Fix getifaddrs() */
530				if ((ifa->ifa_flags & IFF_POINTOPOINT) && d)
531					dst->s_addr = d->sin_addr.s_addr;
532				else
533					dst->s_addr = INADDR_ANY;
534			}
535			retval = 1;
536			break;
537		}
538		if (addr->s_addr == a->sin_addr.s_addr &&
539		    (net == NULL || net->s_addr == n->sin_addr.s_addr))
540		{
541			retval = 1;
542			break;
543		}
544	}
545	freeifaddrs(ifaddrs);
546	return retval;
547}
548
549int
550do_mtu(const char *ifname, short int mtu)
551{
552	struct ifreq ifr;
553	int r;
554
555	memset(&ifr, 0, sizeof(ifr));
556	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
557	ifr.ifr_mtu = mtu;
558	r = ioctl(socket_afnet, mtu ? SIOCSIFMTU : SIOCGIFMTU, &ifr);
559	if (r == -1)
560		return -1;
561	return ifr.ifr_mtu;
562}
563
564void
565free_routes(struct rt *routes)
566{
567	struct rt *r;
568
569	while (routes) {
570		r = routes->next;
571		free(routes);
572		routes = r;
573	}
574}
575
576int
577open_udp_socket(struct interface *iface)
578{
579	int s;
580	struct sockaddr_in sin;
581	int n;
582#ifdef SO_BINDTODEVICE
583	struct ifreq ifr;
584	char *p;
585#endif
586
587	if ((s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
588		return -1;
589
590	n = 1;
591	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n)) == -1)
592		goto eexit;
593#ifdef SO_BINDTODEVICE
594	memset(&ifr, 0, sizeof(ifr));
595	strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
596	/* We can only bind to the real device */
597	p = strchr(ifr.ifr_name, ':');
598	if (p)
599		*p = '\0';
600	if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, &ifr,
601		sizeof(ifr)) == -1)
602		goto eexit;
603#endif
604	/* As we don't use this socket for receiving, set the
605	 * receive buffer to 1 */
606	n = 1;
607	if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) == -1)
608		goto eexit;
609	memset(&sin, 0, sizeof(sin));
610	sin.sin_family = AF_INET;
611	sin.sin_port = htons(DHCP_CLIENT_PORT);
612	sin.sin_addr.s_addr = iface->addr.s_addr;
613	if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == -1)
614		goto eexit;
615
616	iface->udp_fd = s;
617	set_cloexec(s);
618	return 0;
619
620eexit:
621	close(s);
622	return -1;
623}
624
625ssize_t
626send_packet(const struct interface *iface, struct in_addr to,
627    const uint8_t *data, ssize_t len)
628{
629	struct sockaddr_in sin;
630
631	memset(&sin, 0, sizeof(sin));
632	sin.sin_family = AF_INET;
633	sin.sin_addr.s_addr = to.s_addr;
634	sin.sin_port = htons(DHCP_SERVER_PORT);
635	return sendto(iface->udp_fd, data, len, 0,
636	    (struct sockaddr *)&sin, sizeof(sin));
637}
638
639struct udp_dhcp_packet
640{
641	struct ip ip;
642	struct udphdr udp;
643	struct dhcp_message dhcp;
644};
645const size_t udp_dhcp_len = sizeof(struct udp_dhcp_packet);
646
647static uint16_t
648checksum(const void *data, uint16_t len)
649{
650	const uint8_t *addr = data;
651	uint32_t sum = 0;
652
653	while (len > 1) {
654		sum += addr[0] * 256 + addr[1];
655		addr += 2;
656		len -= 2;
657	}
658
659	if (len == 1)
660		sum += *addr * 256;
661
662	sum = (sum >> 16) + (sum & 0xffff);
663	sum += (sum >> 16);
664
665	sum = htons(sum);
666
667	return ~sum;
668}
669
670ssize_t
671make_udp_packet(uint8_t **packet, const uint8_t *data, size_t length,
672    struct in_addr source, struct in_addr dest)
673{
674	struct udp_dhcp_packet *udpp;
675	struct ip *ip;
676	struct udphdr *udp;
677
678	udpp = xzalloc(sizeof(*udpp));
679	ip = &udpp->ip;
680	udp = &udpp->udp;
681
682	/* OK, this is important :)
683	 * We copy the data to our packet and then create a small part of the
684	 * ip structure and an invalid ip_len (basically udp length).
685	 * We then fill the udp structure and put the checksum
686	 * of the whole packet into the udp checksum.
687	 * Finally we complete the ip structure and ip checksum.
688	 * If we don't do the ordering like so then the udp checksum will be
689	 * broken, so find another way of doing it! */
690
691	memcpy(&udpp->dhcp, data, length);
692
693	ip->ip_p = IPPROTO_UDP;
694	ip->ip_src.s_addr = source.s_addr;
695	if (dest.s_addr == 0)
696		ip->ip_dst.s_addr = INADDR_BROADCAST;
697	else
698		ip->ip_dst.s_addr = dest.s_addr;
699
700	udp->uh_sport = htons(DHCP_CLIENT_PORT);
701	udp->uh_dport = htons(DHCP_SERVER_PORT);
702	udp->uh_ulen = htons(sizeof(*udp) + length);
703	ip->ip_len = udp->uh_ulen;
704	udp->uh_sum = checksum(udpp, sizeof(*udpp));
705
706	ip->ip_v = IPVERSION;
707	ip->ip_hl = sizeof(*ip) >> 2;
708	ip->ip_id = arc4random() & UINT16_MAX;
709	ip->ip_ttl = IPDEFTTL;
710	ip->ip_len = htons(sizeof(*ip) + sizeof(*udp) + length);
711	ip->ip_sum = checksum(ip, sizeof(*ip));
712
713	*packet = (uint8_t *)udpp;
714	return sizeof(*ip) + sizeof(*udp) + length;
715}
716
717ssize_t
718get_udp_data(const uint8_t **data, const uint8_t *udp)
719{
720	struct udp_dhcp_packet packet;
721
722	memcpy(&packet, udp, sizeof(packet));
723	*data = udp + offsetof(struct udp_dhcp_packet, dhcp);
724	return ntohs(packet.ip.ip_len) -
725	    sizeof(packet.ip) -
726	    sizeof(packet.udp);
727}
728
729int
730valid_udp_packet(const uint8_t *data, size_t data_len, struct in_addr *from)
731{
732	struct udp_dhcp_packet packet;
733	uint16_t bytes, udpsum;
734
735	if (data_len < sizeof(packet.ip)) {
736		if (from)
737			from->s_addr = INADDR_ANY;
738		errno = EINVAL;
739		return -1;
740	}
741	memcpy(&packet, data, MIN(data_len, sizeof(packet)));
742	if (from)
743		from->s_addr = packet.ip.ip_src.s_addr;
744	if (data_len > sizeof(packet)) {
745		errno = EINVAL;
746		return -1;
747	}
748	if (checksum(&packet.ip, sizeof(packet.ip)) != 0) {
749		errno = EINVAL;
750		return -1;
751	}
752
753	bytes = ntohs(packet.ip.ip_len);
754	if (data_len < bytes) {
755		errno = EINVAL;
756		return -1;
757	}
758	udpsum = packet.udp.uh_sum;
759	packet.udp.uh_sum = 0;
760	packet.ip.ip_hl = 0;
761	packet.ip.ip_v = 0;
762	packet.ip.ip_tos = 0;
763	packet.ip.ip_len = packet.udp.uh_ulen;
764	packet.ip.ip_id = 0;
765	packet.ip.ip_off = 0;
766	packet.ip.ip_ttl = 0;
767	packet.ip.ip_sum = 0;
768	if (udpsum && checksum(&packet, bytes) != udpsum) {
769		errno = EINVAL;
770		return -1;
771	}
772
773	return 0;
774}
775