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