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

This commit is contained in:
Tobias Brunner
2009-08-14 16:14:32 +02:00
parent 26965b4ef3
commit f1777dff59
6 changed files with 128 additions and 130 deletions
-1
View File
@@ -882,7 +882,6 @@ AC_TRY_COMPILE(
) )
AC_CHECK_FUNCS(prctl) AC_CHECK_FUNCS(prctl)
AC_CHECK_FUNCS(gethostbyname_r)
AC_CHECK_HEADERS(sys/sockio.h) AC_CHECK_HEADERS(sys/sockio.h)
AC_CHECK_HEADERS(net/pfkeyv2.h netipsec/ipsec.h netinet6/ipsec.h linux/udp.h) AC_CHECK_HEADERS(net/pfkeyv2.h netipsec/ipsec.h netinet6/ipsec.h linux/udp.h)
+4 -6
View File
@@ -54,7 +54,7 @@ on a big-endian host and
.B 4.3.2.1 .B 4.3.2.1
on a little-endian host), on a little-endian host),
a DNS name to be looked up via 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 or an old-style network name to be looked up via
.IR getnetbyname (3). .IR getnetbyname (3).
.PP .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 or incomplete, and are looked up as specified by local system configuration
(see (see
.IR resolver (5)). .IR resolver (5)).
The The first value returned by
.I h_addr .IR getaddrinfo (3)
value returned by
.IR gethostbyname (3)
is used, is used,
so with current DNS implementations, so with current DNS implementations,
the result when the name corresponds to more than one address is the result when the name corresponds to more than one address is
@@ -102,7 +100,7 @@ difficult to predict.
Name lookup resorts to Name lookup resorts to
.IR getnetbyname (3) .IR getnetbyname (3)
only if only if
.IR gethostbyname (3) .IR getaddrinfo (3)
fails. fails.
.PP .PP
A subnet specification is of the form \fInetwork\fB/\fImask\fR. A subnet specification is of the form \fInetwork\fB/\fImask\fR.
+29 -11
View File
@@ -12,6 +12,8 @@
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
* License for more details. * License for more details.
*/ */
#include <sys/socket.h>
#include "internal.h" #include "internal.h"
#include "freeswan.h" #include "freeswan.h"
@@ -41,7 +43,7 @@ const char *src;
size_t srclen; /* 0 means "apply strlen" */ size_t srclen; /* 0 means "apply strlen" */
struct in_addr *addrp; struct in_addr *addrp;
{ {
struct hostent *h; struct addrinfo hints, *res;
struct netent *ne = NULL; struct netent *ne = NULL;
const char *oops; const char *oops;
# define HEXLEN 10 /* strlen("0x11223344") */ # define HEXLEN 10 /* strlen("0x11223344") */
@@ -51,6 +53,7 @@ struct in_addr *addrp;
char namebuf[ATOADDRBUF]; char namebuf[ATOADDRBUF];
char *p = namebuf; char *p = namebuf;
char *q; char *q;
int error;
if (srclen == 0) if (srclen == 0)
srclen = strlen(src); srclen = strlen(src);
@@ -87,18 +90,33 @@ struct in_addr *addrp;
return "illegal (non-DNS-name) character in name"; return "illegal (non-DNS-name) character in name";
/* try as host name, failing that as /etc/networks network name */ /* try as host name, failing that as /etc/networks network name */
h = gethostbyname(p); memset(&hints, 0, sizeof(hints));
if (h == NULL) hints.ai_family = AF_INET;
error = getaddrinfo(p, NULL, &hints, &res);
if (error != 0)
{
ne = getnetbyname(p); ne = getnetbyname(p);
if (p != namebuf) if (ne == NULL)
FREE(p); {
if (h == NULL && ne == NULL) if (p != namebuf)
return "name lookup failed"; {
FREE(p);
if (h != NULL) }
memcpy(&addrp->s_addr, h->h_addr, sizeof(addrp->s_addr)); return "name lookup failed";
else }
addrp->s_addr = htonl(ne->n_net); 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; return NULL;
} }
+5 -7
View File
@@ -59,7 +59,7 @@ on a big-endian host and
.B 4.3.2.1 .B 4.3.2.1
on a little-endian host), on a little-endian host),
a DNS name to be looked up via 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 or an old-style network name to be looked up via
.IR getnetbyname (3). .IR getnetbyname (3).
.PP .PP
@@ -100,7 +100,7 @@ abbreviating at most one subsequence of multiple zeros (e.g.
which is synonymous with which is synonymous with
.BR 99:ab:0:0:0:0:54:68 ), .BR 99:ab:0:0:0:0:54:68 ),
or a DNS name to be looked up via or a DNS name to be looked up via
.IR gethostbyname (3). .IR getaddrinfo (3).
The result of applying The result of applying
.I addrtot .I addrtot
to an IPv6 address will use 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 or incomplete, and are looked up as specified by local system configuration
(see (see
.IR resolver (5)). .IR resolver (5)).
The The first value returned by
.I h_addr .IR getaddrinfo (3)
value returned by
.IR gethostbyname2 (3)
is used, is used,
so with current DNS implementations, so with current DNS implementations,
the result when the name corresponds to more than one address is the result when the name corresponds to more than one address is
@@ -126,7 +124,7 @@ difficult to predict.
IPv4 name lookup resorts to IPv4 name lookup resorts to
.IR getnetbyname (3) .IR getnetbyname (3)
only if only if
.IR gethostbyname2 (3) .IR getaddrinfo (3)
fails. fails.
.PP .PP
A subnet specification is of the form \fInetwork\fB/\fImask\fR. A subnet specification is of the form \fInetwork\fB/\fImask\fR.
+37 -19
View File
@@ -157,12 +157,15 @@ int nultermd; /* is it known to be NUL-terminated? */
int af; int af;
ip_address *dst; ip_address *dst;
{ {
struct hostent *h; struct addrinfo hints, *res;
struct netent *ne = NULL; struct netent *ne = NULL;
char namebuf[100]; /* enough for most DNS names */ char namebuf[100]; /* enough for most DNS names */
const char *cp; const char *cp;
char *p = namebuf; char *p = namebuf;
unsigned char *addr = NULL;
size_t n; size_t n;
int error;
err_t err = NULL;
for (cp = src, n = srclen; n > 0; cp++, n--) for (cp = src, n = srclen; n > 0; cp++, n--)
if (ISASCII(*cp) && strchr(namechars, *cp) == NULL) if (ISASCII(*cp) && strchr(namechars, *cp) == NULL)
@@ -181,25 +184,40 @@ ip_address *dst;
cp = (const char *)p; cp = (const char *)p;
} }
h = gethostbyname2(cp, af); memset(&hints, 0, sizeof(hints));
if (h == NULL && af == AF_INET) hints.ai_family = af;
ne = getnetbyname(cp); error = getaddrinfo(cp, NULL, &hints, &res);
if (p != namebuf) if (error != 0)
FREE(p); { /* getaddrinfo failed, try getnetbyname */
if (h == NULL && ne == NULL) if (af == AF_INET)
return "does not look numeric and name lookup failed"; {
ne = getnetbyname(cp);
if (h != NULL) { if (ne != NULL)
if (h->h_addrtype != af) {
return "address-type mismatch from gethostbyname2!!!"; ne->n_net = htonl(ne->n_net);
return initaddr((unsigned char *)h->h_addr, h->h_length, af, dst); addr = (unsigned char*)&ne->n_net;
} else { err = initaddr(addr, sizeof(ne->n_net), af, dst);
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);
} }
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;
} }
/* /*
+53 -86
View File
@@ -17,6 +17,7 @@
*/ */
#define _GNU_SOURCE #define _GNU_SOURCE
#include <sys/socket.h>
#include <netdb.h> #include <netdb.h>
#include <string.h> #include <string.h>
@@ -430,19 +431,43 @@ host_t *host_create_from_string(char *string, u_int16_t port)
return NULL; 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. * Described in header.
*/ */
host_t *host_create_from_dns(char *string, int af, u_int16_t port) host_t *host_create_from_dns(char *string, int af, u_int16_t port)
{ {
private_host_t *this; private_host_t *this;
struct hostent *ptr; struct addrinfo hints, *result;
int ret = 0, err; int error;
#ifdef HAVE_GETHOSTBYNAME_R
struct hostent host;
char buf[512];
#endif
if (streq(string, "%any")) if (streq(string, "%any"))
{ {
return host_create_any_port(af ? af : AF_INET, port); 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); 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 */ DBG1("resolving '%s' failed: %s", string, gai_strerror(error));
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));
return NULL; return NULL;
} }
this = host_create_empty(); /* result is a linked list, but we use only the first address */
this->address.sa_family = ptr->h_addrtype; this = (private_host_t*)host_create_from_sockaddr(result->ai_addr);
switch (this->address.sa_family) freeaddrinfo(result);
if (this)
{ {
case AF_INET: switch (this->address.sa_family)
memcpy(&this->address4.sin_addr.s_addr, {
ptr->h_addr_list[0], ptr->h_length); case AF_INET:
this->address4.sin_port = htons(port); this->address4.sin_port = htons(port);
this->socklen = sizeof(struct sockaddr_in); break;
break; case AF_INET6:
case AF_INET6: this->address6.sin6_port = htons(port);
memcpy(&this->address6.sin6_addr.s6_addr, break;
ptr->h_addr_list[0], ptr->h_length); }
this->address6.sin6_port = htons(port); return &this->public;
this->socklen = sizeof(struct sockaddr_in6);
break;
default:
free(this);
return NULL;
} }
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; 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. * Described in header.
*/ */