diff --git a/CHANGELOG b/CHANGELOG index 1d02364..bc402bb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -44,7 +44,12 @@ version 2.68 isn't possible for IPv4 and can generate scary warnings, but as it's always possible for IPv6 (the API always exists) then we should do it always. - + + Tweak the rules on prefix-lengths in --dhcp-range for + IPv6. The new rule is that the specified prefix length + must be larger than or equal to the prefix length of the + corresponding address on the local interface. + version 2.67 Fix crash if upstream server returns SERVFAIL when diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index 049f664..e85d272 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -673,7 +673,8 @@ always optional. It is always allowed to have more than one dhcp-range in a single subnet. For IPv6, the parameters are slightly different: instead of netmask -and broadcast address, there is an optional prefix length. If not +and broadcast address, there is an optional prefix length which must +be equal to or larger then the prefix length on the local interface. If not given, this defaults to 64. Unlike the IPv4 case, the prefix length is not automatically derived from the interface configuration. The mimimum size of the prefix length is 64. diff --git a/src/dhcp6.c b/src/dhcp6.c index ca7014f..8c762fd 100644 --- a/src/dhcp6.c +++ b/src/dhcp6.c @@ -330,9 +330,9 @@ static int complete_context6(struct in6_addr *local, int prefix, { if ((context->flags & CONTEXT_DHCP) && !(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) && - prefix == context->prefix && - is_same_net6(local, &context->start6, prefix) && - is_same_net6(local, &context->end6, prefix)) + prefix <= context->prefix && + is_same_net6(local, &context->start6, context->prefix) && + is_same_net6(local, &context->end6, context->prefix)) { @@ -631,9 +631,9 @@ static int construct_worker(struct in6_addr *local, int prefix, if (!(template->flags & CONTEXT_TEMPLATE)) { /* non-template entries, just fill in interface and local addresses */ - if (prefix == template->prefix && - is_same_net6(local, &template->start6, prefix) && - is_same_net6(local, &template->end6, prefix)) + if (prefix <= template->prefix && + is_same_net6(local, &template->start6, template->prefix) && + is_same_net6(local, &template->end6, template->prefix)) { template->if_index = if_index; template->local6 = *local; @@ -641,7 +641,7 @@ static int construct_worker(struct in6_addr *local, int prefix, } else if (wildcard_match(template->template_interface, ifrn_name) && - template->prefix == prefix) + template->prefix >= prefix) { start6 = *local; setaddr6part(&start6, addr6part(&template->start6)); diff --git a/src/radv.c b/src/radv.c index 93503a0..f01b136 100644 --- a/src/radv.c +++ b/src/radv.c @@ -430,7 +430,7 @@ static int add_prefixes(struct in6_addr *local, int prefix, else if (!IN6_IS_ADDR_LOOPBACK(local) && !IN6_IS_ADDR_MULTICAST(local)) { - int do_prefix = 0; + int real_prefix = 0; int do_slaac = 0; int deprecate = 0; int constructed = 0; @@ -439,9 +439,9 @@ static int add_prefixes(struct in6_addr *local, int prefix, for (context = daemon->dhcp6; context; context = context->next) if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) && - prefix == context->prefix && - is_same_net6(local, &context->start6, prefix) && - is_same_net6(local, &context->end6, prefix)) + prefix <= context->prefix && + is_same_net6(local, &context->start6, context->prefix) && + is_same_net6(local, &context->end6, context->prefix)) { context->saved_valid = valid; @@ -496,7 +496,7 @@ static int add_prefixes(struct in6_addr *local, int prefix, if (!param->first) context->ra_time = 0; context->flags |= CONTEXT_RA_DONE; - do_prefix = 1; + real_prefix = context->prefix; } param->first = 0; @@ -523,18 +523,18 @@ static int add_prefixes(struct in6_addr *local, int prefix, param->link_global = *local; } - if (do_prefix) + if (real_prefix != 0) { struct prefix_opt *opt; if ((opt = expand(sizeof(struct prefix_opt)))) { /* zero net part of address */ - setaddr6part(local, addr6part(local) & ~((prefix == 64) ? (u64)-1LL : (1LLU << (128 - prefix)) - 1LLU)); + setaddr6part(local, addr6part(local) & ~((real_prefix == 64) ? (u64)-1LL : (1LLU << (128 - real_prefix)) - 1LLU)); opt->type = ICMP6_OPT_PREFIX; opt->len = 4; - opt->prefix_len = prefix; + opt->prefix_len = real_prefix; /* autonomous only if we're not doing dhcp, always set "on-link" */ opt->flags = do_slaac ? 0xC0 : 0x80; opt->valid_lifetime = htonl(valid); @@ -645,9 +645,9 @@ static int iface_search(struct in6_addr *local, int prefix, for (context = daemon->dhcp6; context; context = context->next) if (!(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) && - prefix == context->prefix && - is_same_net6(local, &context->start6, prefix) && - is_same_net6(local, &context->end6, prefix) && + prefix <= context->prefix && + is_same_net6(local, &context->start6, context->prefix) && + is_same_net6(local, &context->end6, context->prefix) && context->ra_time != 0 && difftime(context->ra_time, param->now) <= 0.0) { @@ -670,9 +670,9 @@ static int iface_search(struct in6_addr *local, int prefix, /* zero timers for other contexts on the same subnet, so they don't timeout independently */ for (context = context->next; context; context = context->next) - if (prefix == context->prefix && - is_same_net6(local, &context->start6, prefix) && - is_same_net6(local, &context->end6, prefix)) + if (prefix <= context->prefix && + is_same_net6(local, &context->start6, context->prefix) && + is_same_net6(local, &context->end6, context->prefix)) context->ra_time = 0; return 0; /* found, abort */