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>