summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorume <ume@FreeBSD.org>2014-06-25 17:10:26 +0000
committerume <ume@FreeBSD.org>2014-06-25 17:10:26 +0000
commitec8b74659a691e0c2c44e39f4d45de0e3028e851 (patch)
treec90a962403faeaf6c70938436b828702f470ddd7 /lib
parenta526189dcb673580da1396915933002abd7cb464 (diff)
downloadFreeBSD-src-ec8b74659a691e0c2c44e39f4d45de0e3028e851.zip
FreeBSD-src-ec8b74659a691e0c2c44e39f4d45de0e3028e851.tar.gz
MFC r267616, 267640:
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. Use SOCK_CLOEXEC. PR: 190824 Submitted by: Justin McOmie
Diffstat (limited to 'lib')
-rw-r--r--lib/libc/net/getaddrinfo.c91
1 files changed, 62 insertions, 29 deletions
diff --git a/lib/libc/net/getaddrinfo.c b/lib/libc/net/getaddrinfo.c
index 00ab796..22b4103 100644
--- a/lib/libc/net/getaddrinfo.c
+++ b/lib/libc/net/getaddrinfo.c
@@ -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>
@@ -245,6 +248,9 @@ static int get_portmatch(const struct addrinfo *, const char *);
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
@@ -1525,10 +1531,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.
@@ -1536,38 +1543,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 | SOCK_CLOEXEC, 0)) < 0)
- af = AF_INET;
- else {
- _close(s);
- if ((s = _socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC,
- 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 | SOCK_CLOEXEC, 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 | SOCK_CLOEXEC, 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)
OpenPOWER on IntegriCloud