From: Roy Marples Date: Fri, 3 Apr 2015 23:36:06 +0000 (+0000) Subject: If a IPv6 router claims it's a valid router but doesn't have any public X-Git-Tag: v6.8.2~38 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a8e5259b41b43dd89af8ed66ce1dd881806cc129;p=thirdparty%2Fdhcpcd.git If a IPv6 router claims it's a valid router but doesn't have any public prefixes, don't install a default route for it. If we did, some OS's will just stall trying to reach global addresses. By not installing the default route, they can fall back to IPv4 faster. This can be overridden with ipv6ra_always_default. --- diff --git a/dhcpcd.conf.5.in b/dhcpcd.conf.5.in index a0e927e0..8bcf3202 100644 --- a/dhcpcd.conf.5.in +++ b/dhcpcd.conf.5.in @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd March 17, 2015 +.Dd April 4, 2015 .Dt DHCPCD.CONF 5 .Os .Sh NAME @@ -368,6 +368,12 @@ Each time dhcpcd receives an IPv6 Router Adveristment, dhcpcd will manage the default route only. This allows dhcpcd to prefer an interface for outbound traffic based on metric and/or user selection rather than the kernel. +.It Ic ipv6ra_always_default +Some IPv6 routers advertise themselves as a default router without any +public prefixes. +Generally, this is incorrect behaviour and +.Nm dhcpcd +will not install a default route for them unless this option is turned on. .It Ic ipv6rs Enables IPv6 Router Advertisment solicitation. This is on by default, but is documented here in the case where it is disabled diff --git a/if-options.c b/if-options.c index f2d78102..75eda5b9 100644 --- a/if-options.c +++ b/if-options.c @@ -97,6 +97,7 @@ #define O_IPV6RA_AUTOCONF O_BASE + 38 #define O_IPV6RA_NOAUTOCONF O_BASE + 39 #define O_REJECT O_BASE + 40 +#define O_IPV6RA_ALWAYS_DEFAULT O_BASE + 41 const struct option cf_options[] = { {"background", no_argument, NULL, 'b'}, @@ -156,6 +157,7 @@ const struct option cf_options[] = { {"ipv6ra_fork", no_argument, NULL, O_IPV6RA_FORK}, {"ipv6ra_own", no_argument, NULL, O_IPV6RA_OWN}, {"ipv6ra_own_default", no_argument, NULL, O_IPV6RA_OWN_D}, + {"ipv6ra_always_default", no_argument, NULL, O_IPV6RA_ALWAYS_DEFAULT}, {"ipv4only", no_argument, NULL, '4'}, {"ipv6only", no_argument, NULL, '6'}, {"ipv4", no_argument, NULL, O_IPV4}, @@ -1234,6 +1236,9 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo, case O_IPV6RA_OWN_D: ifo->options |= DHCPCD_IPV6RA_OWN_DEFAULT; break; + case O_IPV6RA_ALWAYS_DEFAULT: + ifo->options |= DHCPCD_IPV6RA_ALWAYS_DEFAULT; + break; case O_IPV6RA_AUTOCONF: ifo->options |= DHCPCD_IPV6RA_AUTOCONF; break; diff --git a/if-options.h b/if-options.h index 087615b6..5b697fb1 100644 --- a/if-options.h +++ b/if-options.h @@ -109,6 +109,7 @@ #define DHCPCD_PFXDLGMIX (1ULL << 53) #define DHCPCD_IPV6RA_AUTOCONF (1ULL << 54) #define DHCPCD_ROUTER_HOST_ROUTE_WARNED (1ULL << 55) +#define DHCPCD_IPV6RA_ALWAYS_DEFAULT (1ULL << 56) extern const struct option cf_options[]; diff --git a/ipv6.c b/ipv6.c index 966b516c..530bf45c 100644 --- a/ipv6.c +++ b/ipv6.c @@ -1956,11 +1956,23 @@ make_router(const struct ra *rap) (IN6_ARE_ADDR_EQUAL(&((rtp)->dest), &in6addr_any) && \ IN6_ARE_ADDR_EQUAL(&((rtp)->net), &in6addr_any)) +static int +ra_has_public_addr(const struct ra *rap) +{ + const struct ipv6_addr *ia; + + TAILQ_FOREACH(ia, &rap->addrs, next) { + if (ia->prefix_pltime && (ia->addr.s6_addr[0] & 0xfe) != 0xfc) + return 1; + } + return 0; +} + static void ipv6_build_ra_routes(struct ipv6_ctx *ctx, struct rt6_head *dnr, int expired) { struct rt6 *rt; - const struct ra *rap; + struct ra *rap; const struct ipv6_addr *addr; TAILQ_FOREACH(rap, ctx->ra_routers, next) { @@ -1976,9 +1988,19 @@ ipv6_build_ra_routes(struct ipv6_ctx *ctx, struct rt6_head *dnr, int expired) if (rap->lifetime && rap->iface->options->options & (DHCPCD_IPV6RA_OWN | DHCPCD_IPV6RA_OWN_DEFAULT)) { - rt = make_router(rap); - if (rt) - TAILQ_INSERT_TAIL(dnr, rt, next); + if (!ra_has_public_addr(rap)) { + logger(rap->iface->ctx, + rap->no_default_warned ? + LOG_DEBUG : LOG_WARNING, + "%s: ignoring default route from %s" + " (no public prefix)", + rap->iface->name, rap->sfrom); + rap->no_default_warned = 1; + } else { + rt = make_router(rap); + if (rt) + TAILQ_INSERT_TAIL(dnr, rt, next); + } } } } diff --git a/ipv6nd.h b/ipv6nd.h index 5beaacad..0066f390 100644 --- a/ipv6nd.h +++ b/ipv6nd.h @@ -56,7 +56,8 @@ struct ra { uint32_t mtu; struct ipv6_addrhead addrs; TAILQ_HEAD(, ra_opt) options; - int expired; + uint8_t expired; + uint8_t no_default_warned; }; TAILQ_HEAD(ra_head, ra);