Mercurial > hg > dhcpcd
changeset 4485:9ba7f650a8f7 draft
Merge branch 'dhcpcd-7'
| author | Roy Marples <roy@marples.name> |
|---|---|
| date | Fri, 26 Apr 2019 14:07:35 +0100 |
| parents | 0dcdae5e7954 (current diff) 0f490b4cde2a (diff) |
| children | 6635eac6eb05 |
| files | src/dhcp.c src/ipv4.h src/ipv4ll.c |
| diffstat | 14 files changed, 347 insertions(+), 161 deletions(-) [+] |
line wrap: on
line diff
--- a/src/auth.c Fri Apr 19 21:54:19 2019 +0100 +++ b/src/auth.c Fri Apr 26 14:07:35 2019 +0100 @@ -117,7 +117,11 @@ m = vm; data = vdata; - /* Ensure that d is inside m which *may* not be the case for DHPCPv4 */ + /* Ensure that d is inside m which *may* not be the case for DHCPv4. + * This can occur if the authentication option is split using + * DHCP long option from RFC 3399. Section 9 which does infact note that + * implementations should take this into account. + * Fixing this would be problematic, patches welcome. */ if (data < m || data > m + mlen || data + dlen > m + mlen) { errno = ERANGE; return NULL;
--- a/src/control.c Fri Apr 19 21:54:19 2019 +0100 +++ b/src/control.c Fri Apr 26 14:07:35 2019 +0100 @@ -318,7 +318,7 @@ if ((fd = make_sock(&sa, ifname, 0)) != -1) { socklen_t len; - + len = (socklen_t)SUN_LEN(&sa); if (connect(fd, (struct sockaddr *)&sa, len) == -1) { close(fd);
--- a/src/dhcp.c Fri Apr 19 21:54:19 2019 +0100 +++ b/src/dhcp.c Fri Apr 26 14:07:35 2019 +0100 @@ -2026,7 +2026,7 @@ logdebugx("%s: DAD completed for %s", ifp->name, inet_ntoa(*ia)); if (!(ifp->options->options & DHCPCD_INFORM)) dhcp_bind(ifp); -#ifndef IN_IFF_TENTATIVE +#ifndef IN_IFF_DUPLICATED else { struct bootp *bootp; size_t len; @@ -2393,7 +2393,7 @@ /* If the interface already has the address configured * then we can't ARP for duplicate detection. */ ia = ipv4_iffindaddr(ifp, &addr, NULL); -#ifdef IN_IFF_TENTATIVE +#ifdef IN_IFF_NOTUSEABLE if (ia == NULL || ia->addr_flags & IN_IFF_NOTUSEABLE) { state->state = DHS_PROBE; if (ia == NULL) {
--- a/src/dhcp6.c Fri Apr 19 21:54:19 2019 +0100 +++ b/src/dhcp6.c Fri Apr 26 14:07:35 2019 +0100 @@ -3035,7 +3035,7 @@ * unless those values in those fields are 0. */ logwarnx("%s: ignoring T1 %"PRIu32 - " to due address expiry", + " due to address expiry", ifp->name, state->renew); state->renew = state->rebind = 0; }
--- a/src/dhcpcd.conf.5.in Fri Apr 19 21:54:19 2019 +0100 +++ b/src/dhcpcd.conf.5.in Fri Apr 26 14:07:35 2019 +0100 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd September 15, 2018 +.Dd April 24, 2019 .Dt DHCPCD.CONF 5 .Os .Sh NAME @@ -376,8 +376,7 @@ noipv6rs # disable routing solicitation denyinterfaces eth2 # Don't touch eth2 at all interface eth0 - ipv6rs # enable routing solicitation get the - # default IPv6 route + ipv6rs # enable routing solicitation for eth0 ia_na 1 # request an IPv6 address ia_pd 2 eth1/0 # request a PD and assign it to eth1 ia_pd 3 eth2/1 eth3/2 # req a PD and assign it to eth2 and eth3
--- a/src/dhcpcd.h Fri Apr 19 21:54:19 2019 +0100 +++ b/src/dhcpcd.h Fri Apr 26 14:07:35 2019 +0100 @@ -180,7 +180,9 @@ uint8_t *secret; size_t secret_len; +#ifndef __sun int nd_fd; +#endif struct ra_head *ra_routers; int dhcp6_fd;
--- a/src/if-bsd.c Fri Apr 19 21:54:19 2019 +0100 +++ b/src/if-bsd.c Fri Apr 26 14:07:35 2019 +0100 @@ -943,10 +943,15 @@ priv = (struct priv *)ia->iface->ctx->priv; if (ioctl(priv->pf_inet6_fd, SIOCGIFALIFETIME_IN6, &ifr6) == -1) return -1; + clock_gettime(CLOCK_MONOTONIC, &ia->created); +#if defined(__FreeBSD__) || defined(__DragonFly__) + t = ia->created.tv_sec; +#else t = time(NULL); +#endif + lifetime = &ifr6.ifr_ifru.ifru_lifetime; - if (lifetime->ia6t_preferred) ia->prefix_pltime = (uint32_t)(lifetime->ia6t_preferred - MIN(t, lifetime->ia6t_preferred)); @@ -956,7 +961,6 @@ ia->prefix_vltime = (uint32_t)(lifetime->ia6t_expire - MIN(t, lifetime->ia6t_expire)); /* Calculate the created time */ - clock_gettime(CLOCK_MONOTONIC, &ia->created); ia->created.tv_sec -= lifetime->ia6t_vltime - ia->prefix_vltime; } else ia->prefix_vltime = ND6_INFINITE_LIFETIME;
--- a/src/if-sun.c Fri Apr 19 21:54:19 2019 +0100 +++ b/src/if-sun.c Fri Apr 26 14:07:35 2019 +0100 @@ -74,9 +74,9 @@ #endif #ifndef RT_ROUNDUP -#define RT_ROUNDUP(a) \ - ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) -#define RT_ADVANCE(x, n) (x += RT_ROUNDUP(salen(n))) +#define RT_ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(int32_t) - 1))) : sizeof(int32_t)) +#define RT_ADVANCE(x, n) ((x) += RT_ROUNDUP(salen((n)))) #endif #define COPYOUT(sin, sa) do { \ @@ -268,6 +268,7 @@ if_newaddr(const char *ifname, void *arg) { struct linkwalk *lw = arg; + int error; struct ifaddrs *ifa; dlpi_handle_t dh; dlpi_info_t dlinfo; @@ -276,7 +277,10 @@ struct sockaddr_dl *sdl; ifa = NULL; - if (dlpi_open(ifname, &dh, 0) != DLPI_SUCCESS) + error = dlpi_open(ifname, &dh, 0); + if (error == DLPI_ENOLINK) /* Just vanished or in global zone */ + return B_FALSE; + if (error != DLPI_SUCCESS) goto failed1; if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) goto failed; @@ -317,7 +321,7 @@ ifa->ifa_next = lw->lw_ifa; lw->lw_ifa = ifa; dlpi_close(dh); - return (B_FALSE); + return B_FALSE; failed: dlpi_close(dh); @@ -328,7 +332,7 @@ } failed1: lw->lw_error = errno; - return (B_TRUE); + return B_TRUE; } /* Creates an empty sockaddr_dl for lo0. */ @@ -423,14 +427,16 @@ { const char *cp; int i; + const struct sockaddr **sap; cp = data; for (i = 0; i < RTAX_MAX; i++) { + sap = &sa[i]; if (type & (1 << i)) { - sa[i] = (const struct sockaddr *)cp; - RT_ADVANCE(cp, sa[i]); + *sap = (const struct sockaddr *)cp; + RT_ADVANCE(cp, *sap); } else - sa[i] = NULL; + *sap = NULL; } return 0; } @@ -520,6 +526,7 @@ struct rt_msghdr *rtm; char *bp = rtmsg->buffer; socklen_t sl; + bool gateway_unspec; /* WARNING: Solaris will not allow you to delete RTF_KERNEL routes. * This includes subnet/prefix routes. */ @@ -538,25 +545,28 @@ rtm->rtm_flags = rt->rt_flags; rtm->rtm_addrs = RTA_DST | RTA_GATEWAY; + gateway_unspec = sa_is_unspecified(&rt->rt_gateway); + if (cmd == RTM_ADD || cmd == RTM_CHANGE) { bool netmask_bcast = sa_is_allones(&rt->rt_netmask); rtm->rtm_flags |= RTF_UP; if (!(rtm->rtm_flags & RTF_REJECT) && - !sa_is_loopback(&rt->rt_gateway) && - /* Solaris doesn't like interfaces on default routes. */ - !sa_is_unspecified(&rt->rt_dest)) + !sa_is_loopback(&rt->rt_gateway)) { rtm->rtm_addrs |= RTA_IFP; -#if 0 + /* RTA_IFA is currently ignored by the kernel. + * RTA_SRC and RTF_SETSRC look like what we want, + * but they don't work with RTF_GATEWAY. + * We set RTA_IFA just in the hope that the + * kernel will one day support this. */ if (!sa_is_unspecified(&rt->rt_ifa)) rtm->rtm_addrs |= RTA_IFA; -#endif } if (netmask_bcast) rtm->rtm_flags |= RTF_HOST; - else + else if (!gateway_unspec) rtm->rtm_flags |= RTF_GATEWAY; /* Emulate the kernel by marking address generated @@ -575,7 +585,7 @@ ADDSA(&rt->rt_dest); - if (sa_is_unspecified(&rt->rt_gateway)) + if (gateway_unspec) ADDSA(&rt->rt_ifa); else ADDSA(&rt->rt_gateway); @@ -590,14 +600,13 @@ ADDSA((struct sockaddr *)&sdl); } - if (rtm->rtm_addrs & RTA_IFA) { + if (rtm->rtm_addrs & RTA_IFA) ADDSA(&rt->rt_ifa); - rtm->rtm_addrs |= RTA_SRC; - } + +#if 0 if (rtm->rtm_addrs & RTA_SRC) ADDSA(&rt->rt_ifa); - -#undef ADDSA +#endif rtm->rtm_msglen = (unsigned short)(bp - (char *)rtm); } @@ -747,15 +756,19 @@ rt->rt_mtu = 0; } -static int -if_addrflags0(int fd, const char *ifname) +static uint64_t +if_addrflags0(int fd, const char *ifname, const struct sockaddr *sa) { struct lifreq lifr; memset(&lifr, 0, sizeof(lifr)); strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name)); if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) - return -1; + return 0; + if (ioctl(fd, SIOCGLIFADDR, &lifr) == -1) + return 0; + if (sa_cmp(sa, (struct sockaddr *)&lifr.lifr_addr) != 0) + return 0; return lifr.lifr_flags; } @@ -804,13 +817,56 @@ } } +static bool +if_getalias(struct interface *ifp, const struct sockaddr *sa, char *alias) +{ + struct ifaddrs *ifaddrs, *ifa; + struct interface *ifpx; + bool found; + + ifaddrs = NULL; + if (getallifaddrs(sa->sa_family, &ifaddrs, 0) == -1) + return false; + found = false; + for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) + continue; + if (sa_cmp(sa, ifa->ifa_addr) != 0) + continue; + /* Check it's for the right interace. */ + ifpx = if_find(ifp->ctx->ifaces, ifa->ifa_name); + if (ifp == ifpx) { + strlcpy(alias, ifa->ifa_name, IF_NAMESIZE); + found = true; + break; + } + } + freeifaddrs(ifaddrs); + return found; +} + +static int +if_getbrdaddr(struct dhcpcd_ctx *ctx, const char *ifname, struct in_addr *brd) +{ + struct lifreq lifr = { 0 }; + int r; + + memset(&lifr, 0, sizeof(lifr)); + strlcpy(lifr.lifr_name, ifname, sizeof(lifr.lifr_name)); + errno = 0; + r = ioctl(ctx->pf_inet_fd, SIOCGLIFBRDADDR, &lifr, sizeof(lifr)); + if (r != -1) + COPYOUT(*brd, (struct sockaddr *)&lifr.lifr_broadaddr); + return r; +} + static void if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam) { struct interface *ifp; const struct sockaddr *sa, *rti_info[RTAX_MAX]; int flags; - const char *ifalias; + char ifalias[IF_NAMESIZE]; /* XXX We have no way of knowing who generated these * messages wich truely sucks because we want to @@ -819,6 +875,7 @@ return; sa = (const void *)(ifam + 1); get_addrs(ifam->ifam_addrs, sa, rti_info); + if ((sa = rti_info[RTAX_IFA]) == NULL) return; @@ -835,31 +892,8 @@ * ifam_alias * ifam_pid */ - - ifalias = ifp->name; - if (ifam->ifam_type != RTM_DELADDR && sa->sa_family != AF_LINK) { - struct ifaddrs *ifaddrs, *ifa; - - ifaddrs = NULL; - if (getallifaddrs(sa->sa_family, &ifaddrs, 0) == -1) - return; - for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { - if (ifa->ifa_addr != NULL) { - if (sa_cmp(sa, ifa->ifa_addr) == 0) { - /* Check it's for the right interace. */ - struct interface *ifpx; - - ifpx = if_find(ctx->ifaces, - ifa->ifa_name); - if (ifp == ifpx) { - ifalias = ifa->ifa_name; - break; - } - } - } - } - freeifaddrs(ifaddrs); - } + if (ifam->ifam_type != RTM_DELADDR && !if_getalias(ifp, sa, ifalias)) + return; switch (sa->sa_family) { case AF_LINK: @@ -882,12 +916,25 @@ COPYOUT(mask, rti_info[RTAX_NETMASK]); COPYOUT(bcast, rti_info[RTAX_BRD]); - if (ifam->ifam_type != RTM_DELADDR) { - flags = if_addrflags0(ctx->pf_inet_fd, ifalias); - if (flags == -1) - break; - } else - flags = 0; + if (ifam->ifam_type == RTM_DELADDR) { + struct ipv4_addr *ia; + + ia = ipv4_iffindaddr(ifp, &addr, &mask); + if (ia == NULL) + return; + strlcpy(ifalias, ia->alias, sizeof(ifalias)); + } else if (bcast.s_addr == INADDR_ANY) { + /* Work around a bug where broadcast + * address is not correctly reported. */ + if (if_getbrdaddr(ctx, ifalias, &bcast) == -1) + return; + } + flags = if_addrflags(ifp, &addr, ifalias); + if (ifam->ifam_type == RTM_DELADDR) { + if (flags != -1) + return; + } else if (flags == -1) + return; ipv4_handleifa(ctx, ifam->ifam_type == RTM_CHGADDR ? @@ -907,15 +954,20 @@ sin6 = (const void *)rti_info[RTAX_NETMASK]; mask6 = sin6->sin6_addr; - if (ifam->ifam_type != RTM_DELADDR) { - const struct priv *priv; + if (ifam->ifam_type == RTM_DELADDR) { + struct ipv6_addr *ia; - priv = (struct priv *)ctx->priv; - flags = if_addrflags0(priv->pf_inet6_fd, ifalias); - if (flags == -1) - break; - } else - flags = 0; + ia = ipv6_iffindaddr(ifp, &addr6, 0); + if (ia == NULL) + return; + strlcpy(ifalias, ia->alias, sizeof(ifalias)); + } + flags = if_addrflags6(ifp, &addr6, ifalias); + if (ifam->ifam_type == RTM_DELADDR) { + if (flags != -1) + return; + } else if (flags == -1) + return; ipv6_handleifa(ctx, ifam->ifam_type == RTM_CHGADDR ? @@ -1003,7 +1055,8 @@ static int if_addaddr(int fd, const char *ifname, - struct sockaddr_storage *addr, struct sockaddr_storage *mask) + struct sockaddr_storage *addr, struct sockaddr_storage *mask, + struct sockaddr_storage *brd) { struct lifreq lifr; @@ -1020,6 +1073,13 @@ if (ioctl(fd, SIOCSLIFADDR, &lifr) == -1) return -1; + /* Then assign the broadcast address. */ + if (brd != NULL) { + lifr.lifr_broadaddr = *brd; + if (ioctl(fd, SIOCSLIFBRDADDR, &lifr) == -1) + return -1; + } + /* Now bring it up. */ if (ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) return -1; @@ -1173,15 +1233,11 @@ static int if_unplumbif(const struct dhcpcd_ctx *ctx, int af, const char *ifname) { - struct sockaddr_storage addr, mask; + struct sockaddr_storage addr = { .ss_family = af }; int fd; /* For the time being, don't unplumb the interface, just * set the address to zero. */ - memset(&addr, 0, sizeof(addr)); - addr.ss_family = af; - memset(&mask, 0, sizeof(mask)); - mask.ss_family = af; switch (af) { #ifdef INET case AF_INET: @@ -1202,7 +1258,8 @@ errno = EAFNOSUPPORT; return -1; } - return if_addaddr(fd, ifname, &addr, &mask); + return if_addaddr(fd, ifname, &addr, &addr, + af == AF_INET ? &addr : NULL); } static int @@ -1306,6 +1363,7 @@ ipv6_mask(&in6, re->ipv6RoutePfxLength); sa_in6_init(&rt.rt_netmask, &in6); sa_in6_init(&rt.rt_gateway, &re->ipv6RouteNextHop); + sa_in6_init(&rt.rt_ifa, &re->ipv6RouteInfo.re_src_addr); rt.rt_mtu = re->ipv6RouteInfo.re_max_frag; if_octetstr(ifname, &re->ipv6RouteIfIndex, sizeof(ifname)); rt.rt_ifp = if_find(ctx->ifaces, ifname); @@ -1456,8 +1514,10 @@ int if_address(unsigned char cmd, const struct ipv4_addr *ia) { - struct sockaddr_storage ss_addr, ss_mask; - struct sockaddr_in *sin_addr, *sin_mask; + union { + struct sockaddr sa; + struct sockaddr_storage ss; + } addr, mask, brd; /* Either remove the alias or ensure it exists. */ if (if_plumb(cmd, ia->iface->ctx, AF_INET, ia->alias) == -1) @@ -1474,24 +1534,24 @@ /* We need to update the index now */ ia->iface->index = if_nametoindex(ia->alias); - sin_addr = (struct sockaddr_in *)&ss_addr; - sin_addr->sin_family = AF_INET; - sin_addr->sin_addr = ia->addr; - sin_mask = (struct sockaddr_in *)&ss_mask; - sin_mask->sin_family = AF_INET; - sin_mask->sin_addr = ia->mask; - return if_addaddr(ia->iface->ctx->pf_inet_fd, - ia->alias, &ss_addr, &ss_mask); + sa_in_init(&addr.sa, &ia->addr); + sa_in_init(&mask.sa, &ia->mask); + sa_in_init(&brd.sa, &ia->brd); + return if_addaddr(ia->iface->ctx->pf_inet_fd, ia->alias, + &addr.ss, &mask.ss, &brd.ss); } int -if_addrflags(const struct interface *ifp, __unused const struct in_addr *addr, +if_addrflags(const struct interface *ifp, const struct in_addr *addr, const char *alias) { - int flags, aflags; + union sa_ss ss; + uint64_t aflags; + int flags; - aflags = if_addrflags0(ifp->ctx->pf_inet_fd, alias); - if (aflags == -1) + sa_in_init(&ss.sa, addr); + aflags = if_addrflags0(ifp->ctx->pf_inet_fd, alias, &ss.sa); + if (aflags == 0) return -1; flags = 0; if (aflags & IFF_DUPLICATE) @@ -1505,9 +1565,12 @@ int if_address6(unsigned char cmd, const struct ipv6_addr *ia) { - struct sockaddr_storage ss_addr, ss_mask; - struct sockaddr_in6 *sin6_addr, *sin6_mask; - struct priv *priv; + union { + struct sockaddr sa; + struct sockaddr_in6 sin6; + struct sockaddr_storage ss; + } addr, mask; + const struct priv *priv; int r; /* Either remove the alias or ensure it exists. */ @@ -1522,29 +1585,30 @@ return -1; } - priv = (struct priv *)ia->iface->ctx->priv; - sin6_addr = (struct sockaddr_in6 *)&ss_addr; - sin6_addr->sin6_family = AF_INET6; - sin6_addr->sin6_addr = ia->addr; - sin6_mask = (struct sockaddr_in6 *)&ss_mask; - sin6_mask->sin6_family = AF_INET6; - ipv6_mask(&sin6_mask->sin6_addr, ia->prefix_len); - r = if_addaddr(priv->pf_inet6_fd, - ia->alias, &ss_addr, &ss_mask); + sa_in6_init(&addr.sa, &ia->addr); + mask.sin6.sin6_family = AF_INET6; + ipv6_mask(&mask.sin6.sin6_addr, ia->prefix_len); + priv = (const struct priv *)ia->iface->ctx->priv; + r = if_addaddr(priv->pf_inet6_fd, ia->alias, &addr.ss, &mask.ss, NULL); if (r == -1 && errno == EEXIST) return 0; return r; } int -if_addrflags6(const struct interface *ifp, __unused const struct in6_addr *addr, +if_addrflags6(const struct interface *ifp, const struct in6_addr *addr, const char *alias) { struct priv *priv; - int aflags, flags; + union sa_ss ss; + uint64_t aflags; + int flags; priv = (struct priv *)ifp->ctx->priv; - aflags = if_addrflags0(priv->pf_inet6_fd, alias); + sa_in6_init(&ss.sa, addr); + aflags = if_addrflags0(priv->pf_inet6_fd, alias, &ss.sa); + if (aflags == 0) + return -1; flags = 0; if (aflags & IFF_DUPLICATE) flags |= IN6_IFF_DUPLICATED;
--- a/src/ipv4.h Fri Apr 19 21:54:19 2019 +0100 +++ b/src/ipv4.h Fri Apr 26 14:07:35 2019 +0100 @@ -62,9 +62,8 @@ * While it supports DaD, to seems to only expose IFF_DUPLICATE * so we have no way of knowing if it's tentative or not. * I don't even know if Solaris has any special treatment for tentative. */ -# define IN_IFF_TENTATIVE 0 # define IN_IFF_DUPLICATED 0x02 -# define IN_IFF_DETACHED 0 +# define IN_IFF_NOTUSEABLE IN_IFF_DUPLICATED #endif #ifdef IN_IFF_TENTATIVE
--- a/src/ipv4ll.c Fri Apr 19 21:54:19 2019 +0100 +++ b/src/ipv4ll.c Fri Apr 26 14:07:35 2019 +0100 @@ -398,7 +398,7 @@ ia = ipv4_iffindlladdr(ifp); repick = false; -#ifdef IN_IFF_TENTATIVE +#ifdef IN_IFF_DUPLICATED if (ia != NULL && ia->addr_flags & IN_IFF_DUPLICATED) { state->pickedaddr = ia->addr; /* So it's not picked again. */ repick = true; @@ -419,6 +419,8 @@ ifp->name, inet_ntoa(ia->addr)); return; } +#endif +#ifdef IN_IFF_DUPLICATED loginfox("%s: using IPv4LL address %s", ifp->name, ia->saddr); #endif ipv4ll_not_found(ifp); @@ -431,7 +433,7 @@ #ifndef KERNEL_RFC5227 astate->addr = state->pickedaddr; #endif -#ifdef IN_IFF_TENTATIVE +#ifdef IN_IFF_DUPLICATED ipv4ll_not_found(ifp); #else arp_probe(astate);
--- a/src/ipv6.c Fri Apr 19 21:54:19 2019 +0100 +++ b/src/ipv6.c Fri Apr 26 14:07:35 2019 +0100 @@ -137,7 +137,9 @@ return -1; TAILQ_INIT(ctx->ra_routers); +#ifndef __sun ctx->nd_fd = -1; +#endif ctx->dhcp6_fd = -1; return 0; }
--- a/src/ipv6.h Fri Apr 19 21:54:19 2019 +0100 +++ b/src/ipv6.h Fri Apr 26 14:07:35 2019 +0100 @@ -44,9 +44,6 @@ # endif #endif -#define ALLNODES "ff02::1" -#define ALLROUTERS "ff02::2" - #define EUI64_GBIT 0x01 #define EUI64_UBIT 0x02 #define EUI64_TO_IFID(in6) do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0) @@ -77,6 +74,17 @@ (((d)->s6_addr32[3] ^ (a)->s6_addr32[3]) & (m)->s6_addr32[3]) == 0 ) #endif +#ifndef IN6ADDR_LINKLOCAL_ALLNODES_INIT +#define IN6ADDR_LINKLOCAL_ALLNODES_INIT \ + {{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }}} +#endif +#ifndef IN6ADDR_LINKLOCAL_ALLROUTERS_INIT +#define IN6ADDR_LINKLOCAL_ALLROUTERS_INIT \ + {{{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }}} +#endif + /* * BSD kernels don't inform userland of DAD results. * See the discussion here:
--- a/src/ipv6nd.c Fri Apr 19 21:54:19 2019 +0100 +++ b/src/ipv6nd.c Fri Apr 26 14:07:35 2019 +0100 @@ -160,6 +160,12 @@ #define IPV6_RECVPKTINFO IPV6_PKTINFO #endif +#ifdef __sun +struct in6_addr all_nodes_mcast = { .s6_addr = { + 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } }; +#endif + /* Handy defines */ #define ipv6nd_free_ra(ra) ipv6nd_freedrop_ra((ra), 0) #define ipv6nd_drop_ra(ra) ipv6nd_freedrop_ra((ra), 1) @@ -190,54 +196,106 @@ } static int -ipv6nd_open(struct dhcpcd_ctx *ctx) +ipv6nd_open0(void) { - int on; + int s, on; struct icmp6_filter filt; - if (ctx->nd_fd != -1) - return ctx->nd_fd; #define SOCK_FLAGS SOCK_CLOEXEC | SOCK_NONBLOCK - ctx->nd_fd = xsocket(PF_INET6, SOCK_RAW | SOCK_FLAGS, IPPROTO_ICMPV6); + s = xsocket(PF_INET6, SOCK_RAW | SOCK_FLAGS, IPPROTO_ICMPV6); #undef SOCK_FLAGS - if (ctx->nd_fd == -1) + if (s == -1) return -1; /* RFC4861 4.1 */ on = 255; - if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, + if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &on, sizeof(on)) == -1) goto eexit; on = 1; - if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, - &on, sizeof(on)) == -1) - goto eexit; - - on = 1; - if (setsockopt(ctx->nd_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on)) == -1) goto eexit; ICMP6_FILTER_SETBLOCKALL(&filt); ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filt); ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); - if (setsockopt(ctx->nd_fd, IPPROTO_ICMPV6, ICMP6_FILTER, + if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt)) == -1) goto eexit; - eloop_event_add(ctx->eloop, ctx->nd_fd, ipv6nd_handledata, ctx); - return ctx->nd_fd; + return s; eexit: - if (ctx->nd_fd != -1) { - eloop_event_delete(ctx->eloop, ctx->nd_fd); - close(ctx->nd_fd); - ctx->nd_fd = -1; - } + close(s); return -1; } +#ifdef __sun +static int +ipv6nd_open(struct interface *ifp) +{ + int s; + struct ipv6_mreq mreq = { + .ipv6mr_multiaddr = all_nodes_mcast, + .ipv6mr_interface = ifp->index + }; + struct rs_state *state = RS_STATE(ifp); + uint_t ifindex = ifp->index; + + if (state->nd_fd != -1) + return state->nd_fd; + + s = ipv6nd_open0(); + if (s == -1) + return -1; + + if (setsockopt(s, IPPROTO_IPV6, IPV6_BOUND_IF, + &ifindex, sizeof(ifindex)) == -1) + { + close(s); + return -1; + } + + if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, + &mreq, sizeof(mreq)) == -1) + { + close(s); + return -1; + } + + state->nd_fd = s; + eloop_event_add(ifp->ctx->eloop, s, ipv6nd_handledata, ifp); + return s; +} +#else +static int +ipv6nd_open(struct dhcpcd_ctx *ctx) +{ + int s, on; + + if (ctx->nd_fd != -1) + return ctx->nd_fd; + + s = ipv6nd_open0(); + if (s == -1) + return -1; + + on = 1; + if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, + &on, sizeof(on)) == -1) + { + close(s); + return -1; + } + + ctx->nd_fd = s; + eloop_event_add(ctx->eloop, s, ipv6nd_handledata, ctx); + return s; +} +#endif + static int ipv6nd_makersprobe(struct interface *ifp) { @@ -273,9 +331,12 @@ ipv6nd_sendrsprobe(void *arg) { struct interface *ifp = arg; - struct dhcpcd_ctx *ctx; struct rs_state *state = RS_STATE(ifp); - struct sockaddr_in6 dst = { .sin6_family = AF_INET6 }; + struct sockaddr_in6 dst = { + .sin6_family = AF_INET6, + .sin6_addr = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT, + .sin6_scope_id = ifp->index, + }; struct iovec iov = { .iov_base = state->rs, .iov_len = state->rslen }; unsigned char ctl[CMSG_SPACE(sizeof(struct in6_pktinfo))] = { 0 }; struct msghdr msg = { @@ -285,6 +346,7 @@ }; struct cmsghdr *cm; struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index }; + int s; if (ipv6_linklocal(ifp) == NULL) { logdebugx("%s: delaying Router Solicitation for LL address", @@ -296,13 +358,6 @@ #ifdef HAVE_SA_LEN dst.sin6_len = sizeof(dst); #endif - dst.sin6_scope_id = ifp->index; - if (inet_pton(AF_INET6, ALLROUTERS, &dst.sin6_addr) != 1) { - logerr(__func__); - return; - } - - ctx = ifp->ctx; /* Set the outbound interface */ cm = CMSG_FIRSTHDR(&msg); @@ -314,7 +369,12 @@ memcpy(CMSG_DATA(cm), &pi, sizeof(pi)); logdebugx("%s: sending Router Solicitation", ifp->name); - if (sendmsg(ctx->nd_fd, &msg, 0) == -1) { +#ifdef __sun + s = state->nd_fd; +#else + s = ifp->ctx->nd_fd; +#endif + if (sendmsg(s, &msg, 0) == -1) { logerr(__func__); /* Allow IPv6ND to continue .... at most a few errors * would be logged. @@ -342,6 +402,7 @@ struct dhcpcd_ctx *ctx = ifp->ctx; struct sockaddr_in6 dst = { .sin6_family = AF_INET6, + .sin6_addr = IN6ADDR_LINKLOCAL_ALLNODES_INIT, .sin6_scope_id = ifp->index, }; struct iovec iov = { .iov_base = ia->na, .iov_len = ia->na_len }; @@ -354,6 +415,7 @@ struct cmsghdr *cm; struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index }; const struct rs_state *state = RS_CSTATE(ifp); + int s; if (state == NULL || ifp->carrier <= LINK_DOWN) goto freeit; @@ -361,10 +423,6 @@ #ifdef SIN6_LEN dst.sin6_len = sizeof(dst); #endif - if (inet_pton(AF_INET6, ALLNODES, &dst.sin6_addr) != 1) { - logerr(__func__); - return; - } /* Set the outbound interface. */ cm = CMSG_FIRSTHDR(&msg); @@ -373,10 +431,20 @@ cm->cmsg_type = IPV6_PKTINFO; cm->cmsg_len = CMSG_LEN(sizeof(pi)); memcpy(CMSG_DATA(cm), &pi, sizeof(pi)); - logdebugx("%s: sending NA for %s", ifp->name, ia->saddr); - if (sendmsg(ctx->nd_fd, &msg, 0) == -1) +#ifdef __sun + s = state->nd_fd; +#else + s = ctx->nd_fd; +#endif + if (sendmsg(s, &msg, 0) == -1) +#ifdef __OpenBSD__ +/* This isn't too critical as they don't support IPv6 address sharing */ +#warning Cannot send NA messages on OpenBSD + logdebug(__func__); +#else logerr(__func__); +#endif if (++ia->na_count < MAX_NEIGHBOR_ADVERTISEMENT) { eloop_timeout_add_sec(ctx->eloop, @@ -619,6 +687,11 @@ if (state == NULL) return 0; + ctx = ifp->ctx; +#ifdef __sun + eloop_event_delete(ctx->eloop, state->nd_fd); + close(state->nd_fd); +#endif free(state->rs); free(state); ifp->if_data[IF_DATA_IPV6ND] = NULL; @@ -630,9 +703,9 @@ } } +#ifndef __sun /* If we don't have any more IPv6 enabled interfaces, * close the global socket and release resources */ - ctx = ifp->ctx; TAILQ_FOREACH(ifp, ctx->ifaces, next) { if (RS_STATE(ifp)) break; @@ -644,6 +717,7 @@ ctx->nd_fd = -1; } } +#endif return n; } @@ -1659,6 +1733,7 @@ ipv6nd_handledata(void *arg) { struct dhcpcd_ctx *ctx; + int s; struct sockaddr_in6 from; unsigned char buf[64 * 1024]; /* Maximum ICMPv6 size */ struct iovec iov = { @@ -1677,8 +1752,18 @@ struct icmp6_hdr *icp; struct interface *ifp; +#ifdef __sun + struct rs_state *state; + + ifp = arg; + state = RS_STATE(ifp); + ctx = ifp->ctx; + s = state->nd_fd; +#else ctx = arg; - len = recvmsg(ctx->nd_fd, &msg, 0); + s = ctx->nd_fd; +#endif + len = recvmsg(s, &msg, 0); if (len == -1) { logerr(__func__); return; @@ -1689,11 +1774,15 @@ return; } +#ifdef __sun + if_findifpfromcmsg(ctx, &msg, &hoplimit); +#else ifp = if_findifpfromcmsg(ctx, &msg, &hoplimit); if (ifp == NULL) { logerr(__func__); return; } +#endif /* Don't do anything if the user hasn't configured it. */ if (ifp->active != IF_ACTIVE_USER || @@ -1725,11 +1814,6 @@ struct rs_state *state; loginfox("%s: soliciting an IPv6 router", ifp->name); - if (ipv6nd_open(ifp->ctx) == -1) { - logerr(__func__); - return; - } - state = RS_STATE(ifp); if (state == NULL) { ifp->if_data[IF_DATA_IPV6ND] = calloc(1, sizeof(*state)); @@ -1738,8 +1822,23 @@ logerr(__func__); return; } +#ifdef __sun + state->nd_fd = -1; +#endif } +#ifdef __sun + if (ipv6nd_open(ifp) == -1) { + logerr(__func__); + return; + } +#else + if (ipv6nd_open(ifp->ctx) == -1) { + logerr(__func__); + return; + } +#endif + /* Always make a new probe as the underlying hardware * address could have changed. */ ipv6nd_makersprobe(ifp);
