summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/ipv6.texi10
-rw-r--r--zebra/interface.c7
-rw-r--r--zebra/interface.h14
-rw-r--r--zebra/rtadv.c137
-rw-r--r--zebra/rtadv.h12
5 files changed, 180 insertions, 0 deletions
diff --git a/doc/ipv6.texi b/doc/ipv6.texi
index a78a92fe..519b7798 100644
--- a/doc/ipv6.texi
+++ b/doc/ipv6.texi
@@ -157,15 +157,25 @@ Set default router preference in IPv6 router advertisements per RFC4191.
Default: medium
@end deffn
+@deffn {Interface Command} {ipv6 nd rdnss ipv6prefix [lifetime]} {} Include
+RDNSS options to advertise recursive DNS server addresses. Additionally a
+maximum lifetime (in seconds) can be specified to limit the lifetime of this
+option. The valid range is between @code{<0-4294967295>} where 0 means that the
+RDNSS address must no longer be used. The default lifetime - without explicitly
+specify a lifetime - is unlimited.
+@end deffn
+
@example
@group
interface eth0
no ipv6 nd suppress-ra
ipv6 nd prefix 2001:0DB8:5009::/64
+ ipv6 nd rdnss 2001:0DB8:5009::1
@end group
@end example
For more information see @cite{RFC2462 (IPv6 Stateless Address Autoconfiguration)}
, @cite{RFC2461 (Neighbor Discovery for IP Version 6 (IPv6))}
, @cite{RFC3775 (Mobility Support in IPv6 (Mobile IPv6))}
+, @cite{RFC5006 (IPv6 Router Advertisement Option for DNS Configuration)}
and @cite{RFC4191 (Default Router Preferences and More-Specific Routes)}.
diff --git a/zebra/interface.c b/zebra/interface.c
index e09ca41f..557d7561 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 */
@@ -655,6 +659,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..7d9c0f6c 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_nolife_cmd,
+ "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_nolife_cmd);
}
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 */