summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG12
-rw-r--r--man/dnsmasq.88
-rw-r--r--src/dhcp6.c8
-rw-r--r--src/dnsmasq.c49
-rw-r--r--src/dnsmasq.h1
-rw-r--r--src/option.c12
-rw-r--r--src/radv.c104
-rw-r--r--src/rfc3315.c37
8 files changed, 124 insertions, 107 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 5431b49..0ed3953 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -55,6 +55,18 @@ version 2.61
received from a network which has no valid dhcp-range.
Thanks to Stephane Glondu for the bug report.
+ Add a new DHCP lease time keyword, "deprecated" for
+ --dhcp-range. This is only valid for IPv6, and sets the
+ preffered lease time for both DHCP and RA to zero. The
+ effect is that clients can continue to use the address
+ for existing connections, but new connections will use
+ other addresses, if they exist. This makes hitless
+ renumbering at least possible.
+
+ Fix bug in address6_available() which caused DHCPv6 lease
+ aquistion to fail of more than one dhcp-range in use.
+
+
version 2.60
Fix compilation problem in Mac OS X Lion. Thanks to Olaf
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index 0c9aef8..acc1920 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -522,8 +522,12 @@ options. If the lease time is given, then leases
will be given for that length of time. The lease time is in seconds,
or minutes (eg 45m) or hours (eg 1h) or "infinite". If not given,
the default lease time is one hour. The
-minimum lease time is two minutes. This
-option may be repeated, with different addresses, to enable DHCP
+minimum lease time is two minutes. For IPv6 ranges, the lease time
+maybe "deprecated"; this sets the preferred lifetime sent in a DHCP
+lease or router advertisement to zero, which causes clients to use
+other addresses, if available, for new connections as a prelude to renumbering.
+
+This option may be repeated, with different addresses, to enable DHCP
service to more than one network. For directly connected networks (ie,
networks on which the machine running dnsmasq has an interface) the
netmask is optional: dnsmasq will determine it from the interface
diff --git a/src/dhcp6.c b/src/dhcp6.c
index 305fec7..3956ff1 100644
--- a/src/dhcp6.c
+++ b/src/dhcp6.c
@@ -229,7 +229,7 @@ int address6_allocate(struct dhcp_context *context, unsigned char *clid, int cl
for (pass = 0; pass <= 1; pass++)
for (c = context; c; c = c->current)
- if (c->flags & (CONTEXT_STATIC | CONTEXT_RA_STATELESS))
+ if (c->flags & (CONTEXT_DEPRECATE | CONTEXT_STATIC | CONTEXT_RA_STATELESS))
continue;
else if (!match_netid(c->filter, netids, pass))
continue;
@@ -282,9 +282,9 @@ struct dhcp_context *address6_available(struct dhcp_context *context,
start = addr6part(&tmp->start6);
end = addr6part(&tmp->end6);
- if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_PROXY)) &&
- is_same_net6(&context->start6, taddr, context->prefix) &&
- is_same_net6(&context->end6, taddr, context->prefix) &&
+ if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_RA_STATELESS)) &&
+ is_same_net6(&tmp->start6, taddr, tmp->prefix) &&
+ is_same_net6(&tmp->end6, taddr, tmp->prefix) &&
addr >= start &&
addr <= end &&
match_netid(tmp->filter, netids, 1))
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index 7486738..983fc08 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -530,7 +530,7 @@ int main (int argc, char **argv)
my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
#ifdef HAVE_DHCP
- if (daemon->dhcp || daemon->dhcp6)
+ if (daemon->dhcp || daemon->dhcp6 || daemon->ra_contexts)
{
struct dhcp_context *dhcp_tmp;
int family = AF_INET;
@@ -543,7 +543,7 @@ int main (int argc, char **argv)
{
void *start = &dhcp_tmp->start;
void *end = &dhcp_tmp->end;
-
+
#ifdef HAVE_DHCP6
if (family == AF_INET6)
{
@@ -551,31 +551,48 @@ int main (int argc, char **argv)
end = &dhcp_tmp->end6;
struct in6_addr subnet = dhcp_tmp->start6;
setaddr6part(&subnet, 0);
- inet_ntop(AF_INET6, &subnet, daemon->dhcp_buff2, 256);
+ inet_ntop(AF_INET6, &subnet, daemon->addrbuff, 256);
}
#endif
- prettyprint_time(daemon->namebuff, dhcp_tmp->lease_time);
- inet_ntop(family, start, daemon->dhcp_buff, 256);
- inet_ntop(family, end, daemon->dhcp_buff3, 256);
+ if (family != AF_INET && (dhcp_tmp->flags & CONTEXT_DEPRECATE))
+ strcpy(daemon->namebuff, _("prefix deprecated"));
+ else
+ {
+ char *p = daemon->namebuff;
+ p += sprintf(p, _("lease time "));
+ prettyprint_time(p, dhcp_tmp->lease_time);
+ }
+
+ if (daemon->dhcp_buff)
+ inet_ntop(family, start, daemon->dhcp_buff, 256);
+ if (daemon->dhcp_buff3)
+ inet_ntop(family, end, daemon->dhcp_buff3, 256);
if ((dhcp_tmp->flags & CONTEXT_DHCP) || family == AF_INET)
my_syslog(MS_DHCP | LOG_INFO,
-#ifdef HAVE_DHCP6
(dhcp_tmp->flags & CONTEXT_RA_STATELESS) ?
- _("SLAAC and stateless DHCPv6 on %.0s%s%.0s") :
-#endif
+ _("stateless DHCPv6 on %s%.0s%.0s") :
(dhcp_tmp->flags & CONTEXT_STATIC) ?
- _("DHCP, static leases only on %.0s%s, lease time %s") :
+ _("DHCP, static leases only on %.0s%s, %s") :
(dhcp_tmp->flags & CONTEXT_PROXY) ?
_("DHCP, proxy on subnet %.0s%s%.0s") :
- _("DHCP, IP range %s -- %s, lease time %s"),
+ _("DHCP, IP range %s -- %s, %s"),
daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff);
-#ifdef HAVE_DHCP6
+
if (dhcp_tmp->flags & CONTEXT_RA_NAME)
- my_syslog(MS_DHCP | LOG_INFO, _("SLAAC and DHCPv4-derived names on %s"), daemon->dhcp_buff2);
- if (dhcp_tmp->flags & CONTEXT_RA_ONLY)
- my_syslog(MS_DHCP | LOG_INFO, _("SLAAC on %s"), daemon->dhcp_buff2);
-#endif
+ my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s"),
+ daemon->addrbuff);
+ if (dhcp_tmp->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS))
+ {
+ if (!(dhcp_tmp->flags & CONTEXT_DEPRECATE))
+ {
+ char *p = daemon->namebuff;
+ p += sprintf(p, _("prefix valid "));
+ prettyprint_time(p, dhcp_tmp->lease_time > 7200 ? dhcp_tmp->lease_time : 7200);
+ }
+ my_syslog(MS_DHCP | LOG_INFO, _("SLAAC on %s %s"),
+ daemon->addrbuff, daemon->namebuff);
+ }
}
#ifdef HAVE_DHCP6
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 3df7940..5d2f7e2 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -655,6 +655,7 @@ struct dhcp_context {
#define CONTEXT_RA_NAME 64
#define CONTEXT_RA_STATELESS 128
#define CONTEXT_DHCP 256
+#define CONTEXT_DEPRECATE 512
struct ping_result {
struct in_addr addr;
diff --git a/src/option.c b/src/option.c
index 9be5001..6f5fe62 100644
--- a/src/option.c
+++ b/src/option.c
@@ -2118,6 +2118,8 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
{
if (strcmp(a[leasepos], "infinite") == 0)
new->lease_time = 0xffffffff;
+ else if (strcmp(a[leasepos], "deprecated") == 0)
+ new->flags |= CONTEXT_DEPRECATE;
else
{
int fac = 1;
@@ -2150,16 +2152,6 @@ static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
}
}
}
-
-#ifdef HAVE_DHCP6
- /* lifetimes must be min 2 hrs, by RFC 2462.
- This gets enforced in radv.c for DHCP ranges
- which are legitimately less. */
- if ((new->flags & CONTEXT_RA_ONLY) &&
- new->lease_time < 7200)
- new->lease_time = 7200;
-#endif
-
break;
}
diff --git a/src/radv.c b/src/radv.c
index e184d00..a413c09 100644
--- a/src/radv.c
+++ b/src/radv.c
@@ -276,9 +276,8 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
static int add_prefixes(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
{
- struct dhcp_context *context, *tmp;
+ struct dhcp_context *context;
struct ra_param *param = vparam;
- struct prefix_opt *opt;
(void)scope; /* warning */
(void)dad;
@@ -291,13 +290,17 @@ static int add_prefixes(struct in6_addr *local, int prefix,
!IN6_IS_ADDR_LINKLOCAL(local) &&
!IN6_IS_ADDR_MULTICAST(local))
{
+ int do_slaac = 0;
+ int deprecate = 0;
+ unsigned int time = 0xffffffff;
+ struct in6_addr *addr = NULL;
+ struct prefix_opt *opt;
+
for (context = daemon->ra_contexts; context; context = context->next)
if (prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
{
- int do_slaac = 0;
-
if ((context->flags &
(CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
{
@@ -314,68 +317,51 @@ static int add_prefixes(struct in6_addr *local, int prefix,
param->other = 1;
}
- if (context->flags & CONTEXT_RA_DONE)
- continue;
+ /* find floor time */
+ if (time > context->lease_time)
+ time = context->lease_time;
- /* subsequent prefixes on the same interface don't need timers */
+ if (context->flags & CONTEXT_DEPRECATE)
+ deprecate = 1;
+
+ /* subsequent prefixes on the same interface
+ and subsequent instances of this prefix don't need timers */
if (!param->first)
context->ra_time = 0;
param->first = 0;
param->found_context = 1;
- context->flags |= CONTEXT_RA_DONE;
-
- /* mark this subnet and duplicates: as done. */
- for (tmp = context->next; tmp; tmp = tmp->next)
- if (tmp->prefix == prefix &&
- is_same_net6(local, &tmp->start6, prefix) &&
- is_same_net6(local, &tmp->end6, prefix))
- {
- tmp->flags |= CONTEXT_RA_DONE;
- context->ra_time = 0;
- /* if any dhcp-range with ra-only on this subnet
- set the "do_slaac" bit */
- if (tmp->flags &
- (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS))
- {
- do_slaac = 1;
- if (context->flags & CONTEXT_RA_STATELESS)
- param->other = 1;
- }
- else
- {
- /* don't do RA for non-ra-only unless --enable-ra is set */
- if (!option_bool(OPT_RA))
- continue;
- param->managed = 1;
- param->other = 1;
- }
- }
- if ((opt = expand(sizeof(struct prefix_opt))))
- {
- u64 addrpart = addr6part(&context->start6);
- u64 mask = (prefix == 64) ? (u64)-1LL : (1LLU << (128 - prefix)) - 1LLU;
- unsigned int time = context->lease_time;
-
- /* lifetimes must be min 2 hrs, by RFC 2462 */
- if (time < 7200)
- time = 7200;
-
- opt->type = ICMP6_OPT_PREFIX;
- opt->len = 4;
- opt->prefix_len = prefix;
- /* autonomous only is we're not doing dhcp */
- opt->flags = do_slaac ? 0x40 : 0x00;
- opt->valid_lifetime = opt->preferred_lifetime = htonl(time);
- opt->reserved = 0;
-
- opt->prefix = context->start6;
- setaddr6part(&opt->prefix, addrpart & ~mask);
-
- inet_ntop(AF_INET6, &opt->prefix, daemon->addrbuff, ADDRSTRLEN);
- my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
- }
+ if (context->flags & CONTEXT_RA_DONE)
+ continue;
+
+ context->flags |= CONTEXT_RA_DONE;
+ addr = &context->start6;
}
+
+ if (addr && (opt = expand(sizeof(struct prefix_opt))))
+ {
+ u64 addrpart = addr6part(addr);
+ u64 mask = (prefix == 64) ? (u64)-1LL : (1LLU << (128 - prefix)) - 1LLU;
+
+ /* lifetimes must be min 2 hrs, by RFC 2462 */
+ if (time < 7200)
+ time = 7200;
+
+ opt->type = ICMP6_OPT_PREFIX;
+ opt->len = 4;
+ opt->prefix_len = prefix;
+ /* autonomous only is we're not doing dhcp */
+ opt->flags = do_slaac ? 0x40 : 0x00;
+ opt->valid_lifetime = htonl(time);
+ opt->preferred_lifetime = htonl(deprecate ? 0 : time);
+ opt->reserved = 0;
+
+ opt->prefix = *addr;
+ setaddr6part(&opt->prefix, addrpart & ~mask);
+
+ inet_ntop(AF_INET6, &opt->prefix, daemon->addrbuff, ADDRSTRLEN);
+ my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);
+ }
}
}
return 1;
diff --git a/src/rfc3315.c b/src/rfc3315.c
index c55d90c..377bacc 100644
--- a/src/rfc3315.c
+++ b/src/rfc3315.c
@@ -513,13 +513,13 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
while (1)
{
struct in6_addr alloced_addr, *addrp = NULL;
- u32 preferred_time = 0;
+ u32 requested_time = 0;
struct dhcp_lease *lease = NULL;
if (ia_option)
{
struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
- preferred_time = opt6_uint(ia_option, 16, 4);
+ requested_time = opt6_uint(ia_option, 16, 4);
if (!address6_available(context, req_addr, tags) &&
(!have_config(config, CONFIG_ADDR6) || memcmp(&config->addr6, req_addr, IN6ADDRSZ) != 0))
@@ -621,10 +621,10 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
if (ia_option)
{
- if (preferred_time < 120u )
- preferred_time = 120u; /* sanity */
- if (lease_time == 0xffffffff || (preferred_time != 0xffffffff && preferred_time < lease_time))
- lease_time = preferred_time;
+ if (requested_time < 120u )
+ requested_time = 120u; /* sanity */
+ if (lease_time == 0xffffffff || (requested_time != 0xffffffff && requested_time < lease_time))
+ lease_time = requested_time;
}
if (lease_time < min_time)
@@ -730,8 +730,9 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
{
o1 = new_opt6(OPTION6_IAADDR);
put_opt6(addrp, sizeof(*addrp));
- put_opt6_long(lease_time);
- put_opt6_long(lease_time);
+ /* preferred lifetime */
+ put_opt6_long(this_context && (this_context->flags & CONTEXT_DEPRECATE) ? 0 : lease_time);
+ put_opt6_long(lease_time); /* valid lifetime */
end_opt6(o1);
log6_packet( make_lease ? "DHCPREPLY" : "DHCPADVERTISE",
@@ -842,7 +843,7 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
{
struct dhcp_lease *lease = NULL;
struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
- u32 preferred_time = opt6_uint(ia_option, 16, 4);
+ u32 requested_time = opt6_uint(ia_option, 16, 4);
unsigned int lease_time;
struct dhcp_context *this_context;
struct dhcp_config *valid_config = config;
@@ -873,7 +874,10 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
if (!address6_available(context, req_addr, tagif) ||
!(this_context = narrow_context6(context, req_addr, tagif)))
- lease_time = 0;
+ {
+ lease_time = 0;
+ this_context = NULL;
+ }
else
{
/* get tags from context if we've not used it before */
@@ -895,10 +899,10 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
lease_time = have_config(valid_config, CONFIG_TIME) ? valid_config->lease_time : this_context->lease_time;
- if (preferred_time < 120u )
- preferred_time = 120u; /* sanity */
- if (lease_time == 0xffffffff || (preferred_time != 0xffffffff && preferred_time < lease_time))
- lease_time = preferred_time;
+ if (requested_time < 120u )
+ requested_time = 120u; /* sanity */
+ if (lease_time == 0xffffffff || (requested_time != 0xffffffff && requested_time < lease_time))
+ lease_time = requested_time;
lease_set_expires(lease, lease_time, now);
if (ia_type == OPTION6_IA_NA && hostname)
@@ -917,8 +921,9 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh
o1 = new_opt6(OPTION6_IAADDR);
put_opt6(req_addr, sizeof(*req_addr));
- put_opt6_long(lease_time);
- put_opt6_long(lease_time);
+ /* preferred lifetime */
+ put_opt6_long(this_context && (this_context->flags & CONTEXT_DEPRECATE) ? 0 : lease_time);
+ put_opt6_long(lease_time); /* valid lifetime */
end_opt6(o1);
}