]> git.ipfire.org Git - thirdparty/gnulib.git/commitdiff
getaddrinfo: Support the AI_NUMERICHOST flag.
authorBruno Haible <bruno@clisp.org>
Wed, 12 Feb 2025 19:03:29 +0000 (20:03 +0100)
committerBruno Haible <bruno@clisp.org>
Wed, 12 Feb 2025 19:03:29 +0000 (20:03 +0100)
* 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.

ChangeLog
lib/getaddrinfo.c
modules/getaddrinfo
tests/test-getaddrinfo.c

index 70d5334434a735879dce68c2add2650f13d0b8bf..fec9aab6af5ff4aa060c936c15b9ed5e22052899 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+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.
index cd045c5121f28b520b29f22c85d898138791b65b..4a0aeab9f12a328e1cd28d81c911cabef93deba5 100644 (file)
@@ -169,16 +169,43 @@ validate_family (int family)
 {
   /* 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
@@ -213,7 +240,7 @@ getaddrinfo (const char *restrict nodename,
     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;
 
@@ -225,12 +252,18 @@ getaddrinfo (const char *restrict nodename,
     /* 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";
index b31d395635af9c5280aeb37887d77cf8df8ef7ec..265886e6c02618ffb691640d6f8f5dfc7a97c5b7 100644 (file)
@@ -13,6 +13,7 @@ extensions
 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]
index d09c4c1a2410231404c813b7ce8b8b1de7276918..8f35e6abc6c889e2610874f19dde90f5c3528552 100644 (file)
@@ -34,6 +34,7 @@ SIGNATURE_CHECK (getaddrinfo, int, (char const *, char const *,
 #endif
 
 #include <arpa/inet.h>
+#include <ctype.h>
 #include <errno.h>
 #include <netinet/in.h>
 #include <stdio.h>
@@ -81,7 +82,7 @@ simple (int pass, char const *host, char const *service)
   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;
@@ -92,6 +93,9 @@ simple (int pass, char const *host, char const *service)
 
   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
@@ -171,6 +175,12 @@ simple (int pass, char const *host, char const *service)
 #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)
 {
@@ -183,5 +193,15 @@ 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));
 }