Merge dhcpcd-8.0.4 from branch 'vendor/DHCPCD'
[dragonfly.git] / contrib / dhcpcd / src / if.c
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                                 /* FALLTHROUGH */
479                         case IFT_L2VLAN: /* FALLTHROUGH */
480 #endif
481 #ifdef IFT_L3IPVLAN
482                         case IFT_L3IPVLAN: /* FALLTHROUGH */
483 #endif
484                         case IFT_ETHER:
485                                 ifp->family = ARPHRD_ETHER;
486                                 break;
487 #ifdef IFT_IEEE1394
488                         case IFT_IEEE1394:
489                                 ifp->family = ARPHRD_IEEE1394;
490                                 break;
491 #endif
492 #ifdef IFT_INFINIBAND
493                         case IFT_INFINIBAND:
494                                 ifp->family = ARPHRD_INFINIBAND;
495                                 break;
496 #endif
497                         default:
498                                 /* Don't allow unless explicit */
499                                 if ((argc == 0 || argc == -1) &&
500                                     ctx->ifac == 0 &&
501                                     !if_hasconf(ctx, ifp->name))
502                                         active = IF_INACTIVE;
503                                 if (active)
504                                         logwarnx("%s: unsupported"
505                                             " interface type %.2x",
506                                             ifp->name, sdl->sdl_type);
507                                 /* Pretend it's ethernet */
508                                 ifp->family = ARPHRD_ETHER;
509                                 break;
510                         }
511                         ifp->hwlen = sdl->sdl_alen;
512                         memcpy(ifp->hwaddr, CLLADDR(sdl), ifp->hwlen);
513 #elif AF_PACKET
514                         sll = (const void *)ifa->ifa_addr;
515                         ifp->index = (unsigned int)sll->sll_ifindex;
516                         ifp->family = sll->sll_hatype;
517                         ifp->hwlen = sll->sll_halen;
518                         if (ifp->hwlen != 0)
519                                 memcpy(ifp->hwaddr, sll->sll_addr, ifp->hwlen);
520 #endif
521                 }
522 #ifdef SIOCGIFHWADDR
523                 else {
524                         /* This is a huge bug in getifaddrs(3) as there
525                          * is no reason why this can't be returned in
526                          * ifa_addr. */
527                         memset(&ifr, 0, sizeof(ifr));
528                         strlcpy(ifr.ifr_name, ifa->ifa_name,
529                             sizeof(ifr.ifr_name));
530                         if (ioctl(ctx->pf_inet_fd, SIOCGIFHWADDR, &ifr) == -1)
531                                 logerr("%s: SIOCGIFHWADDR", ifa->ifa_name);
532                         ifp->family = ifr.ifr_hwaddr.sa_family;
533                         if (ioctl(ctx->pf_inet_fd, SIOCGIFINDEX, &ifr) == -1)
534                                 logerr("%s: SIOCGIFINDEX", ifa->ifa_name);
535                         ifp->index = (unsigned int)ifr.ifr_ifindex;
536                 }
537 #endif
538
539                 /* Ensure hardware address is valid. */
540                 if (!if_valid_hwaddr(ifp->hwaddr, ifp->hwlen))
541                         ifp->hwlen = 0;
542
543                 /* We only work on ethernet by default */
544                 if (ifp->family != ARPHRD_ETHER) {
545                         if ((argc == 0 || argc == -1) &&
546                             ctx->ifac == 0 && !if_hasconf(ctx, ifp->name))
547                                 active = IF_INACTIVE;
548                         switch (ifp->family) {
549                         case ARPHRD_IEEE1394:
550                         case ARPHRD_INFINIBAND:
551 #ifdef ARPHRD_LOOPBACK
552                         case ARPHRD_LOOPBACK:
553 #endif
554 #ifdef ARPHRD_PPP
555                         case ARPHRD_PPP:
556 #endif
557 #ifdef ARPHRD_NONE
558                         case ARPHRD_NONE:
559 #endif
560                                 /* We don't warn for supported families */
561                                 break;
562
563 /* IFT already checked */
564 #ifndef AF_LINK
565                         default:
566                                 if (active)
567                                         logwarnx("%s: unsupported"
568                                             " interface family %.2x",
569                                             ifp->name, ifp->family);
570                                 break;
571 #endif
572                         }
573                 }
574
575                 if (!(ctx->options & (DHCPCD_DUMPLEASE | DHCPCD_TEST))) {
576                         /* Handle any platform init for the interface */
577                         if (active != IF_INACTIVE && if_init(ifp) == -1) {
578                                 logerr("%s: if_init", ifp->name);
579                                 if_free(ifp);
580                                 continue;
581                         }
582                 }
583
584                 ifp->vlanid = if_vlanid(ifp);
585
586 #ifdef SIOCGIFPRIORITY
587                 /* Respect the interface priority */
588                 memset(&ifr, 0, sizeof(ifr));
589                 strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
590                 if (ioctl(ctx->pf_inet_fd, SIOCGIFPRIORITY, &ifr) == 0)
591                         ifp->metric = (unsigned int)ifr.ifr_metric;
592                 if_getssid(ifp);
593 #else
594                 /* We reserve the 100 range for virtual interfaces, if and when
595                  * we can work them out. */
596                 ifp->metric = 200 + ifp->index;
597                 if (if_getssid(ifp) != -1) {
598                         ifp->wireless = true;
599                         ifp->metric += 100;
600                 }
601 #endif
602
603                 ifp->active = active;
604                 if (ifp->active)
605                         ifp->carrier = if_carrier(ifp);
606                 else
607                         ifp->carrier = LINK_UNKNOWN;
608                 TAILQ_INSERT_TAIL(ifs, ifp, next);
609         }
610
611 #ifdef IFLR_ACTIVE
612         close(link_fd);
613 #endif
614         return ifs;
615 }
616
617 /* Decode bge0:1 as dev = bge, ppa = 0 and lun = 1 */
618 int
619 if_nametospec(const char *ifname, struct if_spec *spec)
620 {
621         char *ep;
622         int e;
623
624         if (ifname == NULL || *ifname == '\0' ||
625             strlcpy(spec->ifname, ifname, sizeof(spec->ifname)) >=
626             sizeof(spec->ifname) ||
627             strlcpy(spec->drvname, ifname, sizeof(spec->drvname)) >=
628             sizeof(spec->drvname))
629         {
630                 errno = EINVAL;
631                 return -1;
632         }
633         ep = strchr(spec->drvname, ':');
634         if (ep) {
635                 spec->lun = (int)strtoi(ep + 1, NULL, 10, 0, INT_MAX, &e);
636                 if (e != 0) {
637                         errno = e;
638                         return -1;
639                 }
640                 *ep-- = '\0';
641         } else {
642                 spec->lun = -1;
643                 ep = spec->drvname + strlen(spec->drvname) - 1;
644         }
645         strlcpy(spec->devname, spec->drvname, sizeof(spec->devname));
646         while (ep > spec->drvname && isdigit((int)*ep))
647                 ep--;
648         if (*ep++ == ':') {
649                 errno = EINVAL;
650                 return -1;
651         }
652         spec->ppa = (int)strtoi(ep, NULL, 10, 0, INT_MAX, &e);
653         if (e != 0)
654                 spec->ppa = -1;
655         *ep = '\0';
656
657         return 0;
658 }
659
660 static struct interface *
661 if_findindexname(struct if_head *ifaces, unsigned int idx, const char *name)
662 {
663
664         if (ifaces != NULL) {
665                 struct if_spec spec;
666                 struct interface *ifp;
667
668                 if (name && if_nametospec(name, &spec) == -1)
669                         return NULL;
670
671                 TAILQ_FOREACH(ifp, ifaces, next) {
672                         if ((name && strcmp(ifp->name, spec.devname) == 0) ||
673                             (!name && ifp->index == idx))
674                                 return ifp;
675                 }
676         }
677
678         errno = ENXIO;
679         return NULL;
680 }
681
682 struct interface *
683 if_find(struct if_head *ifaces, const char *name)
684 {
685
686         return if_findindexname(ifaces, 0, name);
687 }
688
689 struct interface *
690 if_findindex(struct if_head *ifaces, unsigned int idx)
691 {
692
693         return if_findindexname(ifaces, idx, NULL);
694 }
695
696 struct interface *
697 if_loopback(struct dhcpcd_ctx *ctx)
698 {
699         struct interface *ifp;
700
701         TAILQ_FOREACH(ifp, ctx->ifaces, next) {
702                 if (ifp->flags & IFF_LOOPBACK)
703                         return ifp;
704         }
705         return NULL;
706 }
707
708 int
709 if_domtu(const struct interface *ifp, short int mtu)
710 {
711         int r;
712         struct ifreq ifr;
713
714 #ifdef __sun
715         if (mtu == 0)
716                 return if_mtu_os(ifp);
717 #endif
718
719         memset(&ifr, 0, sizeof(ifr));
720         strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name));
721         ifr.ifr_mtu = mtu;
722         r = ioctl(ifp->ctx->pf_inet_fd, mtu ? SIOCSIFMTU : SIOCGIFMTU, &ifr);
723         if (r == -1)
724                 return -1;
725         return ifr.ifr_mtu;
726 }
727
728 #ifdef ALIAS_ADDR
729 int
730 if_makealias(char *alias, size_t alias_len, const char *ifname, int lun)
731 {
732
733         if (lun == 0)
734                 return strlcpy(alias, ifname, alias_len);
735         return snprintf(alias, alias_len, "%s:%u", ifname, lun);
736 }
737 #endif
738
739 struct interface *
740 if_findifpfromcmsg(struct dhcpcd_ctx *ctx, struct msghdr *msg, int *hoplimit)
741 {
742         struct cmsghdr *cm;
743         unsigned int ifindex = 0;
744         struct interface *ifp;
745 #if defined(INET) && defined(IP_PKTINFO)
746         struct in_pktinfo ipi;
747 #endif
748 #ifdef INET6
749         struct in6_pktinfo ipi6;
750 #else
751         UNUSED(hoplimit);
752 #endif
753
754         for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(msg);
755              cm;
756              cm = (struct cmsghdr *)CMSG_NXTHDR(msg, cm))
757         {
758 #if defined(INET) && defined(IP_PKTINFO)
759                 if (cm->cmsg_level == IPPROTO_IP) {
760                         switch(cm->cmsg_type) {
761                         case IP_PKTINFO:
762                                 if (cm->cmsg_len != CMSG_LEN(sizeof(ipi)))
763                                         continue;
764                                 memcpy(&ipi, CMSG_DATA(cm), sizeof(ipi));
765                                 ifindex = (unsigned int)ipi.ipi_ifindex;
766                                 break;
767                         }
768                 }
769 #endif
770 #ifdef INET6
771                 if (cm->cmsg_level == IPPROTO_IPV6) {
772                         switch(cm->cmsg_type) {
773                         case IPV6_PKTINFO:
774                                 if (cm->cmsg_len != CMSG_LEN(sizeof(ipi6)))
775                                         continue;
776                                 memcpy(&ipi6, CMSG_DATA(cm), sizeof(ipi6));
777                                 ifindex = (unsigned int)ipi6.ipi6_ifindex;
778                                 break;
779                         case IPV6_HOPLIMIT:
780                                 if (cm->cmsg_len != CMSG_LEN(sizeof(int)))
781                                         continue;
782                                 if (hoplimit == NULL)
783                                         break;
784                                 memcpy(hoplimit, CMSG_DATA(cm), sizeof(int));
785                                 break;
786                         }
787                 }
788 #endif
789         }
790
791         /* Find the receiving interface */
792         TAILQ_FOREACH(ifp, ctx->ifaces, next) {
793                 if (ifp->index == ifindex)
794                         break;
795         }
796         if (ifp == NULL)
797                 errno = ESRCH;
798         return ifp;
799 }
800
801 int
802 xsocket(int domain, int type, int protocol)
803 {
804         int s;
805 #if !defined(HAVE_SOCK_CLOEXEC) || !defined(HAVE_SOCK_NONBLOCK)
806         int xflags, xtype = type;
807 #endif
808 #ifdef SO_RERROR
809         int on;
810 #endif
811
812 #ifndef HAVE_SOCK_CLOEXEC
813         if (xtype & SOCK_CLOEXEC)
814                 type &= ~SOCK_CLOEXEC;
815 #endif
816 #ifndef HAVE_SOCK_NONBLOCK
817         if (xtype & SOCK_NONBLOCK)
818                 type &= ~SOCK_NONBLOCK;
819 #endif
820
821         if ((s = socket(domain, type, protocol)) == -1)
822                 return -1;
823
824 #ifndef HAVE_SOCK_CLOEXEC
825         if ((xtype & SOCK_CLOEXEC) && ((xflags = fcntl(s, F_GETFD)) == -1 ||
826             fcntl(s, F_SETFD, xflags | FD_CLOEXEC) == -1))
827                 goto out;
828 #endif
829 #ifndef HAVE_SOCK_NONBLOCK
830         if ((xtype & SOCK_NONBLOCK) && ((xflags = fcntl(s, F_GETFL)) == -1 ||
831             fcntl(s, F_SETFL, xflags | O_NONBLOCK) == -1))
832                 goto out;
833 #endif
834
835 #ifdef SO_RERROR
836         /* Tell recvmsg(2) to return ENOBUFS if the receiving socket overflows. */
837         on = 1;
838         if (setsockopt(s, SOL_SOCKET, SO_RERROR, &on, sizeof(on)) == -1)
839                 logerr("%s: SO_RERROR", __func__);
840 #endif
841
842         return s;
843
844 #if !defined(HAVE_SOCK_CLOEXEC) || !defined(HAVE_SOCK_NONBLOCK)
845 out:
846         close(s);
847         return -1;
848 #endif
849 }