xref: /dragonfly/contrib/dhcpcd/src/if.c (revision 7c4f4eee)
1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3  * dhcpcd - DHCP client daemon
4  * Copyright (c) 2006-2019 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/types.h>
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
33 
34 #include "config.h"
35 
36 #include <net/if.h>
37 #include <net/if_arp.h>
38 #include <netinet/in.h>
39 #ifdef AF_LINK
40 #  include <net/if_dl.h>
41 #  include <net/if_types.h>
42 #  include <netinet/in_var.h>
43 #  undef AF_PACKET	/* Newer Illumos defines this */
44 #endif
45 #ifdef AF_PACKET
46 #  include <netpacket/packet.h>
47 #endif
48 #ifdef SIOCGIFMEDIA
49 #  include <net/if_media.h>
50 #endif
51 #include <net/route.h>
52 
53 #include <ctype.h>
54 #include <errno.h>
55 #include <ifaddrs.h>
56 #include <inttypes.h>
57 #include <fnmatch.h>
58 #include <stddef.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <unistd.h>
63 
64 #include "common.h"
65 #include "dev.h"
66 #include "dhcp.h"
67 #include "dhcp6.h"
68 #include "if.h"
69 #include "if-options.h"
70 #include "ipv4.h"
71 #include "ipv4ll.h"
72 #include "ipv6nd.h"
73 #include "logerr.h"
74 
75 #ifdef __sun
76 /* It has the ioctl, but the member is missing from the struct?
77  * No matter, our getifaddrs foo in if-sun.c will DTRT. */
78 #undef SIOCGIFHWADDR
79 #endif
80 
81 void
82 if_free(struct interface *ifp)
83 {
84 
85 	if (ifp == NULL)
86 		return;
87 #ifdef IPV4LL
88 	ipv4ll_free(ifp);
89 #endif
90 #ifdef INET
91 	dhcp_free(ifp);
92 	ipv4_free(ifp);
93 #endif
94 #ifdef DHCP6
95 	dhcp6_free(ifp);
96 #endif
97 #ifdef INET6
98 	ipv6nd_free(ifp);
99 	ipv6_free(ifp);
100 #endif
101 	rt_freeif(ifp);
102 	free_options(ifp->ctx, ifp->options);
103 	free(ifp);
104 }
105 
106 int
107 if_opensockets(struct dhcpcd_ctx *ctx)
108 {
109 
110 	if (if_opensockets_os(ctx) == -1)
111 		return -1;
112 
113 	/* We use this socket for some operations without INET. */
114 	ctx->pf_inet_fd = xsocket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
115 	if (ctx->pf_inet_fd == -1)
116 		return -1;
117 
118 	return 0;
119 }
120 
121 void
122 if_closesockets(struct dhcpcd_ctx *ctx)
123 {
124 
125 	if (ctx->pf_inet_fd != -1)
126 		close(ctx->pf_inet_fd);
127 
128 	if (ctx->priv) {
129 		if_closesockets_os(ctx);
130 		free(ctx->priv);
131 	}
132 }
133 
134 int
135 if_getflags(struct interface *ifp)
136 {
137 	struct ifreq ifr = { .ifr_flags = 0 };
138 
139 	strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
140 	if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFFLAGS, &ifr) == -1)
141 		return -1;
142 	ifp->flags = (unsigned int)ifr.ifr_flags;
143 	return 0;
144 }
145 
146 int
147 if_setflag(struct interface *ifp, short flag)
148 {
149 	struct ifreq ifr = { .ifr_flags = 0 };
150 	short f;
151 
152 	if (if_getflags(ifp) == -1)
153 		return -1;
154 
155 	f = (short)ifp->flags;
156 	if ((f & flag) == flag)
157 		return 0;
158 
159 	strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
160 	ifr.ifr_flags = f | flag;
161 	if (ioctl(ifp->ctx->pf_inet_fd, SIOCSIFFLAGS, &ifr) == -1)
162 		return -1;
163 
164 	ifp->flags = (unsigned int)ifr.ifr_flags;
165 	return 0;
166 }
167 
168 static int
169 if_hasconf(struct dhcpcd_ctx *ctx, const char *ifname)
170 {
171 	int i;
172 
173 	for (i = 0; i < ctx->ifcc; i++) {
174 		if (strcmp(ctx->ifcv[i], ifname) == 0)
175 			return 1;
176 	}
177 	return 0;
178 }
179 
180 void
181 if_markaddrsstale(struct if_head *ifs)
182 {
183 	struct interface *ifp;
184 
185 	TAILQ_FOREACH(ifp, ifs, next) {
186 #ifdef INET
187 		ipv4_markaddrsstale(ifp);
188 #endif
189 #ifdef INET6
190 		ipv6_markaddrsstale(ifp, 0);
191 #endif
192 	}
193 }
194 
195 void
196 if_learnaddrs(struct dhcpcd_ctx *ctx, struct if_head *ifs,
197     struct ifaddrs **ifaddrs)
198 {
199 	struct ifaddrs *ifa;
200 	struct interface *ifp;
201 #ifdef INET
202 	const struct sockaddr_in *addr, *net, *brd;
203 #endif
204 #ifdef INET6
205 	struct sockaddr_in6 *sin6, *net6;
206 #endif
207 	int addrflags;
208 
209 	for (ifa = *ifaddrs; ifa; ifa = ifa->ifa_next) {
210 		if (ifa->ifa_addr == NULL)
211 			continue;
212 		if ((ifp = if_find(ifs, ifa->ifa_name)) == NULL)
213 			continue;
214 #ifdef HAVE_IFADDRS_ADDRFLAGS
215 		addrflags = (int)ifa->ifa_addrflags;
216 #endif
217 		switch(ifa->ifa_addr->sa_family) {
218 #ifdef INET
219 		case AF_INET:
220 			addr = (void *)ifa->ifa_addr;
221 			net = (void *)ifa->ifa_netmask;
222 			if (ifa->ifa_flags & IFF_POINTOPOINT)
223 				brd = (void *)ifa->ifa_dstaddr;
224 			else
225 				brd = (void *)ifa->ifa_broadaddr;
226 #ifndef HAVE_IFADDRS_ADDRFLAGS
227 			addrflags = if_addrflags(ifp, &addr->sin_addr,
228 			    ifa->ifa_name);
229 			if (addrflags == -1) {
230 				if (errno != EEXIST && errno != EADDRNOTAVAIL)
231 					logerr("%s: if_addrflags", __func__);
232 				continue;
233 			}
234 #endif
235 			ipv4_handleifa(ctx, RTM_NEWADDR, ifs, ifa->ifa_name,
236 				&addr->sin_addr, &net->sin_addr,
237 				brd ? &brd->sin_addr : NULL, addrflags, 0);
238 			break;
239 #endif
240 #ifdef INET6
241 		case AF_INET6:
242 			sin6 = (void *)ifa->ifa_addr;
243 			net6 = (void *)ifa->ifa_netmask;
244 
245 #ifdef __KAME__
246 			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
247 				/* Remove the scope from the address */
248 				sin6->sin6_addr.s6_addr[2] =
249 				    sin6->sin6_addr.s6_addr[3] = '\0';
250 #endif
251 #ifndef HAVE_IFADDRS_ADDRFLAGS
252 			addrflags = if_addrflags6(ifp, &sin6->sin6_addr,
253 			    ifa->ifa_name);
254 			if (addrflags == -1) {
255 				if (errno != EEXIST && errno != EADDRNOTAVAIL)
256 					logerr("%s: if_addrflags6", __func__);
257 				continue;
258 			}
259 #endif
260 			ipv6_handleifa(ctx, RTM_NEWADDR, ifs,
261 			    ifa->ifa_name, &sin6->sin6_addr,
262 			    ipv6_prefixlen(&net6->sin6_addr), addrflags, 0);
263 			break;
264 #endif
265 		}
266 	}
267 
268 	freeifaddrs(*ifaddrs);
269 	*ifaddrs = NULL;
270 }
271 
272 void
273 if_deletestaleaddrs(struct if_head *ifs)
274 {
275 	struct interface *ifp;
276 
277 	TAILQ_FOREACH(ifp, ifs, next) {
278 #ifdef INET
279 		ipv4_deletestaleaddrs(ifp);
280 #endif
281 #ifdef INET6
282 		ipv6_deletestaleaddrs(ifp);
283 #endif
284 	}
285 }
286 
287 bool
288 if_valid_hwaddr(const uint8_t *hwaddr, size_t hwlen)
289 {
290 	size_t i;
291 	bool all_zeros, all_ones;
292 
293 	all_zeros = all_ones = true;
294 	for (i = 0; i < hwlen; i++) {
295 		if (hwaddr[i] != 0x00)
296 			all_zeros = false;
297 		if (hwaddr[i] != 0xff)
298 			all_ones = false;
299 		if (!all_zeros && !all_ones)
300 			return true;
301 	}
302 	return false;
303 }
304 
305 struct if_head *
306 if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs,
307     int argc, char * const *argv)
308 {
309 	struct ifaddrs *ifa;
310 	int i;
311 	unsigned int active;
312 	struct if_head *ifs;
313 	struct interface *ifp;
314 	struct if_spec spec;
315 #ifdef AF_LINK
316 	const struct sockaddr_dl *sdl;
317 #ifdef IFLR_ACTIVE
318 	struct if_laddrreq iflr = { .flags = IFLR_PREFIX };
319 	int link_fd;
320 #endif
321 #elif AF_PACKET
322 	const struct sockaddr_ll *sll;
323 #endif
324 #if defined(SIOCGIFPRIORITY) || defined(SIOCGIFHWADDR)
325 	struct ifreq ifr;
326 #endif
327 
328 	if ((ifs = malloc(sizeof(*ifs))) == NULL) {
329 		logerr(__func__);
330 		return NULL;
331 	}
332 	if (getifaddrs(ifaddrs) == -1) {
333 		logerr(__func__);
334 		free(ifs);
335 		return NULL;
336 	}
337 	TAILQ_INIT(ifs);
338 
339 #ifdef IFLR_ACTIVE
340 	link_fd = xsocket(PF_LINK, SOCK_DGRAM | SOCK_CLOEXEC, 0);
341 	if (link_fd == -1) {
342 		logerr(__func__);
343 		free(ifs);
344 		return NULL;
345 	}
346 #endif
347 
348 	for (ifa = *ifaddrs; ifa; ifa = ifa->ifa_next) {
349 		if (ifa->ifa_addr != NULL) {
350 #ifdef AF_LINK
351 			if (ifa->ifa_addr->sa_family != AF_LINK)
352 				continue;
353 #elif AF_PACKET
354 			if (ifa->ifa_addr->sa_family != AF_PACKET)
355 				continue;
356 #endif
357 		}
358 		if (if_nametospec(ifa->ifa_name, &spec) != 0)
359 			continue;
360 
361 		/* It's possible for an interface to have >1 AF_LINK.
362 		 * For our purposes, we use the first one. */
363 		TAILQ_FOREACH(ifp, ifs, next) {
364 			if (strcmp(ifp->name, spec.devname) == 0)
365 				break;
366 		}
367 		if (ifp)
368 			continue;
369 
370 		if (argc > 0) {
371 			for (i = 0; i < argc; i++) {
372 				if (strcmp(argv[i], spec.devname) == 0)
373 					break;
374 			}
375 			active = (i == argc) ? IF_INACTIVE : IF_ACTIVE_USER;
376 		} else {
377 			/* -1 means we're discovering against a specific
378 			 * interface, but we still need the below rules
379 			 * to apply. */
380 			if (argc == -1 && strcmp(argv[0], spec.devname) != 0)
381 				continue;
382 			active = ctx->options & DHCPCD_INACTIVE ?
383 			    IF_INACTIVE: IF_ACTIVE_USER;
384 		}
385 
386 		for (i = 0; i < ctx->ifdc; i++)
387 			if (fnmatch(ctx->ifdv[i], spec.devname, 0) == 0)
388 				break;
389 		if (i < ctx->ifdc)
390 			active = IF_INACTIVE;
391 		for (i = 0; i < ctx->ifc; i++)
392 			if (fnmatch(ctx->ifv[i], spec.devname, 0) == 0)
393 				break;
394 		if (ctx->ifc && i == ctx->ifc)
395 			active = IF_INACTIVE;
396 		for (i = 0; i < ctx->ifac; i++)
397 			if (fnmatch(ctx->ifav[i], spec.devname, 0) == 0)
398 				break;
399 		if (ctx->ifac && i == ctx->ifac)
400 			active = IF_INACTIVE;
401 
402 #ifdef PLUGIN_DEV
403 		/* Ensure that the interface name has settled */
404 		if (!dev_initialized(ctx, spec.devname))
405 			continue;
406 #endif
407 
408 		/* Don't allow loopback or pointopoint unless explicit */
409 		if (ifa->ifa_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) {
410 			if ((argc == 0 || argc == -1) &&
411 			    ctx->ifac == 0 && !if_hasconf(ctx, spec.devname))
412 				active = IF_INACTIVE;
413 		}
414 
415 		if (if_vimaster(ctx, spec.devname) == 1) {
416 			logfunc_t *logfunc = argc != 0 ? logerrx : logdebugx;
417 			logfunc("%s: is a Virtual Interface Master, skipping",
418 			    spec.devname);
419 			continue;
420 		}
421 
422 		ifp = calloc(1, sizeof(*ifp));
423 		if (ifp == NULL) {
424 			logerr(__func__);
425 			break;
426 		}
427 		ifp->ctx = ctx;
428 		strlcpy(ifp->name, spec.devname, sizeof(ifp->name));
429 		ifp->flags = ifa->ifa_flags;
430 
431 		if (ifa->ifa_addr != NULL) {
432 #ifdef AF_LINK
433 			sdl = (const void *)ifa->ifa_addr;
434 
435 #ifdef IFLR_ACTIVE
436 			/* We need to check for active address */
437 			strlcpy(iflr.iflr_name, ifp->name,
438 			    sizeof(iflr.iflr_name));
439 			memcpy(&iflr.addr, ifa->ifa_addr,
440 			    MIN(ifa->ifa_addr->sa_len, sizeof(iflr.addr)));
441 			iflr.flags = IFLR_PREFIX;
442 			iflr.prefixlen = (unsigned int)sdl->sdl_alen * NBBY;
443 			if (ioctl(link_fd, SIOCGLIFADDR, &iflr) == -1 ||
444 			    !(iflr.flags & IFLR_ACTIVE))
445 			{
446 				if_free(ifp);
447 				continue;
448 			}
449 #endif
450 
451 			ifp->index = sdl->sdl_index;
452 			switch(sdl->sdl_type) {
453 #ifdef IFT_BRIDGE
454 			case IFT_BRIDGE: /* FALLTHROUGH */
455 #endif
456 #ifdef IFT_PPP
457 			case IFT_PPP: /* FALLTHROUGH */
458 #endif
459 #ifdef IFT_PROPVIRTUAL
460 			case IFT_PROPVIRTUAL:
461 #endif
462 #if defined(IFT_BRIDGE) || defined(IFT_PPP) || defined(IFT_PROPVIRTUAL)
463 				/* Don't allow unless explicit */
464 				if ((argc == 0 || argc == -1) &&
465 				    ctx->ifac == 0 && active &&
466 				    !if_hasconf(ctx, ifp->name))
467 				{
468 					logdebugx("%s: ignoring due to"
469 					    " interface type and"
470 					    " no config",
471 					    ifp->name);
472 					active = IF_INACTIVE;
473 				}
474 				__fallthrough; /* Appease gcc-7 */
475 				/* FALLTHROUGH */
476 #endif
477 #ifdef IFT_L2VLAN
478 			case IFT_L2VLAN: /* FALLTHROUGH */
479 #endif
480 #ifdef IFT_L3IPVLAN
481 			case IFT_L3IPVLAN: /* FALLTHROUGH */
482 #endif
483 			case IFT_ETHER:
484 				ifp->family = ARPHRD_ETHER;
485 				break;
486 #ifdef IFT_IEEE1394
487 			case IFT_IEEE1394:
488 				ifp->family = ARPHRD_IEEE1394;
489 				break;
490 #endif
491 #ifdef IFT_INFINIBAND
492 			case IFT_INFINIBAND:
493 				ifp->family = ARPHRD_INFINIBAND;
494 				break;
495 #endif
496 			default:
497 				/* Don't allow unless explicit */
498 				if ((argc == 0 || argc == -1) &&
499 				    ctx->ifac == 0 &&
500 				    !if_hasconf(ctx, ifp->name))
501 					active = IF_INACTIVE;
502 				if (active)
503 					logwarnx("%s: unsupported"
504 					    " interface type %.2x",
505 					    ifp->name, sdl->sdl_type);
506 				/* Pretend it's ethernet */
507 				ifp->family = ARPHRD_ETHER;
508 				break;
509 			}
510 			ifp->hwlen = sdl->sdl_alen;
511 			memcpy(ifp->hwaddr, CLLADDR(sdl), ifp->hwlen);
512 #elif AF_PACKET
513 			sll = (const void *)ifa->ifa_addr;
514 			ifp->index = (unsigned int)sll->sll_ifindex;
515 			ifp->family = sll->sll_hatype;
516 			ifp->hwlen = sll->sll_halen;
517 			if (ifp->hwlen != 0)
518 				memcpy(ifp->hwaddr, sll->sll_addr, ifp->hwlen);
519 #endif
520 		}
521 #ifdef SIOCGIFHWADDR
522 		else {
523 			/* This is a huge bug in getifaddrs(3) as there
524 			 * is no reason why this can't be returned in
525 			 * ifa_addr. */
526 			memset(&ifr, 0, sizeof(ifr));
527 			strlcpy(ifr.ifr_name, ifa->ifa_name,
528 			    sizeof(ifr.ifr_name));
529 			if (ioctl(ctx->pf_inet_fd, SIOCGIFHWADDR, &ifr) == -1)
530 				logerr("%s: SIOCGIFHWADDR", ifa->ifa_name);
531 			ifp->family = ifr.ifr_hwaddr.sa_family;
532 			if (ioctl(ctx->pf_inet_fd, SIOCGIFINDEX, &ifr) == -1)
533 				logerr("%s: SIOCGIFINDEX", ifa->ifa_name);
534 			ifp->index = (unsigned int)ifr.ifr_ifindex;
535 		}
536 #endif
537 
538 		/* Ensure hardware address is valid. */
539 		if (!if_valid_hwaddr(ifp->hwaddr, ifp->hwlen))
540 			ifp->hwlen = 0;
541 
542 		/* We only work on ethernet by default */
543 		if (ifp->family != ARPHRD_ETHER) {
544 			if ((argc == 0 || argc == -1) &&
545 			    ctx->ifac == 0 && !if_hasconf(ctx, ifp->name))
546 				active = IF_INACTIVE;
547 			switch (ifp->family) {
548 			case ARPHRD_IEEE1394:
549 			case ARPHRD_INFINIBAND:
550 #ifdef ARPHRD_LOOPBACK
551 			case ARPHRD_LOOPBACK:
552 #endif
553 #ifdef ARPHRD_PPP
554 			case ARPHRD_PPP:
555 #endif
556 #ifdef ARPHRD_NONE
557 			case ARPHRD_NONE:
558 #endif
559 				/* We don't warn for supported families */
560 				break;
561 
562 /* IFT already checked */
563 #ifndef AF_LINK
564 			default:
565 				if (active)
566 					logwarnx("%s: unsupported"
567 					    " interface family %.2x",
568 					    ifp->name, ifp->family);
569 				break;
570 #endif
571 			}
572 		}
573 
574 		if (!(ctx->options & (DHCPCD_DUMPLEASE | DHCPCD_TEST))) {
575 			/* Handle any platform init for the interface */
576 			if (active != IF_INACTIVE && if_init(ifp) == -1) {
577 				logerr("%s: if_init", ifp->name);
578 				if_free(ifp);
579 				continue;
580 			}
581 		}
582 
583 		ifp->vlanid = if_vlanid(ifp);
584 
585 #ifdef SIOCGIFPRIORITY
586 		/* Respect the interface priority */
587 		memset(&ifr, 0, sizeof(ifr));
588 		strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
589 		if (ioctl(ctx->pf_inet_fd, SIOCGIFPRIORITY, &ifr) == 0)
590 			ifp->metric = (unsigned int)ifr.ifr_metric;
591 		if_getssid(ifp);
592 #else
593 		/* We reserve the 100 range for virtual interfaces, if and when
594 		 * we can work them out. */
595 		ifp->metric = 200 + ifp->index;
596 		if (if_getssid(ifp) != -1) {
597 			ifp->wireless = true;
598 			ifp->metric += 100;
599 		}
600 #endif
601 
602 		ifp->active = active;
603 		if (ifp->active)
604 			ifp->carrier = if_carrier(ifp);
605 		else
606 			ifp->carrier = LINK_UNKNOWN;
607 		TAILQ_INSERT_TAIL(ifs, ifp, next);
608 	}
609 
610 #ifdef IFLR_ACTIVE
611 	close(link_fd);
612 #endif
613 	return ifs;
614 }
615 
616 /* Decode bge0:1 as dev = bge, ppa = 0 and lun = 1 */
617 int
618 if_nametospec(const char *ifname, struct if_spec *spec)
619 {
620 	char *ep;
621 	int e;
622 
623 	if (ifname == NULL || *ifname == '\0' ||
624 	    strlcpy(spec->ifname, ifname, sizeof(spec->ifname)) >=
625 	    sizeof(spec->ifname) ||
626 	    strlcpy(spec->drvname, ifname, sizeof(spec->drvname)) >=
627 	    sizeof(spec->drvname))
628 	{
629 		errno = EINVAL;
630 		return -1;
631 	}
632 	ep = strchr(spec->drvname, ':');
633 	if (ep) {
634 		spec->lun = (int)strtoi(ep + 1, NULL, 10, 0, INT_MAX, &e);
635 		if (e != 0) {
636 			errno = e;
637 			return -1;
638 		}
639 		*ep-- = '\0';
640 	} else {
641 		spec->lun = -1;
642 		ep = spec->drvname + strlen(spec->drvname) - 1;
643 	}
644 	strlcpy(spec->devname, spec->drvname, sizeof(spec->devname));
645 	while (ep > spec->drvname && isdigit((int)*ep))
646 		ep--;
647 	if (*ep++ == ':') {
648 		errno = EINVAL;
649 		return -1;
650 	}
651 	spec->ppa = (int)strtoi(ep, NULL, 10, 0, INT_MAX, &e);
652 	if (e != 0)
653 		spec->ppa = -1;
654 	*ep = '\0';
655 
656 	return 0;
657 }
658 
659 static struct interface *
660 if_findindexname(struct if_head *ifaces, unsigned int idx, const char *name)
661 {
662 
663 	if (ifaces != NULL) {
664 		struct if_spec spec;
665 		struct interface *ifp;
666 
667 		if (name && if_nametospec(name, &spec) == -1)
668 			return NULL;
669 
670 		TAILQ_FOREACH(ifp, ifaces, next) {
671 			if ((name && strcmp(ifp->name, spec.devname) == 0) ||
672 			    (!name && ifp->index == idx))
673 				return ifp;
674 		}
675 	}
676 
677 	errno = ENXIO;
678 	return NULL;
679 }
680 
681 struct interface *
682 if_find(struct if_head *ifaces, const char *name)
683 {
684 
685 	return if_findindexname(ifaces, 0, name);
686 }
687 
688 struct interface *
689 if_findindex(struct if_head *ifaces, unsigned int idx)
690 {
691 
692 	return if_findindexname(ifaces, idx, NULL);
693 }
694 
695 struct interface *
696 if_loopback(struct dhcpcd_ctx *ctx)
697 {
698 	struct interface *ifp;
699 
700 	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
701 		if (ifp->flags & IFF_LOOPBACK)
702 			return ifp;
703 	}
704 	return NULL;
705 }
706 
707 int
708 if_domtu(const struct interface *ifp, short int mtu)
709 {
710 	int r;
711 	struct ifreq ifr;
712 
713 #ifdef __sun
714 	if (mtu == 0)
715 		return if_mtu_os(ifp);
716 #endif
717 
718 	memset(&ifr, 0, sizeof(ifr));
719 	strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
720 	ifr.ifr_mtu = mtu;
721 	r = ioctl(ifp->ctx->pf_inet_fd, mtu ? SIOCSIFMTU : SIOCGIFMTU, &ifr);
722 	if (r == -1)
723 		return -1;
724 	return ifr.ifr_mtu;
725 }
726 
727 #ifdef ALIAS_ADDR
728 int
729 if_makealias(char *alias, size_t alias_len, const char *ifname, int lun)
730 {
731 
732 	if (lun == 0)
733 		return strlcpy(alias, ifname, alias_len);
734 	return snprintf(alias, alias_len, "%s:%u", ifname, lun);
735 }
736 #endif
737 
738 struct interface *
739 if_findifpfromcmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg, int *hoplimit)
740 {
741 	struct cmsghdr *cm;
742 	unsigned int ifindex = 0;
743 	struct interface *ifp;
744 #if defined(INET) && defined(IP_PKTINFO)
745 	struct in_pktinfo ipi;
746 #endif
747 #ifdef INET6
748 	struct in6_pktinfo ipi6;
749 #else
750 	UNUSED(hoplimit);
751 #endif
752 
753 	for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(msg);
754 	     cm;
755 	     cm = (struct cmsghdr *)CMSG_NXTHDR(msg, cm))
756 	{
757 #if defined(INET) && defined(IP_PKTINFO)
758 		if (cm->cmsg_level == IPPROTO_IP) {
759 			switch(cm->cmsg_type) {
760 			case IP_PKTINFO:
761 				if (cm->cmsg_len != CMSG_LEN(sizeof(ipi)))
762 					continue;
763 				memcpy(&ipi, CMSG_DATA(cm), sizeof(ipi));
764 				ifindex = (unsigned int)ipi.ipi_ifindex;
765 				break;
766 			}
767 		}
768 #endif
769 #ifdef INET6
770 		if (cm->cmsg_level == IPPROTO_IPV6) {
771 			switch(cm->cmsg_type) {
772 			case IPV6_PKTINFO:
773 				if (cm->cmsg_len != CMSG_LEN(sizeof(ipi6)))
774 					continue;
775 				memcpy(&ipi6, CMSG_DATA(cm), sizeof(ipi6));
776 				ifindex = (unsigned int)ipi6.ipi6_ifindex;
777 				break;
778 			case IPV6_HOPLIMIT:
779 				if (cm->cmsg_len != CMSG_LEN(sizeof(int)))
780 					continue;
781 				if (hoplimit == NULL)
782 					break;
783 				memcpy(hoplimit, CMSG_DATA(cm), sizeof(int));
784 				break;
785 			}
786 		}
787 #endif
788 	}
789 
790 	/* Find the receiving interface */
791 	TAILQ_FOREACH(ifp, ctx->ifaces, next) {
792 		if (ifp->index == ifindex)
793 			break;
794 	}
795 	if (ifp == NULL)
796 		errno = ESRCH;
797 	return ifp;
798 }
799 
800 int
801 xsocket(int domain, int type, int protocol)
802 {
803 	int s;
804 #if !defined(HAVE_SOCK_CLOEXEC) || !defined(HAVE_SOCK_NONBLOCK)
805 	int xflags, xtype = type;
806 #endif
807 #ifdef SO_RERROR
808 	int on;
809 #endif
810 
811 #ifndef HAVE_SOCK_CLOEXEC
812 	if (xtype & SOCK_CLOEXEC)
813 		type &= ~SOCK_CLOEXEC;
814 #endif
815 #ifndef HAVE_SOCK_NONBLOCK
816 	if (xtype & SOCK_NONBLOCK)
817 		type &= ~SOCK_NONBLOCK;
818 #endif
819 
820 	if ((s = socket(domain, type, protocol)) == -1)
821 		return -1;
822 
823 #ifndef HAVE_SOCK_CLOEXEC
824 	if ((xtype & SOCK_CLOEXEC) && ((xflags = fcntl(s, F_GETFD)) == -1 ||
825 	    fcntl(s, F_SETFD, xflags | FD_CLOEXEC) == -1))
826 		goto out;
827 #endif
828 #ifndef HAVE_SOCK_NONBLOCK
829 	if ((xtype & SOCK_NONBLOCK) && ((xflags = fcntl(s, F_GETFL)) == -1 ||
830 	    fcntl(s, F_SETFL, xflags | O_NONBLOCK) == -1))
831 		goto out;
832 #endif
833 
834 #ifdef SO_RERROR
835 	/* Tell recvmsg(2) to return ENOBUFS if the receiving socket overflows. */
836 	on = 1;
837 	if (setsockopt(s, SOL_SOCKET, SO_RERROR, &on, sizeof(on)) == -1)
838 		logerr("%s: SO_RERROR", __func__);
839 #endif
840 
841 	return s;
842 
843 #if !defined(HAVE_SOCK_CLOEXEC) || !defined(HAVE_SOCK_NONBLOCK)
844 out:
845 	close(s);
846 	return -1;
847 #endif
848 }
849