* lib/getaddrinfo.c (is_numeric_host): New function.
(getaddrinfo): Accept and implement the AI_NUMERICHOST flag.
* modules/getaddrinfo (Depends-on): Add inet_pton.
* tests/test-getaddrinfo.c: Include <ctype.h>.
(simple): In pass 3, pass the AI_NUMERICHOST flag.
(main): Add a pass 3.
+2025-02-12 Bruno Haible <bruno@clisp.org>
+
+ getaddrinfo: Support the AI_NUMERICHOST flag.
+ * lib/getaddrinfo.c (is_numeric_host): New function.
+ (getaddrinfo): Accept and implement the AI_NUMERICHOST flag.
+ * modules/getaddrinfo (Depends-on): Add inet_pton.
+ * tests/test-getaddrinfo.c: Include <ctype.h>.
+ (simple): In pass 3, pass the AI_NUMERICHOST flag.
+ (main): Add a pass 3.
+
2025-02-12 Bruno Haible <bruno@clisp.org>
getaddrinfo tests: Test both a NULL and a non-NULL hints argument.
{
/* FIXME: Support more families. */
# if HAVE_IPV4
- if (family == PF_INET)
- return true;
+ if (family == PF_INET)
+ return true;
# endif
# if HAVE_IPV6
- if (family == PF_INET6)
- return true;
+ if (family == PF_INET6)
+ return true;
# endif
- if (family == PF_UNSPEC)
- return true;
- return false;
+ if (family == PF_UNSPEC)
+ return true;
+ return false;
+}
+
+static bool
+is_numeric_host (const char *host, int family)
+{
+# if HAVE_IPV4
+ if (family == PF_INET || family == PF_UNSPEC)
+ {
+ /* glibc supports IPv4 addresses in numbers-and-dots notation, that is,
+ also hexadecimal and octal number formats and formats that don't
+ require all four bytes to be explicitly written, via inet_aton().
+ But POSIX doesn't require support for these legacy formats. Therefore
+ we are free to use inet_pton() instead of inet_aton(). */
+ struct in_addr addr;
+ if (inet_pton (AF_INET, host, &addr))
+ return true;
+ }
+# endif
+# if HAVE_IPV6
+ if (family == PF_INET6 || family == PF_UNSPEC)
+ {
+ struct in6_addr addr;
+ if (inet_pton (AF_INET6, host, &addr))
+ return true;
+ }
+# endif
+ return false;
}
/* Translate name of a service location and/or a service name to set of
return getaddrinfo_ptr (nodename, servname, hints, res);
# endif
- if (hints && (hints->ai_flags & ~(AI_CANONNAME|AI_PASSIVE)))
+ if (hints && (hints->ai_flags & ~(AI_CANONNAME|AI_PASSIVE|AI_NUMERICHOST)))
/* FIXME: Support more flags. */
return EAI_BADFLAGS;
/* FIXME: Support other socktype. */
return EAI_SOCKTYPE; /* FIXME: Better return code? */
- if (!nodename)
+ if (nodename != NULL)
+ {
+ if (hints && (hints->ai_flags & AI_NUMERICHOST) != 0
+ && !is_numeric_host (nodename, hints->ai_family))
+ return EAI_NONAME;
+ }
+ else
{
if (!(hints->ai_flags & AI_PASSIVE))
return EAI_NONAME;
-# ifdef HAVE_IPV6
+# if HAVE_IPV6
nodename = (hints->ai_family == AF_INET6) ? "::" : "0.0.0.0";
# else
nodename = "0.0.0.0";
gettext-h [test $HAVE_GETADDRINFO = 0 || test $REPLACE_GETADDRINFO = 1 || test $HAVE_DECL_GAI_STRERROR = 0 || test $REPLACE_GAI_STRERROR = 1]
gnulib-i18n [test $HAVE_GETADDRINFO = 0 || test $REPLACE_GETADDRINFO = 1 || test $HAVE_DECL_GAI_STRERROR = 0 || test $REPLACE_GAI_STRERROR = 1]
inet_ntop [test $HAVE_GETADDRINFO = 0 || test $REPLACE_GETADDRINFO = 1]
+inet_pton [test $HAVE_GETADDRINFO = 0 || test $REPLACE_GETADDRINFO = 1]
snprintf [test $HAVE_GETADDRINFO = 0 || test $REPLACE_GETADDRINFO = 1]
bool [test $HAVE_GETADDRINFO = 0 || test $REPLACE_GETADDRINFO = 1]
strdup [test $HAVE_GETADDRINFO = 0 || test $REPLACE_GETADDRINFO = 1]
#endif
#include <arpa/inet.h>
+#include <ctype.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
else
{
memset (&hints, 0, sizeof (hints));
- hints.ai_flags = AI_CANONNAME;
+ hints.ai_flags = AI_CANONNAME | (pass == 3 ? AI_NUMERICHOST : 0);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints_p = &hints;
dbgprintf ("res %d: %s\n", res, gai_strerror (res));
+ if (pass == 3 && ! isdigit (host[0]))
+ return res != EAI_NONAME;
+
if (res != 0)
{
/* EAI_AGAIN is returned if no network is available. Don't fail
#define SERV3 "http"
#define HOST4 "google.org"
#define SERV4 "ldap"
+#if HAVE_IPV4
+# define NUMERICHOSTV4 "1.2.3.4"
+#endif
+#if HAVE_IPV6
+# define NUMERICHOSTV6 "2001:db8:3333:4444:CCCC:DDDD:EEEE:FFFF"
+#endif
int main (void)
{
+ simple (2, HOST1, SERV1)
+ simple (2, HOST2, SERV2)
+ simple (2, HOST3, SERV3)
- + simple (2, HOST4, SERV4));
+ + simple (2, HOST4, SERV4)
+#if HAVE_IPV4
+ + simple (3, NUMERICHOSTV4, SERV1)
+#endif
+#if HAVE_IPV6
+ + simple (3, NUMERICHOSTV6, SERV1)
+#endif
+ + simple (3, HOST1, SERV1)
+ + simple (3, HOST2, SERV2)
+ + simple (3, HOST3, SERV3)
+ + simple (3, HOST4, SERV4));
}