[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#573456: libc6: getaddrinfo() equates AF_UNSPEC with AF_INET for passive lockups



The authentic code included below intends to establish a listening
socket that listens to IPv6 as well as to IPv4.

With libc6-2.7 in Lenny, and also FreeBSD 6.4, this functions as intended,
but with Squeeze and eglibc-2.10.2 the only listening socket sits in IPv4.
Nothing at all is tied to IPv6.

Being a passive resolution there should be no reason to cycle
through the answers that getaddrinfo() care to make. The code
is taken from a package I manage and where I am the upstream
author. I have observed the same difference between glibc
and eglibc for other services I am patching for IPv6 in order
to improve the packages for Debian.

This code is almost identical to the one on display in the
manual page getaddrinfo(3), yet it does not produce the
promised effect! Replacing AF_UNSPEC with AF_INET6 is a
functional workaround with eglibc, but that works by another
mechanism.


	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
#if __OpenBSD__
	hints.ai_flags = AI_PASSIVE;
#else
	hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
#endif

	sprintf(portstr, "%u", port_number);

	if ( (status = getaddrinfo(NULL, portstr, &hints, &ai)) != 0 ) {
		perror("getaddrinfo");
		fprintf(stderr, "Address failure. Quitting...\n\n");
		exit(1);
	}

	if ( (sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))
			== -1 )
	{
		perror("socket");
		fprintf(stderr, "Peer error: (socket). Quitting...\n\n");
		exit(1);
	}

	/* avoid "Address already in use" errors when restarting */
	if ( setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
				(void *) &reuse, sizeof (reuse)) == -1 )
	{
		perror("SO_REUSEADDR");
		fprintf(stderr, "Peer error: (SO_REUSEADDR). Quitting...\n\n");
		exit(1);
	}

	/*
	 * If it succeeds, then IPv6 was used and both address
	 * families will now be acceptable. Otherwise, we do not care.
	 */
	setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
				&null, sizeof(null));

	if ( bind(sockfd, ai->ai_addr, ai->ai_addrlen) == -1)

> Do you have more details about your problems? I have just tried a simple
> code, and getaddrinfo() correctly returns one address with IPv4, and one
> with IPv6.

The important point here is AI_PASSIVE. The client side functions
reliably with eglibc. I hope this explicit code helps.




Reply to: