@@ -256,7 +256,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
{ \
__resolv_context_put (res_ctx); \
result = -EAI_MEMORY; \
- goto free_and_return; \
+ goto done; \
} \
} \
if (status == NSS_STATUS_NOTFOUND \
@@ -266,7 +266,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
{ \
__resolv_context_put (res_ctx); \
result = -EAI_SYSTEM; \
- goto free_and_return; \
+ goto done; \
} \
if (h_errno == TRY_AGAIN) \
no_data = EAI_AGAIN; \
@@ -279,7 +279,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
{ \
__resolv_context_put (res_ctx); \
result = -EAI_SYSTEM; \
- goto free_and_return; \
+ goto done; \
} \
*pat = addrmem; \
\
@@ -290,7 +290,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
{ \
__resolv_context_put (res_ctx); \
result = -EAI_SYSTEM; \
- goto free_and_return; \
+ goto done; \
} \
canon = canonbuf; \
} \
@@ -323,6 +323,123 @@ getcanonname (nss_action_list nip, struct gaih_addrtuple *at, const char *name)
return __strdup (name);
}
+static int
+process_list (const struct addrinfo *req, struct gaih_addrtuple *at,
+ struct gaih_servtuple *st, const char *canon, bool canon_alloc,
+ bool got_ipv6, struct addrinfo **pai, unsigned int *naddrs)
+{
+ struct gaih_servtuple *st2;
+ struct gaih_addrtuple *at2 = at;
+ size_t socklen;
+ sa_family_t family;
+
+ /*
+ buffer is the size of an unformatted IPv6 address in printable format.
+ */
+ for (at2 = at; at2 != NULL; at2 = at2->next)
+ {
+ /* Only the first entry gets the canonical name. */
+ if (at2 == at && (req->ai_flags & AI_CANONNAME) != 0)
+ {
+ bool do_idn = req->ai_flags & AI_CANONIDN;
+ if (do_idn)
+ {
+ char *out;
+ int rc = __idna_from_dns_encoding (canon, &out);
+ if (rc == 0)
+ canon = out;
+ else if (rc == EAI_IDN_ENCODE)
+ /* Use the punycode name as a fallback. */
+ do_idn = false;
+ else
+ return -rc;
+ }
+ if (!do_idn)
+ {
+ if (!canon_alloc)
+ {
+ canon = __strdup (canon);
+ if (canon == NULL)
+ return -EAI_MEMORY;
+ }
+ }
+ }
+
+ family = at2->family;
+ if (family == AF_INET6)
+ {
+ socklen = sizeof (struct sockaddr_in6);
+
+ /* If we looked up IPv4 mapped address discard them here if
+ the caller isn't interested in all address and we have
+ found at least one IPv6 address. */
+ if (got_ipv6
+ && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED
+ && IN6_IS_ADDR_V4MAPPED (at2->addr))
+ continue;
+ }
+ else
+ socklen = sizeof (struct sockaddr_in);
+
+ for (st2 = st; st2 != NULL; st2 = st2->next)
+ {
+ struct addrinfo *ai;
+ ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
+ if (ai == NULL)
+ {
+ free ((char *) canon);
+ return -EAI_MEMORY;
+ }
+
+ ai->ai_flags = req->ai_flags;
+ ai->ai_family = family;
+ ai->ai_socktype = st2->socktype;
+ ai->ai_protocol = st2->protocol;
+ ai->ai_addrlen = socklen;
+ ai->ai_addr = (void *) (ai + 1);
+
+ /* We only add the canonical name once. */
+ ai->ai_canonname = (char *) canon;
+ canon = NULL;
+
+#ifdef _HAVE_SA_LEN
+ ai->ai_addr->sa_len = socklen;
+#endif /* _HAVE_SA_LEN */
+ ai->ai_addr->sa_family = family;
+
+ /* In case of an allocation error the list must be NULL
+ terminated. */
+ ai->ai_next = NULL;
+
+ if (family == AF_INET6)
+ {
+ struct sockaddr_in6 *sin6p =
+ (struct sockaddr_in6 *) ai->ai_addr;
+
+ sin6p->sin6_port = st2->port;
+ sin6p->sin6_flowinfo = 0;
+ memcpy (&sin6p->sin6_addr,
+ at2->addr, sizeof (struct in6_addr));
+ sin6p->sin6_scope_id = at2->scopeid;
+ }
+ else
+ {
+ struct sockaddr_in *sinp =
+ (struct sockaddr_in *) ai->ai_addr;
+ sinp->sin_port = st2->port;
+ memcpy (&sinp->sin_addr,
+ at2->addr, sizeof (struct in_addr));
+ memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
+ }
+
+ pai = &(ai->ai_next);
+ }
+
+ ++*naddrs;
+ }
+ return 0;
+}
+
static int
gaih_inet (const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai,
@@ -479,7 +596,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
else
{
result = -EAI_ADDRFAMILY;
- goto free_and_return;
+ goto done;
}
if (req->ai_flags & AI_CANONNAME)
@@ -507,7 +624,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
else
{
result = -EAI_ADDRFAMILY;
- goto free_and_return;
+ goto done;
}
if (scope_delim != NULL
@@ -516,7 +633,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
&at->scopeid) != 0)
{
result = -EAI_NONAME;
- goto free_and_return;
+ goto done;
}
if (req->ai_flags & AI_CANONNAME)
@@ -555,7 +672,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (!scratch_buffer_grow (tmpbuf))
{
result = -EAI_MEMORY;
- goto free_and_return;
+ goto done;
}
}
@@ -568,7 +685,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
(req, AF_INET, h, &addrmem))
{
result = -EAI_MEMORY;
- goto free_and_return;
+ goto done;
}
*pat = addrmem;
}
@@ -578,7 +695,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
result = -EAI_NODATA;
else
result = -EAI_NONAME;
- goto free_and_return;
+ goto done;
}
}
else
@@ -592,10 +709,13 @@ gaih_inet (const char *name, const struct gaih_service *service,
The name is known, though. */
result = -EAI_NODATA;
- goto free_and_return;
+ goto done;
}
- goto process_list;
+ if (at->family == AF_UNSPEC)
+ result = -EAI_NONAME;
+
+ goto done;
}
#ifdef USE_NSCD
@@ -619,7 +739,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (addrmem == NULL)
{
result = -EAI_MEMORY;
- goto free_and_return;
+ goto done;
}
struct gaih_addrtuple *addrfree = addrmem;
@@ -654,7 +774,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
if (canonbuf == NULL)
{
result = -EAI_MEMORY;
- goto free_and_return;
+ goto done;
}
canon = (*pat)->name = canonbuf;
}
@@ -687,16 +807,13 @@ gaih_inet (const char *name, const struct gaih_service *service,
free (air);
if (at->family == AF_UNSPEC)
- {
- result = -EAI_NONAME;
- goto free_and_return;
- }
+ result = -EAI_NONAME;
- goto process_list;
+ goto done;
}
else if (err == 0)
/* The database contains a negative entry. */
- goto free_and_return;
+ goto done;
else if (__nss_not_use_nscd_hosts == 0)
{
if (h_errno == NETDB_INTERNAL && errno == ENOMEM)
@@ -706,7 +823,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
else
result = -EAI_SYSTEM;
- goto free_and_return;
+ goto done;
}
}
#endif
@@ -755,7 +872,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
{
__resolv_context_put (res_ctx);
result = -EAI_MEMORY;
- goto free_and_return;
+ goto done;
}
}
@@ -854,7 +971,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
{
__resolv_context_put (res_ctx);
result = -EAI_MEMORY;
- goto free_and_return;
+ goto done;
}
canon = canonbuf;
}
@@ -903,7 +1020,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
&& h_errno == NETDB_INTERNAL)
{
result = -EAI_SYSTEM;
- goto free_and_return;
+ goto done;
}
if (no_data != 0 && no_inet6_data != 0)
@@ -916,16 +1033,12 @@ gaih_inet (const char *name, const struct gaih_service *service,
is known, though. */
result = -EAI_NODATA;
- goto free_and_return;
+ goto done;
}
}
- process_list:
if (at->family == AF_UNSPEC)
- {
- result = -EAI_NONAME;
- goto free_and_return;
- }
+ result = -EAI_NONAME;
}
else
{
@@ -955,142 +1068,16 @@ gaih_inet (const char *name, const struct gaih_service *service,
}
}
- {
- struct gaih_servtuple *st2;
- struct gaih_addrtuple *at2 = at;
- size_t socklen;
- sa_family_t family;
-
- /*
- buffer is the size of an unformatted IPv6 address in printable format.
- */
- while (at2 != NULL)
- {
- /* Only the first entry gets the canonical name. */
- if (at2 == at && (req->ai_flags & AI_CANONNAME) != 0)
- {
- if (canon == NULL)
- /* If the canonical name cannot be determined, use
- the passed in string. */
- canon = orig_name;
-
- bool do_idn = req->ai_flags & AI_CANONIDN;
- if (do_idn)
- {
- char *out;
- int rc = __idna_from_dns_encoding (canon, &out);
- if (rc == 0)
- canon = out;
- else if (rc == EAI_IDN_ENCODE)
- /* Use the punycode name as a fallback. */
- do_idn = false;
- else
- {
- result = -rc;
- goto free_and_return;
- }
- }
- if (!do_idn)
- {
- if (canonbuf != NULL)
- /* We already allocated the string using malloc, but
- the buffer is now owned by canon. */
- canonbuf = NULL;
- else
- {
- canon = __strdup (canon);
- if (canon == NULL)
- {
- result = -EAI_MEMORY;
- goto free_and_return;
- }
- }
- }
- }
-
- family = at2->family;
- if (family == AF_INET6)
- {
- socklen = sizeof (struct sockaddr_in6);
-
- /* If we looked up IPv4 mapped address discard them here if
- the caller isn't interested in all address and we have
- found at least one IPv6 address. */
- if (got_ipv6
- && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED
- && IN6_IS_ADDR_V4MAPPED (at2->addr))
- goto ignore;
- }
- else
- socklen = sizeof (struct sockaddr_in);
-
- for (st2 = st; st2 != NULL; st2 = st2->next)
- {
- struct addrinfo *ai;
- ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
- if (ai == NULL)
- {
- free ((char *) canon);
- result = -EAI_MEMORY;
- goto free_and_return;
- }
-
- ai->ai_flags = req->ai_flags;
- ai->ai_family = family;
- ai->ai_socktype = st2->socktype;
- ai->ai_protocol = st2->protocol;
- ai->ai_addrlen = socklen;
- ai->ai_addr = (void *) (ai + 1);
-
- /* We only add the canonical name once. */
- ai->ai_canonname = (char *) canon;
- canon = NULL;
-
-#ifdef _HAVE_SA_LEN
- ai->ai_addr->sa_len = socklen;
-#endif /* _HAVE_SA_LEN */
- ai->ai_addr->sa_family = family;
-
- /* In case of an allocation error the list must be NULL
- terminated. */
- ai->ai_next = NULL;
-
- if (family == AF_INET6)
- {
- struct sockaddr_in6 *sin6p =
- (struct sockaddr_in6 *) ai->ai_addr;
-
- sin6p->sin6_port = st2->port;
- sin6p->sin6_flowinfo = 0;
- memcpy (&sin6p->sin6_addr,
- at2->addr, sizeof (struct in6_addr));
- sin6p->sin6_scope_id = at2->scopeid;
- }
- else
- {
- struct sockaddr_in *sinp =
- (struct sockaddr_in *) ai->ai_addr;
- sinp->sin_port = st2->port;
- memcpy (&sinp->sin_addr,
- at2->addr, sizeof (struct in_addr));
- memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
- }
-
- pai = &(ai->ai_next);
- }
-
- ++*naddrs;
-
- ignore:
- at2 = at2->next;
- }
- }
+done:
+ if (result == 0)
+ result = process_list (req, at, st, canon ?: orig_name, canonbuf != NULL,
+ got_ipv6, pai, naddrs);
- free_and_return:
if (malloc_name)
free ((char *) name);
free (addrmem);
- free (canonbuf);
+ if (result != 0)
+ free (canonbuf);
return result;
}