Bug#520628: libc6: getaddrinfo now prefers listening on ipv4-only over ipv4+ipv6.

2009-05-01 Thread Aurelien Jarno
On Tue, Apr 14, 2009 at 07:15:12PM +0200, Nicolas George wrote:
 Le primidi 1er germinal, an CCXVII, Andreas Henriksson a écrit :
  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
 
 I stumbled on the same problem and found the cause:
 
  g...@amd64:/tmp$ grep '^#*label' /etc/gai.conf
  label ::1/128   0
  label ::/0  1
  #label 2002::/16 2
  label ::/96 3
  label :::0:0/96 4
  label fec0::/10 5
  label fc00::/7  6
  label 2001:0::/32   7
 
 The labels are related to the rule 6 of RFC 3484 (although the comment in
 the source code of the glibc says rule 5). The algorithm needs to choose
 between two addresses:

They are two paragraphs in the RFC3484, one for the source addresses,
one for the destinations addresses. The source code correctly matches
the rules for destination addresses in the RFC.

 - ::0 (IPv6 mildcard)
 
 - :::0.0.0.0 (mapped IPv4 wildcard)
 
 It uses a corresponding source address, respectively:
 
 According to the labels above (or the hardcoded ones), the addresses get the
 following labels:
 
 - ::1 (IPv6 looopback) - 0
 
 - ::0 (IPv6 mildcard) - 3
 
 - :::0.0.0.0 (mapped IPv4 wildcard) - 4
 
 - :::127.0.0.1 (mapped IPv4 loopback) - 4
 
 The rule 6 says that addresses with the same label for the source and the
 destination should be selected.
 
 I fixed the problem by adding the following line to gai.conf:
 
 label ::/1280
 
 I am not completely sure whether this is correct, but it seems to work.
 

In my opinion, it is more a workaround then a fix, as the default labels
are defined by the RFC. Moreover this may have some side effects.

-- 
Aurelien Jarno  GPG: 1024D/F1BCDB73
aurel...@aurel32.net http://www.aurel32.net



-- 
To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org
with a subject of unsubscribe. Trouble? Contact listmas...@lists.debian.org



Bug#520628: libc6: getaddrinfo now prefers listening on ipv4-only over ipv4+ipv6.

2009-04-14 Thread Nicolas George
Le primidi 1er germinal, an CCXVII, Andreas Henriksson a écrit :
 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

I stumbled on the same problem and found the cause:

 g...@amd64:/tmp$ grep '^#*label' /etc/gai.conf
 label ::1/128   0
 label ::/0  1
 #label 2002::/16 2
 label ::/96 3
 label :::0:0/96 4
 label fec0::/10 5
 label fc00::/7  6
 label 2001:0::/32   7

The labels are related to the rule 6 of RFC 3484 (although the comment in
the source code of the glibc says rule 5). The algorithm needs to choose
between two addresses:

- ::0 (IPv6 mildcard)

- :::0.0.0.0 (mapped IPv4 wildcard)

It uses a corresponding source address, respectively:

According to the labels above (or the hardcoded ones), the addresses get the
following labels:

- ::1 (IPv6 looopback) - 0

- ::0 (IPv6 mildcard) - 3

- :::0.0.0.0 (mapped IPv4 wildcard) - 4

- :::127.0.0.1 (mapped IPv4 loopback) - 4

The rule 6 says that addresses with the same label for the source and the
destination should be selected.

I fixed the problem by adding the following line to gai.conf:

label ::/1280

I am not completely sure whether this is correct, but it seems to work.

Regards,

-- 
  Nicolas George


signature.asc
Description: Digital signature


Bug#520628: libc6: getaddrinfo now prefers listening on ipv4-only over ipv4+ipv6.

2009-03-21 Thread Andreas Henriksson
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 :::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;
}