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