Package: libc6 Version: 2.9-6 Severity: normal Tags: ipv6 I've written a test program, gaitest.c, attached...
On Sid: e...@amd64:/tmp$ gcc -o gt gaitest.c && ./gt When given unspecified protocol, host:(null) and port:12345, as hints... This machine prefers listening on (in order of preference): * ipv4 (only) * ipv6+ipv4 g...@amd64:/tmp$ grep '^#*label' /etc/gai.conf label ::1/128 0 label ::/0 1 #label 2002::/16 2 label ::/96 3 label ::ffff:0:0/96 4 label fec0::/10 5 label fc00::/7 6 label 2001:0::/32 7 g...@amd64:/tmp$ grep localhost /etc/hosts 127.0.0.1 localhost localhost.localdomain ::1 localhost ip6-localhost ip6-loopback g...@amd64:/tmp$ getent hosts localhost ::1 localhost ip6-localhost ip6-loopback g...@amd64:/tmp$ ./gt localhost When given unspecified protocol, host:localhost and port:12345, as hints... This machine prefers listening on (in order of preference): * ipv6+ipv4 * ipv4 (only) Test program on Etch for comparison: g...@gamezone:/tmp$ gcc -o gt gaitest.c && ./gt When given unspecified protocol, NULL host and port 12345, as hints... This machine prefers listening on (in order of preference): * ipv6+ipv4 * ipv4 (only) Both machines have both ipv4 and ipv6 connectivity. I don't understand why it should be preferred to listen for ipv4-only connections over *both*. Listening for ipv6 connections never hurts, even if noone will ever reach the server via ipv6..... Right now the socket option IPV6_V6ONLY is pretty useless, since we'll have to explicitly set up an ipv6 socket if we ever want anything else then ipv4. I hope this is not a duplicate, couldn't find a suitable existing bug. I know there's been a long history of getaddrinfo issues. While some are debatable I really wonder about this one since I can't think of any use for looking up without address for anything but listening. I'm really starting to wonder how many times getaddrinfo can be implemented incorrectly. With everchanging behaviour it'll probably become one of those functions you can't rely on and every application writer starts having their own version of. I hope someone with clue on what's going on upstream can help me sort this out! Regards, Andreas Henriksson -- System Information: Debian Release: squeeze/sid APT prefers unstable APT policy: (300, 'unstable'), (100, 'experimental') Architecture: amd64 (x86_64) Kernel: Linux 2.6.26-1-amd64 (SMP w/1 CPU core) Locale: LANG=en_US.UTF-8, LC_CTYPE=sv_SE.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/bash Versions of packages libc6 depends on: ii libgcc1 1:4.3.3-5 GCC support library libc6 recommends no packages. Versions of packages libc6 suggests: ii glibc-doc 2.9-6 GNU C Library: Documentation ii locales 2.9-6 GNU C Library: National Language ( -- debconf-show failed
/* A test program that prints out what the machines preferred options * when getaddrinfo gets free hands. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> int main(int argc, char *argv[]) { int listenfd, err; struct addrinfo hints, *res, *curr; char *host = NULL, *serv = "12345"; if (argc > 1) host = argv[1]; if (argc > 2) serv = argv[2]; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = AI_PASSIVE; err = getaddrinfo(host, serv, &hints, &res); if (err) { fprintf(stderr, "ERROR: getaddrinfo() failed: %s\n", gai_strerror(err)); return -1; } #if 1 printf("When given unspecified protocol, host:%s and port:%s, as hints...\n", host, serv); printf("This machine prefers listening on (in order of preference):\n"); for (curr = res; curr != NULL; curr = curr->ai_next) { listenfd = socket(curr->ai_family, curr->ai_socktype, curr->ai_protocol); if (listenfd < 0) continue; switch (curr->ai_family) { case AF_INET6: { int v6only; socklen_t len = sizeof(v6only); getsockopt(listenfd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, &len); if (v6only) printf("\t* ipv6 (only)\n"); else printf("\t* ipv6+ipv4\n"); break; } case AF_INET: printf("\t* ipv4 (only)\n"); break; default: printf("\t* other protocol\n"); break; } #else /* usually you'd do something like this */ /* make sure IPV6_V6ONLY is off (Linux default) */ if (curr->ai_family == AF_INET6) { int off = 0; setsockopt(listenfd, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off)); } err = bind(listenfd, curr->ai_addr, curr->ai_addrlen); if (err) { close(listenfd); continue; } err = listen(listenfd, 5); if (err) { close(listenfd); continue; } /* listening socket successfully created! */ break; #endif } if (curr == NULL) { listenfd = -2; } freeaddrinfo(res); return 0; }