Hide Forgot
getaddrinfo does not return all ip addresses on first call when name resolution is done from /etc/hosts. This has been fixed by the following commits upstream: 1f0398248c1c581a1203c0d294acde295b949fea 1ce7d80ddc62d4bb3e8e4f89fbcb6fa21361733d 1ce7d80ddc62d4bb3e8e4f89fbcb6fa21361733d is needed because nscd links in getaddrinfo. The side-effect is that a similar bug in nscd will also be fixed (upstream bug #4814). Private branch: private-spoyarek-ROS00401237 Build: http://brewweb.devel.redhat.com/brew/taskinfo?taskID=3051905 Customer has verified that the patch works This issue was first reported to Oracle as a problem with Java. The public link to the report can be found here: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7007462 Consider the following setup on RedHat Enterprise Linux 5.5 x64. 1) Add the following lines to /etc/hosts: multihost 1.1.1.1 multihost 2.2.2.2 multihost 3.3.3.3 2) Add the following line to /etc/host.conf: multi on 3) Compile and execute the following program (provided by Oracle Java engineering team): /* This test code is to be used for demonstrating the * issue associated with SR 2-8229521. */ #include <stdio.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <string.h> #include <strings.h> #include <stdlib.h> #include <ctype.h> void dump_res(struct addrinfo * p_res){ struct addrinfo *iter = p_res; while(iter != 0){ struct sockaddr_in *addr1b; addr1b = (struct sockaddr_in *)iter->ai_addr; printf("getaddrinfo returns: %s %d %d\n", inet_ntoa(addr1b->sin_addr) , iter->ai_family, iter->ai_protocol ); iter=iter->ai_next; } } int main(int argc, char *argv[]){ if (argc != 2){ printf("Usage prog hostname\n"); exit(7); } struct addrinfo hints, *res; int error; bzero(&hints, sizeof(hints)); hints.ai_flags = AI_CANONNAME; hints.ai_family = AF_UNSPEC; printf("======== RH BUG ===============\n"); if ( (error = getaddrinfo(argv[1], NULL, &hints, &res) ) ){ perror("getaddrinfo"); exit(-1); } dump_res(res); freeaddrinfo(res); printf("======== WORKAROUND ===============\n"); hints.ai_family = AF_INET; if ( (error = getaddrinfo(argv[1], NULL, &hints, &res) ) ){ perror("getaddrinfo"); exit(-1); } dump_res(res); freeaddrinfo(res); } 4) You can see the following output from the above program: # ./a.out multihost ======== RH BUG =============== getaddrinfo returns: 1.1.1.1 2 6 getaddrinfo returns: 1.1.1.1 2 17 getaddrinfo returns: 1.1.1.1 2 0 ======== WORKAROUND =============== getaddrinfo returns: 1.1.1.1 2 6 getaddrinfo returns: 1.1.1.1 2 17 getaddrinfo returns: 1.1.1.1 2 0 getaddrinfo returns: 2.2.2.2 2 6 getaddrinfo returns: 2.2.2.2 2 17 getaddrinfo returns: 2.2.2.2 2 0 getaddrinfo returns: 3.3.3.3 2 6 getaddrinfo returns: 3.3.3.3 2 17 getaddrinfo returns: 3.3.3.3 2 0 Note that a similarly configured Ubuntu 10.10 Server (x64), provides the following - correct - output: $ ./a.out multihost ======== RH BUG =============== getaddrinfo returns: 1.1.1.1 2 6 getaddrinfo returns: 1.1.1.1 2 17 getaddrinfo returns: 1.1.1.1 2 0 getaddrinfo returns: 2.2.2.2 2 6 getaddrinfo returns: 2.2.2.2 2 17 getaddrinfo returns: 2.2.2.2 2 0 getaddrinfo returns: 3.3.3.3 2 6 getaddrinfo returns: 3.3.3.3 2 17 getaddrinfo returns: 3.3.3.3 2 0 ======== WORKAROUND =============== getaddrinfo returns: 1.1.1.1 2 6 getaddrinfo returns: 1.1.1.1 2 17 getaddrinfo returns: 1.1.1.1 2 0 getaddrinfo returns: 2.2.2.2 2 6 getaddrinfo returns: 2.2.2.2 2 17 getaddrinfo returns: 2.2.2.2 2 0 getaddrinfo returns: 3.3.3.3 2 6 getaddrinfo returns: 3.3.3.3 2 17 getaddrinfo returns: 3.3.3.3 2 0 In other words, hints.ai_family / hints.ai_flags for getaddrinfo are not working properly. According to the manual of getaddrinfo (excerpts): "AF_UNSPEC in ai_family specifies any protocol family (either IPv4 or IPv6, for example)."
A more accurate reproducer: #include <stdio.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <string.h> #include <strings.h> #include <stdlib.h> #include <ctype.h> void dump_res (struct addrinfo *p_res) { struct addrinfo *iter = p_res; while (iter != 0) { struct sockaddr_in *addr1b; addr1b = (struct sockaddr_in *) iter->ai_addr; printf ("getaddrinfo returns: %s %d %d\n", inet_ntoa (addr1b->sin_addr), iter->ai_family, iter->ai_protocol); iter = iter->ai_next; } } int main (int argc, char *argv[]) { if (argc != 2) { printf ("Usage prog hostname\n"); exit (7); } struct addrinfo hints, *res; int error, i; bzero (&hints, sizeof (hints)); hints.ai_flags = AI_CANONNAME; hints.ai_family = AF_UNSPEC; for (i = 0; i < 2; i++) { printf ("======== ATTEMPT %d ===============\n", i); if ((error = getaddrinfo (argv[1], NULL, &hints, &res))) { perror ("getaddrinfo"); exit (-1); } dump_res (res); freeaddrinfo (res); } } since it does not have anything to do with AF_UNSPEC per say and the earlier reproducer tries to imply otherwise. It's just that the first call does not return all addresses since _res_hconf_init has not been called yet.
// glibc-2.5-57 # getent ahosts multihost multihost 1.1.1.1 STREAM multihost 1.1.1.1 DGRAM 1.1.1.1 RAW 1.1.1.1 STREAM multihost 1.1.1.1 DGRAM 1.1.1.1 RAW 2.2.2.2 STREAM 2.2.2.2 DGRAM 2.2.2.2 RAW 3.3.3.3 STREAM 3.3.3.3 DGRAM 3.3.3.3 RAW // glibc-2.5-57 # ./a.out multihost ======== ATTEMPT 0 =============== getaddrinfo returns: 1.1.1.1 2 6 getaddrinfo returns: 1.1.1.1 2 17 getaddrinfo returns: 1.1.1.1 2 0 ======== ATTEMPT 1 =============== getaddrinfo returns: 1.1.1.1 2 6 getaddrinfo returns: 1.1.1.1 2 17 getaddrinfo returns: 1.1.1.1 2 0 getaddrinfo returns: 2.2.2.2 2 6 getaddrinfo returns: 2.2.2.2 2 17 getaddrinfo returns: 2.2.2.2 2 0 getaddrinfo returns: 3.3.3.3 2 6 getaddrinfo returns: 3.3.3.3 2 17 getaddrinfo returns: 3.3.3.3 2 0 // glibc-2.5-65 # getent ahosts multihost multihost 1.1.1.1 STREAM multihost 1.1.1.1 DGRAM 1.1.1.1 RAW 2.2.2.2 STREAM 2.2.2.2 DGRAM 2.2.2.2 RAW 3.3.3.3 STREAM 3.3.3.3 DGRAM 3.3.3.3 RAW 1.1.1.1 STREAM multihost 1.1.1.1 DGRAM 1.1.1.1 RAW 2.2.2.2 STREAM 2.2.2.2 DGRAM 2.2.2.2 RAW 3.3.3.3 STREAM 3.3.3.3 DGRAM 3.3.3.3 RAW // glibc-2.5-65 ======== ATTEMPT 0 =============== getaddrinfo returns: 1.1.1.1 2 6 getaddrinfo returns: 1.1.1.1 2 17 getaddrinfo returns: 1.1.1.1 2 0 getaddrinfo returns: 2.2.2.2 2 6 getaddrinfo returns: 2.2.2.2 2 17 getaddrinfo returns: 2.2.2.2 2 0 getaddrinfo returns: 3.3.3.3 2 6 getaddrinfo returns: 3.3.3.3 2 17 getaddrinfo returns: 3.3.3.3 2 0 ======== ATTEMPT 1 =============== getaddrinfo returns: 1.1.1.1 2 6 getaddrinfo returns: 1.1.1.1 2 17 getaddrinfo returns: 1.1.1.1 2 0 getaddrinfo returns: 2.2.2.2 2 6 getaddrinfo returns: 2.2.2.2 2 17 getaddrinfo returns: 2.2.2.2 2 0 getaddrinfo returns: 3.3.3.3 2 6 getaddrinfo returns: 3.3.3.3 2 17 getaddrinfo returns: 3.3.3.3 2 0
An advisory has been issued which should help the problem described in this bug report. This report is therefore being closed with a resolution of ERRATA. For more information on therefore solution and/or where to find the updated files, please follow the link below. You may reopen this bug report if the solution does not work for you. http://rhn.redhat.com/errata/RHBA-2011-1034.html