diff options
author | Hagen Paul Pfeifer <hagen@jauu.net> | 2009-07-18 18:45:02 +0000 |
---|---|---|
committer | David Lamparter <equinox@diac24.net> | 2010-02-03 16:45:36 +0100 |
commit | 244dc8dd4b741ee0873d83427ca6c378de8c2354 (patch) | |
tree | d4bac45be71e9b3d6ec5d2b7dd349fa93ae672f9 /zebra | |
parent | dca6c883ea6219460efbe3dadde4b8b9cb12c845 (diff) | |
download | quagga-244dc8dd4b741ee0873d83427ca6c378de8c2354.tar.bz2 quagga-244dc8dd4b741ee0873d83427ca6c378de8c2354.tar.xz |
IPv6 Router Advertisement Option for RDNSS
IPv6 Router Advertisement Option for DNS Configuration (RFC 5006)[1]
introduced a mechanism to hand out recursive DNS server addresses via
router advertisement (RA) messages. This simple combines the IPv6
stateless address auto-configuration process with the ability to get DNS
server information - in one message. This options frees many
environments from operating an additional DHCPv6 server that provides
such information.
This patch extends quagga by the ability to generate and transport RDNS
addresses. RDNSS options are currently supported at radvd(1) and the
Linux Kernel by handover this information to the user-space (via netlink
socket).
A simple RA configuration with two RDNS entries can be enabled via
no ipv6 nd suppress-ra
ipv6 nd prefix 2001:db8::/64
ipv6 nd rdnss 2001:db8::1
ipv6 nd rdnss 2001:db8::2
It is additionally possible to specify the lifetime of an RDNSS option
as stated in [1] section 4.1. The default is infinity lifetime
(0xfffffff) as it serves the most common application areas.
ip nd rdnss 2001:db8::1 300000
[1] http://tools.ietf.org/html/rfc5006
Signed-off-by: Hagen Paul Pfeifer <hagen@jauu.net>
Diffstat (limited to 'zebra')
-rw-r--r-- | zebra/interface.c | 7 | ||||
-rw-r--r-- | zebra/interface.h | 14 | ||||
-rw-r--r-- | zebra/rtadv.c | 137 | ||||
-rw-r--r-- | zebra/rtadv.h | 12 |
4 files changed, 170 insertions, 0 deletions
diff --git a/zebra/interface.c b/zebra/interface.c index ba4cf25f..a4f32e78 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -83,6 +83,10 @@ if_zebra_new_hook (struct interface *ifp) rtadv->DefaultPreference = RTADV_PREF_MEDIUM; rtadv->AdvPrefixList = list_new (); + + rtadv->AdvRDNSSFlag = 0; + rtadv->AdvRDNSSLifetime = RTADV_RDNSS_DEFAULT_LIFETIME; + rtadv->AdvRDNSSList = list_new (); } #endif /* RTADV */ @@ -641,6 +645,9 @@ nd_dump_vty (struct vty *vty, struct interface *ifp) vty_out (vty, " ND router advertisements with " "Home Agent flag bit set.%s", VTY_NEWLINE); + if (rtadv->AdvRDNSSFlag) + vty_out (vty, " ND router advertisements with " + "RDNSS information.%s", VTY_NEWLINE); if (rtadv->AdvIntervalOption) vty_out (vty, " ND router advertisements with Adv. Interval option.%s", VTY_NEWLINE); diff --git a/zebra/interface.h b/zebra/interface.h index 0cf66403..305abaac 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -178,6 +178,20 @@ struct rtadvconf Default: 0 (medium) */ int DefaultPreference; #define RTADV_PREF_MEDIUM 0x0 /* Per RFC4191. */ + + /* A list of Recursive DNS server addresses specified in + RFC 5006 */ + int AdvRDNSSFlag; + struct list *AdvRDNSSList; + + /* the maximum lifetime in seconds over which the RDNSS entry + * may be used. After this time a host may send a router solicitation + * message to refresh the RDNSS information. + * + * Default is infinity lifetime (0xffffffff) */ + uint32_t AdvRDNSSLifetime; +#define RTADV_RDNSS_INFINITY_LIFETIME (0xffffffff) +#define RTADV_RDNSS_DEFAULT_LIFETIME RTADV_RDNSS_INFINITY_LIFETIME }; #endif /* RTADV */ diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 8cc3c4cb..2ac62e5b 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -233,6 +233,32 @@ rtadv_send_packet (int sock, struct interface *ifp) len += sizeof(struct nd_opt_homeagent_info); } + if (zif->rtadv.AdvRDNSSFlag) + { + char *addr_ptr; + struct nd_opt_rdnss *ndopt_rdnss; + struct prefix *rdnss_prefix; + unsigned int rdnss_entries = 1; + + ndopt_rdnss = (struct nd_opt_rdnss *) (buf + len); + ndopt_rdnss->nd_opt_type = ND_OPT_RDNSS; + ndopt_rdnss->nd_opt_reserved = 0; + ndopt_rdnss->nd_opt_lifetime = htonl(zif->rtadv.AdvRDNSSLifetime); + + len += sizeof(struct nd_opt_rdnss); + + /* Fill in all RDNS server entries */ + for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvRDNSSList, node, rdnss_prefix)) + { + addr_ptr = (char *)(buf + len); + memcpy(addr_ptr, &rdnss_prefix->u.prefix6, sizeof (struct in6_addr)); + len += sizeof (struct in6_addr); + rdnss_entries += 2; + } + + ndopt_rdnss->nd_opt_len = rdnss_entries; + } + if (zif->rtadv.AdvIntervalOption) { struct nd_opt_adv_interval *ndopt_adv = @@ -1430,6 +1456,115 @@ DEFUN (no_ipv6_nd_router_preference, return CMD_SUCCESS; } +static struct prefix * +rtadv_rdnss_lookup (struct list *list, struct prefix *p) +{ + struct listnode *node; + struct prefix *prefix; + + for (ALL_LIST_ELEMENTS_RO (list, node, prefix)) + if (prefix_same (prefix, p)) + return prefix; + return NULL; +} + +static void +rtadv_rdnss_set (struct zebra_if *zif, struct prefix *p) +{ + struct prefix *prefix; + struct list *rdnsslist = zif->rtadv.AdvRDNSSList; + + prefix = rtadv_rdnss_lookup (rdnsslist, p); + if (prefix) + return; + + prefix = prefix_new (); + memcpy (prefix, p, sizeof (struct prefix)); + listnode_add (rdnsslist, prefix); + + return; +} + +static int +rtadv_rdnss_reset (struct zebra_if *zif, struct prefix *rp) +{ + struct prefix *prefix; + + prefix = rtadv_rdnss_lookup(zif->rtadv.AdvRDNSSList, rp); + if (prefix != NULL) + { + listnode_delete (zif->rtadv.AdvRDNSSList, (void *) prefix); + prefix_free (prefix); + return 1; + } + else + return 0; +} + +DEFUN (ipv6_nd_rdnss, + ipv6_nd_rdnss_cmd, + "ipv6 nd rdnss X:X::X:X (<0-4294967295>|infinite)", + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "RDNSS Option\n" + "IPv6 address of recursive DNS server\n") +{ + int ret; + char *pnt; + struct interface *ifp; + struct zebra_if *zif; + struct prefix rp; + + ifp = (struct interface *) vty->index; + zif = ifp->info; + + /* make sure no slash exists in the argument */ + pnt = strchr (argv[0], '/'); + if (pnt != NULL) + { + vty_out (vty, "Malformed IPv6 RDNS address - no prefix notation allowed%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + /* now we can abuse str2prefix_ipv6 for a sanity check + * because IPv6 addresses with missing prefix + * slashes '/' are treated as host routes */ + ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp); + if (!ret) + { + vty_out (vty, "Malformed IPv6 RDNS address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rtadv_rdnss_set(zif, &rp); + zif->rtadv.AdvRDNSSFlag = 1; + + if (argc > 1) + { + if ( strncmp (argv[1], "i", 1) == 0) + { + zif->rtadv.AdvRDNSSLifetime = RTADV_RDNSS_INFINITY_LIFETIME; + } + else + { + zif->rtadv.AdvRDNSSLifetime = + (u_int32_t) strtoll (argv[1], (char **)NULL, 10); + } + } + + return CMD_SUCCESS; +} + +ALIAS (ipv6_nd_rdnss, + ipv6_nd_rdnss_cmd_nolife, + "ipv6 nd rdnss X:X::X:X", + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "RDNSS Option\n" + "IPv6 address of recursive DNS server\n") + + /* Write configuration about router advertisement. */ void rtadv_config_write (struct vty *vty, struct interface *ifp) @@ -1605,6 +1740,8 @@ rtadv_init (void) install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_cmd); install_element (INTERFACE_NODE, &ipv6_nd_router_preference_cmd); install_element (INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd); + install_element (INTERFACE_NODE, &ipv6_nd_rdnss_cmd); + install_element (INTERFACE_NODE, &ipv6_nd_rdnss_cmd_nolife); } static int diff --git a/zebra/rtadv.h b/zebra/rtadv.h index d8d263d0..0893ba53 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -66,6 +66,9 @@ extern void rtadv_init (void); #ifndef ND_OPT_HA_INFORMATION #define ND_OPT_HA_INFORMATION 8 /* HA Information Option */ #endif +#ifndef ND_OPT_RDNSS +#define ND_OPT_RDNSS 25 /* RDNSS option (RFC 5006) */ +#endif #ifndef HAVE_STRUCT_ND_OPT_ADV_INTERVAL struct nd_opt_adv_interval { /* Advertisement interval option */ @@ -94,6 +97,15 @@ struct nd_opt_homeagent_info { /* Home Agent info */ } __attribute__((__packed__)); #endif +/* see RFC 5006, section 5.1 */ +struct nd_opt_rdnss { + uint8_t nd_opt_type; + uint8_t nd_opt_len; + uint16_t nd_opt_reserved; + uint32_t nd_opt_lifetime; + /* followed by n (16 byte) entries */ +} __attribute__((__packed__)); + extern const char *rtadv_pref_strs[]; #endif /* _ZEBRA_RTADV_H */ |