[radvd-devel-l] RDNSS Option

Pekka Savola pekkas at netcore.fi
Wed Mar 29 07:38:18 EST 2006


Hi,

On Tue, 28 Mar 2006, Mickaël Guérin wrote:
> I'm still alive ;)
> 
> I've completed the path.
> The parser has been modified so you can now use "RDNSS ip [ip] [ip] { ... }" 
> syntax. I have also deleted the grouping of rdnss ip : it can be done in the 
> configuration file by hand.
> (radvdump now supports the rdnss option)

Thanks a lot.  I've added this to the CVS.  I made some minor changes and 
fixes, mainly to the documentation (e.g., the example used 'rdnss ip ...' while 
the syntax was 'RDNSS ip ...'. (see attached.)

The only thing missing seems to be an implementation of this (if you could 
patch this if it makes sense -- great; if not, I'll just take a look at it 
myself) :

                                        Lifetime SHOULD be bounded as
                       follows:
                       MaxRtrAdvInterval<=Lifetime<=2*MaxRtrAdvInterval.

If you have some spare time, you might also consider submitting a dissector 
(now or at a later phase, e.g., when the doc has been approved for publication) 
to the tcpdump/ethereal communities.

-- 
Pekka Savola                 "You each name yourselves king, yet the
Netcore Oy                    kingdom bleeds."
Systems. Networks. Security. -- George R.R. Martin: A Clash of Kings
-------------- next part --------------
Index: CHANGES
===================================================================
RCS file: /work/cvsroot/radvd/CHANGES,v
retrieving revision 1.56
diff -u -r1.56 CHANGES
--- CHANGES	6 Mar 2006 09:29:15 -0000	1.56
+++ CHANGES	29 Mar 2006 12:30:57 -0000
@@ -1,5 +1,8 @@
 $Id: CHANGES,v 1.56 2006/03/06 09:29:15 psavola Exp $
 
+03/29/2006	Implement RDNSS draft, using non-allocated
+		IANA ND type value 25, by Mickaël Guérin.
+
 03/06/2006	Exit when sending RAs if the interface no longer
 		exists unless IgnoreIfMissing is defined.  Fix
 		the default STDERR+syslog logging methods, so
Index: defaults.h
===================================================================
RCS file: /work/cvsroot/radvd/defaults.h,v
retrieving revision 1.15
diff -u -r1.15 defaults.h
--- defaults.h	18 Oct 2005 19:17:29 -0000	1.15
+++ defaults.h	29 Mar 2006 12:30:58 -0000
@@ -62,6 +62,11 @@
 
 #define DFLT_AdvRoutePreference		0 /* medium*/
 
+/* RDNSS */
+#define DFLT_AdvRDNSSPreference				8 /* medium */
+#define DFLT_AdvRDNSSOpenFlag				0
+#define DFLT_AdvRDNSSLifetime				30 /* seconds */
+
 /* Protocol (RFC2461) constants: */
 
 /* Router constants: */
@@ -148,6 +153,28 @@
 #define ND_OPT_RI_PRF_SHIFT	3
 #define ND_OPT_RI_PRF_MASK	(3 << ND_OPT_RI_PRF_SHIFT) /* 00011000 = 0x18 */
 
+#undef ND_OPT_RDNSS_INFORMATION
+#define  ND_OPT_RDNSS_INFORMATION	25
+
+/* */
+struct nd_opt_rdnss_info_local
+{
+	uint8_t   			nd_opt_rdnssi_type;
+	uint8_t   			nd_opt_rdnssi_len;
+	uint16_t   			nd_opt_rdnssi_pref_flag_reserved;
+	uint32_t			nd_opt_rdnssi_lifetime;
+	struct in6_addr		nd_opt_rdnssi_adrr1;
+	struct in6_addr		nd_opt_rdnssi_adrr2;
+	struct in6_addr		nd_opt_rdnssi_adrr3;
+};
+/* pref/flag/reserved field : yyyyx00000000000 (big endian) - 00000000yyyyx000 (little indian); where yyyy = pref, x = flag */
+#if BYTE_ORDER == BIG_ENDIAN
+#define ND_OPT_RDNSSI_PREF_SHIFT	12
+#else
+#define ND_OPT_RDNSSI_PREF_SHIFT	4
+#endif
+#define ND_OPT_RDNSSI_PREF_MASK		(0xf << ND_OPT_RDNSSI_PREF_SHIFT)
+
 /* Flags */
 
 #ifndef ND_RA_FLAG_HOME_AGENT
@@ -156,6 +183,13 @@
 #ifndef ND_OPT_PI_FLAG_RADDR
 #define ND_OPT_PI_FLAG_RADDR		0x20
 #endif
+#ifndef ND_OPT_RDNSSI_FLAG_S
+#if BYTE_ORDER == BIG_ENDIAN
+#define ND_OPT_RDNSSI_FLAG_S         0x0800
+#else
+#define ND_OPT_RDNSSI_FLAG_S         0x0008
+#endif
+#endif
 
 /* Configurable values */
 
Index: gram.y
===================================================================
RCS file: /work/cvsroot/radvd/gram.y,v
retrieving revision 1.14
diff -u -r1.14 gram.y
--- gram.y	30 Dec 2005 15:13:11 -0000	1.14
+++ gram.y	29 Mar 2006 12:30:58 -0000
@@ -23,6 +23,7 @@
 struct Interface *iface = NULL;
 struct AdvPrefix *prefix = NULL;
 struct AdvRoute *route = NULL;
+struct AdvRDNSS *rdnss = NULL;
 
 extern char *conf_file;
 extern int num_lines;
@@ -48,6 +49,7 @@
 %token		T_INTERFACE
 %token		T_PREFIX
 %token		T_ROUTE
+%token		T_RDNSS
 
 %token	<str>	STRING
 %token	<num>	NUMBER
@@ -91,6 +93,10 @@
 %token		T_AdvRoutePreference
 %token		T_AdvRouteLifetime
 
+%token		T_AdvRDNSSPreference
+%token		T_AdvRDNSSOpenFlag
+%token		T_AdvRDNSSLifetime
+
 %token		T_AdvMobRtrSupportFlag
 
 %token		T_BAD_TOKEN
@@ -98,7 +104,9 @@
 %type	<str>	name
 %type	<pinfo> optional_prefixlist prefixdef prefixlist
 %type	<rinfo>	optional_routelist routedef routelist
+%type	<rdnssinfo> optional_rdnsslist rdnssdef rdnsslist
 %type   <num>	number_or_infinity
+%type	<addr>	rdnssaddrs
 
 %union {
 	unsigned int		num;
@@ -109,6 +117,7 @@
 	char			*str;
 	struct AdvPrefix	*pinfo;
 	struct AdvRoute		*rinfo;
+	struct AdvRDNSS		*rdnssinfo;
 };
 
 %%
@@ -183,10 +192,11 @@
 		}
 		;
 
-ifaceparams	: optional_ifacevlist optional_prefixlist optional_routelist
+ifaceparams	: optional_ifacevlist optional_prefixlist optional_routelist optional_rdnsslist
 		{
 			iface->AdvPrefixList = $2;
 			iface->AdvRouteList = $3;
+			iface->AdvRDNSSList = $4;
 		}
 		;
 
@@ -207,6 +217,13 @@
 		}
 		| routelist
 		;
+		
+optional_rdnsslist: /* empty */
+		{
+			$$ = NULL;
+		}
+		| rdnsslist
+		;
 
 ifacevlist	: ifacevlist ifaceval
 		| ifaceval
@@ -472,7 +489,92 @@
 			route->AdvRouteLifetime = $2;
 		}
 		;
+		
+rdnsslist	: rdnssdef
+		{
+			$$ = $1;
+		}
+		| rdnsslist rdnssdef
+		{
+			$2->next = $1;
+			$$ = $2;
+		}
+		;
+		
+rdnssdef	: rdnsshead '{' optional_rdnssplist '}' ';'
+		{
+			$$ = rdnss;
+			rdnss = NULL;
+		}
+		;
 
+rdnssaddrs: 	/* empty */
+		| rdnssaddrs IPV6ADDR
+		{
+			if (!rdnss) {
+				/* first IP found */
+				rdnss = malloc(sizeof(struct AdvRDNSS));
+				
+				if (rdnss == NULL) {
+					flog(LOG_CRIT, "malloc failed: %s", strerror(errno));
+					ABORT;
+				}
+
+				rdnss_init_defaults(rdnss, iface);
+			}
+			
+			switch (rdnss->AdvRDNSSNumber) {
+				case 0:
+					memcpy(&rdnss->AdvRDNSSAddr1, $2, sizeof(struct in6_addr));
+					rdnss->AdvRDNSSNumber++;
+					break;
+				case 1:
+					memcpy(&rdnss->AdvRDNSSAddr2, $2, sizeof(struct in6_addr));
+					rdnss->AdvRDNSSNumber++;
+					break;
+				case 2:
+					memcpy(&rdnss->AdvRDNSSAddr3, $2, sizeof(struct in6_addr));
+					rdnss->AdvRDNSSNumber++;
+					break;
+				default:
+					flog(LOG_CRIT, "Too many addresses in RDNSS section");
+					ABORT;
+			}
+			
+		}
+		;
+		
+rdnsshead	: T_RDNSS rdnssaddrs
+		{
+			if (!rdnss) {
+				flog(LOG_CRIT, "No address specified in RDNSS section");
+				ABORT;
+			}
+		}
+		;
+		
+optional_rdnssplist: /* empty */
+		| rdnssplist 
+		;
+		
+rdnssplist	: rdnssplist rdnssparms
+		| rdnssparms
+		;
+
+
+rdnssparms	: T_AdvRDNSSPreference NUMBER ';'
+		{
+			rdnss->AdvRDNSSPreference = $2;
+		}
+		| T_AdvRDNSSOpenFlag SWITCH ';'
+		{
+			rdnss->AdvRDNSSOpenFlag = $2;
+		}
+		| T_AdvRDNSSLifetime number_or_infinity ';'
+		{
+			rdnss->AdvRDNSSLifetime = $2;
+		}
+		;
 
 number_or_infinity      : NUMBER
                         {
Index: interface.c
===================================================================
RCS file: /work/cvsroot/radvd/interface.c,v
retrieving revision 1.14
diff -u -r1.14 interface.c
--- interface.c	18 Jan 2006 16:06:00 -0000	1.14
+++ interface.c	29 Mar 2006 12:30:58 -0000
@@ -67,6 +67,17 @@
 	route->AdvRoutePreference = DFLT_AdvRoutePreference;
 }
 
+void
+rdnss_init_defaults(struct AdvRDNSS *rdnss, struct Interface *iface)
+{
+	memset(rdnss, 0, sizeof(struct AdvRDNSS));
+		
+	rdnss->AdvRDNSSPreference = DFLT_AdvRDNSSPreference;
+	rdnss->AdvRDNSSOpenFlag = DFLT_AdvRDNSSOpenFlag;
+	rdnss->AdvRDNSSLifetime = DFLT_AdvRDNSSLifetime;
+	rdnss->AdvRDNSSNumber = 0;
+}
+
 int
 check_iface(struct Interface *iface)
 {
Index: radvd.c
===================================================================
RCS file: /work/cvsroot/radvd/radvd.c,v
retrieving revision 1.26
diff -u -r1.26 radvd.c
--- radvd.c	6 Mar 2006 09:29:15 -0000	1.26
+++ radvd.c	29 Mar 2006 12:30:58 -0000
@@ -397,6 +397,7 @@
 		struct Interface *next_iface = iface->next;
 		struct AdvPrefix *prefix;
 		struct AdvRoute *route;
+		struct AdvRDNSS *rdnss;
 
 		dlog(LOG_DEBUG, 4, "freeing interface %s", iface->Name);
 		
@@ -416,7 +417,16 @@
 
 			free(route);
 			route = next_route;
-		}  
+		}
+		
+		rdnss = iface->AdvRDNSSList;
+		while (rdnss) 
+		{
+			struct AdvRDNSS *next_rdnss = rdnss->next;
+			
+			free(rdnss);
+			rdnss = next_rdnss;
+		}	 
 
 		free(iface);
 		iface = next_iface;
Index: radvd.conf.5.man
===================================================================
RCS file: /work/cvsroot/radvd/radvd.conf.5.man,v
retrieving revision 1.17
diff -u -r1.17 radvd.conf.5.man
--- radvd.conf.5.man	6 Mar 2006 09:26:56 -0000	1.17
+++ radvd.conf.5.man	29 Mar 2006 12:30:59 -0000
@@ -29,6 +29,7 @@
 	list of interface specific options
 	list of prefix definitions
 	list of route definitions
+	list of RDNSS definitions
 .B };
 .fi
 
@@ -65,6 +66,14 @@
 The prefix of a route definition should be network prefix; it can be used to
 advertise more specific routes to the hosts.
 
+RDNSS (Recursive DNS server) definitions are of the form:
+
+.nf
+.BR "RDNSS " "ip [ip] [ip] " {
+	list of rdnss specific options
+.B };
+.fi
+
 .SH INTERFACE SPECIFIC OPTIONS
 
 .TP
@@ -426,6 +435,29 @@
 
 Default: medium
 
+.SH RDNSS SPECIFIC OPTIONS
+
+.TP
+.BR "AdvRDNSSPreference " integer;
+
+The preference of the DNS server, compared to other DNS servers advertised and used.
+0 to 7 means less important than manually configured nameservers in resolv.conf, while 12 to 15 means more important.
+
+Default: 8
+
+.TP
+.BR "AdvRDNSSOpen " on | off;
+
+"Service Open" flag. When set, indicates that RDNSS continues to be available to hosts even if they moved to a different subnet.
+
+Default: off
+
+.TP
+.BR "AdvRDNSSLifetime " seconds | infinity;
+The maximum duration how long the RDNSS entries are used for name resolution. A value of 0 means the nameserver should no longer be used.
+
+Default: 30 seconds
+
 .SH EXAMPLES
 
 .nf
@@ -541,6 +573,9 @@
 .PP
 Devarapalli, V., Wakikawa, R., Petrescu, A., and P. Thubert "Network Mobility (NEMO) Basic Support Protocol",
 RFC 3963, January 2005.
+.PP
+J. Jeong, L. Beloeil, and S. Madanapalli, "IPv6 Router Advertisement Option for DNS Configuration",
+IETF Draft v08 (January 18, 2006).
 
 .SH "SEE ALSO"
 
Index: radvd.conf.example
===================================================================
RCS file: /work/cvsroot/radvd/radvd.conf.example,v
retrieving revision 1.7
diff -u -r1.7 radvd.conf.example
--- radvd.conf.example	8 Jul 2005 11:44:46 -0000	1.7
+++ radvd.conf.example	29 Mar 2006 12:30:59 -0000
@@ -50,16 +50,6 @@
 	};
 
 #
-# example of a more specific route
-# NOTE: This feature is still being specified and is not widely supported!
-#
-	route 2001:db0:fff::/48
-	{
-		AdvRoutePreference high;
-		AdvRouteLifetime 3600;
-	};
-
-#
 # example of a 6to4 prefix
 #
 # Note that the first 48 bits are specified here as zeros.  These will be
@@ -101,5 +91,27 @@
 		AdvPreferredLifetime 120;
 		AdvValidLifetime 300;
 	};
+#
+# example of a more specific route
+# NOTE: This feature is still being specified and is not widely supported!
+#
+	route 2001:db0:fff::/48
+	{
+		AdvRoutePreference high;
+		AdvRouteLifetime 3600;
+	};
+
+#
+# RDNSS
+# NOTE: This feature is still a draft has no IANA number type for the moment
+#
+        RDNSS 2001:db8::1 2001:db8::2
+        {
+                AdvRDNSSPreference 8;
+                AdvRDNSSOpen off;
+                AdvRDNSSLifetime 30;
+        };
+
 
 };
+
Index: radvd.h
===================================================================
RCS file: /work/cvsroot/radvd/radvd.h,v
retrieving revision 1.19
diff -u -r1.19 radvd.h
--- radvd.h	18 Jan 2006 16:21:16 -0000	1.19
+++ radvd.h	29 Mar 2006 12:30:59 -0000
@@ -83,11 +83,11 @@
 
 	struct AdvPrefix	*AdvPrefixList;
 	struct AdvRoute		*AdvRouteList;
+	struct AdvRDNSS		*AdvRDNSSList;
 	struct timer_lst	tm;
-	time_t                  last_multicast_sec;
-	suseconds_t             last_multicast_usec;
+	time_t			last_multicast_sec;
+	suseconds_t		last_multicast_usec;
 	struct Interface	*next;
-
 };
 
 struct AdvPrefix {
@@ -100,7 +100,7 @@
 	uint32_t		AdvPreferredLifetime;
 
 	/* Mobile IPv6 extensions */
-        int                     AdvRouterAddr;
+	int             	AdvRouterAddr;
 
 	/* 6to4 extensions */
 	char			if6to4[IFNAMSIZ];
@@ -121,6 +121,19 @@
 	struct AdvRoute		*next;
 };
 
+/* Option for DNS configuration */
+struct AdvRDNSS {
+	int 			AdvRDNSSNumber;
+	uint8_t			AdvRDNSSPreference;
+	int 			AdvRDNSSOpenFlag;
+	uint32_t		AdvRDNSSLifetime;
+	struct in6_addr		AdvRDNSSAddr1;
+	struct in6_addr		AdvRDNSSAddr2;
+	struct in6_addr		AdvRDNSSAddr3;
+	
+	struct AdvRDNSS 	*next; 
+};
+
 /* Mobile IPv6 extensions */
 
 struct AdvInterval {
@@ -178,6 +191,7 @@
 void iface_init_defaults(struct Interface *);
 void prefix_init_defaults(struct AdvPrefix *);
 void route_init_defaults(struct AdvRoute *, struct Interface *);
+void rdnss_init_defaults(struct AdvRDNSS *, struct Interface *);
 int check_iface(struct Interface *);
 
 /* socket.c */
Index: radvdump.c
===================================================================
RCS file: /work/cvsroot/radvd/radvdump.c,v
retrieving revision 1.13
diff -u -r1.13 radvdump.c
--- radvdump.c	30 Dec 2005 16:12:23 -0000	1.13
+++ radvdump.c	29 Mar 2006 12:30:59 -0000
@@ -281,6 +281,8 @@
 			break;
 		case ND_OPT_ROUTE_INFORMATION:
 			break;
+		case ND_OPT_RDNSS_INFORMATION:
+			break;
 		default:
 			dlog(LOG_DEBUG, 1, "unknown option %d in RA",
 				(int)*opt_str);
@@ -303,6 +305,7 @@
 		int optlen;
 		struct nd_opt_prefix_info *pinfo;
 		struct nd_opt_route_info_local *rinfo;
+		struct nd_opt_rdnss_info_local *rdnss_info;
 		char prefix_str[INET6_ADDRSTRLEN];
 
 		if (orig_len < 2)
@@ -390,6 +393,45 @@
 				printf("\t\tAdvRouteLifetime infinity; # (0xffffffff)\n");
 			else
 				printf("\t\tAdvRouteLifetime %u;\n", ntohl(rinfo->nd_opt_ri_lifetime));
+
+			printf("\t}; # End of route definition\n\n");
+			break;
+		case ND_OPT_RDNSS_INFORMATION:
+			rdnss_info = (struct nd_opt_rdnss_info_local *) opt_str;
+
+			printf("\n\tRDNSS");
+
+			print_addr(&rdnss_info->nd_opt_rdnssi_adrr1, prefix_str);
+			printf(" %s", prefix_str);
+
+			if (rdnss_info->nd_opt_rdnssi_len >= 5) {
+				print_addr(&rdnss_info->nd_opt_rdnssi_adrr2, prefix_str);
+				printf(" %s", prefix_str);
+			}
+			if (rdnss_info->nd_opt_rdnssi_len >= 7) {
+				print_addr(&rdnss_info->nd_opt_rdnssi_adrr3, prefix_str);
+				printf(" %s", prefix_str);
+			}
+			
+			printf("\n\t{\n");
+			if (!edefs 
+			    || ((rdnss_info->nd_opt_rdnssi_pref_flag_reserved & ND_OPT_RDNSSI_PREF_MASK) >> ND_OPT_RDNSSI_PREF_SHIFT) != DFLT_AdvRDNSSPreference)
+				printf("\t\tAdvRDNSSPreference %d;\n", 
+				  (rdnss_info->nd_opt_rdnssi_pref_flag_reserved & ND_OPT_RDNSSI_PREF_MASK) >> ND_OPT_RDNSSI_PREF_SHIFT);
+
+			if (!edefs 
+			    || ((rdnss_info->nd_opt_rdnssi_pref_flag_reserved & ND_OPT_RDNSSI_FLAG_S) == 0 ) == DFLT_AdvRDNSSOpenFlag)
+				printf("\t\tAdvRDNSSOpen %s;\n", rdnss_info->nd_opt_rdnssi_pref_flag_reserved & ND_OPT_RDNSSI_FLAG_S ? "on" : "off");
+			if (!edefs
+			    || ntohl(rdnss_info->nd_opt_rdnssi_lifetime) != DFLT_AdvRDNSSLifetime ) {
+				if (ntohl(rdnss_info->nd_opt_rdnssi_lifetime) == 0xffffffff)
+					printf("\t\tAdvRDNSSLifetime infinity; # (0xffffffff)\n");
+				else
+					printf("\t\tAdvRDNSSLifetime %u;\n", ntohl(rdnss_info->nd_opt_rdnssi_lifetime));
+			}
+			
+			printf("\t}; # End of RDNSS definition\n\n");
+			break;
 		default:
 			break;
 		}
Index: scanner.l
===================================================================
RCS file: /work/cvsroot/radvd/scanner.l,v
retrieving revision 1.11
diff -u -r1.11 scanner.l
--- scanner.l	18 Oct 2005 19:17:29 -0000	1.11
+++ scanner.l	29 Mar 2006 12:30:59 -0000
@@ -44,6 +44,7 @@
 interface		{ return T_INTERFACE; }
 prefix			{ return T_PREFIX; }
 route			{ return T_ROUTE; }
+RDNSS			{ return T_RDNSS; }
 
 IgnoreIfMissing		{ return T_IgnoreIfMissing; }
 AdvSendAdvert		{ return T_AdvSendAdvert; }
@@ -78,6 +79,10 @@
 AdvRoutePreference	{ return T_AdvRoutePreference; }
 AdvRouteLifetime	{ return T_AdvRouteLifetime; }
 
+AdvRDNSSPreference 	{ return T_AdvRDNSSPreference; }
+AdvRDNSSOpen		{ return T_AdvRDNSSOpenFlag; }
+AdvRDNSSLifetime	{ return T_AdvRDNSSLifetime; }
+
 MinDelayBetweenRAs      { return T_MinDelayBetweenRAs; }
 
 AdvMobRtrSupportFlag	{ return T_AdvMobRtrSupportFlag; }
Index: send.c
===================================================================
RCS file: /work/cvsroot/radvd/send.c,v
retrieving revision 1.21
diff -u -r1.21 send.c
--- send.c	6 Mar 2006 09:26:56 -0000	1.21
+++ send.c	29 Mar 2006 12:30:59 -0000
@@ -31,6 +31,7 @@
 	struct nd_router_advert *radvert;
 	struct AdvPrefix *prefix;
 	struct AdvRoute *route;
+	struct AdvRDNSS *rdnss;
 	unsigned char buff[MSG_SIZE];
 	int len = 0;
 	int err;
@@ -160,6 +161,38 @@
 		route = route->next;
 	}
 	
+	rdnss = iface->AdvRDNSSList;
+	
+	/*
+	 *	add rdnss options
+	 */
+
+	while(rdnss)
+	{
+		struct nd_opt_rdnss_info_local *rdnssinfo;
+		
+		rdnssinfo = (struct nd_opt_rdnss_info_local *) (buff + len);
+
+		rdnssinfo->nd_opt_rdnssi_type	     = ND_OPT_RDNSS_INFORMATION;
+		rdnssinfo->nd_opt_rdnssi_len	     = 1 + 2*rdnss->AdvRDNSSNumber;
+		rdnssinfo->nd_opt_rdnssi_pref_flag_reserved = 
+		((rdnss->AdvRDNSSPreference << ND_OPT_RDNSSI_PREF_SHIFT) & ND_OPT_RDNSSI_PREF_MASK);
+		rdnssinfo->nd_opt_rdnssi_pref_flag_reserved |=
+		((rdnss->AdvRDNSSOpenFlag)?ND_OPT_RDNSSI_FLAG_S:0);
+
+		rdnssinfo->nd_opt_rdnssi_lifetime	= htonl(rdnss->AdvRDNSSLifetime);
+			
+		memcpy(&rdnssinfo->nd_opt_rdnssi_adrr1, &rdnss->AdvRDNSSAddr1,
+		       sizeof(struct in6_addr));
+		memcpy(&rdnssinfo->nd_opt_rdnssi_adrr2, &rdnss->AdvRDNSSAddr2,
+		       sizeof(struct in6_addr));
+		memcpy(&rdnssinfo->nd_opt_rdnssi_adrr3, &rdnss->AdvRDNSSAddr3,
+		       sizeof(struct in6_addr));
+		len += sizeof(*rdnssinfo) - (3-rdnss->AdvRDNSSNumber)*sizeof(struct in6_addr);
+
+		rdnss = rdnss->next;
+	}
+	
 	/*
 	 *	add MTU option
 	 */


More information about the radvd-devel-l mailing list