"Fossies" - the Fresh Open Source Software Archive 
Member "dhcpcd-9.4.1/src/if.c" (22 Oct 2021, 23664 Bytes) of package /linux/misc/dhcpcd-9.4.1.tar.xz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "if.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
9.4.0_vs_9.4.1.
1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3 * dhcpcd - DHCP client daemon
4 * Copyright (c) 2006-2021 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
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 #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
131 void
132 if_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
148 int
149 if_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
159 int
160 if_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
171 int
172 if_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
196 bool
197 if_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
205 int
206 if_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
246 static int
247 if_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
258 void
259 if_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
273 void
274 if_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
369 void
370 if_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
384 bool
385 if_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)
403 static unsigned int
404 if_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
440 struct if_head *
441 if_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 */
724 int
725 if_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
796 static struct interface *
797 if_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
818 struct interface *
819 if_find(struct if_head *ifaces, const char *name)
820 {
821
822 return if_findindexname(ifaces, 0, name);
823 }
824
825 struct interface *
826 if_findindex(struct if_head *ifaces, unsigned int idx)
827 {
828
829 return if_findindexname(ifaces, idx, NULL);
830 }
831
832 struct interface *
833 if_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
844 int
845 if_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
869 int
870 if_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
879 struct interface *
880 if_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
957 int
958 xsocket(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)
991 out:
992 close(s);
993 return -1;
994 #endif
995 }
996
997 int
998 xsocketpair(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)
1037 out:
1038 close(fd[0]);
1039 close(fd[1]);
1040 return -1;
1041 #endif
1042 }