[PATCH v5 1/2] resolv: implement ipv4+ipv6 flags in resolv.conf (bug 30544)
Petr Menšík
pemensik@redhat.com
Fri Oct 10 10:43:27 GMT 2025
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.
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.
Or adding similar new flag AI_ALLAF instead? Allowing to ignore those
flags per-request only? What do you think about this change itself?
Cheers,
Petr
On 09/10/2025 16:34, 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 | 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);
> + 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. */
> + 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. */
>
> #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