From nobody@FreeBSD.org  Fri May  2 21:54:20 2014
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115])
	(using TLSv1 with cipher ADH-AES256-SHA (256/256 bits))
	(No client certificate requested)
	by hub.freebsd.org (Postfix) with ESMTPS id EB0743A9
	for <freebsd-gnats-submit@FreeBSD.org>; Fri,  2 May 2014 21:54:20 +0000 (UTC)
Received: from cgiserv.freebsd.org (cgiserv.freebsd.org [IPv6:2001:1900:2254:206a::50:4])
	(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
	(Client did not present a certificate)
	by mx1.freebsd.org (Postfix) with ESMTPS id D7E9710BD
	for <freebsd-gnats-submit@FreeBSD.org>; Fri,  2 May 2014 21:54:20 +0000 (UTC)
Received: from cgiserv.freebsd.org ([127.0.1.6])
	by cgiserv.freebsd.org (8.14.8/8.14.8) with ESMTP id s42LsKCZ075398
	for <freebsd-gnats-submit@FreeBSD.org>; Fri, 2 May 2014 21:54:20 GMT
	(envelope-from nobody@cgiserv.freebsd.org)
Received: (from nobody@localhost)
	by cgiserv.freebsd.org (8.14.8/8.14.8/Submit) id s42LsKAV075397;
	Fri, 2 May 2014 21:54:20 GMT
	(envelope-from nobody)
Message-Id: <201405022154.s42LsKAV075397@cgiserv.freebsd.org>
Date: Fri, 2 May 2014 21:54:20 GMT
From: Dreamcat4 <dreamcat4@gmail.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: man 3 getaddrinfo - hostanme="localhost", but it returns IN_ADDR_ANY (0.0.0.0)
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         189268
>Category:       docs
>Synopsis:       3 getaddrinfo(3) - hostanme="localhost", but it returns IN_ADDR_ANY (0.0.0.0)
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-doc
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri May 02 22:00:00 UTC 2014
>Closed-Date:    
>Last-Modified:  Mon May 19 18:30:00 UTC 2014
>Originator:     Dreamcat4
>Release:        9.2-RELEASE-p3
>Organization:
>Environment:
FreeBSD freenas.local 9.2-RELEASE-p3 FreeBSD 9.2-RELEASE-p3 #0 r262572+7b72365: Fri Mar 14 15:50:04 PDT 2014     root@build.ixsystems.com:/home/jkh/9.2.1-BRANCH/freenas/os-base/amd64/tank/home/jkh/9.2.1-BRANCH/freenas/FreeBSD/src/sys/FREENAS.amd64  amd64

>Description:
* Inside a jail, no lo0 loopback interface.
* Calling this function returns the ip "0.0.0.0" (also known as "IN_ADDR_ANY").
* But we asked for the hostname "localhost" - which in our /etc/hosts file is set to "127.0.0.1".

The proof:
Example 'C' test program "test.c" is attached.
getaddrinfo ~/ root~# gcc test.c -o test && ./test
0.0.0.0

This affects the gSOAP library, it's function soap_bind(), which is called by VirtualBox's SOAP webservice ("vboxwebsrv").

These applications seem to do everything correctly. But the result is a bug. Please see test script "test.c" included.

The real-life bug occurs in this code where:

vboxweb.cpp:858:
    SOAP_SOCKET m, s; // master and slave sockets
    m = soap_bind(&soap,
                  g_pcszBindToHost ? g_pcszBindToHost : "localhost",    // safe default host
                  g_uBindToPort,    // port
                  g_uBacklog);      // backlog = max queue size for requests
    if (m < 0)
        WebLogSoapError(&soap);


and:

stdsoap2.cpp:4143:
  err = getaddrinfo(host, soap_int2s(soap, port), &hints, &addrinfo);

Is passing in "localhost", is told "0.0.0.0". Then later on in soap_bind(), the returned address "0.0.0.0" is passed into bind(). And bind() then binds to ALL interfaces (not just only the localhost interface, or should error out in the jail where lo0 has no IP address).

I looked hard in these applications but the bug isn't in there - it seems to be in the result returned be "getaddrinfo()" C library call.

I confirmed this was the case with "test.c" example program (below). Which was run in the same jail.

The test jail was created like this:

$ qjail create -4 192.168.1.203 getaddrinfo
$ qjail config -k getaddrinfo
$ qjail start getaddrinfo

>How-To-Repeat:
getaddrinfo ~/ root~# ifconfig
re0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
	options=8209b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,VLAN_HWCSUM,WOL_MAGIC,LINKSTATE>
	ether 00:1e:ec:d7:3a:1f
	inet 192.168.1.203 netmask 0xffffffff broadcast 192.168.1.203
	media: Ethernet autoselect (1000baseT <full-duplex>)
	status: active
ipfw0: flags=8801<UP,SIMPLEX,MULTICAST> metric 0 mtu 65536
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
	options=600003<RXCSUM,TXCSUM,RXCSUM_IPV6,TXCSUM_IPV6>
getaddrinfo ~/ root~# ping -c 1 "localhost"
PING localhost (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.168 ms

--- localhost ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.168/0.168/0.168/0.000 ms
getaddrinfo ~/ root~# cat /etc/hosts | grep localhost
::1			localhost localhost.my.domain
127.0.0.1		localhost localhost.my.domain
getaddrinfo ~/ root~# cat test.c
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>


/* man getaddrinfo */

int main()
{
  struct addrinfo *addrinfo = NULL;
  struct addrinfo hints;
  struct addrinfo res;
  int err;

  memset((void*)&hints, 0, sizeof(hints));
  hints.ai_family   = PF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags    = AI_PASSIVE;

  err = getaddrinfo("localhost", "18083", &hints, &addrinfo);

  if (addrinfo)
  { 
    res = *addrinfo;
    printf("%s\n", inet_ntoa( ((struct sockaddr_in*)addrinfo->ai_addr)->sin_addr ));

    freeaddrinfo(addrinfo);
    return(0);
  }

  if (err || !addrinfo)
  {
    printf("getaddrinfo failed with code %i.\n",err);
    return(1);
  }

  printf("end_main()\n");
  return (0);

}

getaddrinfo ~/ root~# gcc test.c -o test && ./test
0.0.0.0
getaddrinfo ~/ root~# exit
logout

>Fix:
I suspect this function (getaddrinfo) shouldn't be returning IN_ADDR_ANY. It should either fail, or return "127.0.0.1" as per "/etc/hosts".


>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->freebsd-doc 
Responsible-Changed-By: linimon 
Responsible-Changed-When: Sat May 3 02:54:22 UTC 2014 
Responsible-Changed-Why:  
reclassify. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=189268 

From: Allan Jude <freebsd@allanjude.com>
To: bug-followup@FreeBSD.org, dreamcat4@gmail.com
Cc:  
Subject: Re: docs/189268: 3 getaddrinfo(3) - hostanme=&quot;localhost&quot;,
 but it returns IN_ADDR_ANY (0.0.0.0)
Date: Sat, 03 May 2014 00:13:05 -0400

 for me, the 0.0.0.0 results go away when I remove the ipv6 ::1 entry
 from /etc/hosts in my jail
 
 However, I get the same results both inside and outside of a jail.
 
 -- 
 Allan Jude

From: Dreamcat4 <dreamcat4@gmail.com>
To: bug-followup@freebsd.org, dreamcat4@gmail.com
Cc:  
Subject: Re: docs/189268: 3 getaddrinfo(3) - hostanme=&quot;localhost&quot;,
 but it returns IN_ADDR_ANY (0.0.0.0)
Date: Sat, 3 May 2014 08:29:44 +0100

 --089e012953d0181fd904f879df3a
 Content-Type: text/plain; charset=UTF-8
 
 Ah,
 I have researched a little more. It is my impression that the expected
 result aught to be "::1" if the protocol family was PF_UNSPEC or PF_INET6.
 
 Now that Allan has mentioned it. Commenting out the ::1 in /etc/hosts does
 change the result. However that isn't something the gSOAP library which is
 making that API call has any control over.
 
 Also:
 
 This bug occurs when the protocol family being requested is set to
 "PF_UNSPEC" (unspecified). OR "PF_INET6". With the default "/etc/hosts"
 file (where that ::1 localhost entry exists).
 
 Wheras setting:
 
 hints.ai_family   = PF_INET;
 
 returns 127.0.0.1 regardless of the ::1 in /etc/hosts file.
 
 Setting:
 
 hints.ai_family   = PF_INET6;
 
 also gives such incorrect "0.0.0.0", except if commenting out ::1 in
 /etc/hosts as Alan says.
 
 Then it gives:
 
 getaddrinfo ~/ root~# gcc test.c -o test && ./test
 getaddrinfo failed with code 8.
 
 Which would be correct to error out since no corresponding ip6 address
 found.
 
 
 The gSOAP library seems to choose PF_UNSPEC because they want to support
 both ipv4 and ipv6 protocols simultaneously (as many others also do). I'm
 not sure if they could fix downstream the issue by avoiding PF_UNSPEC
 because the bug will still occur on PF_INET6.
 
 
 Anyway. Heres is the gSOAP code where getaddrinfo() is being called in
 "soap_bind()":
 
 http://sourceforge.net/p/gsoap2/code/HEAD/tree/gsoap/stdsoap2.cpp#l4789
 
 http://sourceforge.net/p/gsoap2/code/HEAD/tree/gsoap/stdsoap2.cpp#l4791
 
 Then later on in soap_bind() the incorrect address (0.0.0.0), is used are
 the parameter being passed into bind()
 
 http://sourceforge.net/p/gsoap2/code/HEAD/tree/gsoap/stdsoap2.cpp#l4876
 
 --089e012953d0181fd904f879df3a--

From: Dreamcat4 <dreamcat4@gmail.com>
To: bug-followup@freebsd.org, dreamcat4@gmail.com
Cc:  
Subject: Re: docs/189268: 3 getaddrinfo(3) - hostanme=&quot;localhost&quot;,
 but it returns IN_ADDR_ANY (0.0.0.0)
Date: Sat, 3 May 2014 08:44:57 +0100

 --001a1133059e7da3f704f87a150e
 Content-Type: text/plain; charset=UTF-8
 
 getaddrinfo() returns a list of results. So I have updated my test program
 to walk the entire list. It now prints two results for PF_UNSPEC
 
 getaddrinfo ~/ root~# gcc test.c -o test && ./test
 0.0.0.0
 127.0.0.1
 getaddrinfo ~/ root~#
 
 Where the first result in the list is supposed to be the ipv6's "::1" (but
 isn't).
 
 Anyway heres the new version of the test.c
 
 getaddrinfo ~/ root~# cat test.c
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netdb.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
 
 /* man getaddrinfo */
 
 int main()
 {
   struct addrinfo *addrinfo = NULL;
   struct addrinfo *rp = NULL;
   struct addrinfo hints;
   struct addrinfo res;
   int err;
 
   memset((void*)&hints, 0, sizeof(hints));
   hints.ai_family   = PF_UNSPEC;
   hints.ai_socktype = SOCK_STREAM;
   hints.ai_flags    = AI_PASSIVE;
 
   err = getaddrinfo("localhost", "18083", &hints, &addrinfo);
 
   if (addrinfo)
   {
     for (rp = addrinfo; rp != NULL; rp = rp->ai_next)
     {
       printf("%s\n", inet_ntoa( ((struct
 sockaddr_in*)rp->ai_addr)->sin_addr ));
     }
 
     freeaddrinfo(addrinfo);
     return(0);
   }
 
   if (err || !addrinfo)
   {
     printf("getaddrinfo failed with code %i.\n",err);
     return(1);
   }
 
   printf("end_main()\n");
   return (0);
 
 }
 
 getaddrinfo ~/ root~# gcc test.c -o test && ./test
 0.0.0.0
 127.0.0.1
 getaddrinfo ~/ root~#
 
 --001a1133059e7da3f704f87a150e--

From: Allan Jude <allanjude@freebsd.org>
To: bug-followup@FreeBSD.org, dreamcat4@gmail.com
Cc:  
Subject: Re: docs/189268: 3 getaddrinfo(3) - hostanme=&quot;localhost&quot;,
 but it returns IN_ADDR_ANY (0.0.0.0)
Date: Mon, 19 May 2014 14:26:44 -0400

 So do you still think there is an issue here? or can I close this PR?
 
 -- 
 Allan Jude
>Unformatted:
