Replacing gethostbyname, gethostbyname2 and their _r variants with getaddrinfo to increase portability.

This commit is contained in:
Tobias Brunner 2009-08-14 15:47:04 +02:00
parent 26965b4ef3
commit f1777dff59
6 changed files with 128 additions and 130 deletions

View File

@ -882,7 +882,6 @@ AC_TRY_COMPILE(
)
AC_CHECK_FUNCS(prctl)
AC_CHECK_FUNCS(gethostbyname_r)
AC_CHECK_HEADERS(sys/sockio.h)
AC_CHECK_HEADERS(net/pfkeyv2.h netipsec/ipsec.h netinet6/ipsec.h linux/udp.h)

View File

@ -54,7 +54,7 @@ on a big-endian host and
.B 4.3.2.1
on a little-endian host),
a DNS name to be looked up via
.IR gethostbyname (3),
.IR getaddrinfo (3),
or an old-style network name to be looked up via
.IR getnetbyname (3).
.PP
@ -91,10 +91,8 @@ DNS names may be complete (optionally terminated with a ``.'')
or incomplete, and are looked up as specified by local system configuration
(see
.IR resolver (5)).
The
.I h_addr
value returned by
.IR gethostbyname (3)
The first value returned by
.IR getaddrinfo (3)
is used,
so with current DNS implementations,
the result when the name corresponds to more than one address is
@ -102,7 +100,7 @@ difficult to predict.
Name lookup resorts to
.IR getnetbyname (3)
only if
.IR gethostbyname (3)
.IR getaddrinfo (3)
fails.
.PP
A subnet specification is of the form \fInetwork\fB/\fImask\fR.

View File

@ -12,6 +12,8 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
* License for more details.
*/
#include <sys/socket.h>
#include "internal.h"
#include "freeswan.h"
@ -41,7 +43,7 @@ const char *src;
size_t srclen; /* 0 means "apply strlen" */
struct in_addr *addrp;
{
struct hostent *h;
struct addrinfo hints, *res;
struct netent *ne = NULL;
const char *oops;
# define HEXLEN 10 /* strlen("0x11223344") */
@ -51,6 +53,7 @@ struct in_addr *addrp;
char namebuf[ATOADDRBUF];
char *p = namebuf;
char *q;
int error;
if (srclen == 0)
srclen = strlen(src);
@ -87,18 +90,33 @@ struct in_addr *addrp;
return "illegal (non-DNS-name) character in name";
/* try as host name, failing that as /etc/networks network name */
h = gethostbyname(p);
if (h == NULL)
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
error = getaddrinfo(p, NULL, &hints, &res);
if (error != 0)
{
ne = getnetbyname(p);
if (p != namebuf)
FREE(p);
if (h == NULL && ne == NULL)
return "name lookup failed";
if (h != NULL)
memcpy(&addrp->s_addr, h->h_addr, sizeof(addrp->s_addr));
else
if (ne == NULL)
{
if (p != namebuf)
{
FREE(p);
}
return "name lookup failed";
}
addrp->s_addr = htonl(ne->n_net);
}
else
{
memcpy(&addrp->s_addr, res->ai_addr->sa_data, sizeof(addrp->s_addr));
freeaddrinfo(res);
}
if (p != namebuf)
{
FREE(p);
}
return NULL;
}

View File

@ -59,7 +59,7 @@ on a big-endian host and
.B 4.3.2.1
on a little-endian host),
a DNS name to be looked up via
.IR gethostbyname (3),
.IR getaddrinfo (3),
or an old-style network name to be looked up via
.IR getnetbyname (3).
.PP
@ -100,7 +100,7 @@ abbreviating at most one subsequence of multiple zeros (e.g.
which is synonymous with
.BR 99:ab:0:0:0:0:54:68 ),
or a DNS name to be looked up via
.IR gethostbyname (3).
.IR getaddrinfo (3).
The result of applying
.I addrtot
to an IPv6 address will use
@ -115,10 +115,8 @@ DNS names may be complete (optionally terminated with a ``.'')
or incomplete, and are looked up as specified by local system configuration
(see
.IR resolver (5)).
The
.I h_addr
value returned by
.IR gethostbyname2 (3)
The first value returned by
.IR getaddrinfo (3)
is used,
so with current DNS implementations,
the result when the name corresponds to more than one address is
@ -126,7 +124,7 @@ difficult to predict.
IPv4 name lookup resorts to
.IR getnetbyname (3)
only if
.IR gethostbyname2 (3)
.IR getaddrinfo (3)
fails.
.PP
A subnet specification is of the form \fInetwork\fB/\fImask\fR.

View File

@ -157,12 +157,15 @@ int nultermd; /* is it known to be NUL-terminated? */
int af;
ip_address *dst;
{
struct hostent *h;
struct addrinfo hints, *res;
struct netent *ne = NULL;
char namebuf[100]; /* enough for most DNS names */
const char *cp;
char *p = namebuf;
unsigned char *addr = NULL;
size_t n;
int error;
err_t err = NULL;
for (cp = src, n = srclen; n > 0; cp++, n--)
if (ISASCII(*cp) && strchr(namechars, *cp) == NULL)
@ -181,25 +184,40 @@ ip_address *dst;
cp = (const char *)p;
}
h = gethostbyname2(cp, af);
if (h == NULL && af == AF_INET)
ne = getnetbyname(cp);
if (p != namebuf)
FREE(p);
if (h == NULL && ne == NULL)
return "does not look numeric and name lookup failed";
if (h != NULL) {
if (h->h_addrtype != af)
return "address-type mismatch from gethostbyname2!!!";
return initaddr((unsigned char *)h->h_addr, h->h_length, af, dst);
} else {
if (ne->n_addrtype != af)
return "address-type mismatch from getnetbyname!!!";
ne->n_net = htonl(ne->n_net);
return initaddr((unsigned char *)&ne->n_net, sizeof(ne->n_net),
af, dst);
memset(&hints, 0, sizeof(hints));
hints.ai_family = af;
error = getaddrinfo(cp, NULL, &hints, &res);
if (error != 0)
{ /* getaddrinfo failed, try getnetbyname */
if (af == AF_INET)
{
ne = getnetbyname(cp);
if (ne != NULL)
{
ne->n_net = htonl(ne->n_net);
addr = (unsigned char*)&ne->n_net;
err = initaddr(addr, sizeof(ne->n_net), af, dst);
}
}
}
else
{
addr = res->ai_addr->sa_data;
err = initaddr(addr, res->ai_addrlen, af, dst);
freeaddrinfo(res);
}
if (p != namebuf)
{
FREE(p);
}
if (addr == NULL)
{
return "does not look numeric and name lookup failed";
}
return err;
}
/*

View File

@ -17,6 +17,7 @@
*/
#define _GNU_SOURCE
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
@ -430,19 +431,43 @@ host_t *host_create_from_string(char *string, u_int16_t port)
return NULL;
}
/*
* Described in header.
*/
host_t *host_create_from_sockaddr(sockaddr_t *sockaddr)
{
private_host_t *this = host_create_empty();
switch (sockaddr->sa_family)
{
case AF_INET:
{
memcpy(&this->address4, sockaddr, sizeof(struct sockaddr_in));
this->socklen = sizeof(struct sockaddr_in);
return &this->public;
}
case AF_INET6:
{
memcpy(&this->address6, sockaddr, sizeof(struct sockaddr_in6));
this->socklen = sizeof(struct sockaddr_in6);
return &this->public;
}
default:
break;
}
free(this);
return NULL;
}
/*
* Described in header.
*/
host_t *host_create_from_dns(char *string, int af, u_int16_t port)
{
private_host_t *this;
struct hostent *ptr;
int ret = 0, err;
#ifdef HAVE_GETHOSTBYNAME_R
struct hostent host;
char buf[512];
#endif
struct addrinfo hints, *result;
int error;
if (streq(string, "%any"))
{
return host_create_any_port(af ? af : AF_INET, port);
@ -451,62 +476,32 @@ host_t *host_create_from_dns(char *string, int af, u_int16_t port)
{
return host_create_any_port(af ? af : AF_INET6, port);
}
else if (strchr(string, ':'))
memset(&hints, 0, sizeof(hints));
hints.ai_family = af;
error = getaddrinfo(string, NULL, &hints, &result);
if (error != 0)
{
/* gethostbyname does not like IPv6 addresses - fallback */
return host_create_from_string(string, port);
}
#ifdef HAVE_GETHOSTBYNAME_R
if (af)
{
ret = gethostbyname2_r(string, af, &host, buf, sizeof(buf), &ptr, &err);
}
else
{
ret = gethostbyname_r(string, &host, buf, sizeof(buf), &ptr, &err);
}
#else
/* Some systems (e.g. Mac OS X) do not support gethostbyname_r */
if (af)
{
ptr = gethostbyname2(string, af);
}
else
{
ptr = gethostbyname(string);
}
if (ptr == NULL)
{
err = h_errno;
}
#endif
if (ret != 0 || ptr == NULL)
{
DBG1("resolving '%s' failed: %s", string, hstrerror(err));
DBG1("resolving '%s' failed: %s", string, gai_strerror(error));
return NULL;
}
this = host_create_empty();
this->address.sa_family = ptr->h_addrtype;
switch (this->address.sa_family)
/* result is a linked list, but we use only the first address */
this = (private_host_t*)host_create_from_sockaddr(result->ai_addr);
freeaddrinfo(result);
if (this)
{
case AF_INET:
memcpy(&this->address4.sin_addr.s_addr,
ptr->h_addr_list[0], ptr->h_length);
this->address4.sin_port = htons(port);
this->socklen = sizeof(struct sockaddr_in);
break;
case AF_INET6:
memcpy(&this->address6.sin6_addr.s6_addr,
ptr->h_addr_list[0], ptr->h_length);
this->address6.sin6_port = htons(port);
this->socklen = sizeof(struct sockaddr_in6);
break;
default:
free(this);
return NULL;
switch (this->address.sa_family)
{
case AF_INET:
this->address4.sin_port = htons(port);
break;
case AF_INET6:
this->address6.sin6_port = htons(port);
break;
}
return &this->public;
}
return &this->public;
return NULL;
}
/*
@ -566,34 +561,6 @@ host_t *host_create_from_chunk(int family, chunk_t address, u_int16_t port)
return &this->public;
}
/*
* Described in header.
*/
host_t *host_create_from_sockaddr(sockaddr_t *sockaddr)
{
private_host_t *this = host_create_empty();
switch (sockaddr->sa_family)
{
case AF_INET:
{
memcpy(&this->address4, sockaddr, sizeof(struct sockaddr_in));
this->socklen = sizeof(struct sockaddr_in);
return &this->public;
}
case AF_INET6:
{
memcpy(&this->address6, sockaddr, sizeof(struct sockaddr_in6));
this->socklen = sizeof(struct sockaddr_in6);
return &this->public;
}
default:
break;
}
free(this);
return NULL;
}
/*
* Described in header.
*/