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

Petr Menšík pemensik@redhat.com
Thu Oct 9 09:55:35 GMT 2025


Ah, I have sent already v3 on 2024-11-25, this should have been v4 then.

On 09/10/2025 11:40, Petr Menšík wrote:
> Add separate flags to mark support of address family. Its intention is
> to react dynamically to changing network conditions. If the host has
> IPv4 connectivity only, it would set ipv4 option. If it has also IPv6
> connectivity, it would set ipv6 option. If it connects IPv6-only
> network, then it set ipv6 only.
>
> For backward compatibility it will keep old behaviour when both ipv4 and
> ipv6 flags are missing. In this case it behaves the same way as if both
> were present.
>
> This is quite useful when default AF_UNSPEC is used in hints, but the
> host is on network with just single AF used.
>
> Unlike no-aaaa option it would change just AF_UNSPEC behaviour, ie.
> getent ahosts example.com. getent ahostsv4 and getent ahostsv6 would
> remain unmodified.
>
> Signed-off-by: Petr Menšík <pemensik@redhat.com>
> ---
>   resolv/nss_dns/dns-host.c             | 55 ++++++++++++++++++---------
>   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, 45 insertions(+), 18 deletions(-)
>
> diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
> index 14da73ee1d..68d383b81f 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 ();
> @@ -413,25 +414,43 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
>     int olderr = errno;
>     int n;
>   
> -  if ((ctx->resp->options & RES_NOAAAA) == 0)
> -    {
> -      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
> +  switch (ctx->resp->options & (RES_NOAAAA|RES_IPV4|RES_IPV6))
>       {
> -      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. */
> +      case RES_IPV4|RES_IPV6|RES_NOAAAA: /*< this does not make sense. */
> +	n = __res_context_search (ctx, name, C_IN, T_A,
> +				  dns_packet_buffer, sizeof (dns_packet_buffer),
> +				  NULL, NULL, NULL, NULL, NULL);
> +	if (n >= 0)
> +	  status = gaih_getanswer_noaaaa (alt_dns_packet_buffer, n,
> +					  &abuf, pat, errnop, herrnop, ttlp);
> +	break;
> +
> +      case RES_IPV6:
> +	n = __res_context_search (ctx, name, C_IN, T_AAAA,
> +				  dns_packet_buffer, sizeof (dns_packet_buffer),
> +				  NULL, NULL, NULL, NULL, NULL);
> +	if (n >= 0) /* oh we want AAAA, but not A here. code is the same. */
> +	  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. */
>   
>   #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 Engieer, RHEL
Red Hat, https://www.redhat.com/
PGP: DFCF908DB7C87E8E529925BC4931CA5B6C9FC5CB



More information about the Libc-alpha mailing list