Bug 1000924

Summary: GETAI(AF_UNSPEC) does not return both IPv6 and IPv4 addresses on first request from /etc/hosts
Product: [Fedora] Fedora Reporter: Siddhesh Poyarekar <spoyarek>
Component: glibcAssignee: Siddhesh Poyarekar <spoyarek>
Status: CLOSED RAWHIDE QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: high Docs Contact:
Priority: urgent    
Version: rawhideCC: akarlsso, ashankar, codonell, fweimer, jakub, jdonohue, law, mfranc, mnewsome, pfrankli, richard.alpe, schwab, snagar, spoyarek
Target Milestone: ---   
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2013-08-26 10:12:57 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:

Description Siddhesh Poyarekar 2013-08-26 06:48:09 UTC
GETAI only returns the IPv4 result via nscd on first request via getaddrinfo (PF_UNSPEC) if the host is resolved from /etc/hosts (localhost for example).  One may run `nscd -i hosts` and then call getaddrinfo to work around this.

How to reproduce:

Sample program:

#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <strings.h>

#ifndef   NI_MAXHOST
#define   NI_MAXHOST 1025
#endif

int main(int argc, char *argv[])
{
	struct addrinfo *result;
	struct addrinfo hints = {0};
	struct addrinfo *res;
	int error;
	char *host = argv[1];

	if (argc > 2) {
		if (strcasecmp(argv[1], "AF_INET6") == 0)
			hints.ai_family = AF_INET6;
		if (strcasecmp(argv[1], "AF_INET") == 0)
			hints.ai_family = AF_INET;
		host = argv[2];
	}

	printf("Hints family=%d\n", hints.ai_family);

	/* resolve the domain name into a list of addresses */
	error = getaddrinfo(host, NULL, &hints, &result);
	if (error != 0) {
		if (error == EAI_SYSTEM) {
			perror("getaddrinfo");
		}
		else {
			fprintf(stderr, "error in getaddrinfo: %s\n", gai_strerror(error));
		}
		exit(EXIT_FAILURE);
	}

	/* loop over all returned results and do inverse lookup */
	for (res = result; res != NULL; res = res->ai_next) {
		char hostname[NI_MAXHOST] = "";
		char buf[130] = {0};

		error = getnameinfo(res->ai_addr, res->ai_addrlen, hostname, NI_MAXHOST, NULL, 0, 0);
		if (error != 0) {
			fprintf(stderr, "error in getnameinfo: %s\n", gai_strerror(error));
			continue;
		}
		if (*hostname != '\0') {
			if (res->ai_family == AF_INET)
				inet_ntop(res->ai_family, &((struct sockaddr_in *)res->ai_addr)->sin_addr, buf, sizeof(buf));
			if (res->ai_family == AF_INET6)
				inet_ntop(res->ai_family, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, buf, sizeof(buf));

			printf("host=%s, family=%d addr=%s\n", hostname, res->ai_family, buf);
		}
	}

	freeaddrinfo(result);
	printf("\n");
	return 0;
}

Delete nscd cache, Build and run program:

# service nscd stop
# rm -f /var/db/nscd/*
# service nscd start
# gcc foo.c
# ./a.out localhost

Actual Result:

Hints family=0
host=localhost, family=2 addr=127.0.0.1
host=localhost, family=2 addr=127.0.0.1
host=localhost, family=2 addr=127.0.0.1

Expected Result:

Hints family=0
host=localhost, family=10 addr=::1
host=localhost, family=10 addr=::1
host=localhost, family=10 addr=::1
host=localhost, family=2 addr=127.0.0.1
host=localhost, family=2 addr=127.0.0.1
host=localhost, family=2 addr=127.0.0.1

This is because res_hconf is not initialized in aicache.c.