From: Roy Marples Date: Sat, 4 Apr 2015 21:40:47 +0000 (+0000) Subject: If we receieve an RA without a public prefix but with the Managed flag set, X-Git-Tag: v6.8.2~34 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d40f2f7b8da5733fae2e43f408e095851d1636fd;p=thirdparty%2Fdhcpcd.git If we receieve an RA without a public prefix but with the Managed flag set, ignore the RA until we recieve a DHCPv6 lease with a public address at which point it is applied. --- diff --git a/dhcp6.c b/dhcp6.c index b588be78..7b94caf7 100644 --- a/dhcp6.c +++ b/dhcp6.c @@ -487,6 +487,22 @@ dhcp6_delegateaddr(struct in6_addr *addr, struct interface *ifp, return sla->prefix_len; } +int +dhcp6_has_public_addr(const struct interface *ifp) +{ + const struct dhcp6_state *state = D6_CSTATE(ifp); + const struct ipv6_addr *ia; + + if (state == NULL) + return 0; + TAILQ_FOREACH(ia, &state->addrs, next) { + if (ia->prefix_pltime && + (ia->addr.s6_addr[0] & 0xfe) != 0xc) + return 1; + } + return 0; +} + static int dhcp6_makemessage(struct interface *ifp) { @@ -3033,6 +3049,7 @@ recv: eloop_timeout_add_sec(ifp->ctx->eloop, (time_t)state->expire, dhcp6_startexpire, ifp); + ipv6nd_runignoredra(ifp); ipv6_addaddrs(&state->addrs); dhcp6_delegate_prefix(ifp); diff --git a/dhcp6.h b/dhcp6.h index aee627a6..41b2213c 100644 --- a/dhcp6.h +++ b/dhcp6.h @@ -235,6 +235,7 @@ void dhcp6_printoptions(const struct dhcpcd_ctx *, struct ipv6_addr *dhcp6_findaddr(struct dhcpcd_ctx *, const struct in6_addr *, short); size_t dhcp6_find_delegates(struct interface *); +int dhcp6_has_public_addr(const struct interface *); int dhcp6_start(struct interface *, enum DH6S); void dhcp6_reboot(struct interface *); ssize_t dhcp6_env(char **, const char *, const struct interface *, diff --git a/ipv6nd.c b/ipv6nd.c index 7b803471..5f33d9fc 100644 --- a/ipv6nd.c +++ b/ipv6nd.c @@ -1136,8 +1136,9 @@ extra_opt: if (new_rap) add_router(ifp->ctx->ipv6, rap); if (!ipv6nd_ra_has_public_addr(rap) && - !(rap->flags & ND_RA_FLAG_MANAGED) && - !(rap->iface->options->options & DHCPCD_IPV6RA_ACCEPT_NOPUBLIC)) + !(rap->iface->options->options & DHCPCD_IPV6RA_ACCEPT_NOPUBLIC) && + (!(rap->flags & ND_RA_FLAG_MANAGED) || + !dhcp6_has_public_addr(rap->iface))) { logger(rap->iface->ctx, rap->no_public_warned ? LOG_DEBUG : LOG_WARNING, @@ -1194,6 +1195,34 @@ nodhcp6: ipv6nd_expirera(ifp); } +/* Run RA's we ignored becuase they had no public addresses + * This should only be called when DHCPv6 applies a public address */ +void +ipv6nd_runignoredra(struct interface *ifp) +{ + struct ra *rap; + + TAILQ_FOREACH(rap, ifp->ctx->ipv6->ra_routers, next) { + if (rap->iface == ifp && + !rap->expired && + rap->no_public_warned) + { + rap->no_public_warned = 0; + logger(rap->iface->ctx, LOG_INFO, + "%s: applying ignored RA from %s", + rap->iface->name, rap->sfrom); + if (ifp->ctx->options & DHCPCD_TEST) { + script_runreason(ifp, "TEST"); + continue; + } + if (ipv6nd_scriptrun(rap)) + return; + eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp); + eloop_timeout_delete(ifp->ctx->eloop, NULL, rap); + } + } +} + int ipv6nd_hasra(const struct interface *ifp) { diff --git a/ipv6nd.h b/ipv6nd.h index e1e74570..cb71d746 100644 --- a/ipv6nd.h +++ b/ipv6nd.h @@ -94,6 +94,7 @@ ssize_t ipv6nd_free(struct interface *); void ipv6nd_expirera(void *arg); int ipv6nd_hasra(const struct interface *); int ipv6nd_hasradhcp(const struct interface *); +void ipv6nd_runignoredra(struct interface *); void ipv6nd_handleifa(struct dhcpcd_ctx *, int, const char *, const struct in6_addr *, int); int ipv6nd_dadcompleted(const struct interface *);