Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 12 Feb 2009 23:16:12 GMT
From:      Guillaume Morin <guillaume@morinfr.org>
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   misc/131623: gethostbyname_r
Message-ID:  <200902122316.n1CNGCll047997@www.freebsd.org>
Resent-Message-ID: <200902122320.n1CNK0oe030779@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         131623
>Category:       misc
>Synopsis:       gethostbyname_r
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Feb 12 23:20:00 UTC 2009
>Closed-Date:
>Last-Modified:
>Originator:     Guillaume Morin
>Release:        7.1-RELEASE
>Organization:
>Environment:
FreeBSD freebsd 7.1-RELEASE FreeBSD 7.1-RELEASE #0: Thu Jan  1 08:58:24 UTC 2009     root@driscoll.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  amd64
>Description:
The output parameters of gethostbyname_r do not allow to distinguish between a failure to resolve and situations where the buffer is too small.

Here is a simple program:
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv) {
    struct hostent h;
    char buf[BUF_LEN] = {0};
    struct hostent *result;
    int err,i;

    if (argc < 2) {
        puts("Pass an argument");
        return 1;
    }

    int ret = gethostbyname_r(argv[1], &h, buf, sizeof(buf), &result, &err);

    printf("gethostbyname_r returned ret %d, res %p, err %d, "
           "errno \"%s\" for %s\n",
           ret, result, err, strerror(errno), argv[1]);

    for (i = 0; 0 == ret && h.h_addr_list[i]; ++i) {
        if (AF_INET != h.h_addrtype) {
            continue;
        }
        int addr;
        memcpy(&addr, h.h_addr_list[i], sizeof(addr));
        addr = htonl(addr);
        char *ipBytes = (char *) &addr;
        printf("Found address: %hu.%hu.%hu.%hu\n",
               (unsigned char) ipBytes[3], (unsigned char) ipBytes[2],
               (unsigned char) ipBytes[1], (unsigned char) ipBytes[0]);
    }


    return 0;
}

gcc -DBUF_LEN=1 -Wall -o gh gethostbyname.c && ./gh sdv1
gethostbyname_r returned ret -1, res 0x0, err 2, errno "Unknown error: 0" for sdv1
$gcc -DBUF_LEN=1024 -Wall -o gh gethostbyname.c && ./gh sdv1
gethostbyname_r returned ret 0, res 0x7fffffffcf30, err 0, errno "Unknown error: 0" for sdv1
Found address: x.x.x.x (edited)


One might think that err = 2 and non-zero ret means that the buffer is too small, but: 
$gcc -DBUF_LEN=1024 -Wall -o gh gethostbyname.c && ./gh nosuchaddr
gethostbyname_r returned ret -1, res 0x0, err 2, errno "Unknown error: 0" for nosuchaddr

We got the exact same output for two different conditions.  Trying to resolve localhost shows the same kind of behavior but different values for err.

$gcc -DBUF_LEN=1 -Wall -o gh gethostbyname.c && ./gh localhost
gethostbyname_r returned ret -1, res 0x0, err 0, errno "Unknown error: 0" for localhost
$gcc -DBUF_LEN=128 -Wall -o gh gethostbyname.c && ./gh localhost
gethostbyname_r returned ret 0, res 0x7fffffffcf30, err 0, errno "Unknown error: 0" for localhost
Found address: 127.0.0.1

getservbyname_r has a similar (glibc-like) interface but returns what should be errno.  A return value == ERANGE indicates that the buffer is too small.  A similar scheme should be used here.

>How-To-Repeat:
Compile, run the same tests
>Fix:


>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200902122316.n1CNGCll047997>