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>
