Mercurial > hg > dhcpcd
changeset 5018:c6939d42b8f5 draft
BSD: When applying RA base information, ensure flags are correct
For some resaon, under privsep only, SIOCGIFINFO_IN6 returns 0
in flags even though the kernel seems to set it correctly.
SIOCSIFINFO_IN6 *will* overwrite flags regardless, so ensure
it has the correct value for dhcpcd.
| author | Roy Marples <roy@marples.name> |
|---|---|
| date | Tue, 04 Feb 2020 15:21:40 +0000 |
| parents | 77229ebb3f6b |
| children | b7da0da3e019 |
| files | src/if-bsd.c |
| diffstat | 1 files changed, 63 insertions(+), 45 deletions(-) [+] |
line wrap: on
line diff
--- a/src/if-bsd.c Tue Feb 04 15:01:18 2020 +0000 +++ b/src/if-bsd.c Tue Feb 04 15:21:40 2020 +0000 @@ -1585,23 +1585,71 @@ } #endif +#if defined(SIOCSIFINFO_IN6) || defined(SIOCSIFINFO_FLAGS) +static uint32_t +if_if6flags(const struct interface *ifp, uint32_t oflags) +{ + int flags = (int)oflags; + +#ifdef ND6_IFF_AUTO_LINKLOCAL + /* Unlike the kernel, + * dhcpcd make make a stable private address. */ + flags &= ~ND6_IFF_AUTO_LINKLOCAL; +#endif + +#ifdef ND6_IFF_IFDISABLED + /* Ensure the interface is not disabled. */ + flags &= ~ND6_IFF_IFDISABLED; +#endif + +#ifdef ND6_IFF_PERFORMNUD + /* NUD is kind of essential. */ + flags |= ND6_IFF_PERFORMNUD; +#endif + + /* + * If not doing autoconf, don't disable the kernel from doing it. + * If we need to, we should have another option actively disable it. + */ +#ifdef ND6_IFF_ACCEPT_RTADV + if (ifp->options->options & DHCPCD_IPV6RS) + flags &= ~ND6_IFF_ACCEPT_RTADV; +#ifdef ND6_IFF_OVERRIDE_RTADV + if (ifp->options->options & DHCPCD_IPV6RS) + flags |= ND6_IFF_OVERRIDE_RTADV; +#endif +#endif + + return (uint32_t)flags; +} +#endif + int if_applyra(const struct ra *rap) { #ifdef SIOCSIFINFO_IN6 - struct in6_ndireq ndi = { .ndi.chlim = 0 }; + struct in6_ndireq nd; struct dhcpcd_ctx *ctx = rap->iface->ctx; int error; - strlcpy(ndi.ifname, rap->iface->name, sizeof(ndi.ifname)); - if (if_ioctl6(ctx, SIOCGIFINFO_IN6, &ndi, sizeof(ndi)) == -1) + memset(&nd, 0, sizeof(nd)); + strlcpy(nd.ifname, rap->iface->name, sizeof(nd.ifname)); + if (if_ioctl6(ctx, SIOCGIFINFO_IN6, &nd, sizeof(nd)) == -1) return -1; - ndi.ndi.linkmtu = rap->mtu; - ndi.ndi.chlim = rap->hoplimit; - ndi.ndi.retrans = rap->retrans; - ndi.ndi.basereachable = rap->reachable; - error = if_ioctl6(ctx, SIOCSIFINFO_IN6, &ndi, sizeof(ndi)); + nd.ndi.linkmtu = rap->mtu; + nd.ndi.chlim = rap->hoplimit; + nd.ndi.retrans = rap->retrans; + nd.ndi.basereachable = rap->reachable; + /* + * Under privsep, flags are returned as zero - no idea why. + * SIOCSIFINFO_IN6 will replace the flags anyway so force them + * to our idea again. + */ + if (nd.ndi.flags == 0) + nd.ndi.flags = if_if6flags(rap->iface, nd.ndi.flags); + + error = if_ioctl6(ctx, SIOCSIFINFO_IN6, &nd, sizeof(nd)); if (error == -1 && errno == EINVAL) { /* * Very likely that this is caused by a dodgy MTU @@ -1610,8 +1658,8 @@ * Doesn't really matter as we fix the MTU against the * routes we add as not all OS support SIOCSIFINFO_IN6. */ - ndi.ndi.linkmtu = 0; - error = if_ioctl6(ctx, SIOCSIFINFO_IN6, &ndi, sizeof(ndi)); + nd.ndi.linkmtu = 0; + error = if_ioctl6(ctx, SIOCSIFINFO_IN6, &nd, sizeof(nd)); } return error; #else @@ -1815,7 +1863,7 @@ int s; #ifdef ND6_NDI_FLAGS struct in6_ndireq nd; - int flags; + uint32_t flags; #endif priv = (struct priv *)ifp->ctx->priv; @@ -1825,42 +1873,12 @@ memset(&nd, 0, sizeof(nd)); strlcpy(nd.ifname, ifp->name, sizeof(nd.ifname)); if (ioctl(s, SIOCGIFINFO_IN6, &nd) == -1) - logerr("%s: SIOCGIFINFO_FLAGS", ifp->name); - flags = (int)nd.ndi.flags; -#endif - -#ifdef ND6_IFF_AUTO_LINKLOCAL - /* Unlike the kernel, - * dhcpcd make make a stable private address. */ - flags &= ~ND6_IFF_AUTO_LINKLOCAL; -#endif - -#ifdef ND6_IFF_PERFORMNUD - /* NUD is kind of essential. */ - flags |= ND6_IFF_PERFORMNUD; -#endif + logerr("%s: SIOCGIFINFO_IN6", ifp->name); -#ifdef ND6_IFF_IFDISABLED - /* Ensure the interface is not disabled. */ - flags &= ~ND6_IFF_IFDISABLED; -#endif + flags = if_if6flags(ifp, nd.ndi.flags); - /* - * If not doing autoconf, don't disable the kernel from doing it. - * If we need to, we should have another option actively disable it. - */ -#ifdef ND6_IFF_ACCEPT_RTADV - if (ifp->options->options & DHCPCD_IPV6RS) - flags &= ~ND6_IFF_ACCEPT_RTADV; -#ifdef ND6_IFF_OVERRIDE_RTADV - if (ifp->options->options & DHCPCD_IPV6RS) - flags |= ND6_IFF_OVERRIDE_RTADV; -#endif -#endif - -#ifdef ND6_NDI_FLAGS - if (nd.ndi.flags != (uint32_t)flags) { - nd.ndi.flags = (uint32_t)flags; + if (nd.ndi.flags != flags) { + nd.ndi.flags = flags; if (if_ioctl6(ifp->ctx, SIOCSIFINFO_FLAGS, &nd, sizeof(nd)) == -1) logerr("%s: SIOCSIFINFO_FLAGS", ifp->name);
