(I sent this diff to Éric Faurot on the 12th, but received no reply.)

Tech,

While everyone's having fun removing code from OpenSSL, I decided to add some to libasr. I implemented AI_ADDRCONFIG, a getaddrinfo() flag defined in RFC 2553/3493. Basically, it tells getaddrinfo() to skip IPvX lookups when there are no IPvX addresses configured on any interface. It is present on most other OSes. Tons of software out there have to play Autoconf games to cope with its absence (which, on OpenBSD, predates libasr if I'm not mistaken).

Noteworthy:

- I call getifaddrs() from getaddrinfo_run_async(). This should not block, so no need to change the state machine.

- I added AI_ADDRCONFIG to the default hints, like glibc does, and as was specified in RFC 2553. (RFC 3493 says nothing about default flags.)

ok? comments?

Simon


Index: include/netdb.h
===================================================================
RCS file: /cvs/src/include/netdb.h,v
retrieving revision 1.31
diff -u -p -r1.31 netdb.h
--- include/netdb.h     15 Sep 2012 00:47:08 -0000      1.31
+++ include/netdb.h     12 Apr 2014 17:40:38 -0000
@@ -167,9 +167,11 @@ extern int h_errno;
 #define AI_EXT         8       /* enable non-portable extensions */
 #define AI_NUMERICSERV 16      /* don't ever try servname lookup */
 #define AI_FQDN                32      /* return the FQDN that was resolved */
+#define AI_ADDRCONFIG  64      /* return configured address families only */
 /* valid flags for addrinfo */
 #define AI_MASK \
- (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_NUMERICSERV | AI_FQDN) + (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_NUMERICSERV | AI_FQDN | \
+     AI_ADDRCONFIG)

 #define NI_NUMERICHOST 1       /* return the host address, not the name */
 #define NI_NUMERICSERV 2       /* return the service address, not the name */
Index: lib/libc/asr/getaddrinfo_async.c
===================================================================
RCS file: /cvs/src/lib/libc/asr/getaddrinfo_async.c,v
retrieving revision 1.26
diff -u -p -r1.26 getaddrinfo_async.c
--- lib/libc/asr/getaddrinfo_async.c    26 Mar 2014 18:13:15 -0000      1.26
+++ lib/libc/asr/getaddrinfo_async.c    12 Apr 2014 17:40:39 -0000
@@ -21,6 +21,7 @@
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/nameser.h>
+#include <net/if.h>
 #ifdef YP
 #include <rpc/rpc.h>
 #include <rpcsvc/yp.h>
@@ -32,6 +33,7 @@
 #include <asr.h>
 #include <err.h>
 #include <errno.h>
+#include <ifaddrs.h>
 #include <resolv.h> /* for res_hnok */
 #include <stdlib.h>
 #include <string.h>
@@ -104,6 +106,7 @@ getaddrinfo_async(const char *hostname,
        else {
                memset(&as->as.ai.hints, 0, sizeof as->as.ai.hints);
                as->as.ai.hints.ai_family = PF_UNSPEC;
+               as->as.ai.hints.ai_flags = AI_ADDRCONFIG;
        }

        asr_ctx_unref(ac);
@@ -127,8 +130,9 @@ getaddrinfo_async_run(struct asr_query *
        char             fqdn[MAXDNAME];
        const char      *str;
        struct addrinfo *ai;
-       int              i, family, r;
+       int              i, family, r, v4, v6;
        FILE            *f;
+       struct ifaddrs  *ifa, *ifa0;
        union {
                struct sockaddr         sa;
                struct sockaddr_in      sain;
@@ -193,6 +197,44 @@ getaddrinfo_async_run(struct asr_query *
                        ar->ar_gai_errno = EAI_SERVICE;
                        async_set_state(as, ASR_STATE_HALT);
                        break;
+               }
+
+               /* Restrict result set to configured address families */
+               if (ai->ai_flags & AI_ADDRCONFIG) {
+                       if (getifaddrs(&ifa0) != 0) {
+                               ar->ar_gai_errno = EAI_FAIL;
+                               async_set_state(as, ASR_STATE_HALT);
+                               break;
+                       }
+                       v4 = 0;
+                       v6 = 0;
+                       for (ifa = ifa0; ifa != NULL; ifa = ifa->ifa_next) {
+                               if (ifa->ifa_addr->sa_family == PF_INET &&
+                                   ((struct sockaddr_in *)ifa->ifa_addr)
+                                   ->sin_addr.s_addr != INADDR_LOOPBACK)
+                                       v4 = 1;
+                               else if (ifa->ifa_addr->sa_family == PF_INET6 &&
+                                   !IN6_IS_ADDR_LOOPBACK(
+                                   &((struct sockaddr_in6 *)ifa->ifa_addr)
+                                   ->sin6_addr) &&
+                                   !((ifa->ifa_flags & IFF_LOOPBACK) &&
+                                   IN6_IS_ADDR_LINKLOCAL(
+                                   &((struct sockaddr_in6 *)ifa->ifa_addr)
+                                   ->sin6_addr)))
+                                       v6 = 1;
+                       }
+                       freeifaddrs(ifa0);
+                       if (ai->ai_family == PF_UNSPEC && !v4 && !v6 ||
+                           ai->ai_family == PF_INET && !v4 ||
+                           ai->ai_family == PF_INET6 && !v6) {
+                               ar->ar_gai_errno = EAI_NONAME;
+                               async_set_state(as, ASR_STATE_HALT);
+                               break;
+                       }
+                       if (ai->ai_family == PF_UNSPEC && v4 && !v6)
+                               ai->ai_family = PF_INET;
+                       if (ai->ai_family == PF_UNSPEC && !v4 && v6)
+                               ai->ai_family = PF_INET6;
                }

                /* Make sure there is at least a valid combination */
Index: lib/libc/net/getaddrinfo.3
===================================================================
RCS file: /cvs/src/lib/libc/net/getaddrinfo.3,v
retrieving revision 1.54
diff -u -p -r1.54 getaddrinfo.3
--- lib/libc/net/getaddrinfo.3  21 Jan 2014 03:15:45 -0000      1.54
+++ lib/libc/net/getaddrinfo.3  12 Apr 2014 17:40:39 -0000
@@ -119,6 +119,13 @@ is zero the caller will accept any proto
 is formed by
 .Tn OR Ns 'ing
 the following values:
+.It Dv AI_ADDRCONFIG
+If the
+.Dv AI_ADDRCONFIG
+bit is set, IPv4 addresses will be returned only if an IPv4 address is
+configured on an interface, and IPv6 addresses will be returned only if an IPv6 +address is configured on an interface. The loopback address is not considered
+for this case as valid as a configured address.
 .Bl -tag -width "AI_CANONNAMEXX"
 .It Dv AI_CANONNAME
 If the
@@ -219,7 +226,10 @@ behaves as if the caller provided a
 with
 .Fa ai_family
 set to
-.Dv PF_UNSPEC
+.Dv PF_UNSPEC ,
+.Fa ai_flags
+set to
+.Dv AI_ADDRCONFIG ,
 and all other elements set to zero or
 .Dv NULL .
 .Pp

Reply via email to