summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2018-07-14 20:20:19 -0400
committerRich Felker <dalias@aerifal.cx>2018-07-14 20:57:24 -0400
commit187bcc3bf40bf187c5d76d206b04028fa8ca403b (patch)
treebb1420a891d816d56f33bfe54c38ecccb3b9397a /src
parent9cad27a3dc1a4eb349b6591e4dc8cc89dce32277 (diff)
downloadmusl-187bcc3bf40bf187c5d76d206b04028fa8ca403b.tar.gz
implement getaddrinfo's AI_ADDRCONFIG flag
this flag is notoriously under-/mis-specified, and in the past it was implemented as a nop, essentially considering the absence of a loopback interface with 127.0.0.1 and ::1 addresses an unsupported configuration. however, common real-world container environments omit IPv6 support (even for the network-namespaced loopback interface), and some kernels omit IPv6 support entirely. future systems on the other hand might omit IPv4 entirely. treat these as supported configurations and suppress results of the unconfigured/unsupported address families when AI_ADDRCONFIG is requested. use routability of the loopback address to make the determination; unlike other implementations, we do not exclude loopback from the "an address is configured" condition, since there is no basis in the specification for such exclusion. obtaining a result with AI_ADDRCONFIG does not imply routability of the result, and applications must still be able to cope with unroutable results even if they pass AI_ADDRCONFIG.
Diffstat (limited to 'src')
-rw-r--r--src/network/getaddrinfo.c39
1 files changed, 39 insertions, 0 deletions
diff --git a/src/network/getaddrinfo.c b/src/network/getaddrinfo.c
index b9439f77..ba26847a 100644
--- a/src/network/getaddrinfo.c
+++ b/src/network/getaddrinfo.c
@@ -3,6 +3,10 @@
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <endian.h>
+#include <errno.h>
#include "lookup.h"
int getaddrinfo(const char *restrict host, const char *restrict serv, const struct addrinfo *restrict hint, struct addrinfo **restrict res)
@@ -43,6 +47,41 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru
}
}
+ if (flags & AI_ADDRCONFIG) {
+ /* Define the "an address is configured" condition for address
+ * families via ability to create a socket for the family plus
+ * routability of the loopback address for the family. */
+ static const struct sockaddr_in lo4 = {
+ .sin_family = AF_INET, .sin_port = 65535,
+ .sin_addr.s_addr = __BYTE_ORDER == __BIG_ENDIAN
+ ? 0x7f000001 : 0x0100007f
+ };
+ static const struct sockaddr_in6 lo6 = {
+ .sin6_family = AF_INET6, .sin6_port = 65535,
+ .sin6_addr = IN6ADDR_LOOPBACK_INIT
+ };
+ int tf[2] = { AF_INET, AF_INET6 };
+ const void *ta[2] = { &lo4, &lo6 };
+ socklen_t tl[2] = { sizeof lo4, sizeof lo6 };
+ for (i=0; i<2; i++) {
+ if (family==tf[1-i]) continue;
+ int s = socket(tf[i], SOCK_CLOEXEC|SOCK_DGRAM,
+ IPPROTO_UDP);
+ if (s>=0) {
+ int cs;
+ pthread_setcancelstate(
+ PTHREAD_CANCEL_DISABLE, &cs);
+ int r = connect(s, ta[i], tl[i]);
+ pthread_setcancelstate(cs, 0);
+ close(s);
+ if (!r) continue;
+ }
+ if (errno != EAFNOSUPPORT) return EAI_SYSTEM;
+ if (family == tf[i]) return EAI_NONAME;
+ family = tf[1-i];
+ }
+ }
+
nservs = __lookup_serv(ports, serv, proto, socktype, flags);
if (nservs < 0) return nservs;