Re: family inet[46]" and NULL for getaddrinfo()

Florian Obser <[email protected]>
Newsgroups gmane.os.openbsd.tech
Message-ID <[email protected]>
On 2026-06-25 06:56 +09, YASUOKA Masahiko <[email protected]> wrote:
> Hi,
>
> On Tue, 23 Jun 2026 20:03:58 +0200
> Florian Obser <[email protected]> wrote:
>> On 2025-12-13 14:02 +09, YASUOKA Masahiko <[email protected]> wrote:
>>> Hello,
>>>
>>> On Wed, 17 Sep 2025 12:00:09 +0900 (JST)
>>> YASUOKA Masahiko <[email protected]> wrote:
>>>> On Tue, 16 Sep 2025 13:27:36 +0200
>>>> Florian Obser <[email protected]> wrote:
>>>>> Coming back to an old email.
>>>>> 
>>>>> On 2025-03-07 09:43 +09, YASUOKA Masahiko <[email protected]> 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?

I think you can drop the comment about "statically built sockaddrs". If
I'm not mistaken you had removed it from the previous version of the
diff.

Either way, OK florian

>
> 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);
>  }
>  
>  /*
>

-- 
In my defence, I have been left unsupervised.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.