Download raw body.
Hi,
On Tue, 23 Jun 2026 20:03:58 +0200
Florian Obser <florian@openbsd.org> wrote:
> On 2025-12-13 14:02 +09, YASUOKA Masahiko <yasuoka@openbsd.org> wrote:
>> Hello,
>>
>> On Wed, 17 Sep 2025 12:00:09 +0900 (JST)
>> YASUOKA Masahiko <yasuoka@openbsd.org> wrote:
>>> On Tue, 16 Sep 2025 13:27:36 +0200
>>> Florian Obser <florian@openbsd.org> wrote:
>>>> Coming back to an old email.
>>>>
>>>> On 2025-03-07 09:43 +09, YASUOKA Masahiko <yasuoka@openbsd.org> wrote:
>>>>> Hello,
>>>>>
>>>>> sshd's config has the following default values,
>>>>>
>>>>> #AddressFamily any
>>>>> #ListenAddress 0.0.0.0
>>>>> #ListenAddress ::
>>>>>
>>>>> If we configure "family" in /etc/resolv.conf, sshd will stop listening
>>>>> 0.0.0.0 or :: following the "family" config.
>>>>>
>>>>> - "family inet4" => stop listening on ::
>>>>> - "family inet6" => stop listening on 0.0.0.0
>>>>>
>>>>> This is because getaddrinfo() doesn't convert a numeric address if the
>>>>> family is disabled and NI_NUMERIC_HOST is not specified.
>>>>>
>>>>> I don't think this is correct behavior.
>>>>
>>>> I don't think this is correct behaviour either.
>>
>> Other than this problem, getaddrinfo can receive NULL for hostname.
>> Then returning "::" and "0.0.0.0" is expected when AI_PASSIVE. I
>> suppose that "family" in "resolv.conf" must not affect this behavior
>> in this case as well, but our resolver changes the result. (Only
>> "0.0.0.0" is returned when "family inet4" is configured).
>>
>> Also, because the default sshd_config doesn't have "ListenAddress"
>> line, the previous diff hasn't fixed the original problem of sshd.
>>
>> The diff fixes the problem. It prepares the constant variables for
>> IPv6 but not for IPv4 because I avoided to use htonl() in the
>> initializers.
>>
>
> I think (and I've also checked with deraadt at g2k26) that using htonl()
> in the initializers is fine, it's a local variable.
Thanks for the review. I updated the diff so it use const variables
for IPv4 as well.
> I'd prefer to have the v4 case symmetric to the v6 case.
>
> I agree the change makes sense and I also like the simplification of the
> code.
>
>> We can reproduce the problem in regress/lib/libc/getaddrinfo/ by
>> modifying "/etc/resolv.conf".
ok?
Index: lib/libc/asr/getaddrinfo_async.c
===================================================================
RCS file: /cvs/src/lib/libc/asr/getaddrinfo_async.c,v
diff -u -p -r1.67 getaddrinfo_async.c
--- lib/libc/asr/getaddrinfo_async.c 23 Jun 2026 11:36:36 -0000 1.67
+++ lib/libc/asr/getaddrinfo_async.c 24 Jun 2026 21:44:22 -0000
@@ -43,7 +43,6 @@ struct match {
static int getaddrinfo_async_run(struct asr_query *, struct asr_result *);
static int get_port(const char *, const char *, int);
-static int iter_family(struct asr_query *, int);
static int addrinfo_add(struct asr_query *, const struct sockaddr *, const char *);
static int addrinfo_from_file(struct asr_query *, int, FILE *);
static int addrinfo_from_pkt(struct asr_query *, char *, size_t);
@@ -123,6 +122,26 @@ getaddrinfo_async_run(struct asr_query *
struct sockaddr_in sain;
struct sockaddr_in6 sain6;
} sa;
+ const struct sockaddr_in sockaddr_in_any = {
+ .sin_family = AF_INET,
+ .sin_len = sizeof(struct sockaddr_in),
+ .sin_addr = htonl(INADDR_ANY)
+ };
+ const struct sockaddr_in sockaddr_in_lo = {
+ .sin_family = AF_INET,
+ .sin_len = sizeof(struct sockaddr_in),
+ .sin_addr = htonl(INADDR_LOOPBACK)
+ };
+ const struct sockaddr_in6 sockaddr_in6_any = {
+ .sin6_family = AF_INET6,
+ .sin6_len = sizeof(struct sockaddr_in6),
+ .sin6_addr = IN6ADDR_ANY_INIT
+ };
+ const struct sockaddr_in6 sockaddr_in6_lo = {
+ .sin6_family = AF_INET6,
+ .sin6_len = sizeof(struct sockaddr_in6),
+ .sin6_addr = IN6ADDR_LOOPBACK_INIT
+ };
next:
switch (as->as_state) {
@@ -231,6 +250,8 @@ getaddrinfo_async_run(struct asr_query *
if (!(ai->ai_flags & AI_NUMERICHOST))
is_localhost = _asr_is_localhost(as->as.ai.hostname);
+ if (as->as.ai.hostname == NULL)
+ is_localhost = (ai->ai_flags & AI_PASSIVE)? 0 : 1;
/*
* If hostname is NULL, "localhost" or falls within the
* ".localhost." domain, use local address.
@@ -243,27 +264,26 @@ getaddrinfo_async_run(struct asr_query *
* DNS server(s).
*/
if (as->as.ai.hostname == NULL || is_localhost) {
- for (family = iter_family(as, 1);
- family != -1;
- family = iter_family(as, 0)) {
- /*
- * We could use statically built sockaddrs for
- * those, rather than parsing over and over.
- */
- if (family == PF_INET)
- str = (ai->ai_flags & AI_PASSIVE &&
- !is_localhost) ? "0.0.0.0" :
- "127.0.0.1";
- else /* PF_INET6 */
- str = (ai->ai_flags & AI_PASSIVE &&
- !is_localhost) ? "::" : "::1";
- /* This can't fail */
- _asr_sockaddr_from_str(&sa.sa, family, str);
- if ((r = addrinfo_add(as, &sa.sa,
- "localhost."))) {
+ /*
+ * We could use statically built sockaddrs for
+ * those, rather than parsing over and over.
+ */
+ if (ai->ai_family == AF_UNSPEC ||
+ ai->ai_family == AF_INET) {
+ if ((r = addrinfo_add(as,
+ (const struct sockaddr *)((is_localhost)?
+ &sockaddr_in_lo : &sockaddr_in_any),
+ "localhost.")))
+ ar->ar_gai_errno = r;
+ }
+ if (ar->ar_gai_errno == 0 &&
+ (ai->ai_family == AF_UNSPEC ||
+ ai->ai_family == AF_INET6)) {
+ if ((r = addrinfo_add(as,
+ (const struct sockaddr *)((is_localhost)?
+ &sockaddr_in6_lo : &sockaddr_in6_any),
+ "localhost.")))
ar->ar_gai_errno = r;
- break;
- }
}
if (ar->ar_gai_errno == 0 && as->as_count == 0) {
ar->ar_gai_errno = EAI_NODATA;
@@ -507,28 +527,6 @@ get_port(const char *servname, const cha
endservent_r(&sed);
return (port);
-}
-
-/*
- * Iterate over the address families that are to be queried. Use the
- * list on the async context, unless a specific family was given in hints.
- */
-static int
-iter_family(struct asr_query *as, int first)
-{
- if (first) {
- as->as_family_idx = 0;
- if (as->as.ai.hints.ai_family != PF_UNSPEC)
- return as->as.ai.hints.ai_family;
- return AS_FAMILY(as);
- }
-
- if (as->as.ai.hints.ai_family != PF_UNSPEC)
- return (-1);
-
- as->as_family_idx++;
-
- return AS_FAMILY(as);
}
/*