misc/131623: gethostbyname_r
Guillaume Morin
guillaume at morinfr.org
Thu Feb 12 15:20:03 PST 2009
>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 at 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:
More information about the freebsd-bugs
mailing list