Bug 676039

Summary: Resolver fails to return all addresses of multi-homed hosts in /etc/hosts
Product: Red Hat Enterprise Linux 5 Reporter: Alan Matsuoka <alanm>
Component: glibcAssignee: Andreas Schwab <schwab>
Status: CLOSED ERRATA QA Contact: qe-baseos-tools-bugs
Severity: high Docs Contact:
Priority: high    
Version: 5.5CC: ebachalo, fweimer, mfranc, pmuller, spoyarek
Target Milestone: rc   
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: glibc-2.5-64 Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2011-07-21 08:31:39 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:

Description Alan Matsuoka 2011-02-08 17:08:00 UTC
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)."

Comment 1 Siddhesh Poyarekar 2011-02-08 17:23:36 UTC
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.

Comment 3 Miroslav Franc 2011-04-21 15:22:18 UTC
// 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

Comment 5 errata-xmlrpc 2011-07-21 08:31:39 UTC
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