Hi folks, I've run across an ipv4/ipv6 configuration issue which I think needs to have light cast on it so we can try to resolve this in time for lenny (whatever the right resolution actually is), in order to avoid a pile-up of /etc/hosts-related kludges as has been known to happen before...
In response to bug #427067, the netbase maintainer made a change that adds localhost as an alias for ::1 on new installs. In April of this year, the Debian Installer team followed suit, adding this line in the netcfg udeb. The result of these changes is that since July 2007, any new lenny or sid chroots have had two addresses listed for localhost, and since April of this year, any new installs of lenny done using d-i have had it as well. Now, the problem I ran into is that when I enabled the test suite in the openldap2.3 package, the build failed mysteriously on a seemingly random set of architectures. The reason? The test suite configures slapd to run on a particular port on localhost, and the glibc "files" NSS backend special-cases the ::1 IPv6 loopback address, so that when you request an IPv4 address, it will map any ::1 entries to 127.0.0.1 for you. But of course we already have an entry for localhost as 127.0.0.1, so now we end up with duplicate addresses returned, and slapd tries to bind twice to the same address and port! A test program showing this behavior is attached - compile and run it on a system with '::1 localhost' set in /etc/hosts, and you'll see 127.0.0.1 returned twice. An alternate test case, which also works on systems with older /etc/hosts and which I think shows the counterintuitiveness of the nss_files special-casing, is to run "getent ahostsv4 ip6-localhost". I don't think it's the responsibility of callers such as slapd to check that getaddrinfo() hasn't returned duplicate entries, so I see a couple of solutions here: - the ::1 address should *not* be special-cased by nss_files. I really can't perceive any reason why it should be special-cased in the first place; i.e., why should the files backend behave differently than the DNS backend, and why would we want names that were specifically assigned to ::1, including names like "ip6-loopback", to be automatically mapped to 127.0.0.1? - we should only set up a single 'localhost' entry in /etc/hosts, pointing at ::1, and let nss_files handle the mapping to 127.0.0.1 automatically. Are there other solutions that should be considered? Is one of these more acceptable than the other? To me it seems obvious that the best choice is to not treat the files backend specially in the first place, but I don't know the rationale behind this special-casing either. Cheers, -- Steve Langasek Give me a lever long enough and a Free OS Debian Developer to set it on, and I can move the world. Ubuntu Developer http://www.debian.org/ [EMAIL PROTECTED] [EMAIL PROTECTED]
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> int main() { const char *host= "localhost"; const char *port= "9011"; struct addrinfo hints, *res, *sai; struct hostent *result; char buf[INET6_ADDRSTRLEN]; int buflen = sizeof(buf); int err; /* this call is just here to force glibc to set up the internal * _res state, so that it sees the "multi on" that's configured * by default in /etc/host.conf when we call getaddrinfo() below. * Of course we could just use gethostbyname_r() itself, but * getaddrinfo() is a truer test case. */ gethostbyname_r(host, NULL, NULL, 0, &result, &err); memset( &hints, '\0', sizeof(hints) ); hints.ai_flags = AI_PASSIVE; hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_UNSPEC; err = getaddrinfo(host, port, &hints, &res); if (err) { perror("getaddrinfo failed"); exit(1); } for (sai = res; sai != NULL; sai = sai->ai_next) { switch (sai->ai_family) { case AF_INET6: inet_ntop(AF_INET6, &((struct sockaddr_in6 *)sai->ai_addr)->sin6_addr, buf, buflen); break; case AF_INET: inet_ntop(AF_INET, &((struct sockaddr_in *)sai->ai_addr)->sin_addr, buf, buflen); break; } printf("name returned: %s\n",buf); } }