Author: ume
Date: Tue Jul  1 17:31:47 2014
New Revision: 268106
URL: http://svnweb.freebsd.org/changeset/base/268106

Log:
  MFS r267876 (MFC r267616):
  
  Retooling addrconfig() to exclude addresses on loopback interfaces
  when looking for configured addresses.
  This change is based upon the code from the submitter, and made
  following changes:
  - Exclude addresses assigned on interfaces which are down, like NetBSD
    does.
  - Exclude addresses assigned on interfaces which are ifdisabled.
  
  PR:           190824
  Submitted by: Justin McOmie
  Approved by:  re (marius)

Modified:
  releng/9.3/lib/libc/net/getaddrinfo.c
Directory Properties:
  releng/9.3/lib/libc/   (props changed)

Modified: releng/9.3/lib/libc/net/getaddrinfo.c
==============================================================================
--- releng/9.3/lib/libc/net/getaddrinfo.c       Tue Jul  1 17:27:48 2014        
(r268105)
+++ releng/9.3/lib/libc/net/getaddrinfo.c       Tue Jul  1 17:31:47 2014        
(r268106)
@@ -62,12 +62,15 @@ __FBSDID("$FreeBSD$");
 #include <sys/socket.h>
 #include <net/if.h>
 #include <netinet/in.h>
+#include <net/if_types.h>
+#include <ifaddrs.h>
 #include <sys/queue.h>
 #ifdef INET6
 #include <net/if_var.h>
 #include <sys/sysctl.h>
 #include <sys/ioctl.h>
-#include <netinet6/in6_var.h>  /* XXX */
+#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
 #endif
 #include <arpa/inet.h>
 #include <arpa/nameser.h>
@@ -244,6 +247,9 @@ static int get_portmatch(const struct ad
 static int get_port(struct addrinfo *, const char *, int);
 static const struct afd *find_afd(int);
 static int addrconfig(struct addrinfo *);
+#ifdef INET6
+static int is_ifdisabled(char *);
+#endif
 static void set_source(struct ai_order *, struct policyhead *);
 static int comp_dst(const void *, const void *);
 #ifdef INET6
@@ -1520,10 +1526,11 @@ find_afd(int af)
 }
 
 /*
- * post-2553: AI_ADDRCONFIG check.  if we use getipnodeby* as backend, backend
- * will take care of it.
- * the semantics of AI_ADDRCONFIG is not defined well.  we are not sure
- * if the code is right or not.
+ * post-2553: AI_ADDRCONFIG check.  Determines which address families are
+ * configured on the local system and correlates with pai->ai_family value.
+ * If an address family is not configured on the system, it will not be
+ * queried for.  For this purpose, loopback addresses are not considered
+ * configured addresses.
  *
  * XXX PF_UNSPEC -> PF_INET6 + PF_INET mapping needs to be in sync with
  * _dns_getaddrinfo.
@@ -1531,37 +1538,64 @@ find_afd(int af)
 static int
 addrconfig(struct addrinfo *pai)
 {
-       int s, af;
+       struct ifaddrs *ifaddrs, *ifa;
+       int seen_inet = 0, seen_inet6 = 0;
 
-       /*
-        * TODO:
-        * Note that implementation dependent test for address
-        * configuration should be done everytime called
-        * (or apropriate interval),
-        * because addresses will be dynamically assigned or deleted.
-        */
-       af = pai->ai_family;
-       if (af == AF_UNSPEC) {
-               if ((s = _socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
-                       af = AF_INET;
-               else {
-                       _close(s);
-                       if ((s = _socket(AF_INET, SOCK_DGRAM, 0)) < 0)
-                               af = AF_INET6;
-                       else
-                               _close(s);
+       if (getifaddrs(&ifaddrs) != 0)
+               return 0;
+
+       for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+               if (ifa->ifa_addr == NULL || (ifa->ifa_flags & IFF_UP) == 0)
+                       continue;
+               if ((ifa->ifa_flags & IFT_LOOP) != 0)
+                       continue;
+               switch (ifa->ifa_addr->sa_family) {
+               case AF_INET:
+                       seen_inet = 1;
+                       break;
+#ifdef INET6
+               case AF_INET6:
+                       if (!seen_inet6 && !is_ifdisabled(ifa->ifa_name))
+                               seen_inet6 = 1;
+                       break;
+#endif
                }
        }
-       if (af != AF_UNSPEC) {
-               if ((s = _socket(af, SOCK_DGRAM, 0)) < 0)
-                       return 0;
-               _close(s);
+       freeifaddrs(ifaddrs);
+
+       switch(pai->ai_family) {
+       case AF_INET6:
+               return seen_inet6;
+       case AF_INET:
+               return seen_inet;
+       case AF_UNSPEC:
+               if (seen_inet == seen_inet6)
+                       return seen_inet;
+               pai->ai_family = seen_inet ? AF_INET : AF_INET6;
+               return 1;
        }
-       pai->ai_family = af;
        return 1;
 }
 
 #ifdef INET6
+static int
+is_ifdisabled(char *name)
+{
+       struct in6_ndireq nd;
+       int fd;
+
+       if ((fd = _socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
+               return -1;
+       memset(&nd, 0, sizeof(nd));
+       strlcpy(nd.ifname, name, sizeof(nd.ifname));
+       if (_ioctl(fd, SIOCGIFINFO_IN6, &nd) < 0) {
+               _close(fd);
+               return -1;
+       }
+       _close(fd);
+       return ((nd.ndi.flags & ND6_IFF_IFDISABLED) != 0);
+}
+
 /* convert a string to a scope identifier. XXX: IPv6 specific */
 static int
 ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid)
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to