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