From 7ea3d3fdca34e026e3a0f83188733000fca3cf88 Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Fri, 25 Apr 2014 22:04:05 +0100 Subject: ra-advrouter mode for RFC-3775 mobile IPv6 support. --- CHANGELOG | 4 ++++ man/dnsmasq.8 | 7 ++++++- src/dhcp6.c | 3 +-- src/dnsmasq.h | 3 +-- src/option.c | 6 ++++-- src/radv-protocol.h | 1 + src/radv.c | 44 +++++++++++++++++++++++++++++++++++--------- 7 files changed, 52 insertions(+), 16 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e0d2fed..62019ff 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +version 2.71 + Add ra-advrouter mode, for RFC-3775 mobile IPv6 support. + + version 2.70 Fix crash, introduced in 2.69, on TCP request when dnsmasq compiled with DNSSEC support, but running without DNSSEC diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index 6658f16..f25119d 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -794,7 +794,7 @@ and for details.) For IPv6, the mode may be some combination of -.B ra-only, slaac, ra-names, ra-stateless. +.B ra-only, slaac, ra-names, ra-stateless, ra-advrouter. .B ra-only tells dnsmasq to offer Router Advertisement only on this subnet, @@ -829,6 +829,11 @@ can be combined with and .B slaac. +.B ra-advrouter +enables a mode where router address(es) rather than prefix(es) are included in the advertisements. +This is described in RFC-3775 section 7.2 and is used in mobile IPv6. In this mode the interval option +is also included, as described in RFC-3775 section 7.3. + .TP .B \-G, --dhcp-host=[][,id:|*][,set:][,][,][,][,ignore] Specify per host parameters for the DHCP server. This allows a machine diff --git a/src/dhcp6.c b/src/dhcp6.c index 3a83c18..bc48fdd 100644 --- a/src/dhcp6.c +++ b/src/dhcp6.c @@ -727,8 +727,7 @@ void dhcp_construct_contexts(time_t now) if (context->flags & CONTEXT_GC && !(context->flags & CONTEXT_OLD)) { - if ((context->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)) || - option_bool(OPT_RA)) + if ((context->flags & CONTEXT_RA) || option_bool(OPT_RA)) { /* previously constructed context has gone. advertise it's demise */ context->flags |= CONTEXT_OLD; diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 3032546..e11fad4 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -823,7 +823,7 @@ struct dhcp_context { #define CONTEXT_NETMASK (1u<<1) #define CONTEXT_BRDCAST (1u<<2) #define CONTEXT_PROXY (1u<<3) -#define CONTEXT_RA_ONLY (1u<<4) +#define CONTEXT_RA_ROUTER (1u<<4) #define CONTEXT_RA_DONE (1u<<5) #define CONTEXT_RA_NAME (1u<<6) #define CONTEXT_RA_STATELESS (1u<<7) @@ -838,7 +838,6 @@ struct dhcp_context { #define CONTEXT_OLD (1u<<16) #define CONTEXT_V6 (1u<<17) - struct ping_result { struct in_addr addr; time_t time; diff --git a/src/option.c b/src/option.c index daa728f..a0a6e46 100644 --- a/src/option.c +++ b/src/option.c @@ -2583,9 +2583,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma if (strcmp(a[leasepos], "static") == 0) new->flags |= CONTEXT_STATIC | CONTEXT_DHCP; else if (strcmp(a[leasepos], "ra-only") == 0 || strcmp(a[leasepos], "slaac") == 0 ) - new->flags |= CONTEXT_RA_ONLY | CONTEXT_RA; + new->flags |= CONTEXT_RA; else if (strcmp(a[leasepos], "ra-names") == 0) new->flags |= CONTEXT_RA_NAME | CONTEXT_RA; + else if (strcmp(a[leasepos], "ra-advrouter") == 0) + new->flags |= CONTEXT_RA_ROUTER | CONTEXT_RA; else if (strcmp(a[leasepos], "ra-stateless") == 0) new->flags |= CONTEXT_RA_STATELESS | CONTEXT_DHCP | CONTEXT_RA; else if (leasepos == 1 && inet_pton(AF_INET6, a[leasepos], &new->end6)) @@ -2615,7 +2617,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma if (new->prefix != 64) { - if ((new->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS))) + if (new->flags & CONTEXT_RA) ret_err(_("prefix length must be exactly 64 for RA subnets")); else if (new->flags & CONTEXT_TEMPLATE) ret_err(_("prefix length must be exactly 64 for subnet constructors")); diff --git a/src/radv-protocol.h b/src/radv-protocol.h index 9e53d8e..e576012 100644 --- a/src/radv-protocol.h +++ b/src/radv-protocol.h @@ -49,6 +49,7 @@ struct prefix_opt { #define ICMP6_OPT_SOURCE_MAC 1 #define ICMP6_OPT_PREFIX 3 #define ICMP6_OPT_MTU 5 +#define ICMP6_OPT_ADV_INTERVAL 7 #define ICMP6_OPT_RDNSS 25 #define ICMP6_OPT_DNSSL 31 diff --git a/src/radv.c b/src/radv.c index 84d4a3e..f5b517b 100644 --- a/src/radv.c +++ b/src/radv.c @@ -28,7 +28,7 @@ struct ra_param { time_t now; - int ind, managed, other, found_context, first; + int ind, managed, other, found_context, first, adv_router; char *if_name; struct dhcp_netid *tags; struct in6_addr link_local, link_global, ula; @@ -226,6 +226,7 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de parm.managed = 0; parm.other = 0; parm.found_context = 0; + parm.adv_router = 0; parm.if_name = iface_name; parm.first = 1; parm.now = now; @@ -286,8 +287,7 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de setaddr6part(&local, addr6part(&local) & ~((context->prefix == 64) ? (u64)-1LL : (1LLU << (128 - context->prefix)) - 1LLU)); - if ((context->flags & - (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS))) + if (context->flags & CONTEXT_RA) { do_slaac = 1; if (context->flags & CONTEXT_DHCP) @@ -339,6 +339,17 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de if (!old_prefix && !parm.found_context) return; + /* If we're sending router address instead of prefix in at least on prefix, + include the advertisement interval option. */ + if (parm.adv_router) + { + put_opt6_char(ICMP6_OPT_ADV_INTERVAL); + put_opt6_char(1); + put_opt6_short(0); + /* interval value is in milliseconds */ + put_opt6_long(1000 * calc_interval(find_iface_param(iface_name))); + } + #ifdef HAVE_LINUX_NETWORK /* Note that IPv6 MTU is not necessarilly the same as the IPv4 MTU available from SIOCGIFMTU */ @@ -500,6 +511,7 @@ static int add_prefixes(struct in6_addr *local, int prefix, int do_slaac = 0; int deprecate = 0; int constructed = 0; + int adv_router = 0; unsigned int time = 0xffffffff; struct dhcp_context *context; @@ -511,8 +523,7 @@ static int add_prefixes(struct in6_addr *local, int prefix, { context->saved_valid = valid; - if ((context->flags & - (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS))) + if (context->flags & CONTEXT_RA) { do_slaac = 1; if (context->flags & CONTEXT_DHCP) @@ -530,7 +541,17 @@ static int add_prefixes(struct in6_addr *local, int prefix, param->managed = 1; param->other = 1; } - + + /* Configured to advertise router address, not prefix. See RFC 3775 7.2 + In this case we do all addresses associated with a context, + hence the real_prefix setting here. */ + if (context->flags & CONTEXT_RA_ROUTER) + { + adv_router = 1; + param->adv_router = 1; + real_prefix = context->prefix; + } + /* find floor time, don't reduce below 3 * RA interval. */ if (time > context->lease_time) { @@ -556,7 +577,7 @@ static int add_prefixes(struct in6_addr *local, int prefix, /* subsequent prefixes on the same interface and subsequent instances of this prefix don't need timers. Be careful not to find the same prefix twice with different - addresses. */ + addresses unless we're advertising the actual addresses. */ if (!(context->flags & CONTEXT_RA_DONE)) { if (!param->first) @@ -607,13 +628,18 @@ static int add_prefixes(struct in6_addr *local, int prefix, if ((opt = expand(sizeof(struct prefix_opt)))) { /* zero net part of address */ - setaddr6part(local, addr6part(local) & ~((real_prefix == 64) ? (u64)-1LL : (1LLU << (128 - real_prefix)) - 1LLU)); + if (!adv_router) + 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 = real_prefix; /* autonomous only if we're not doing dhcp, always set "on-link" */ - opt->flags = do_slaac ? 0xC0 : 0x80; + opt->flags = 0x80; + if (do_slaac) + opt->flags |= 0x40; + if (adv_router) + opt->flags |= 0x20; opt->valid_lifetime = htonl(valid); opt->preferred_lifetime = htonl(preferred); opt->reserved = 0; -- cgit v1.2.1