[PATCH v5 1/2] resolv: implement ipv4+ipv6 flags in resolv.conf (bug 30544)

Petr Menšík pemensik@redhat.com
Thu Oct 16 10:30:37 GMT 2025


Ah, AI_ALL flag cannot modify _nss_dns_gethostbyname4_r behavior, 
because _nss_dns_gethostbyname4_r does not receive original hints data 
passed into getaddrinfo call. Nor its ai_flags field at least.

I think new bug requesting more fields in some 
new _nss_dns_gethostbyname5_r should mention also ai_flags should be 
passed into gethostbyname4 successor. Ideally whole hints pointer.

So no, cannot implement it with current interface, will have to wait for 
later improved interface.

Created bug https://sourceware.org/bugzilla/show_bug.cgi?id=33544 for this.

Is there is a bug for new _nss_dns_gethostbyname5_r requirements? Is it 
tracked somewhere else?

Cheers, Petr

On 15/10/2025 20:29, Adhemerval Zanella Netto wrote:
>>> The name of new options is for a discussion. I like ipv4 and ipv6 as more beginner friendly. It might make sense to rename ipv4 to "a" and ipv6 to "aaaa" instead. But it would be a bit confusing that aaaa is not just negative of no-aaaa option, but something slightly different.
>>>
> I don't have a strong preference, but I tend to prefer 'ipv4'/'ipv6'
> instead of the historical 'a'/'aaaa'.
>
>>> Also, it might help adding supporting AI_ALL flag to get all addresses, just like ipv4 and ipv6 options were specified, but per request. Reverting to current behaviour regarless of flags.
> Would it be the same as the current behavior (without flags)? Not sure
> if this is an improvement.
>
>>> Or adding similar new flag AI_ALLAF instead? Allowing to ignore those flags per-request only? What do you think about this change itself?
> It is not clear to me how different it would be from AI_ALL.
>
> The patch is sound, although I don't have much experience in this area.
>
>> ---
>>   resolv/nss_dns/dns-host.c             | 50 +++++++++++++++++----------
>>   resolv/res_debug.c                    |  2 ++
>>   resolv/res_init.c                     |  2 ++
>>   resolv/resolv.h                       |  2 ++
>>   resolv/tst-resolv-res_init-skeleton.c |  2 ++
>>   5 files changed, 40 insertions(+), 18 deletions(-)
>>
>> diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
>> index 14da73ee1d..99e8e5ce4c 100644
>> --- a/resolv/nss_dns/dns-host.c
>> +++ b/resolv/nss_dns/dns-host.c
>> @@ -379,6 +379,7 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
>>   {
>>     enum nss_status status = check_name (name, herrnop);
>>     char tmp[NS_MAXDNAME];
>> +
>>     if (status != NSS_STATUS_SUCCESS)
>>       return status;
>>     struct resolv_context *ctx = __resolv_context_get ();
>> @@ -412,26 +413,39 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
>>   
>>     int olderr = errno;
>>     int n;
>> +  int res_options = ctx->resp->options & (RES_NOAAAA|RES_IPV4|RES_IPV6);
> The 'struct __res_state' option is an unsigned long, using int might be
> problem with flags that exceeds INT_MAX.
>
>> +  int qtype;
>>   
>> -  if ((ctx->resp->options & RES_NOAAAA) == 0)
>> +  switch (res_options)
>>       {
>> -      n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA,
>> -				dns_packet_buffer, sizeof (dns_packet_buffer),
>> -				&alt_dns_packet_buffer, &ans2p, &nans2p,
>> -				&resplen2, &ans2p_malloced);
>> -      if (n >= 0)
>> -	status = gaih_getanswer (alt_dns_packet_buffer, n, ans2p, resplen2,
>> -				 &abuf, pat, errnop, herrnop, ttlp);
>> -    }
>> -  else
>> -    {
>> -      n = __res_context_search (ctx, name, C_IN, T_A,
>> -				dns_packet_buffer, sizeof (dns_packet_buffer),
>> -				&alt_dns_packet_buffer, NULL, NULL, NULL, NULL);
>> -      if (n >= 0)
>> -	status = gaih_getanswer_noaaaa (alt_dns_packet_buffer, n,
>> -					&abuf, pat, errnop, herrnop, ttlp);
>> -    }
>> +      case RES_IPV4:
>> +      case RES_IPV4|RES_NOAAAA:
>> +      case RES_NOAAAA:
>> +      case RES_IPV6|RES_NOAAAA: /*< this combination should never be used. */
> Double space after period.
>
>> +      case RES_IPV4|RES_IPV6|RES_NOAAAA: /*< this does not make sense. */
>> +      case RES_IPV6: /*< oh we want AAAA, but not A here. code is the same. */
>> +	qtype = (res_options == RES_IPV6 ? T_AAAA : T_A);
>> +	n = __res_context_search (ctx, name, C_IN, qtype,
>> +				  dns_packet_buffer, sizeof (dns_packet_buffer),
>> +				  &alt_dns_packet_buffer, NULL, NULL, NULL, NULL);
>> +	if (n >= 0)
>> +	  status = gaih_getanswer_noaaaa (alt_dns_packet_buffer, n,
>> +					  &abuf, pat, errnop, herrnop, ttlp);
>> +	break;
>> +
>> +      case 0:
>> +      case RES_IPV4|RES_IPV6:
>> +      default:
>> +	n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA,
>> +				  dns_packet_buffer, sizeof (dns_packet_buffer),
>> +				  &alt_dns_packet_buffer, &ans2p, &nans2p,
>> +				  &resplen2, &ans2p_malloced);
>> +	if (n >= 0)
>> +	  status = gaih_getanswer (alt_dns_packet_buffer, n, ans2p, resplen2,
>> +				  &abuf, pat, errnop, herrnop, ttlp);
>> +	break;
>> +  }
>> +
>>     if (n < 0)
>>       {
>>         switch (errno)
>> diff --git a/resolv/res_debug.c b/resolv/res_debug.c
>> index 73af0c72fe..f73bccd7bd 100644
>> --- a/resolv/res_debug.c
>> +++ b/resolv/res_debug.c
>> @@ -613,6 +613,8 @@ p_option(u_long option) {
>>   	case RES_NORELOAD:	return "no-reload";
>>   	case RES_TRUSTAD:	return "trust-ad";
>>   	case RES_NOAAAA:	return "no-aaaa";
>> +	case RES_IPV4:		return "ipv4";
>> +	case RES_IPV6:		return "ipv6";
>>   				/* XXX nonreentrant */
>>   	default:		sprintf(nbuf, "?0x%lx?", (u_long)option);
>>   				return (nbuf);
>> diff --git a/resolv/res_init.c b/resolv/res_init.c
>> index aed1902ec5..2e898d3fb3 100644
>> --- a/resolv/res_init.c
>> +++ b/resolv/res_init.c
>> @@ -696,6 +696,8 @@ res_setoptions (struct resolv_conf_parser *parser, const char *options)
>>               { STRnLEN ("trust-ad"), RES_TRUSTAD },
>>               { STRnLEN ("no-aaaa"), RES_NOAAAA },
>>               { STRnLEN ("strict-error"), RES_STRICTERR },
>> +            { STRnLEN ("ipv4"), RES_IPV4 },
>> +            { STRnLEN ("ipv6"), RES_IPV6 },
>>             };
>>   #define noptions (sizeof (options) / sizeof (options[0]))
>>             bool negate_option = *cp == '-';
>> diff --git a/resolv/resolv.h b/resolv/resolv.h
>> index b8a0f66a5f..647881243d 100644
>> --- a/resolv/resolv.h
>> +++ b/resolv/resolv.h
>> @@ -134,6 +134,8 @@ struct res_sym {
>>   #define RES_TRUSTAD     0x04000000 /* Request AD bit, keep it in responses.  */
>>   #define RES_NOAAAA      0x08000000 /* Suppress AAAA queries.  */
>>   #define RES_STRICTERR   0x10000000 /* Report more DNS errors as errors.  */
>> +#define RES_IPV4        0x20000000 /* Query A records on PF_UNSPEC hints. */
>> +#define RES_IPV6        0x40000000 /* Query AAAA records on PF_UNSPEC hints. */
> Double space after period.
>
>>   
>>   #define RES_DEFAULT	(RES_RECURSE|RES_DEFNAMES|RES_DNSRCH)
>>   
>> diff --git a/resolv/tst-resolv-res_init-skeleton.c b/resolv/tst-resolv-res_init-skeleton.c
>> index 3ccbe71db9..3d99f4b5e5 100644
>> --- a/resolv/tst-resolv-res_init-skeleton.c
>> +++ b/resolv/tst-resolv-res_init-skeleton.c
>> @@ -130,6 +130,8 @@ print_resp (FILE *fp, res_state resp)
>>           print_option_flag (fp, &options, RES_TRUSTAD, "trust-ad");
>>           print_option_flag (fp, &options, RES_NOAAAA, "no-aaaa");
>>           print_option_flag (fp, &options, RES_STRICTERR, "strict-error");
>> +        print_option_flag (fp, &options, RES_IPV4, "ipv4");
>> +        print_option_flag (fp, &options, RES_IPV6, "ipv6");
>>           fputc ('\n', fp);
>>           if (options != 0)
>>             fprintf (fp, "; error: unresolved option bits: 0x%x\n", options);

-- 
Petr Menšík
Senior Software Engineer, RHEL
Red Hat,https://www.redhat.com/
PGP: DFCF908DB7C87E8E529925BC4931CA5B6C9FC5CB
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://sourceware.org/pipermail/libc-alpha/attachments/20251016/368de234/attachment.htm>


More information about the Libc-alpha mailing list