Hi, I don't like AI_ADDRCONFIG. It's useless as specified, and making it useful requires interpretations and deviations.
My understanding is that its goal is to solve a real world problem, as in avoiding useless and potentially harmful DNS requests. So why not make it do that, and just that? Because I don't think the end goal is preventing IPv6 link-local communication, or communication with ::1 or "localhost", etc. What do you folks think? The diff below seems to work well, as a bonus it avoids changing the hints passed by the caller, and extends the use of local variable "ai" ("ai" could probably be renamed to "hints", btw). Index: asr/getaddrinfo_async.c =================================================================== RCS file: /cvs/src/lib/libc/asr/getaddrinfo_async.c,v retrieving revision 1.27 diff -u -p -r1.27 getaddrinfo_async.c --- asr/getaddrinfo_async.c 28 Apr 2014 21:38:59 -0000 1.27 +++ asr/getaddrinfo_async.c 2 May 2014 06:25:03 -0000 @@ -129,7 +129,7 @@ getaddrinfo_async_run(struct asr_query * #endif char fqdn[MAXDNAME]; const char *str; - struct addrinfo *ai; + struct addrinfo *ai, *saved_ai, addrconfig_hints; int i, family, r, v4, v6; FILE *f; struct ifaddrs *ifa, *ifa0; @@ -157,7 +157,7 @@ getaddrinfo_async_run(struct asr_query * break; } - ai = &as->as.ai.hints; + ai = saved_ai = &as->as.ai.hints; if (ai->ai_addrlen || ai->ai_canonname || @@ -219,17 +219,12 @@ getaddrinfo_async_run(struct asr_query * 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; - } + + memcpy(&addrconfig_hints, ai, sizeof(addrconfig_hints)); if (ai->ai_family == PF_UNSPEC && v4 && !v6) - ai->ai_family = PF_INET; + addrconfig_hints.ai_family = PF_INET; if (ai->ai_family == PF_UNSPEC && !v4 && v6) - ai->ai_family = PF_INET6; + addrconfig_hints.ai_family = PF_INET6; } /* Make sure there is at least a valid combination */ @@ -246,10 +241,10 @@ getaddrinfo_async_run(struct asr_query * if (ai->ai_protocol == 0 || ai->ai_protocol == IPPROTO_UDP) as->as.ai.port_udp = get_port(as->as.ai.servname, "udp", - as->as.ai.hints.ai_flags & AI_NUMERICSERV); + ai->ai_flags & AI_NUMERICSERV); if (ai->ai_protocol == 0 || ai->ai_protocol == IPPROTO_TCP) as->as.ai.port_tcp = get_port(as->as.ai.servname, "tcp", - as->as.ai.hints.ai_flags & AI_NUMERICSERV); + ai->ai_flags & AI_NUMERICSERV); if (as->as.ai.port_tcp == -2 || as->as.ai.port_udp == -2 || (as->as.ai.port_tcp == -1 && as->as.ai.port_udp == -1) || (ai->ai_protocol && (as->as.ai.port_udp == -1 || @@ -322,13 +317,24 @@ getaddrinfo_async_run(struct asr_query * async_set_state(as, ASR_STATE_NOT_FOUND); break; } + ai = saved_ai; + /* AF filtering is only for dns */ + if (ai->ai_flags & AI_ADDRCONFIG && AS_DB(as) == ASR_DB_DNS) { + if (ai->ai_family == PF_UNSPEC && !v4 && !v6 || + ai->ai_family == PF_INET && !v4 || + ai->ai_family == PF_INET6 && !v6) { + async_set_state(as, ASR_STATE_NEXT_DB); + break; + } + ai = &addrconfig_hints; + } as->as_family_idx = 0; async_set_state(as, ASR_STATE_SAME_DB); break; case ASR_STATE_NEXT_FAMILY: as->as_family_idx += 1; - if (as->as.ai.hints.ai_family != AF_UNSPEC || + if (ai->ai_family != AF_UNSPEC || AS_FAMILY(as) == -1) { /* The family was specified, or we have tried all * families with this DB. @@ -384,8 +390,8 @@ getaddrinfo_async_run(struct asr_query * break; } - family = (as->as.ai.hints.ai_family == AF_UNSPEC) ? - AS_FAMILY(as) : as->as.ai.hints.ai_family; + family = (ai->ai_family == AF_UNSPEC) ? + AS_FAMILY(as) : ai->ai_family; as->as.ai.subq = res_query_async_ctx(as->as.ai.fqdn, C_IN, (family == AF_INET6) ? T_AAAA : T_A, @@ -408,8 +414,8 @@ getaddrinfo_async_run(struct asr_query * async_set_state(as, ASR_STATE_NEXT_DB); break; } - family = (as->as.ai.hints.ai_family == AF_UNSPEC) ? - AS_FAMILY(as) : as->as.ai.hints.ai_family; + family = (ai->ai_family == AF_UNSPEC) ? + AS_FAMILY(as) : ai->ai_family; r = addrinfo_from_file(as, family, f); if (r == -1) { @@ -429,8 +435,8 @@ getaddrinfo_async_run(struct asr_query * async_set_state(as, ASR_STATE_NEXT_DB); break; } - family = (as->as.ai.hints.ai_family == AF_UNSPEC) ? - AS_FAMILY(as) : as->as.ai.hints.ai_family; + family = (ai->ai_family == AF_UNSPEC) ? + AS_FAMILY(as) : ai->ai_family; name = as->as.ai.hostname; Index: net/getaddrinfo.3 =================================================================== RCS file: /cvs/src/lib/libc/net/getaddrinfo.3,v retrieving revision 1.55 diff -u -p -r1.55 getaddrinfo.3 --- net/getaddrinfo.3 28 Apr 2014 21:38:59 -0000 1.55 +++ net/getaddrinfo.3 2 May 2014 06:50:01 -0000 @@ -123,9 +123,10 @@ 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. +bit is set, DNS requests for IPv4 addresses will be performed only if an +IPv4 address is configured on an interface, and DNS requetsts for IPv6 +addresses will be performed only if an IPv6 address is configured on an +interface. Addresses on a loopback interface and link-local IPv6 addresses are not considered valid as configured addresses. .It Dv AI_CANONNAME -- jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF DDCC 0DFA 74AE 1524 E7EE