summaryrefslogtreecommitdiff
path: root/sysdeps
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps')
-rw-r--r--sysdeps/posix/getaddrinfo.c189
1 files changed, 116 insertions, 73 deletions
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 9a27efdf83..3de83e3948 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -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)
+ int herrno;
+
+ while (1)
{
- gethosts (AF_INET6, struct in6_addr);
- no_inet6_data = no_data;
- inet6_status = status;
+ 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 (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 (status == NSS_STATUS_SUCCESS)
{
- gethosts (AF_INET, struct in_addr);
+ canon = (*pat)->name;
- if (req->ai_family == AF_INET)
+ 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;
+
+ 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;
+ }
+ }
- /* 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;
+ 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)