[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