It seems that glibc's resolver does not support IPv6 link-local addresses with an explicit scope (like fe80::[...]%eth0), in the nameserver options in /etc/resolv.conf. Currently, nameservers with a scope fail to be parsed. Nameservers with a link-local address (without scope) are parsed and used, but obviously do not work (connect() fails with EINVAL because a sin6_scope_id of 0 is used with the link-local address). With the apparition of the new RDNSS option (RFC5006), which allows for DNS configuration through stateless autoconf, we expect that IPv6 link-local resolvers may be used, and set into /etc/resolv.conf. Kernel-side support is included in Linux 2.6.24, and the corresponding userland RDNSS daemon is currently under development and will be shipped in the next release of Rémi Denis-Courmont's ndisc6 tool suite. We would need glibc to support this feature to integrate our work. I use Debian sid's glibc 2.7-4, under Linux 2.6.23.9-grsec, on i686 hardware. Debian's glibc maintainers referred me to you regarding this issue (please see http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=455671). Please review this patch, made against upstream sources shipped in the Debian package and compiled using Debian's build system, and consider it for application. --- resolv/res_init.c 2007-12-09 17:30:57.000000000 +0100 +++ resolv/res_init.c 2007-12-09 18:19:40.000000000 +0100 @@ -74,11 +74,14 @@ static const char rcsid[] = "$BINDId: re #include <sys/socket.h> #include <sys/time.h> +#include <net/if.h> #include <netinet/in.h> #include <arpa/inet.h> #include <arpa/nameser.h> +#include <assert.h> #include <ctype.h> +#include <netdb.h> #include <resolv.h> #include <stdio.h> #include <stdio_ext.h> @@ -327,6 +330,8 @@ __res_vinit(res_state statp, int preinit if ((el = strchr(cp, '\n')) != NULL) *el = '\0'; + if ((el = strchr(cp, SCOPE_DELIMITER)) != NULL) + *el = '\0'; if ((*cp != '\0') && (inet_pton(AF_INET6, cp, &a6) > 0)) { struct sockaddr_in6 *sa6; @@ -336,6 +341,27 @@ __res_vinit(res_state statp, int preinit sa6->sin6_addr = a6; sa6->sin6_family = AF_INET6; sa6->sin6_port = htons(NAMESERVER_PORT); + + if (el != NULL) { + int try_numericscope = 0; + if (IN6_IS_ADDR_LINKLOCAL(&a6) + || IN6_IS_ADDR_MC_LINKLOCAL(&a6)) { + sa6->sin6_scope_id = if_nametoindex(el + 1); + if (sa6->sin6_scope_id == 0) + try_numericscope = 1; + } else + try_numericscope = 1; + + if (try_numericscope != 0) { + char *end; + assert(sizeof(uint32_t) <= sizeof(unsigned long)); + sa6->sin6_scope_id = (uint32_t) strtoul(el + 1, &end, 10); + if (*end != '\0') + sa6->sin6_scope_id = 0; + } + } else + sa6->sin6_scope_id = 0; + statp->_u._ext.nsaddrs[nservall] = sa6; statp->_u._ext.nssocks[nservall] = -1; statp->_u._ext.nsmap[nservall] = MAXNS + 1; Regards, -- Pierre Ynard
Created attachment 2132 [details] Unmangled version of the patch
I've added the code to cvs. You should have said that you took the code sequence from getaddrinfo.c. And the formatting was throwing me off at first before I realized it's wrong and the code is copied.