* include/resolv.h: Adjust __libc_res_nquery and __libc_res_nsend

prototypes.
	* include/arpa/nameser_compat.h: Define T_UNSPEC.
	* nis/Versions (libnss_nis): Export _nss_nis_gethostbyname4_r.
	(libnss_nisplus): Export _nss_nisplus_gethostbyname4_r.
	* nis/nss_nis/nis-hosts.c (LINE_PARSER): Change to also handle
	af==AF_UNSPEC.
	(_nss_nis_gethostbyname4_r): New function.
	* nis/nss_nisplus/nisplus-hosts.c (_nss_nisplus_parse_hostent):
	Change to also handle af==AF_UNSPEC.
	(get_tablename): New function.  Use it to avoid duplication.
	(_nss_nisplus_gethostbyname4_r): New function.
	* nscd/aicache.c (addhstaiX): Use gethostbyname4_r function is
	available.
	* nss/Versions (libnss_files): Export _nss_files_gethostbyname4_r.
	* nss/nss.h: Define struct gaih_addrtuple.
	* nss/nss_files/files-hosts.c (LINE_PARSER): Change to also handle
	af==AF_UNSPEC.
	(_nss_files_gethostbyname4_r): New function.
	* resolv/Versions (libnss_dns): Export _nss_dns_gethostbyname4_r.
	* resolv/gethnmaddr.c: Adjust __libc_res_nsearch and __libc_res_nquery
	calls.
	* resolv/res_query.c (__libc_res_nquery): Take two additional
	parameters for second answer buffer.  Handle type=T_UNSPEC to mean
	look up IPv4 and IPv6.
	Change all callers.
	* resolv/res_send.c (__libc_res_nsend): Take five aditional parameters
	for an additional query and answer buffer.  Pass to send_vc and
	send_dg.
	(send_vc): Send possibly two requests and receive two answers.
	(send_dg): Likewise.
	* resolv/nss_dns/dns-host.c: Adjust calls to __libc_res_nsearch and
	__libc_res_nquery.
	(_nss_dns_gethostbyname4_r): New function.
	(gaih_getanswer_slice): Likewise.
	(gaih_getanswer): Likewise.
	* resolv/nss_dns/dns-canon.c (_nss_dns_getcanonname_r): Adjust
	__libc_res_nquery call.
	* resolv/nss_dns/dns-network.c (_nss_dns_getnetbyaddr_r): Likewise.
	(_nss_dns_getnetbyname_r): Adjust __libc_res_nsearch call.
	* sysdeps/posix/getaddrinfo.c: Use gethostbyname4_r function is
	available.
This commit is contained in:
Ulrich Drepper 2008-05-10 23:27:39 +00:00
parent a82e8bb8d0
commit 1eb946b935
17 changed files with 1565 additions and 527 deletions

View File

@ -1,3 +1,48 @@
2008-05-10 Ulrich Drepper <drepper@redhat.com>
* include/resolv.h: Adjust __libc_res_nquery and __libc_res_nsend
prototypes.
* include/arpa/nameser_compat.h: Define T_UNSPEC.
* nis/Versions (libnss_nis): Export _nss_nis_gethostbyname4_r.
(libnss_nisplus): Export _nss_nisplus_gethostbyname4_r.
* nis/nss_nis/nis-hosts.c (LINE_PARSER): Change to also handle
af==AF_UNSPEC.
(_nss_nis_gethostbyname4_r): New function.
* nis/nss_nisplus/nisplus-hosts.c (_nss_nisplus_parse_hostent):
Change to also handle af==AF_UNSPEC.
(get_tablename): New function. Use it to avoid duplication.
(_nss_nisplus_gethostbyname4_r): New function.
* nscd/aicache.c (addhstaiX): Use gethostbyname4_r function is
available.
* nss/Versions (libnss_files): Export _nss_files_gethostbyname4_r.
* nss/nss.h: Define struct gaih_addrtuple.
* nss/nss_files/files-hosts.c (LINE_PARSER): Change to also handle
af==AF_UNSPEC.
(_nss_files_gethostbyname4_r): New function.
* resolv/Versions (libnss_dns): Export _nss_dns_gethostbyname4_r.
* resolv/gethnmaddr.c: Adjust __libc_res_nsearch and __libc_res_nquery
calls.
* resolv/res_query.c (__libc_res_nquery): Take two additional
parameters for second answer buffer. Handle type=T_UNSPEC to mean
look up IPv4 and IPv6.
Change all callers.
* resolv/res_send.c (__libc_res_nsend): Take five aditional parameters
for an additional query and answer buffer. Pass to send_vc and
send_dg.
(send_vc): Send possibly two requests and receive two answers.
(send_dg): Likewise.
* resolv/nss_dns/dns-host.c: Adjust calls to __libc_res_nsearch and
__libc_res_nquery.
(_nss_dns_gethostbyname4_r): New function.
(gaih_getanswer_slice): Likewise.
(gaih_getanswer): Likewise.
* resolv/nss_dns/dns-canon.c (_nss_dns_getcanonname_r): Adjust
__libc_res_nquery call.
* resolv/nss_dns/dns-network.c (_nss_dns_getnetbyaddr_r): Likewise.
(_nss_dns_getnetbyname_r): Adjust __libc_res_nsearch call.
* sysdeps/posix/getaddrinfo.c: Use gethostbyname4_r function is
available.
2008-05-05 David S. Miller <davem@davemloft.net>
* sysdeps/sparc/sparc32/Makefile: Use -mcpu=v7 for initfini.s build.

View File

@ -1 +1,8 @@
#ifndef _ARPA_NAMESER_COMPAT_
#include <resolv/arpa/nameser_compat.h>
/* Picksome unused number to represent lookups of IPv4 and IPv6 (i.e.,
T_A and T_AAAA). */
#define T_UNSPEC 62321
#endif

View File

@ -95,7 +95,7 @@ libnss_nis {
_nss_nis_setgrent; _nss_nis_sethostent; _nss_nis_setnetent;
_nss_nis_setnetgrent; _nss_nis_setprotoent; _nss_nis_setpwent;
_nss_nis_setrpcent; _nss_nis_setservent; _nss_nis_setspent;
_nss_nis_initgroups_dyn;
_nss_nis_initgroups_dyn; _nss_nis_gethostbyname4_r;
}
}
@ -126,5 +126,6 @@ libnss_nisplus {
_nss_nisplus_setnetent; _nss_nisplus_setnetgrent; _nss_nisplus_setprotoent;
_nss_nisplus_setpwent; _nss_nisplus_setrpcent; _nss_nisplus_setservent;
_nss_nisplus_setspent; _nss_nisplus_initgroups_dyn;
_nss_nisplus_gethostbyname4_r;
}
}

View File

@ -1,4 +1,5 @@
/* Copyright (C) 1996-2000, 2002, 2003, 2006, 2007 Free Software Foundation, Inc.
/* Copyright (C) 1996-2000, 2002, 2003, 2006, 2007, 2008
Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
@ -17,6 +18,7 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <assert.h>
#include <nss.h>
#include <ctype.h>
/* The following is an ugly trick to avoid a prototype declaration for
@ -61,9 +63,12 @@ LINE_PARSER
STRING_FIELD (addr, isspace, 1);
assert (af == AF_INET || af == AF_INET6 || af == AF_UNSPEC);
/* Parse address. */
if (af == AF_INET && inet_pton (AF_INET, addr, entdata->host_addr) > 0)
if (af != AF_INET6 && inet_pton (AF_INET, addr, entdata->host_addr) > 0)
{
assert ((flags & AI_V4MAPPED) == 0 || af != AF_UNSPEC);
if (flags & AI_V4MAPPED)
{
map_v4v6_address ((char *) entdata->host_addr,
@ -77,7 +82,7 @@ LINE_PARSER
result->h_length = INADDRSZ;
}
}
else if (af == AF_INET6
else if (af != AF_INET
&& inet_pton (AF_INET6, addr, entdata->host_addr) > 0)
{
result->h_addrtype = AF_INET6;
@ -102,6 +107,7 @@ static bool_t new_start = 1;
static char *oldkey = NULL;
static int oldkeylen = 0;
enum nss_status
_nss_nis_sethostent (int stayopen)
{
@ -124,6 +130,7 @@ _nss_nis_sethostent (int stayopen)
is used so this makes no difference. */
strong_alias (_nss_nis_sethostent, _nss_nis_endhostent)
/* The calling function always need to get a lock first. */
static enum nss_status
internal_nis_gethostent_r (struct hostent *host, char *buffer,
@ -216,6 +223,7 @@ internal_nis_gethostent_r (struct hostent *host, char *buffer,
return NSS_STATUS_SUCCESS;
}
enum nss_status
_nss_nis_gethostent_r (struct hostent *host, char *buffer, size_t buflen,
int *errnop, int *h_errnop)
@ -233,6 +241,7 @@ _nss_nis_gethostent_r (struct hostent *host, char *buffer, size_t buflen,
return status;
}
static enum nss_status
internal_gethostbyname2_r (const char *name, int af, struct hostent *host,
char *buffer, size_t buflen, int *errnop,
@ -323,16 +332,24 @@ internal_gethostbyname2_r (const char *name, int af, struct hostent *host,
return NSS_STATUS_SUCCESS;
}
enum nss_status
_nss_nis_gethostbyname2_r (const char *name, int af, struct hostent *host,
char *buffer, size_t buflen, int *errnop,
int *h_errnop)
{
if (af != AF_INET && af != AF_INET6)
{
*h_errnop = HOST_NOT_FOUND;
return NSS_STATUS_NOTFOUND;
}
return internal_gethostbyname2_r (name, af, host, buffer, buflen, errnop,
h_errnop,
((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0));
}
enum nss_status
_nss_nis_gethostbyname_r (const char *name, struct hostent *host, char *buffer,
size_t buflen, int *errnop, int *h_errnop)
@ -351,6 +368,7 @@ _nss_nis_gethostbyname_r (const char *name, struct hostent *host, char *buffer,
errnop, h_errnop, 0);
}
enum nss_status
_nss_nis_gethostbyaddr_r (const void *addr, socklen_t addrlen, int af,
struct hostent *host, char *buffer, size_t buflen,
@ -430,13 +448,93 @@ _nss_nis_gethostbyaddr_r (const void *addr, socklen_t addrlen, int af,
return NSS_STATUS_SUCCESS;
}
#if 0
enum nss_status
_nss_nis_getipnodebyname_r (const char *name, int af, int flags,
struct hostent *result, char *buffer,
size_t buflen, int *errnop, int *herrnop)
_nss_nis_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
char *buffer, size_t buflen, int *errnop,
int *herrnop, int32_t *ttlp)
{
return internal_gethostbyname2_r (name, af, result, buffer, buflen,
errnop, herrnop, flags);
char *domain;
if (yp_get_default_domain (&domain))
return NSS_STATUS_UNAVAIL;
/* Convert name to lowercase. */
size_t namlen = strlen (name);
char name2[namlen + 1];
size_t i;
for (i = 0; i < namlen; ++i)
name2[i] = tolower (name[i]);
name2[i] = '\0';
char *result;
int len;
int yperr = yp_match (domain, "hosts.byname", name2, namlen, &result, &len);
if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
{
enum nss_status retval = yperr2nss (yperr);
if (retval == NSS_STATUS_TRYAGAIN)
{
*herrnop = TRY_AGAIN;
*errnop = errno;
}
if (retval == NSS_STATUS_NOTFOUND)
*herrnop = HOST_NOT_FOUND;
return retval;
}
struct parser_data data;
struct hostent host;
int parse_res = parse_line (result, &host, &data, buflen, errnop, AF_UNSPEC,
0);
if (__builtin_expect (parse_res < 1, 0))
{
if (parse_res == -1)
{
*herrnop = NETDB_INTERNAL;
return NSS_STATUS_TRYAGAIN;
}
else
{
*herrnop = HOST_NOT_FOUND;
return NSS_STATUS_NOTFOUND;
}
}
if (*pat == NULL)
{
uintptr_t pad = (-(uintptr_t) buffer
% __alignof__ (struct gaih_addrtuple));
buffer += pad;
buflen = buflen > pad ? buflen - pad : 0;
if (__builtin_expect (buflen < sizeof (struct gaih_addrtuple), 0))
{
erange:
free (result);
*errnop = ERANGE;
*herrnop = NETDB_INTERNAL;
return NSS_STATUS_TRYAGAIN;
}
*pat = (struct gaih_addrtuple *) buffer;
buffer += sizeof (struct gaih_addrtuple);
buflen -= sizeof (struct gaih_addrtuple);
}
(*pat)->next = NULL;
size_t h_name_len = strlen (host.h_name);
if (h_name_len >= buflen)
goto erange;
(*pat)->name = memcpy (buffer, host.h_name, h_name_len + 1);
(*pat)->family = host.h_addrtype;
memcpy ((*pat)->addr, host.h_addr_list[0], host.h_length);
(*pat)->scopeid = 0;
assert (host.h_addr_list[1] == NULL);
free (result);
return NSS_STATUS_SUCCESS;
}
#endif

View File

@ -1,4 +1,4 @@
/* Copyright (C) 1997-2002, 2003, 2005, 2006 Free Software Foundation, Inc.
/* Copyright (C) 1997-2003, 2005, 2006, 2008 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997.
@ -17,6 +17,7 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <assert.h>
#include <atomic.h>
#include <ctype.h>
#include <errno.h>
@ -58,15 +59,15 @@ _nss_nisplus_parse_hostent (nis_result *result, int af, struct hostent *host,
if (result == NULL)
return 0;
if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS) ||
__type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ ||
strcmp(NIS_RES_OBJECT (result)[0].EN_data.en_type, "hosts_tbl") != 0 ||
NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 4)
if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
|| __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
|| strcmp (NIS_RES_OBJECT (result)[0].EN_data.en_type, "hosts_tbl") != 0
|| NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 4)
return 0;
char *data = first_unused;
if (room_left < (af == AF_INET6 || (flags & AI_V4MAPPED) != 0
if (room_left < (af != AF_INET || (flags & AI_V4MAPPED) != 0
? IN6ADDRSZ : INADDRSZ))
{
no_more_room:
@ -75,8 +76,10 @@ _nss_nisplus_parse_hostent (nis_result *result, int af, struct hostent *host,
}
/* Parse address. */
if (af == AF_INET && inet_pton (af, NISENTRYVAL (0, 2, result), data) > 0)
if (af != AF_INET6
&& inet_pton (AF_INET, NISENTRYVAL (0, 2, result), data) > 0)
{
assert ((flags & AI_V4MAPPED) == 0 || af != AF_UNSPEC);
if (flags & AI_V4MAPPED)
{
map_v4v6_address (data, data);
@ -89,7 +92,7 @@ _nss_nisplus_parse_hostent (nis_result *result, int af, struct hostent *host,
host->h_length = INADDRSZ;
}
}
else if (af == AF_INET6
else if (af != AF_INET
&& inet_pton (AF_INET6, NISENTRYVAL (0, 2, result), data) > 0)
{
host->h_addrtype = AF_INET6;
@ -109,27 +112,33 @@ _nss_nisplus_parse_hostent (nis_result *result, int af, struct hostent *host,
first_unused = __stpncpy (first_unused, NISENTRYVAL (0, 0, result),
NISENTRYLEN (0, 0, result));
*first_unused++ = '\0';
room_left -= NISENTRYLEN (0, 0, result) + 1;
/* XXX Rewrite at some point to allocate the array first and then
copy the strings. It wasteful to first concatenate the strings
to just split them again later. */
char *line = first_unused;
for (i = 0; i < NIS_RES_NUMOBJ (result); ++i)
{
if (strcmp (NISENTRYVAL (i, 1, result), host->h_name) != 0)
{
if (NISENTRYLEN (i, 1, result) + 2 > room_left)
goto no_more_room;
*first_unused++ = ' ';
first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result),
NISENTRYLEN (i, 1, result));
*first_unused = '\0';
room_left -= NISENTRYLEN (i, 1, result) + 1;
/* When this is a call to gethostbyname4_r we do not need the aliases. */
if (af != AF_UNSPEC)
{
/* XXX Rewrite at some point to allocate the array first and then
copy the strings. It is wasteful to first concatenate the strings
to just split them again later. */
for (i = 0; i < NIS_RES_NUMOBJ (result); ++i)
{
if (strcmp (NISENTRYVAL (i, 1, result), host->h_name) != 0)
{
if (NISENTRYLEN (i, 1, result) + 2 > room_left)
goto no_more_room;
*first_unused++ = ' ';
first_unused = __stpncpy (first_unused,
NISENTRYVAL (i, 1, result),
NISENTRYLEN (i, 1, result));
*first_unused = '\0';
room_left -= NISENTRYLEN (i, 1, result) + 1;
}
}
*first_unused++ = '\0';
}
*first_unused++ = '\0';
/* Adjust the pointer so it is aligned for
storing pointers. */
@ -147,31 +156,35 @@ _nss_nisplus_parse_hostent (nis_result *result, int af, struct hostent *host,
host->h_addr_list[1] = NULL;
host->h_aliases = &host->h_addr_list[2];
i = 0;
while (*line != '\0')
/* When this is a call to gethostbyname4_r we do not need the aliases. */
if (af != AF_UNSPEC)
{
/* Skip leading blanks. */
while (isspace (*line))
++line;
i = 0;
while (*line != '\0')
{
/* Skip leading blanks. */
while (isspace (*line))
++line;
if (*line == '\0')
break;
if (*line == '\0')
break;
if (room_left < sizeof (char *))
goto no_more_room;
if (room_left < sizeof (char *))
goto no_more_room;
room_left -= sizeof (char *);
host->h_aliases[i++] = line;
room_left -= sizeof (char *);
host->h_aliases[i++] = line;
while (*line != '\0' && *line != ' ')
++line;
while (*line != '\0' && *line != ' ')
++line;
if (*line == ' ')
*line++ = '\0';
if (*line == ' ')
*line++ = '\0';
}
host->h_aliases[i] = NULL;
}
host->h_aliases[i] = NULL;
return 1;
}
@ -204,6 +217,7 @@ _nss_create_tablename (int *errnop)
return NSS_STATUS_SUCCESS;
}
enum nss_status
_nss_nisplus_sethostent (int stayopen)
{
@ -226,6 +240,7 @@ _nss_nisplus_sethostent (int stayopen)
return status;
}
enum nss_status
_nss_nisplus_endhostent (void)
{
@ -242,6 +257,7 @@ _nss_nisplus_endhostent (void)
return NSS_STATUS_SUCCESS;
}
static enum nss_status
internal_nisplus_gethostent_r (struct hostent *host, char *buffer,
size_t buflen, int *errnop, int *herrnop)
@ -329,6 +345,7 @@ internal_nisplus_gethostent_r (struct hostent *host, char *buffer,
return NSS_STATUS_SUCCESS;
}
enum nss_status
_nss_nisplus_gethostent_r (struct hostent *result, char *buffer,
size_t buflen, int *errnop, int *herrnop)
@ -345,26 +362,33 @@ _nss_nisplus_gethostent_r (struct hostent *result, char *buffer,
return status;
}
static enum nss_status
get_tablename (int *herrnop)
{
__libc_lock_lock (lock);
enum nss_status status = _nss_create_tablename (herrnop);
__libc_lock_unlock (lock);
if (status != NSS_STATUS_SUCCESS)
*herrnop = NETDB_INTERNAL;
return status;
}
static enum nss_status
internal_gethostbyname2_r (const char *name, int af, struct hostent *host,
char *buffer, size_t buflen, int *errnop,
int *herrnop, int flags)
{
int parse_res, retval;
if (tablename_val == NULL)
{
__libc_lock_lock (lock);
enum nss_status status = _nss_create_tablename (errnop);
__libc_lock_unlock (lock);
enum nss_status status = get_tablename (herrnop);
if (status != NSS_STATUS_SUCCESS)
{
*herrnop = NETDB_INTERNAL;
return NSS_STATUS_UNAVAIL;
}
return status;
}
if (name == NULL)
@ -374,39 +398,36 @@ internal_gethostbyname2_r (const char *name, int af, struct hostent *host,
return NSS_STATUS_NOTFOUND;
}
nis_result *result;
char buf[strlen (name) + 10 + tablename_len];
int olderr = errno;
/* Search at first in the alias list, and use the correct name
for the next search. */
snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
nis_result *result = nis_list (buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
if (result != NULL)
{
char *bufptr = buf;
/* If we did not find it, try it as original name. But if the
database is correct, we should find it in the first case, too. */
if ((result->status != NIS_SUCCESS
&& result->status != NIS_S_SUCCESS)
|| __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
|| strcmp (result->objects.objects_val->EN_data.en_type,
"hosts_tbl") != 0
|| result->objects.objects_val->EN_data.en_cols.en_cols_len < 3)
snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val);
else
char *bufptr = buf;
size_t buflen = sizeof (buf);
if ((result->status == NIS_SUCCESS || result->status == NIS_S_SUCCESS)
&& __type_of (result->objects.objects_val) == NIS_ENTRY_OBJ
&& strcmp (result->objects.objects_val->EN_data.en_type,
"hosts_tbl") == 0
&& result->objects.objects_val->EN_data.en_cols.en_cols_len >= 3)
{
/* We need to allocate a new buffer since there is no
guarantee the returned name has a length limit. */
const char *entryval = NISENTRYVAL(0, 0, result);
size_t buflen = strlen (entryval) + 10 + tablename_len;
guarantee the returned alias name has a length limit. */
name = NISENTRYVAL(0, 0, result);
size_t buflen = strlen (name) + 10 + tablename_len;
bufptr = alloca (buflen);
snprintf (bufptr, buflen, "[cname=%s],%s",
entryval, tablename_val);
}
snprintf (bufptr, buflen, "[cname=%s],%s", name, tablename_val);
nis_freeresult (result);
result = nis_list (bufptr, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL);
}
@ -417,7 +438,7 @@ internal_gethostbyname2_r (const char *name, int af, struct hostent *host,
return NSS_STATUS_TRYAGAIN;
}
retval = niserr2nss (result->status);
int retval = niserr2nss (result->status);
if (__builtin_expect (retval != NSS_STATUS_SUCCESS, 0))
{
if (retval == NSS_STATUS_TRYAGAIN)
@ -431,8 +452,8 @@ internal_gethostbyname2_r (const char *name, int af, struct hostent *host,
return retval;
}
parse_res = _nss_nisplus_parse_hostent (result, af, host, buffer,
buflen, errnop, flags);
int parse_res = _nss_nisplus_parse_hostent (result, af, host, buffer,
buflen, errnop, flags);
nis_freeresult (result);
@ -450,16 +471,24 @@ internal_gethostbyname2_r (const char *name, int af, struct hostent *host,
return NSS_STATUS_NOTFOUND;
}
enum nss_status
_nss_nisplus_gethostbyname2_r (const char *name, int af, struct hostent *host,
char *buffer, size_t buflen, int *errnop,
int *herrnop)
{
if (af != AF_INET && af != AF_INET6)
{
*herrnop = HOST_NOT_FOUND;
return NSS_STATUS_NOTFOUND;
}
return internal_gethostbyname2_r (name, af, host, buffer, buflen, errnop,
herrnop,
((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0));
}
enum nss_status
_nss_nisplus_gethostbyname_r (const char *name, struct hostent *host,
char *buffer, size_t buflen, int *errnop,
@ -480,6 +509,7 @@ _nss_nisplus_gethostbyname_r (const char *name, struct hostent *host,
buflen, errnop, h_errnop, 0);
}
enum nss_status
_nss_nisplus_gethostbyaddr_r (const void *addr, socklen_t addrlen, int af,
struct hostent *host, char *buffer,
@ -487,12 +517,7 @@ _nss_nisplus_gethostbyaddr_r (const void *addr, socklen_t addrlen, int af,
{
if (tablename_val == NULL)
{
__libc_lock_lock (lock);
enum nss_status status = _nss_create_tablename (errnop);
__libc_lock_unlock (lock);
enum nss_status status = get_tablename (herrnop);
if (status != NSS_STATUS_SUCCESS)
return status;
}
@ -547,3 +572,44 @@ _nss_nisplus_gethostbyaddr_r (const void *addr, socklen_t addrlen, int af,
__set_errno (olderr);
return NSS_STATUS_NOTFOUND;
}
enum nss_status
_nss_nisplus_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
char *buffer, size_t buflen, int *errnop,
int *herrnop, int32_t *ttlp)
{
struct hostent host;
enum nss_status status = internal_gethostbyname2_r (name, AF_UNSPEC, &host,
buffer, buflen,
errnop, herrnop, 0);
if (__builtin_expect (status == NSS_STATUS_SUCCESS, 1))
{
if (*pat == NULL)
{
uintptr_t pad = (-(uintptr_t) buffer
% __alignof__ (struct gaih_addrtuple));
buffer += pad;
buflen = buflen > pad ? buflen - pad : 0;
if (__builtin_expect (buflen < sizeof (struct gaih_addrtuple), 0))
{
free (result);
*errnop = ERANGE;
*herrnop = NETDB_INTERNAL;
return NSS_STATUS_TRYAGAIN;
}
}
(*pat)->next = NULL;
(*pat)->name = host.h_name;
(*pat)->family = host.h_addrtype;
memcpy ((*pat)->addr, host.h_addr_list[0], host.h_length);
(*pat)->scopeid = 0;
assert (host.h_addr_list[1] == NULL);
}
return status;
}

View File

@ -21,6 +21,7 @@
#include <errno.h>
#include <libintl.h>
#include <netdb.h>
#include <nss.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
@ -33,6 +34,10 @@
#endif
typedef enum nss_status (*nss_gethostbyname4_r)
(const char *name, struct gaih_addrtuple **pat,
char *buffer, size_t buflen, int *errnop,
int *h_errnop, int32_t *ttlp);
typedef enum nss_status (*nss_gethostbyname3_r)
(const char *name, int af, struct hostent *host,
char *buffer, size_t buflen, int *errnop,
@ -117,16 +122,104 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
while (!no_more)
{
void *cp;
int status[2] = { NSS_STATUS_UNAVAIL, NSS_STATUS_UNAVAIL };
int naddrs = 0;
size_t addrslen = 0;
size_t canonlen;
/* Prefer the function which also returns the TTL and canonical name. */
nss_gethostbyname3_r fct = __nss_lookup_function (nip,
"gethostbyname3_r");
if (fct == NULL)
fct = __nss_lookup_function (nip, "gethostbyname2_r");
if (fct != NULL)
nss_gethostbyname4_r fct4 = __nss_lookup_function (nip,
"gethostbyname4_r");
if (fct4 != NULL)
{
struct gaih_addrtuple *at = NULL;
while (1)
{
rc6 = 0;
status[0] = DL_CALL_FCT (fct4, (key, &at, tmpbuf6, tmpbuf6len,
&rc6, &herrno, &ttl));
if (rc6 != ERANGE || herrno != NETDB_INTERNAL)
break;
tmpbuf6 = extend_alloca (tmpbuf6, tmpbuf6len, 2 * tmpbuf6len);
}
if (rc6 != 0 && herrno == NETDB_INTERNAL)
goto out;
if (status[0] != NSS_STATUS_SUCCESS)
goto next_nip;
/* We found the data. Count the addresses and the size. */
for (struct gaih_addrtuple *at2 = at; at2 != NULL; at2 = at2->next)
{
++naddrs;
/* We handle unknown types here the best we can: assume
the maximum size for the address. */
if (at2->family == AF_INET)
addrslen += INADDRSZ;
else if (at2->family == AF_INET6
&& IN6ADDRSZ != sizeof (at2->addr))
addrslen += IN6ADDRSZ;
else
addrslen += sizeof (at2->addr);
}
canon = at->name;
canonlen = strlen (canon) + 1;
total = sizeof (*dataset) + naddrs + addrslen + canonlen;
/* Now we can allocate the data structure. If the TTL of the
entry is reported as zero do not cache the entry at all. */
if (ttl != 0 && he == NULL)
{
dataset = (struct dataset *) mempool_alloc (db, total
+ req->key_len,
IDX_result_data);
if (dataset == NULL)
++db->head->addfailed;
}
if (dataset == NULL)
{
/* We cannot permanently add the result in the moment. But
we can provide the result as is. Store the data in some
temporary memory. */
dataset = (struct dataset *) alloca (total + req->key_len);
/* We cannot add this record to the permanent database. */
alloca_used = true;
}
/* Fill in the address and address families. */
char *addrs = (char *) (&dataset->resp + 1);
uint8_t *family = (uint8_t *) (addrs + addrslen);
for (struct gaih_addrtuple *at2 = at; at2 != NULL; at2 = at2->next)
{
*family++ = at2->family;
if (at2->family == AF_INET)
addrs = mempcpy (addrs, at2->addr, INADDRSZ);
else if (at2->family == AF_INET6
&& IN6ADDRSZ != sizeof (at2->addr))
addrs = mempcpy (addrs, at2->addr, IN6ADDRSZ);
else
addrs = mempcpy (addrs, at2->addr, sizeof (at2->addr));
}
cp = family;
}
else
{
/* Prefer the function which also returns the TTL and
canonical name. */
nss_gethostbyname3_r fct = __nss_lookup_function (nip,
"gethostbyname3_r");
if (fct == NULL)
fct = __nss_lookup_function (nip, "gethostbyname2_r");
if (fct == NULL)
goto next_nip;
struct hostent th[2];
/* Collect IPv6 information first. */
@ -134,8 +227,8 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
{
rc6 = 0;
status[0] = DL_CALL_FCT (fct, (key, AF_INET6, &th[0], tmpbuf6,
tmpbuf6len, &rc6, &herrno,
&ttl, &canon));
tmpbuf6len, &rc6, &herrno, &ttl,
&canon));
if (rc6 != ERANGE || herrno != NETDB_INTERNAL)
break;
tmpbuf6 = extend_alloca (tmpbuf6, tmpbuf6len, 2 * tmpbuf6len);
@ -173,231 +266,226 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
if (rc4 != 0 && herrno == NETDB_INTERNAL)
goto out;
if (status[0] == NSS_STATUS_SUCCESS
|| status[1] == NSS_STATUS_SUCCESS)
if (status[0] != NSS_STATUS_SUCCESS
&& status[1] != NSS_STATUS_SUCCESS)
goto next_nip;
/* We found the data. Count the addresses and the size. */
for (int j = 0; j < 2; ++j)
if (status[j] == NSS_STATUS_SUCCESS)
for (int i = 0; th[j].h_addr_list[i] != NULL; ++i)
{
++naddrs;
addrslen += th[j].h_length;
}
if (canon == NULL)
{
/* We found the data. Count the addresses and the size. */
int naddrs = 0;
size_t addrslen = 0;
for (int j = 0; j < 2; ++j)
if (status[j] == NSS_STATUS_SUCCESS)
for (int i = 0; th[j].h_addr_list[i] != NULL; ++i)
{
++naddrs;
addrslen += th[j].h_length;
}
if (canon == NULL)
/* Determine the canonical name. */
nss_getcanonname_r cfct;
cfct = __nss_lookup_function (nip, "getcanonname_r");
if (cfct != NULL)
{
/* Determine the canonical name. */
nss_getcanonname_r cfct;
cfct = __nss_lookup_function (nip, "getcanonname_r");
if (cfct != NULL)
{
const size_t max_fqdn_len = 256;
char *buf = alloca (max_fqdn_len);
char *s;
int rc;
const size_t max_fqdn_len = 256;
char *buf = alloca (max_fqdn_len);
char *s;
int rc;
if (DL_CALL_FCT (cfct, (key, buf, max_fqdn_len, &s, &rc,
&herrno)) == NSS_STATUS_SUCCESS)
canon = s;
else
/* Set to name now to avoid using gethostbyaddr. */
canon = key;
}
if (DL_CALL_FCT (cfct, (key, buf, max_fqdn_len, &s,
&rc, &herrno))
== NSS_STATUS_SUCCESS)
canon = s;
else
{
struct hostent *he = NULL;
int herrno;
struct hostent he_mem;
void *addr;
size_t addrlen;
int addrfamily;
if (status[1] == NSS_STATUS_SUCCESS)
{
addr = th[1].h_addr_list[0];
addrlen = sizeof (struct in_addr);
addrfamily = AF_INET;
}
else
{
addr = th[0].h_addr_list[0];
addrlen = sizeof (struct in6_addr);
addrfamily = AF_INET6;
}
size_t tmpbuflen = 512;
char *tmpbuf = alloca (tmpbuflen);
int rc;
while (1)
{
rc = __gethostbyaddr2_r (addr, addrlen, addrfamily,
&he_mem, tmpbuf, tmpbuflen,
&he, &herrno, NULL);
if (rc != ERANGE || herrno != NETDB_INTERNAL)
break;
tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
tmpbuflen * 2);
}
if (rc == 0)
{
if (he != NULL)
canon = he->h_name;
else
canon = key;
}
}
}
size_t canonlen = canon == NULL ? 0 : (strlen (canon) + 1);
total = sizeof (*dataset) + naddrs + addrslen + canonlen;
/* Now we can allocate the data structure. If the TTL
of the entry is reported as zero do not cache the
entry at all. */
if (ttl != 0 && he == NULL)
{
dataset = (struct dataset *) mempool_alloc (db,
total
+ req->key_len,
IDX_result_data);
if (dataset == NULL)
++db->head->addfailed;
}
if (dataset == NULL)
{
/* We cannot permanently add the result in the moment. But
we can provide the result as is. Store the data in some
temporary memory. */
dataset = (struct dataset *) alloca (total + req->key_len);
/* We cannot add this record to the permanent database. */
alloca_used = true;
}
dataset->head.allocsize = total + req->key_len;
dataset->head.recsize = total - offsetof (struct dataset, resp);
dataset->head.notfound = false;
dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
dataset->head.usable = true;
/* Compute the timeout time. */
dataset->head.timeout = time (NULL) + (ttl == INT32_MAX
? db->postimeout : ttl);
dataset->resp.version = NSCD_VERSION;
dataset->resp.found = 1;
dataset->resp.naddrs = naddrs;
dataset->resp.addrslen = addrslen;
dataset->resp.canonlen = canonlen;
dataset->resp.error = NETDB_SUCCESS;
char *addrs = (char *) (&dataset->resp + 1);
uint8_t *family = (uint8_t *) (addrs + addrslen);
for (int j = 0; j < 2; ++j)
if (status[j] == NSS_STATUS_SUCCESS)
for (int i = 0; th[j].h_addr_list[i] != NULL; ++i)
{
addrs = mempcpy (addrs, th[j].h_addr_list[i],
th[j].h_length);
*family++ = th[j].h_addrtype;
}
void *cp = family;
if (canon != NULL)
cp = mempcpy (cp, canon, canonlen);
key_copy = memcpy (cp, key, req->key_len);
/* Now we can determine whether on refill we have to
create a new record or not. */
if (he != NULL)
{
assert (fd == -1);
if (total + req->key_len == dh->allocsize
&& total - offsetof (struct dataset, resp) == dh->recsize
&& memcmp (&dataset->resp, dh->data,
dh->allocsize
- offsetof (struct dataset, resp)) == 0)
{
/* The data has not changed. We will just bump the
timeout value. Note that the new record has been
allocated on the stack and need not be freed. */
dh->timeout = dataset->head.timeout;
++dh->nreloads;
}
else
{
/* We have to create a new record. Just allocate
appropriate memory and copy it. */
struct dataset *newp
= (struct dataset *) mempool_alloc (db,
total
+ req->key_len,
IDX_result_data);
if (__builtin_expect (newp != NULL, 1))
{
/* Adjust pointer into the memory block. */
key_copy = (char *) newp + (key_copy
- (char *) dataset);
dataset = memcpy (newp, dataset,
total + req->key_len);
alloca_used = false;
}
else
++db->head->addfailed;
/* Mark the old record as obsolete. */
dh->usable = false;
}
/* Set to name now to avoid using gethostbyaddr. */
canon = key;
}
else
{
/* We write the dataset before inserting it to the
database since while inserting this thread might
block and so would unnecessarily let the receiver
wait. */
assert (fd != -1);
struct hostent *he = NULL;
int herrno;
struct hostent he_mem;
void *addr;
size_t addrlen;
int addrfamily;
#ifdef HAVE_SENDFILE
if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
if (status[1] == NSS_STATUS_SUCCESS)
{
assert (db->wr_fd != -1);
assert ((char *) &dataset->resp > (char *) db->data);
assert ((char *) &dataset->resp - (char *) db->head
+ total
<= (sizeof (struct database_pers_head)
+ db->head->module * sizeof (ref_t)
+ db->head->data_size));
ssize_t written;
written = sendfileall (fd, db->wr_fd,
(char *) &dataset->resp
- (char *) db->head, total);
# ifndef __ASSUME_SENDFILE
if (written == -1 && errno == ENOSYS)
goto use_write;
# endif
addr = th[1].h_addr_list[0];
addrlen = sizeof (struct in_addr);
addrfamily = AF_INET;
}
else
# ifndef __ASSUME_SENDFILE
use_write:
# endif
#endif
writeall (fd, &dataset->resp, total);
}
{
addr = th[0].h_addr_list[0];
addrlen = sizeof (struct in6_addr);
addrfamily = AF_INET6;
}
goto out;
size_t tmpbuflen = 512;
char *tmpbuf = alloca (tmpbuflen);
int rc;
while (1)
{
rc = __gethostbyaddr2_r (addr, addrlen, addrfamily,
&he_mem, tmpbuf, tmpbuflen,
&he, &herrno, NULL);
if (rc != ERANGE || herrno != NETDB_INTERNAL)
break;
tmpbuf = extend_alloca (tmpbuf, tmpbuflen,
tmpbuflen * 2);
}
if (rc == 0)
{
if (he != NULL)
canon = he->h_name;
else
canon = key;
}
}
}
canonlen = canon == NULL ? 0 : (strlen (canon) + 1);
total = sizeof (*dataset) + naddrs + addrslen + canonlen;
/* Now we can allocate the data structure. If the TTL of the
entry is reported as zero do not cache the entry at all. */
if (ttl != 0 && he == NULL)
{
dataset = (struct dataset *) mempool_alloc (db, total
+ req->key_len,
IDX_result_data);
if (dataset == NULL)
++db->head->addfailed;
}
if (dataset == NULL)
{
/* We cannot permanently add the result in the moment. But
we can provide the result as is. Store the data in some
temporary memory. */
dataset = (struct dataset *) alloca (total + req->key_len);
/* We cannot add this record to the permanent database. */
alloca_used = true;
}
/* Fill in the address and address families. */
char *addrs = (char *) (&dataset->resp + 1);
uint8_t *family = (uint8_t *) (addrs + addrslen);
for (int j = 0; j < 2; ++j)
if (status[j] == NSS_STATUS_SUCCESS)
for (int i = 0; th[j].h_addr_list[i] != NULL; ++i)
{
addrs = mempcpy (addrs, th[j].h_addr_list[i],
th[j].h_length);
*family++ = th[j].h_addrtype;
}
cp = family;
}
/* Fill in the rest of the dataset. */
dataset->head.allocsize = total + req->key_len;
dataset->head.recsize = total - offsetof (struct dataset, resp);
dataset->head.notfound = false;
dataset->head.nreloads = he == NULL ? 0 : (dh->nreloads + 1);
dataset->head.usable = true;
/* Compute the timeout time. */
dataset->head.timeout = time (NULL) + (ttl == INT32_MAX
? db->postimeout : ttl);
dataset->resp.version = NSCD_VERSION;
dataset->resp.found = 1;
dataset->resp.naddrs = naddrs;
dataset->resp.addrslen = addrslen;
dataset->resp.canonlen = canonlen;
dataset->resp.error = NETDB_SUCCESS;
if (canon != NULL)
cp = mempcpy (cp, canon, canonlen);
key_copy = memcpy (cp, key, req->key_len);
/* Now we can determine whether on refill we have to create a
new record or not. */
if (he != NULL)
{
assert (fd == -1);
if (total + req->key_len == dh->allocsize
&& total - offsetof (struct dataset, resp) == dh->recsize
&& memcmp (&dataset->resp, dh->data,
dh->allocsize - offsetof (struct dataset,
resp)) == 0)
{
/* The data has not changed. We will just bump the
timeout value. Note that the new record has been
allocated on the stack and need not be freed. */
dh->timeout = dataset->head.timeout;
++dh->nreloads;
}
else
{
/* We have to create a new record. Just allocate
appropriate memory and copy it. */
struct dataset *newp
= (struct dataset *) mempool_alloc (db, total + req->key_len,
IDX_result_data);
if (__builtin_expect (newp != NULL, 1))
{
/* Adjust pointer into the memory block. */
key_copy = (char *) newp + (key_copy - (char *) dataset);
dataset = memcpy (newp, dataset, total + req->key_len);
alloca_used = false;
}
else
++db->head->addfailed;
/* Mark the old record as obsolete. */
dh->usable = false;
}
}
else
{
/* We write the dataset before inserting it to the database
since while inserting this thread might block and so
would unnecessarily let the receiver wait. */
assert (fd != -1);
#ifdef HAVE_SENDFILE
if (__builtin_expect (db->mmap_used, 1) && !alloca_used)
{
assert (db->wr_fd != -1);
assert ((char *) &dataset->resp > (char *) db->data);
assert ((char *) &dataset->resp - (char *) db->head + total
<= (sizeof (struct database_pers_head)
+ db->head->module * sizeof (ref_t)
+ db->head->data_size));
ssize_t written;
written = sendfileall (fd, db->wr_fd, (char *) &dataset->resp
- (char *) db->head, total);
# ifndef __ASSUME_SENDFILE
if (written == -1 && errno == ENOSYS)
goto use_write;
# endif
}
else
# ifndef __ASSUME_SENDFILE
use_write:
# endif
#endif
writeall (fd, &dataset->resp, total);
}
goto out;
next_nip:
if (nss_next_action (nip, status[1]) == NSS_ACTION_RETURN)
break;

View File

@ -38,6 +38,7 @@ libnss_files {
_nss_files_endhostent;
_nss_files_gethostbyaddr_r;
_nss_files_gethostbyname2_r;
_nss_files_gethostbyname4_r;
_nss_files_gethostbyname_r;
_nss_files_gethostent_r;
_nss_files_gethostton_r;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 1996, 1997, 1999 Free Software Foundation, Inc.
/* Copyright (C) 1996, 1997, 1999, 2008 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@ -23,6 +23,7 @@
#define _NSS_H 1
#include <features.h>
#include <stdint.h>
__BEGIN_DECLS
@ -38,6 +39,17 @@ enum nss_status
};
/* Data structure used for the 'gethostbyname4_r' function. */
struct gaih_addrtuple
{
struct gaih_addrtuple *next;
char *name;
int family;
uint32_t addr[4];
uint32_t scopeid;
};
/* Overwrite service selection for database DBNAME using specification
in STRING.
This function should only be used by system programs which have to

View File

@ -1,6 +1,5 @@
/* Hosts file parser in nss_files module.
Copyright (C) 1996-2001, 2003, 2004, 2006, 2007
Free Software Foundation, Inc.
Copyright (C) 1996-2001, 2003-2007, 2008 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@ -56,7 +55,10 @@ LINE_PARSER
STRING_FIELD (addr, isspace, 1);
/* Parse address. */
if (inet_pton (af, addr, entdata->host_addr) <= 0)
if (inet_pton (af == AF_UNSPEC ? AF_INET : af, addr, entdata->host_addr)
> 0)
af = af == AF_UNSPEC ? AF_INET : af;
else
{
if (af == AF_INET6 && (flags & AI_V4MAPPED) != 0
&& inet_pton (AF_INET, addr, entdata->host_addr) > 0)
@ -76,6 +78,9 @@ LINE_PARSER
/* Illegal address: ignore line. */
return 0;
}
else if (af == AF_UNSPEC
&& inet_pton (AF_INET6, addr, entdata->host_addr) > 0)
af = AF_INET6;
else
/* Illegal address: ignore line. */
return 0;
@ -101,8 +106,6 @@ _nss_files_get##name##_r (proto, \
struct STRUCTURE *result, char *buffer, \
size_t buflen, int *errnop H_ERRNO_PROTO) \
{ \
enum nss_status status; \
\
uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct hostent_data); \
buffer += pad; \
buflen = buflen > pad ? buflen - pad : 0; \
@ -110,7 +113,7 @@ _nss_files_get##name##_r (proto, \
__libc_lock_lock (lock); \
\
/* Reset file pointer to beginning or open file. */ \
status = internal_setent (keep_stream); \
enum nss_status status = internal_setent (keep_stream); \
\
if (status == NSS_STATUS_SUCCESS) \
{ \
@ -288,9 +291,9 @@ HOST_DB_LOOKUP (hostbyname, ,,
{
LOOKUP_NAME_CASE (h_name, h_aliases)
}, const char *name)
#undef EXTRA_ARGS_VALUE
/* XXX Is using _res to determine whether we want to convert IPv4 addresses
to IPv6 addresses really the right thing to do? */
#define EXTRA_ARGS_VALUE \
@ -299,8 +302,9 @@ HOST_DB_LOOKUP (hostbyname2, ,,
{
LOOKUP_NAME_CASE (h_name, h_aliases)
}, const char *name, int af)
#undef EXTRA_ARGS_VALUE
/* We only need to consider IPv4 mapped addresses if the input to the
gethostbyaddr() function is an IPv6 address. */
#define EXTRA_ARGS_VALUE \
@ -311,3 +315,116 @@ DB_LOOKUP (hostbyaddr, ,,
&& ! memcmp (addr, result->h_addr_list[0], len))
break;
}, const void *addr, socklen_t len, int af)
#undef EXTRA_ARGS_VALUE
enum nss_status
_nss_files_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
char *buffer, size_t buflen, int *errnop,
int *herrnop, int32_t *ttlp)
{
__libc_lock_lock (lock);
/* Reset file pointer to beginning or open file. */
enum nss_status status = internal_setent (keep_stream);
if (status == NSS_STATUS_SUCCESS)
{
/* Tell getent function that we have repositioned the file pointer. */
last_use = getby;
bool any = false;
bool got_canon = false;
while (1)
{
/* Align the buffer for the next record. */
uintptr_t pad = (-(uintptr_t) buffer
% __alignof__ (struct hostent_data));
buffer += pad;
buflen = buflen > pad ? buflen - pad : 0;
struct hostent result;
status = internal_getent (&result, buffer, buflen, errnop
H_ERRNO_ARG, AF_UNSPEC, 0);
if (status != NSS_STATUS_SUCCESS)
break;
int naliases = 0;
if (__strcasecmp (name, result.h_name) != 0)
{
for (; result.h_aliases[naliases] != NULL; ++naliases)
if (! __strcasecmp (name, result.h_aliases[naliases]))
break;
if (result.h_aliases[naliases] == NULL)
continue;
/* We know this alias exist. Count it. */
++naliases;
}
/* Determine how much memory has been used so far. */
// XXX It is not necessary to preserve the aliases array
while (result.h_aliases[naliases] != NULL)
++naliases;
char *bufferend = (char *) &result.h_aliases[naliases + 1];
assert (buflen >= bufferend - buffer);
buflen -= bufferend - buffer;
buffer = bufferend;
/* We found something. */
any = true;
/* Create the record the caller expects. There is only one
address. */
assert (result.h_addr_list[1] == NULL);
if (*pat == NULL)
{
uintptr_t pad = (-(uintptr_t) buffer
% __alignof__ (struct gaih_addrtuple));
buffer += pad;
buflen = buflen > pad ? buflen - pad : 0;
if (__builtin_expect (buflen < sizeof (struct gaih_addrtuple),
0))
{
*errnop = ERANGE;
*herrnop = NETDB_INTERNAL;
status = NSS_STATUS_TRYAGAIN;
break;
}
*pat = (struct gaih_addrtuple *) buffer;
buffer += sizeof (struct gaih_addrtuple);
buflen -= sizeof (struct gaih_addrtuple);
}
(*pat)->next = NULL;
(*pat)->name = got_canon ? NULL : result.h_name;
got_canon = true;
(*pat)->family = result.h_addrtype;
memcpy ((*pat)->addr, result.h_addr_list[0], result.h_length);
(*pat)->scopeid = 0;
pat = &((*pat)->next);
/* If we only look for the first matching entry we are done. */
if ((_res_hconf.flags & HCONF_FLAG_MULTI) == 0)
break;
}
/* If we have to look for multiple records and found one, this
is a success. */
if (status == NSS_STATUS_NOTFOUND && any)
{
assert ((_res_hconf.flags & HCONF_FLAG_MULTI) != 0);
status = NSS_STATUS_SUCCESS;
}
if (! keep_stream)
internal_endent ();
}
__libc_lock_unlock (lock);
return status;
}

View File

@ -89,6 +89,7 @@ libnss_dns {
_nss_dns_gethostbyname_r; _nss_dns_getnetbyaddr_r;
_nss_dns_getnetbyname_r; _nss_dns_getcanonname_r;
_nss_dns_gethostbyaddr2_r;
_nss_dns_gethostbyname4_r;
}
}

View File

@ -621,7 +621,7 @@ gethostbyname2(name, af)
buf.buf = origbuf = (querybuf *) alloca (1024);
if ((n = __libc_res_nsearch(&_res, name, C_IN, type, buf.buf->buf, 1024,
&buf.ptr)) < 0) {
&buf.ptr, NULL, NULL)) < 0) {
if (buf.buf != origbuf)
free (buf.buf);
Dprintf("res_nsearch failed (%d)\n", n);
@ -716,12 +716,12 @@ gethostbyaddr(addr, len, af)
buf.buf = orig_buf = (querybuf *) alloca (1024);
n = __libc_res_nquery(&_res, qbuf, C_IN, T_PTR, buf.buf->buf, 1024,
&buf.ptr);
&buf.ptr, NULL, NULL);
if (n < 0 && af == AF_INET6 && (_res.options & RES_NOIP6DOTINT) == 0) {
strcpy(qp, "ip6.int");
n = __libc_res_nquery(&_res, qbuf, C_IN, T_PTR, buf.buf->buf,
buf.buf != orig_buf ? MAXPACKET : 1024,
&buf.ptr);
&buf.ptr, NULL, NULL);
}
if (n < 0) {
if (buf.buf != orig_buf)

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2004, 2006 Free Software Foundation, Inc.
/* Copyright (C) 2004, 2006, 2008 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
@ -61,7 +61,7 @@ _nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen,
for (int i = 0; i < nqtypes; ++i)
{
int r = __libc_res_nquery (&_res, name, ns_c_in, qtypes[i],
buf, sizeof (buf), &ansp.ptr);
buf, sizeof (buf), &ansp.ptr, NULL, NULL);
if (r > 0)
{
/* We need to decode the response. Just one question record.

View File

@ -71,6 +71,7 @@
* --Copyright--
*/
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <netdb.h>
@ -127,6 +128,14 @@ static enum nss_status getanswer_r (const querybuf *answer, int anslen,
size_t buflen, int *errnop, int *h_errnop,
int map, int32_t *ttlp, char **canonp);
static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1,
const querybuf *answer2, int anslen2,
const char *qname,
struct gaih_addrtuple **pat,
char *buffer, size_t buflen,
int *errnop, int *h_errnop,
int32_t *ttlp);
extern enum nss_status _nss_dns_gethostbyname3_r (const char *name, int af,
struct hostent *result,
char *buffer, size_t buflen,
@ -186,11 +195,11 @@ _nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result,
host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
n = __libc_res_nsearch (&_res, name, C_IN, type, host_buffer.buf->buf,
1024, &host_buffer.ptr);
1024, &host_buffer.ptr, NULL, NULL);
if (n < 0)
{
enum nss_status status = (errno == ECONNREFUSED
? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND);
status = (errno == ECONNREFUSED
? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND);
*h_errnop = h_errno;
if (h_errno == TRY_AGAIN)
*errnop = EAGAIN;
@ -203,7 +212,8 @@ _nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result,
if (af == AF_INET6 && (_res.options & RES_USE_INET6))
n = __libc_res_nsearch (&_res, name, C_IN, T_A, host_buffer.buf->buf,
host_buffer.buf != orig_host_buffer
? MAXPACKET : 1024, &host_buffer.ptr);
? MAXPACKET : 1024, &host_buffer.ptr,
NULL, NULL);
if (n < 0)
{
@ -255,6 +265,70 @@ _nss_dns_gethostbyname_r (const char *name, struct hostent *result,
}
enum nss_status
_nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
char *buffer, size_t buflen, int *errnop,
int *herrnop, int32_t *ttlp)
{
if (__res_maybe_init (&_res, 0) == -1)
return NSS_STATUS_UNAVAIL;
char tmp[NS_MAXDNAME];
/*
* if there aren't any dots, it could be a user-level alias.
* this is also done in res_query() since we are not the only
* function that looks up host names.
*/
if (strchr (name, '.') == NULL)
{
const char *cp = res_hostalias (&_res, name, tmp, sizeof (tmp));
if (cp != NULL)
name = cp;
}
union
{
querybuf *buf;
u_char *ptr;
} host_buffer;
querybuf *orig_host_buffer;
host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048);
u_char *ans2p = NULL;
int nans2p = 0;
int olderr = errno;
enum nss_status status;
int n = __libc_res_nsearch (&_res, name, C_IN, T_UNSPEC,
host_buffer.buf->buf, 2048, &host_buffer.ptr,
&ans2p, &nans2p);
if (n < 0)
{
status = (errno == ECONNREFUSED
? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND);
*herrnop = h_errno;
if (h_errno == TRY_AGAIN)
*errnop = EAGAIN;
else
__set_errno (olderr);
if (host_buffer.buf != orig_host_buffer)
free (host_buffer.buf);
return status;
}
status = gaih_getanswer(host_buffer.buf, n, (const querybuf *) ans2p,
nans2p, name, pat, buffer, buflen,
errnop, herrnop, ttlp);
if (host_buffer.buf != orig_host_buffer)
free (host_buffer.buf);
return status;
}
extern enum nss_status _nss_dns_gethostbyaddr2_r (const void *addr,
socklen_t len, int af,
struct hostent *result,
@ -342,7 +416,8 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
qp += sprintf (qp, "%02hhx", uaddr[n]);
strcpy (qp, "].ip6.arpa");
n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR,
host_buffer.buf->buf, 1024, &host_buffer.ptr);
host_buffer.buf->buf, 1024, &host_buffer.ptr,
NULL, NULL);
if (n >= 0)
goto got_it_already;
}
@ -363,13 +438,14 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
}
n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
1024, &host_buffer.ptr);
1024, &host_buffer.ptr, NULL, NULL);
if (n < 0 && af == AF_INET6 && (_res.options & RES_NOIP6DOTINT) == 0)
{
strcpy (qp, "ip6.int");
n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
host_buffer.buf != orig_host_buffer
? MAXPACKET : 1024, &host_buffer.ptr);
? MAXPACKET : 1024, &host_buffer.ptr,
NULL, NULL);
}
if (n < 0)
{
@ -555,7 +631,8 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
if (n > 0 && bp[0] == '.')
bp[0] = '\0';
if (n < 0 || (*name_ok) (bp) == 0)
if (__builtin_expect (n < 0 || ((*name_ok) (bp) == 0 && (errno = EBADMSG)),
0))
{
*errnop = errno;
*h_errnop = NO_RECOVERY;
@ -629,7 +706,7 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
continue; /* XXX - had_error++ ? */
}
if ((qtype ==T_A || qtype == T_AAAA) && type == T_CNAME)
if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME)
{
if (ap >= &host_data->aliases[MAX_NR_ALIASES - 1])
continue;
@ -857,3 +934,245 @@ getanswer_r (const querybuf *answer, int anslen, const char *qname, int qtype,
return ((qtype == T_A || qtype == T_AAAA) && ap != host_data->aliases
? NSS_STATUS_NOTFOUND : NSS_STATUS_TRYAGAIN);
}
static enum nss_status
gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname,
struct gaih_addrtuple ***patp,
char **bufferp, size_t *buflenp,
int *errnop, int *h_errnop, int32_t *ttlp, int *firstp)
{
char *buffer = *bufferp;
size_t buflen = *buflenp;
struct gaih_addrtuple **pat = *patp;
const HEADER *hp = &answer->hdr;
int ancount = ntohs (hp->ancount);
int qdcount = ntohs (hp->qdcount);
const u_char *cp = answer->buf + HFIXEDSZ;
const u_char *end_of_message = answer->buf + anslen;
if (__builtin_expect (qdcount != 1, 0))
{
*h_errnop = NO_RECOVERY;
return NSS_STATUS_UNAVAIL;
}
u_char packtmp[NS_MAXCDNAME];
int n = __ns_name_unpack (answer->buf, end_of_message, cp,
packtmp, sizeof packtmp);
/* We unpack the name to check it for validity. But we do not need
it later. */
if (n != -1 && __ns_name_ntop (packtmp, buffer, buflen) == -1)
{
if (__builtin_expect (errno, 0) == EMSGSIZE)
{
too_small:
*errnop = ERANGE;
*h_errnop = NETDB_INTERNAL;
return NSS_STATUS_TRYAGAIN;
}
n = -1;
}
if (__builtin_expect (n < 0 || (res_hnok (buffer) == 0
&& (errno = EBADMSG)), 0))
{
*errnop = errno;
*h_errnop = NO_RECOVERY;
return NSS_STATUS_UNAVAIL;
}
cp += n + QFIXEDSZ;
int haveanswer = 0;
int had_error = 0;
char *canon = NULL;
char *h_name = NULL;
int h_namelen = 0;
while (ancount-- > 0 && cp < end_of_message && had_error == 0)
{
n = __ns_name_unpack (answer->buf, end_of_message, cp,
packtmp, sizeof packtmp);
if (n != -1 &&
(h_namelen = __ns_name_ntop (packtmp, buffer, buflen)) == -1)
{
if (__builtin_expect (errno, 0) == EMSGSIZE)
goto too_small;
n = -1;
}
if (n < 0 || res_hnok (buffer) == 0)
{
++had_error;
continue;
}
if (*firstp)
{
h_name = buffer;
buffer += h_namelen;
buflen -= h_namelen;
}
cp += n; /* name */
int type = ns_get16 (cp);
cp += INT16SZ; /* type */
int class = ns_get16 (cp);
cp += INT16SZ; /* class */
int32_t ttl = ns_get32 (cp);
cp += INT32SZ; /* TTL */
n = ns_get16 (cp);
cp += INT16SZ; /* len */
if (class != C_IN)
{
cp += n;
continue;
}
if (type == T_CNAME)
{
char tbuf[MAXDNAME];
n = dn_expand (answer->buf, end_of_message, cp, tbuf, sizeof tbuf);
if (n < 0 || res_hnok (tbuf) == 0)
{
++had_error;
continue;
}
cp += n;
if (*firstp)
{
/* Reclaim buffer space. */
if (h_name + h_namelen == buffer)
{
buffer = h_name;
buflen += h_namelen;
}
n = strlen (tbuf) + 1;
if (__builtin_expect (n > buflen, 0))
goto too_small;
if (__builtin_expect (n >= MAXHOSTNAMELEN, 0))
{
++had_error;
continue;
}
canon = buffer;
buffer = __mempcpy (buffer, tbuf, n);
buflen -= n;
h_namelen = 0;
}
continue;
}
if (__builtin_expect (type == T_SIG, 0)
|| __builtin_expect (type == T_KEY, 0)
|| __builtin_expect (type == T_NXT, 0)
|| __builtin_expect (type == T_PTR, 0))
{
/* We don't support DNSSEC yet. For now, ignore the record
and send a low priority message to syslog.
We also don't expect T_PTR messages. */
syslog (LOG_DEBUG | LOG_AUTH,
"getaddrinfo*.gaih_getanswer: got type \"%s\"",
p_type (type));
cp += n;
continue;
}
if (type != T_A && type != T_AAAA)
abort ();
if (*pat == NULL)
{
uintptr_t pad = (-(uintptr_t) buffer
% __alignof__ (struct gaih_addrtuple));
buffer += pad;
buflen = buflen > pad ? buflen - pad : 0;
if (__builtin_expect (buflen < sizeof (struct gaih_addrtuple),
0))
{
*errnop = ERANGE;
*h_errnop = NETDB_INTERNAL;
return NSS_STATUS_TRYAGAIN;
}
*pat = (struct gaih_addrtuple *) buffer;
buffer += sizeof (struct gaih_addrtuple);
buflen -= sizeof (struct gaih_addrtuple);
}
(*pat)->name = NULL;
(*pat)->next = NULL;
if (*firstp)
{
if (ttl != 0 && ttlp != NULL)
*ttlp = ttl;
if (canon != NULL)
{
(*pat)->name = canon;
/* Reclaim buffer space. */
if (h_name + h_namelen == buffer)
{
buffer = h_name;
buflen += h_namelen;
}
}
else
(*pat)->name = h_name;
*firstp = 0;
}
(*pat)->family = type == T_A ? AF_INET : AF_INET6;
memcpy ((*pat)->addr, cp, n);
cp += n;
(*pat)->scopeid = 0;
pat = &((*pat)->next);
haveanswer = 1;
}
if (haveanswer)
{
*patp = pat;
*bufferp = buffer;
*buflenp = buflen;
*h_errnop = NETDB_SUCCESS;
return NSS_STATUS_SUCCESS;
}
/* Special case here: if the resolver sent a result but it only
contains a CNAME while we are looking for a T_A or T_AAAA record,
we fail with NOTFOUND instead of TRYAGAIN. */
return canon == NULL ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND;
}
static enum nss_status
gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2,
int anslen2, const char *qname,
struct gaih_addrtuple **pat, char *buffer, size_t buflen,
int *errnop, int *h_errnop, int32_t *ttlp)
{
int first = 1;
enum nss_status status = gaih_getanswer_slice(answer1, anslen1, qname,
&pat, &buffer, &buflen,
errnop, h_errnop, ttlp,
&first);
if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND)
&& answer2 != NULL)
status = gaih_getanswer_slice(answer2, anslen2, qname,
&pat, &buffer, &buflen,
errnop, h_errnop, ttlp, &first);
return status;
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 1996, 1997, 1998, 1999, 2002, 2004, 2007
/* Copyright (C) 1996, 1997, 1998, 1999, 2002, 2004, 2007, 2008
Free Software Foundation, Inc.
This file is part of the GNU C Library.
Extended from original form by Ulrich Drepper <drepper@cygnus.com>, 1996.
@ -130,7 +130,7 @@ _nss_dns_getnetbyname_r (const char *name, struct netent *result,
net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024);
anslen = __libc_res_nsearch (&_res, qbuf, C_IN, T_PTR, net_buffer.buf->buf,
1024, &net_buffer.ptr);
1024, &net_buffer.ptr, NULL, NULL);
if (anslen < 0)
{
/* Nothing found. */
@ -206,7 +206,7 @@ _nss_dns_getnetbyaddr_r (uint32_t net, int type, struct netent *result,
net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024);
anslen = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, net_buffer.buf->buf,
1024, &net_buffer.ptr);
1024, &net_buffer.ptr, NULL, NULL);
if (anslen < 0)
{
/* Nothing found. */

View File

@ -97,7 +97,7 @@ static const char rcsid[] = "$BINDId: res_query.c,v 8.20 2000/02/29 05:39:12 vix
static int
__libc_res_nquerydomain(res_state statp, const char *name, const char *domain,
int class, int type, u_char *answer, int anslen,
u_char **answerp);
u_char **answerp, u_char **answerp2, int *nanswerp2);
/*
* Formulate a normal query, send, and await answer.
@ -115,15 +115,20 @@ __libc_res_nquery(res_state statp,
int class, int type, /* class and type of query */
u_char *answer, /* buffer to put answer */
int anslen, /* size of answer buffer */
u_char **answerp) /* if buffer needs to be enlarged */
u_char **answerp, /* if buffer needs to be enlarged */
u_char **answerp2,
int *nanswerp2)
{
u_char *buf;
HEADER *hp = (HEADER *) answer;
int n, use_malloc = 0;
u_int oflags = statp->_flags;
size_t bufsize = QUERYSIZE;
buf = alloca (bufsize);
size_t bufsize = (type == T_UNSPEC ? 2 : 1) * QUERYSIZE;
u_char *buf = alloca (bufsize);
u_char *query1 = buf;
int nquery1 = -1;
u_char *query2 = NULL;
int nquery2 = 0;
again:
hp->rcode = NOERROR; /* default */
@ -133,18 +138,47 @@ __libc_res_nquery(res_state statp,
printf(";; res_query(%s, %d, %d)\n", name, class, type);
#endif
n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
buf, bufsize);
if (n > 0
&& (oflags & RES_F_EDNS0ERR) == 0
&& (statp->options & RES_USE_EDNS0) != 0)
n = __res_nopt(statp, n, buf, bufsize, anslen);
if (type == T_UNSPEC)
{
n = res_nmkquery(statp, QUERY, name, class, T_A, NULL, 0, NULL,
query1, bufsize);
if (n > 0)
{
if ((oflags & RES_F_EDNS0ERR) == 0
&& (statp->options & RES_USE_EDNS0) != 0)
n = __res_nopt(statp, n, query1, bufsize, anslen / 2);
nquery1 = n;
query2 = buf + nquery1;
n = res_nmkquery(statp, QUERY, name, class, T_AAAA, NULL, 0,
NULL, query2, bufsize - n);
if (n > 0
&& (oflags & RES_F_EDNS0ERR) == 0
&& (statp->options & RES_USE_EDNS0) != 0)
n = __res_nopt(statp, n, query2, bufsize - n, anslen / 2);
nquery2 = n;
}
}
else
{
n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
query1, bufsize);
if (n > 0
&& (oflags & RES_F_EDNS0ERR) == 0
&& (statp->options & RES_USE_EDNS0) != 0)
n = __res_nopt(statp, n, query1, bufsize, anslen);
nquery1 = n;
}
if (__builtin_expect (n <= 0, 0) && !use_malloc) {
/* Retry just in case res_nmkquery failed because of too
short buffer. Shouldn't happen. */
bufsize = MAXPACKET;
bufsize = (type == T_UNSPEC ? 2 : 1) * MAXPACKET;
buf = malloc (bufsize);
if (buf != NULL) {
query1 = buf;
use_malloc = 1;
goto again;
}
@ -168,7 +202,8 @@ __libc_res_nquery(res_state statp,
return (n);
}
assert (answerp == NULL || (void *) *answerp == (void *) answer);
n = __libc_res_nsend(statp, buf, n, answer, anslen, answerp);
n = __libc_res_nsend(statp, query1, nquery1, query2, nquery2, answer,
anslen, answerp, answerp2, nanswerp2);
if (use_malloc)
free (buf);
if (n < 0) {
@ -184,20 +219,37 @@ __libc_res_nquery(res_state statp,
/* __libc_res_nsend might have reallocated the buffer. */
hp = (HEADER *) *answerp;
if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
/* We simplify the following tests by assigning HP to HP2. It
is easy to verify that this is the same as ignoring all
tests of HP2. */
HEADER *hp2 = answerp2 ? (HEADER *) *answerp2 : hp;
if ((hp->rcode != NOERROR || ntohs(hp->ancount) == 0)
&& (hp2->rcode != NOERROR || ntohs(hp2->ancount) == 0)) {
#ifdef DEBUG
if (statp->options & RES_DEBUG)
if (statp->options & RES_DEBUG) {
printf(";; rcode = %d, ancount=%d\n", hp->rcode,
ntohs(hp->ancount));
if (hp != hp2)
printf(";; rcode2 = %d, ancount2=%d\n", hp2->rcode,
ntohs(hp2->ancount));
}
#endif
switch (hp->rcode) {
switch (hp->rcode == NOERROR ? hp2->rcode : hp->rcode) {
case NXDOMAIN:
if ((hp->rcode == NOERROR && ntohs (hp->ancount) != 0)
|| (hp2->rcode == NOERROR
&& ntohs (hp2->ancount) != 0))
goto success;
RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
break;
case SERVFAIL:
RES_SET_H_ERRNO(statp, TRY_AGAIN);
break;
case NOERROR:
if (ntohs (hp->ancount) != 0
|| ntohs (hp2->ancount) != 0)
goto success;
RES_SET_H_ERRNO(statp, NO_DATA);
break;
case FORMERR:
@ -209,6 +261,7 @@ __libc_res_nquery(res_state statp,
}
return (-1);
}
success:
return (n);
}
libresolv_hidden_def (__libc_res_nquery)
@ -221,7 +274,7 @@ res_nquery(res_state statp,
int anslen) /* size of answer buffer */
{
return __libc_res_nquery(statp, name, class, type, answer, anslen,
NULL);
NULL, NULL, NULL);
}
libresolv_hidden_def (res_nquery)
@ -233,11 +286,13 @@ libresolv_hidden_def (res_nquery)
*/
int
__libc_res_nsearch(res_state statp,
const char *name, /* domain name */
int class, int type, /* class and type of query */
u_char *answer, /* buffer to put answer */
int anslen, /* size of answer */
u_char **answerp)
const char *name, /* domain name */
int class, int type, /* class and type of query */
u_char *answer, /* buffer to put answer */
int anslen, /* size of answer */
u_char **answerp,
u_char **answerp2,
int *nanswerp2)
{
const char *cp, * const *domain;
HEADER *hp = (HEADER *) answer;
@ -260,7 +315,8 @@ __libc_res_nsearch(res_state statp,
/* If there aren't any dots, it could be a user-level alias. */
if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL)
return (__libc_res_nquery(statp, cp, class, type, answer,
anslen, answerp));
anslen, answerp, answerp2,
nanswerp2));
#ifdef DEBUG
if (statp->options & RES_DEBUG)
@ -276,7 +332,8 @@ __libc_res_nsearch(res_state statp,
saved_herrno = -1;
if (dots >= statp->ndots || trailing_dot) {
ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
answer, anslen, answerp);
answer, anslen, answerp,
answerp2, nanswerp2);
if (ret > 0 || trailing_dot)
return (ret);
saved_herrno = h_errno;
@ -285,6 +342,12 @@ __libc_res_nsearch(res_state statp,
answer = *answerp;
anslen = MAXPACKET;
}
if (answerp2
&& (*answerp2 < answer || *answerp2 >= answer + anslen))
{
free (*answerp2);
*answerp2 = NULL;
}
}
/*
@ -307,7 +370,8 @@ __libc_res_nsearch(res_state statp,
ret = __libc_res_nquerydomain(statp, name, *domain,
class, type,
answer, anslen, answerp);
answer, anslen, answerp,
answerp2, nanswerp2);
if (ret > 0)
return (ret);
@ -315,6 +379,13 @@ __libc_res_nsearch(res_state statp,
answer = *answerp;
anslen = MAXPACKET;
}
if (answerp2
&& (*answerp2 < answer
|| *answerp2 >= answer + anslen))
{
free (*answerp2);
*answerp2 = NULL;
}
/*
* If no server present, give up.
@ -368,7 +439,8 @@ __libc_res_nsearch(res_state statp,
*/
if (dots && !(tried_as_is || root_on_list)) {
ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
answer, anslen, answerp);
answer, anslen, answerp,
answerp2, nanswerp2);
if (ret > 0)
return (ret);
}
@ -380,6 +452,11 @@ __libc_res_nsearch(res_state statp,
* else send back meaningless H_ERRNO, that being the one from
* the last DNSRCH we did.
*/
if (answerp2 && (*answerp2 < answer || *answerp2 >= answer + anslen))
{
free (*answerp2);
*answerp2 = NULL;
}
if (saved_herrno != -1)
RES_SET_H_ERRNO(statp, saved_herrno);
else if (got_nodata)
@ -398,7 +475,7 @@ res_nsearch(res_state statp,
int anslen) /* size of answer */
{
return __libc_res_nsearch(statp, name, class, type, answer,
anslen, NULL);
anslen, NULL, NULL, NULL);
}
libresolv_hidden_def (res_nsearch)
@ -408,12 +485,14 @@ libresolv_hidden_def (res_nsearch)
*/
static int
__libc_res_nquerydomain(res_state statp,
const char *name,
const char *domain,
int class, int type, /* class and type of query */
u_char *answer, /* buffer to put answer */
int anslen, /* size of answer */
u_char **answerp)
const char *name,
const char *domain,
int class, int type, /* class and type of query */
u_char *answer, /* buffer to put answer */
int anslen, /* size of answer */
u_char **answerp,
u_char **answerp2,
int *nanswerp2)
{
char nbuf[MAXDNAME];
const char *longname = nbuf;
@ -450,7 +529,7 @@ __libc_res_nquerydomain(res_state statp,
sprintf(nbuf, "%s.%s", name, domain);
}
return (__libc_res_nquery(statp, longname, class, type, answer,
anslen, answerp));
anslen, answerp, answerp2, nanswerp2));
}
int
@ -462,7 +541,7 @@ res_nquerydomain(res_state statp,
int anslen) /* size of answer */
{
return __libc_res_nquerydomain(statp, name, domain, class, type,
answer, anslen, NULL);
answer, anslen, NULL, NULL, NULL);
}
libresolv_hidden_def (res_nquerydomain)

View File

@ -176,10 +176,14 @@ evNowTime(struct timespec *res) {
/* Forward. */
static int send_vc(res_state, const u_char *, int,
u_char **, int *, int *, int, u_char **);
const u_char *, int,
u_char **, int *, int *, int, u_char **,
u_char **, int *, int *);
static int send_dg(res_state, const u_char *, int,
const u_char *, int,
u_char **, int *, int *, int,
int *, int *, u_char **);
int *, int *, u_char **,
u_char **, int *, int *);
#ifdef DEBUG
static void Aerror(const res_state, FILE *, const char *, int,
const struct sockaddr *);
@ -334,33 +338,41 @@ libresolv_hidden_def (res_queriesmatch)
int
__libc_res_nsend(res_state statp, const u_char *buf, int buflen,
u_char *ans, int anssiz, u_char **ansp)
const u_char *buf2, int buflen2,
u_char *ans, int anssiz, u_char **ansp, u_char **ansp2,
int *nansp2)
{
int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
int gotsomewhere, terrno, try, v_circuit, resplen, resplen2, ns, n;
if (statp->nscount == 0) {
__set_errno (ESRCH);
return (-1);
}
if (anssiz < HFIXEDSZ) {
if (anssiz < (buf2 == NULL ? 1 : 2) * HFIXEDSZ) {
__set_errno (EINVAL);
return (-1);
}
if ((statp->qhook || statp->rhook) && anssiz < MAXPACKET && ansp) {
u_char *buf = malloc (MAXPACKET);
if (buf == NULL)
return (-1);
memcpy (buf, ans, HFIXEDSZ);
*ansp = buf;
ans = buf;
anssiz = MAXPACKET;
#ifdef USE_HOOKS
if (__builtin_expect (statp->qhook || statp->rhook, 0)) {
if (anssiz < MAXPACKET && ansp) {
u_char *buf = malloc (MAXPACKET);
if (buf == NULL)
return (-1);
memcpy (buf, ans, HFIXEDSZ);
*ansp = buf;
ans = buf;
anssiz = MAXPACKET;
}
}
#endif
DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
(stdout, ";; res_send()\n"), buf, buflen);
v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
v_circuit = ((statp->options & RES_USEVC)
|| buflen > PACKETSZ
|| buflen2 > PACKETSZ);
gotsomewhere = 0;
terrno = ETIMEDOUT;
@ -442,7 +454,7 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
* Some resolvers want to even out the load on their nameservers.
* Note that RES_BLAST overrides RES_ROTATE.
*/
if ((statp->options & RES_ROTATE) != 0 &&
if (__builtin_expect ((statp->options & RES_ROTATE) != 0, 0) &&
(statp->options & RES_BLAST) == 0) {
struct sockaddr_in6 *ina;
unsigned int map;
@ -479,8 +491,9 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
if (nsap == NULL)
goto next_ns;
same_ns:
if (statp->qhook) {
same_ns:
#ifdef USE_HOOKS
if (__builtin_expect (statp->qhook != NULL, 0)) {
int done = 0, loops = 0;
do {
@ -512,6 +525,7 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
}
} while (!done);
}
#endif
#ifdef DEBUG
char tmpbuf[40];
@ -521,29 +535,34 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
ns + 1, inet_ntop(AF_INET6, &nsap->sin6_addr,
tmpbuf, sizeof (tmpbuf))));
if (v_circuit) {
if (__builtin_expect (v_circuit, 0)) {
/* Use VC; at most one attempt per server. */
try = statp->retry;
n = send_vc(statp, buf, buflen, &ans, &anssiz, &terrno,
ns, ansp);
n = send_vc(statp, buf, buflen, buf2, buflen2,
&ans, &anssiz, &terrno,
ns, ansp, ansp2, nansp2, &resplen2);
if (n < 0)
return (-1);
if (n == 0)
goto next_ns;
resplen = n;
} else {
/* Use datagrams. */
n = send_dg(statp, buf, buflen, &ans, &anssiz, &terrno,
ns, &v_circuit, &gotsomewhere, ansp);
n = send_dg(statp, buf, buflen, buf2, buflen2,
&ans, &anssiz, &terrno,
ns, &v_circuit, &gotsomewhere, ansp,
ansp2, nansp2, &resplen2);
if (n < 0)
return (-1);
if (n == 0)
goto next_ns;
if (v_circuit)
// XXX Check whether both requests failed or
// XXX whether one have been answered successfully
goto same_ns;
resplen = n;
}
resplen = n;
Dprint((statp->options & RES_DEBUG) ||
((statp->pfcode & RES_PRF_REPLY) &&
(statp->pfcode & RES_PRF_HEAD1)),
@ -553,6 +572,11 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
(statp->pfcode & RES_PRF_REPLY),
(stdout, "%s", ""),
ans, (resplen > anssiz) ? anssiz : resplen);
if (buf2 != NULL)
DprintQ((statp->options & RES_DEBUG) ||
(statp->pfcode & RES_PRF_REPLY),
(stdout, "%s", ""),
*ansp2, (resplen2 > *nansp2) ? *nansp2 : resplen2);
/*
* If we have temporarily opened a virtual circuit,
@ -563,7 +587,8 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
(statp->options & RES_STAYOPEN) == 0) {
__res_iclose(statp, false);
}
if (statp->rhook) {
#ifdef USE_HOOKS
if (__builtin_expect (statp->rhook, 0)) {
int done = 0, loops = 0;
do {
@ -593,6 +618,7 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
} while (!done);
}
#endif
return (resplen);
next_ns: ;
} /*foreach ns*/
@ -612,7 +638,8 @@ int
res_nsend(res_state statp,
const u_char *buf, int buflen, u_char *ans, int anssiz)
{
return __libc_res_nsend(statp, buf, buflen, ans, anssiz, NULL);
return __libc_res_nsend(statp, buf, buflen, NULL, 0, ans, anssiz,
NULL, NULL, NULL);
}
libresolv_hidden_def (res_nsend)
@ -620,17 +647,23 @@ libresolv_hidden_def (res_nsend)
static int
send_vc(res_state statp,
const u_char *buf, int buflen, u_char **ansp, int *anssizp,
int *terrno, int ns, u_char **anscp)
const u_char *buf, int buflen, const u_char *buf2, int buflen2,
u_char **ansp, int *anssizp,
int *terrno, int ns, u_char **anscp, u_char **ansp2, int *anssizp2,
int *resplen2)
{
const HEADER *hp = (HEADER *) buf;
const HEADER *hp2 = (HEADER *) buf2;
u_char *ans = *ansp;
int anssiz = *anssizp;
int orig_anssizp = *anssizp;
// XXX REMOVE
// int anssiz = *anssizp;
HEADER *anhp = (HEADER *) ans;
struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
int truncating, connreset, resplen, n;
struct iovec iov[2];
struct iovec iov[4];
u_short len;
u_short len2;
u_char *cp;
connreset = 0;
@ -677,11 +710,19 @@ send_vc(res_state statp,
/*
* Send length & message
*/
ns_put16((u_short)buflen, (u_char*)&len);
len = htons ((u_short) buflen);
evConsIovec(&len, INT16SZ, &iov[0]);
evConsIovec((void*)buf, buflen, &iov[1]);
if (TEMP_FAILURE_RETRY (writev(statp->_vcsock, iov, 2))
!= (INT16SZ + buflen)) {
int niov = 2;
ssize_t explen = INT16SZ + buflen;
if (buf2 != NULL) {
len2 = htons ((u_short) buflen2);
evConsIovec(&len2, INT16SZ, &iov[2]);
evConsIovec((void*)buf2, buflen2, &iov[3]);
niov = 4;
explen += INT16SZ + buflen2;
}
if (TEMP_FAILURE_RETRY (writev(statp->_vcsock, iov, niov)) != explen) {
*terrno = errno;
Perror(statp, stderr, "write failed", errno);
__res_iclose(statp, false);
@ -690,6 +731,8 @@ send_vc(res_state statp,
/*
* Receive length & response
*/
int recvresp1 = 0;
int recvresp2 = buf2 == NULL;
read_len:
cp = ans;
len = INT16SZ;
@ -718,30 +761,66 @@ send_vc(res_state statp,
}
return (0);
}
#ifdef _STRING_ARCH_unaligned
resplen = ntohs (*(uint16_t *) ans);
#else
resplen = ns_get16(ans);
if (resplen > anssiz) {
#endif
int *thisanssizp;
u_char **thisansp;
int *thisresplenp;
if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
thisanssizp = anssizp;
thisansp = anscp ?: ansp;
assert (anscp != NULL || ansp2 == NULL);
thisresplenp = &resplen;
} else {
if (*anssizp != MAXPACKET) {
/* No buffer allocated for the first
reply. We can try to use the rest
of the user-provided buffer. */
*anssizp2 = orig_anssizp - resplen;
*ansp2 = *ansp + resplen;
} else {
/* The first reply did not fit into the
user-provided buffer. Maybe the second
answer will. */
*anssizp2 = orig_anssizp;
*ansp2 = *ansp;
}
thisanssizp = anssizp2;
thisansp = ansp2;
thisresplenp = resplen2;
}
anhp = (HEADER *) *thisansp;
*thisresplenp = resplen;
if (resplen > *thisanssizp) {
/* Yes, we test ANSCP here. If we have two buffers
both will be allocatable. */
if (anscp) {
ans = malloc (MAXPACKET);
if (ans == NULL) {
u_char *newp = malloc (MAXPACKET);
if (newp == NULL) {
*terrno = ENOMEM;
__res_iclose(statp, false);
return (0);
}
anssiz = MAXPACKET;
*anssizp = MAXPACKET;
*ansp = ans;
*anscp = ans;
anhp = (HEADER *) ans;
*thisanssizp = MAXPACKET;
*thisansp = newp;
anhp = (HEADER *) newp;
len = resplen;
} else {
Dprint(statp->options & RES_DEBUG,
(stdout, ";; response truncated\n")
);
truncating = 1;
len = anssiz;
len = *thisanssizp;
}
} else
len = resplen;
if (len < HFIXEDSZ) {
/*
* Undersized message.
@ -752,7 +831,8 @@ send_vc(res_state statp,
__res_iclose(statp, false);
return (0);
}
cp = ans;
cp = *thisansp;
while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0){
cp += n;
len -= n;
@ -768,7 +848,7 @@ send_vc(res_state statp,
* Flush rest of answer so connection stays in synch.
*/
anhp->tc = 1;
len = resplen - anssiz;
len = resplen - *thisanssizp;
while (len != 0) {
char junk[PACKETSZ];
@ -787,14 +867,25 @@ send_vc(res_state statp,
* itself confused, then drop the packet and
* wait for the correct one.
*/
if (hp->id != anhp->id) {
if ((recvresp1 || hp->id != anhp->id)
&& (recvresp2 || hp2->id != anhp->id)) {
DprintQ((statp->options & RES_DEBUG) ||
(statp->pfcode & RES_PRF_REPLY),
(stdout, ";; old answer (unexpected):\n"),
ans, (resplen > anssiz) ? anssiz: resplen);
*thisansp,
(resplen > *thisanssiz) ? *thisanssiz: resplen);
goto read_len;
}
/* Mark which reply we received. */
if (recvresp1 == 0 && hp->id == anhp->id)
recvresp1 = 1;
else
recvresp2 = 1;
/* Repeat waiting if we have a second answer to arrive. */
if ((recvresp1 & recvresp2) == 0)
goto read_len;
/*
* All is well, or the error is fatal. Signal that the
* next nameserver ought not be tried.
@ -804,19 +895,20 @@ send_vc(res_state statp,
static int
send_dg(res_state statp,
const u_char *buf, int buflen, u_char **ansp, int *anssizp,
int *terrno, int ns, int *v_circuit, int *gotsomewhere, u_char **anscp)
const u_char *buf, int buflen, const u_char *buf2, int buflen2,
u_char **ansp, int *anssizp,
int *terrno, int ns, int *v_circuit, int *gotsomewhere, u_char **anscp,
u_char **ansp2, int *anssizp2, int *resplen2)
{
const HEADER *hp = (HEADER *) buf;
const HEADER *hp2 = (HEADER *) buf2;
u_char *ans = *ansp;
int anssiz = *anssizp;
HEADER *anhp = (HEADER *) ans;
int orig_anssizp = *anssizp;
struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
struct timespec now, timeout, finish;
struct pollfd pfd[1];
int ptimeout;
struct sockaddr_in6 from;
socklen_t fromlen;
int resplen, seconds, n;
if (EXT(statp).nssocks[ns] == -1) {
@ -879,6 +971,8 @@ send_dg(res_state statp,
evAddTime(&finish, &now, &timeout);
int need_recompute = 0;
int nwritten = 0;
int recvresp1 = 0;
int recvresp2 = buf2 == NULL;
pfd[0].fd = EXT(statp).nssocks[ns];
pfd[0].events = POLLOUT;
wait:
@ -918,35 +1012,73 @@ send_dg(res_state statp,
}
__set_errno (0);
if (pfd[0].revents & POLLOUT) {
if (send (pfd[0].fd, buf, buflen, MSG_NOSIGNAL) != buflen) {
ssize_t sr;
if (nwritten != 0)
sr = send (pfd[0].fd, buf2, buflen2, MSG_NOSIGNAL);
else
sr = send (pfd[0].fd, buf, buflen, MSG_NOSIGNAL);
if (sr != buflen) {
if (errno == EINTR || errno == EAGAIN)
goto recompute_resend;
Perror(statp, stderr, "send", errno);
goto err_out;
}
pfd[0].events = POLLIN;
if (nwritten != 0 || buf2 == NULL)
pfd[0].events = POLLIN;
else
pfd[0].events = POLLIN | POLLOUT;
++nwritten;
goto wait;
} else if (pfd[0].revents & POLLIN) {
fromlen = sizeof(struct sockaddr_in6);
if (anssiz < MAXPACKET
int *thisanssizp;
u_char **thisansp;
int *thisresplenp;
if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
thisanssizp = anssizp;
thisansp = anscp ?: ansp;
assert (anscp != NULL || ansp2 == NULL);
thisresplenp = &resplen;
} else {
if (*anssizp != MAXPACKET) {
/* No buffer allocated for the first
reply. We can try to use the rest
of the user-provided buffer. */
*anssizp2 = orig_anssizp - resplen;
*ansp2 = *ansp + resplen;
} else {
/* The first reply did not fit into the
user-provided buffer. Maybe the second
answer will. */
*anssizp2 = orig_anssizp;
*ansp2 = *ansp;
}
thisanssizp = anssizp2;
thisansp = ansp2;
thisresplenp = resplen2;
}
if (*thisanssizp < MAXPACKET
/* Yes, we test ANSCP here. If we have two buffers
both will be allocatable. */
&& anscp
&& (ioctl (pfd[0].fd, FIONREAD, &resplen) < 0
|| anssiz < resplen)) {
ans = malloc (MAXPACKET);
if (ans == NULL)
ans = *ansp;
else {
anssiz = MAXPACKET;
&& (ioctl (pfd[0].fd, FIONREAD, thisresplenp) < 0
|| *thisanssizp < *thisresplenp)) {
u_char *newp = malloc (MAXPACKET);
if (newp != NULL) {
*anssizp = MAXPACKET;
*ansp = ans;
*anscp = ans;
anhp = (HEADER *) ans;
*thisansp = ans = newp;
}
}
resplen = recvfrom(pfd[0].fd, (char*)ans, anssiz,0,
(struct sockaddr *)&from, &fromlen);
if (resplen <= 0) {
HEADER *anhp = (HEADER *) *thisansp;
socklen_t fromlen = sizeof(struct sockaddr_in6);
assert (sizeof(from) <= fromlen);
*thisresplenp = recvfrom(pfd[0].fd, (char*)*thisansp,
*thisanssizp, 0,
(struct sockaddr *)&from, &fromlen);
if (*thisresplenp <= 0) {
if (errno == EINTR || errno == EAGAIN) {
need_recompute = 1;
goto wait;
@ -955,17 +1087,18 @@ send_dg(res_state statp,
goto err_out;
}
*gotsomewhere = 1;
if (resplen < HFIXEDSZ) {
if (*thisresplenp < HFIXEDSZ) {
/*
* Undersized message.
*/
Dprint(statp->options & RES_DEBUG,
(stdout, ";; undersized: %d\n",
resplen));
*thisresplen));
*terrno = EMSGSIZE;
goto err_out;
}
if (hp->id != anhp->id) {
if ((recvresp1 || hp->id != anhp->id)
&& (recvresp2 || hp2->id != anhp->id)) {
/*
* response from old query, ignore it.
* XXX - potential security hazard could
@ -974,7 +1107,9 @@ send_dg(res_state statp,
DprintQ((statp->options & RES_DEBUG) ||
(statp->pfcode & RES_PRF_REPLY),
(stdout, ";; old answer:\n"),
ans, (resplen > anssiz) ? anssiz : resplen);
thisansp,
(*thisresplen > *thisanssiz)
? *thisanssiz : *thisresplen);
goto wait;
}
if (!(statp->options & RES_INSECURE1) &&
@ -987,14 +1122,16 @@ send_dg(res_state statp,
DprintQ((statp->options & RES_DEBUG) ||
(statp->pfcode & RES_PRF_REPLY),
(stdout, ";; not our server:\n"),
ans, (resplen > anssiz) ? anssiz : resplen);
thisansp,
(*thisresplen > *thisanssiz)
? *thisanssiz : *thisresplen);
goto wait;
}
#ifdef RES_USE_EDNS0
if (anhp->rcode == FORMERR
&& (statp->options & RES_USE_EDNS0) != 0U) {
/*
* Do not retry if the server do not understand
* Do not retry if the server does not understand
* EDNS0. The case has to be captured here, as
* FORMERR packet do not carry query section, hence
* res_queriesmatch() returns 0.
@ -1002,15 +1139,23 @@ send_dg(res_state statp,
DprintQ(statp->options & RES_DEBUG,
(stdout,
"server rejected query with EDNS0:\n"),
ans, (resplen > anssiz) ? anssiz : resplen);
thisans,
(*thisresplen > *thisanssiz)
? *thisanssiz : *thisresplen);
/* record the error */
statp->_flags |= RES_F_EDNS0ERR;
goto err_out;
}
#endif
if (!(statp->options & RES_INSECURE2) &&
!res_queriesmatch(buf, buf + buflen,
ans, ans + anssiz)) {
if (!(statp->options & RES_INSECURE2)
&& (recvresp1 || !res_queriesmatch(buf, buf + buflen,
*thisansp,
*thisansp
+ *thisanssizp))
&& (recvresp2 || !res_queriesmatch(buf2, buf2 + buflen2,
*thisansp,
*thisansp
+ *thisanssizp))) {
/*
* response contains wrong query? ignore it.
* XXX - potential security hazard could
@ -1019,7 +1164,9 @@ send_dg(res_state statp,
DprintQ((statp->options & RES_DEBUG) ||
(statp->pfcode & RES_PRF_REPLY),
(stdout, ";; wrong query name:\n"),
ans, (resplen > anssiz) ? anssiz : resplen);
thisansp,
(*thisresplen > *thisanssiz)
? *thisanssiz : *thisresplen);
goto wait;
}
if (anhp->rcode == SERVFAIL ||
@ -1027,7 +1174,9 @@ send_dg(res_state statp,
anhp->rcode == REFUSED) {
DprintQ(statp->options & RES_DEBUG,
(stdout, "server rejected query:\n"),
ans, (resplen > anssiz) ? anssiz : resplen);
thisansp,
(*thisresplen > *thisanssiz)
? *thisanssiz : *thisresplen);
next_ns:
__res_iclose(statp, false);
/* don't retry if called from dig */
@ -1038,7 +1187,9 @@ send_dg(res_state statp,
&& anhp->aa == 0 && anhp->ra == 0 && anhp->arcount == 0) {
DprintQ(statp->options & RES_DEBUG,
(stdout, "referred query:\n"),
ans, (resplen > anssiz) ? anssiz : resplen);
thisansp,
(*thisresplen > *thisanssiz)
? *thisanssiz : *thisresplen);
goto next_ns;
}
if (!(statp->options & RES_IGNTC) && anhp->tc) {
@ -1050,8 +1201,18 @@ send_dg(res_state statp,
(stdout, ";; truncated answer\n"));
*v_circuit = 1;
__res_iclose(statp, false);
// XXX if we have received one reply we could
// XXX use it and not repeat it over TCP...
return (1);
}
/* Mark which reply we received. */
if (recvresp1 == 0 && hp->id == anhp->id)
recvresp1 = 1;
else
recvresp2 = 1;
/* Repeat waiting if we have a second answer to arrive. */
if ((recvresp1 & recvresp2) == 0)
goto wait;
/*
* All is well, or the error is fatal. Signal that the
* next nameserver ought not be tried.

View File

@ -40,6 +40,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <errno.h>
#include <ifaddrs.h>
#include <netdb.h>
#include <nss.h>
#include <resolv.h>
#include <stdbool.h>
#include <stdio.h>
@ -91,14 +92,6 @@ struct gaih_servtuple
static const struct gaih_servtuple nullserv;
struct gaih_addrtuple
{
struct gaih_addrtuple *next;
char *name;
int family;
uint32_t addr[4];
uint32_t scopeid;
};
struct gaih_typeproto
{
@ -202,6 +195,7 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
if (herrno == NETDB_INTERNAL) \
{ \
__set_h_errno (herrno); \
_res.options = old_res_options; \
return -EAI_SYSTEM; \
} \
if (herrno == TRY_AGAIN) \
@ -246,6 +240,10 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp,
}
typedef enum nss_status (*nss_gethostbyname4_r)
(const char *name, struct gaih_addrtuple **pat,
char *buffer, size_t buflen, int *errnop,
int *h_errnop, int32_t *ttlp);
typedef enum nss_status (*nss_gethostbyname3_r)
(const char *name, int af, struct hostent *host,
char *buffer, size_t buflen, int *errnop,
@ -685,87 +683,132 @@ gaih_inet (const char *name, const struct gaih_service *service,
while (!no_more)
{
nss_gethostbyname3_r fct = NULL;
if (req->ai_flags & AI_CANONNAME)
/* No need to use this function if we do not look for
the canonical name. The function does not exist in
all NSS modules and therefore the lookup would
often fail. */
fct = __nss_lookup_function (nip, "gethostbyname3_r");
if (fct == NULL)
/* We are cheating here. The gethostbyname2_r function does
not have the same interface as gethostbyname3_r but the
extra arguments the latter takes are added at the end.
So the gethostbyname2_r code will just ignore them. */
fct = __nss_lookup_function (nip, "gethostbyname2_r");
if (fct != NULL)
nss_gethostbyname4_r fct4
= __nss_lookup_function (nip, "gethostbyname4_r");
if (fct4 != NULL)
{
if (req->ai_family == AF_INET6
|| req->ai_family == AF_UNSPEC)
{
gethosts (AF_INET6, struct in6_addr);
no_inet6_data = no_data;
inet6_status = status;
}
if (req->ai_family == AF_INET
|| req->ai_family == AF_UNSPEC
|| (req->ai_family == AF_INET6
&& (req->ai_flags & AI_V4MAPPED)
/* Avoid generating the mapped addresses if we
know we are not going to need them. */
&& ((req->ai_flags & AI_ALL) || !got_ipv6)))
{
gethosts (AF_INET, struct in_addr);
int herrno;
if (req->ai_family == AF_INET)
while (1)
{
rc = 0;
status = DL_CALL_FCT (fct4, (name, pat, tmpbuf,
tmpbuflen, &rc, &herrno,
NULL));
if (status != NSS_STATUS_TRYAGAIN
|| rc != ERANGE || herrno != NETDB_INTERNAL)
{
if (herrno == NETDB_INTERNAL)
{
__set_h_errno (herrno);
_res.options = old_res_options;
return -EAI_SYSTEM;
}
if (herrno == TRY_AGAIN)
no_data = EAI_AGAIN;
else
no_data = herrno == NO_DATA;
break;
}
tmpbuf = extend_alloca (tmpbuf,
tmpbuflen, 2 * tmpbuflen);
}
if (status == NSS_STATUS_SUCCESS)
{
canon = (*pat)->name;
while (*pat != NULL)
pat = &((*pat)->next);
}
}
else
{
nss_gethostbyname3_r fct = NULL;
if (req->ai_flags & AI_CANONNAME)
/* No need to use this function if we do not look for
the canonical name. The function does not exist in
all NSS modules and therefore the lookup would
often fail. */
fct = __nss_lookup_function (nip, "gethostbyname3_r");
if (fct == NULL)
/* We are cheating here. The gethostbyname2_r
function does not have the same interface as
gethostbyname3_r but the extra arguments the
latter takes are added at the end. So the
gethostbyname2_r code will just ignore them. */
fct = __nss_lookup_function (nip, "gethostbyname2_r");
if (fct != NULL)
{
if (req->ai_family == AF_INET6
|| req->ai_family == AF_UNSPEC)
{
gethosts (AF_INET6, struct in6_addr);
no_inet6_data = no_data;
inet6_status = status;
}
}
/* If we found one address for AF_INET or AF_INET6,
don't continue the search. */
if (inet6_status == NSS_STATUS_SUCCESS
|| status == NSS_STATUS_SUCCESS)
{
if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
if (req->ai_family == AF_INET
|| req->ai_family == AF_UNSPEC
|| (req->ai_family == AF_INET6
&& (req->ai_flags & AI_V4MAPPED)
/* Avoid generating the mapped addresses if we
know we are not going to need them. */
&& ((req->ai_flags & AI_ALL) || !got_ipv6)))
{
/* If we need the canonical name, get it
from the same service as the result. */
nss_getcanonname_r cfct;
int herrno;
gethosts (AF_INET, struct in_addr);
cfct = __nss_lookup_function (nip, "getcanonname_r");
if (cfct != NULL)
if (req->ai_family == AF_INET)
{
const size_t max_fqdn_len = 256;
char *buf = alloca (max_fqdn_len);
char *s;
if (DL_CALL_FCT (cfct, (at->name ?: name, buf,
max_fqdn_len, &s, &rc,
&herrno))
== NSS_STATUS_SUCCESS)
canon = s;
else
/* Set to name now to avoid using
gethostbyaddr. */
canon = name;
no_inet6_data = no_data;
inet6_status = status;
}
}
break;
}
/* If we found one address for AF_INET or AF_INET6,
don't continue the search. */
if (inet6_status == NSS_STATUS_SUCCESS
|| status == NSS_STATUS_SUCCESS)
{
if ((req->ai_flags & AI_CANONNAME) != 0
&& canon == NULL)
{
/* If we need the canonical name, get it
from the same service as the result. */
nss_getcanonname_r cfct;
int herrno;
/* We can have different states for AF_INET and
AF_INET6. Try to find a useful one for both. */
if (inet6_status == NSS_STATUS_TRYAGAIN)
status = NSS_STATUS_TRYAGAIN;
else if (status == NSS_STATUS_UNAVAIL
&& inet6_status != NSS_STATUS_UNAVAIL)
status = inet6_status;
cfct = __nss_lookup_function (nip,
"getcanonname_r");
if (cfct != NULL)
{
const size_t max_fqdn_len = 256;
char *buf = alloca (max_fqdn_len);
char *s;
if (DL_CALL_FCT (cfct, (at->name ?: name,
buf, max_fqdn_len,
&s, &rc, &herrno))
== NSS_STATUS_SUCCESS)
canon = s;
else
/* Set to name now to avoid using
gethostbyaddr. */
canon = name;
}
}
break;
}
/* We can have different states for AF_INET and
AF_INET6. Try to find a useful one for both. */
if (inet6_status == NSS_STATUS_TRYAGAIN)
status = NSS_STATUS_TRYAGAIN;
else if (status == NSS_STATUS_UNAVAIL
&& inet6_status != NSS_STATUS_UNAVAIL)
status = inet6_status;
}
}
if (nss_next_action (nip, status) == NSS_ACTION_RETURN)