diff --git a/src/network/getaddrinfo.c b/src/network/getaddrinfo.c index b9439f7..664a72a 100644 --- a/src/network/getaddrinfo.c +++ b/src/network/getaddrinfo.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include "lookup.h" int getaddrinfo(const char *restrict host, const char *restrict serv, const struct addrinfo *restrict hint, struct addrinfo **restrict res) @@ -43,6 +45,46 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru } } + if (flags & AI_ADDRCONFIG) { + int cs; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + if (family != AF_INET6) { + struct sockaddr_in sa4 = { + .sin_family = AF_INET, + .sin_port = 65535, + .sin_addr.s_addr = INADDR_LOOPBACK + }; + int s = socket(AF_INET, SOCK_CLOEXEC|SOCK_DGRAM, + IPPROTO_UDP); + if (s>=0) { + int r = connect(s, (void *)&sa4, sizeof sa4); + close(s); + if (r) { + if (family == AF_INET) return EAI_NONAME; + family = AF_INET6; + } + } + } + if (family != AF_INET) { + struct sockaddr_in6 sa6 = { + .sin6_family = AF_INET6, + .sin6_port = 65535, + .sin6_addr = IN6ADDR_LOOPBACK_INIT + }; + int s = socket(AF_INET6, SOCK_CLOEXEC|SOCK_DGRAM, + IPPROTO_UDP); + if (s>=0) { + int r = connect(s, (void *)&sa6, sizeof sa6); + close(s); + if (r) { + if (family == AF_INET6) return EAI_NONAME; + family = AF_INET; + } + } + } + pthread_setcancelstate(cs, 0); + } + nservs = __lookup_serv(ports, serv, proto, socktype, flags); if (nservs < 0) return nservs;