summaryrefslogtreecommitdiff
path: root/nss
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2008-05-10 23:27:39 +0000
committerUlrich Drepper <drepper@redhat.com>2008-05-10 23:27:39 +0000
commit1eb946b93509b94db2bddce741f2f3b483418a6d (patch)
tree054e49d0b1be9539a0d778c4b1a6252ac4d68523 /nss
parenta82e8bb8d0b51d30cb0d8d24f0ff0f72066cf2ce (diff)
* 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.
Diffstat (limited to 'nss')
-rw-r--r--nss/Versions1
-rw-r--r--nss/nss.h14
-rw-r--r--nss/nss_files/files-hosts.c133
3 files changed, 139 insertions, 9 deletions
diff --git a/nss/Versions b/nss/Versions
index 8f2f0fb371..f7f0e56979 100644
--- a/nss/Versions
+++ b/nss/Versions
@@ -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;
diff --git a/nss/nss.h b/nss/nss.h
index f5c12afab6..611b2580ad 100644
--- a/nss/nss.h
+++ b/nss/nss.h
@@ -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
diff --git a/nss/nss_files/files-hosts.c b/nss/nss_files/files-hosts.c
index b06467225b..7b69d47fcb 100644
--- a/nss/nss_files/files-hosts.c
+++ b/nss/nss_files/files-hosts.c
@@ -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
-#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;
+}