KO Myung-Hun wrote:
> +  if (hints && (hints->ai_flags & AI_NUMERICHOST))
> +    {
> +      int valid = 0;
> +
> +# ifdef HAVE_IPV6
> +      valid |= !valid &&
> +               (hints->ai_family == AF_INET6 ||
> +                hints->ai_family == AF_UNSPEC) &&
> +               inet_pton (AF_INET6, nodename, &addr6) == 1;
> +# endif
> +# ifdef HAVE_IPV4
> +      valid |= !valid &&
> +               (hints->ai_family == AF_INET ||
> +                hints->ai_family == AF_UNSPEC) &&
> +               inet_pton (AF_INET, nodename, &addr4) == 1;
> +# endif
> +      if (!valid)
> +        return EAI_NONAME;
> +    }

The logic seems right, but is hard to understand when written in this way.
With a separate function, it becomes much clearer.

>        if (res == EAI_NONAME)
> -        return 0;
> +        return (flags & (AI_NUMERICHOST | AI_NUMERICSERV)) ? 2 : 0;

This does only part of the necessary checks.

I prefer to commit this patch. Tested on a glibc system, with
'gl_cv_func_getaddrinfo=no ./configure ...'


2025-02-12  Bruno Haible  <[email protected]>

        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.

diff --git a/lib/getaddrinfo.c b/lib/getaddrinfo.c
index cd045c5121..4a0aeab9f1 100644
--- a/lib/getaddrinfo.c
+++ b/lib/getaddrinfo.c
@@ -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";
diff --git a/modules/getaddrinfo b/modules/getaddrinfo
index b31d395635..265886e6c0 100644
--- a/modules/getaddrinfo
+++ b/modules/getaddrinfo
@@ -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]
diff --git a/tests/test-getaddrinfo.c b/tests/test-getaddrinfo.c
index d09c4c1a24..8f35e6abc6 100644
--- a/tests/test-getaddrinfo.c
+++ b/tests/test-getaddrinfo.c
@@ -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));
 }




Reply via email to