Package: rdnssd
Version: 0.9.7-1
Severity: normal
Tags: patch

Hi,

According to RFC 5006, section 5.1, the lifetime field of an RDNSS option has a
special meaning for the values of zero and all-ones:

   A value of all one bits (0xffffffff) represents infinity.  A value of
   zero means that the RDNSS address MUST no longer be used.

Thus said, rdnssd unconditionally adds the value of lifetime to the 
current timestamp (now), which causes two undesired effects:

1. In the case of all ones, it causes the unsigned 32-bit expiry variable to
   wrap-around and the subsequent code to completely ignore the DNS servers 
specified.
2. In the case of lifetime being zero, it ignores the current RDNSS, but does
   not remove the specified nameservers from the server list.

Attached you will find a patch working around this issue. The patch is 
against 1.0.0, but it applies cleanly to 0.9.7 as well.

Thanks

-- System Information:
Debian Release: 5.0.7
  APT prefers stable
  APT policy: (500, 'stable'), (80, 'testing'), (70, 'unstable'), (1, 
'experimental')
Architecture: amd64 (x86_64)

Kernel: Linux 2.6.32-5-amd64 (SMP w/2 CPU cores)
Locale: LANG=el_GR.UTF-8, LC_CTYPE=el_GR.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/bash

Versions of packages rdnssd depends on:
ii  adduser                       3.110      add and remove users and groups
ii  libc6                         2.10.2-2   GNU C Library: Shared libraries

Versions of packages rdnssd recommends:
pn  resolvconf                    <none>     (no description available)

Versions of packages rdnssd suggests:
ii  ndisc6                        0.9.7-1    IPv6 diagnostic tools

-- no debconf information
Index: ndisc6-1.0.0/rdnssd/rdnssd.c
===================================================================
--- ndisc6-1.0.0.orig/rdnssd/rdnssd.c	2010-12-02 21:53:21.000000000 +0200
+++ ndisc6-1.0.0/rdnssd/rdnssd.c	2010-12-02 22:57:49.000000000 +0200
@@ -156,6 +156,19 @@
 			if ((expiry - servers.list[MAX_RDNSS - 1].expiry) >= 0)
 				i = MAX_RDNSS - 1;
 		}
+	} else if (expiry == now) {
+		/* Per RFC 5006 "A [lifetime] value of zero means that the
+		   RDNSS address MUST no longer be used", so remove the
+		   server from the list and replace it with the last server */
+
+		if (servers.count > 1) {
+			addr = &servers.list[servers.count - 1].addr;
+			ifindex = servers.list[servers.count - 1].ifindex;
+			expiry = servers.list[servers.count - 1].expiry;
+		}
+		servers.count--;
+		if (servers.count == 0)
+			return;
 	}
 
 	memcpy (&servers.list[i].addr, addr, sizeof (*addr));
@@ -185,6 +198,7 @@
 		struct nd_opt_rdnss *rdnss_opt;
 		size_t nd_opt_len = opt->nd_opt_len;
 		uint32_t lifetime;
+		uint32_t rdnss_lifetime;
 
 		if (nd_opt_len == 0 || opts_len < (nd_opt_len << 3))
 			return -1;
@@ -204,7 +218,13 @@
 			now = ts.tv_sec;
 		}
 
-		lifetime = now + ntohl(rdnss_opt->nd_opt_rdnss_lifetime);
+		rdnss_lifetime = ntohl(rdnss_opt->nd_opt_rdnss_lifetime);
+		if (rdnss_lifetime == 0xffffffff) {
+			/* Per RFC 5006, unlimited */
+			lifetime = rdnss_lifetime;
+		} else {
+			lifetime = now + rdnss_lifetime;
+		}
 
 		for (struct in6_addr *addr = (struct in6_addr *) (rdnss_opt + 1);
 		     nd_opt_len >= 2; addr++, nd_opt_len -= 2)

Reply via email to