]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
If a IPv6 router claims it's a valid router but doesn't have any public
authorRoy Marples <roy@marples.name>
Fri, 3 Apr 2015 23:36:06 +0000 (23:36 +0000)
committerRoy Marples <roy@marples.name>
Fri, 3 Apr 2015 23:36:06 +0000 (23:36 +0000)
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.

dhcpcd.conf.5.in
if-options.c
if-options.h
ipv6.c
ipv6nd.h

index a0e927e0b0ce712c6fc39736abc2580d957bd5aa..8bcf320235d9a16ecb7b7f1aa9a9121b899fbc70 100644 (file)
@@ -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
index f2d781022cdc4cc9853c0e01faa9af3c7f30562d..75eda5b9f60e2ebc2beee6205464b4dc656fd4e1 100644 (file)
@@ -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;
index 087615b6b62783b4026f2f716a3d5c7e143c45fe..5b697fb17fb801d4e79bc150654e245ee22c70da 100644 (file)
 #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 966b516ce3d145dd3c13fb262636c809a75ac764..530bf45c2ff72c2a7c41c3a19f8a50797b58dd05 100644 (file)
--- 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);
+                       }
                }
        }
 }
index 5beaacad12781271691a4bc08b227f80345a51bf..0066f3909818a6696b361c0b57c7af4f06aafe06 100644 (file)
--- 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);