[PATCH] resolv: Add test for getaddrinfo returning FQDN in ai_canonname
Florian Weimer
fweimer@redhat.com
Mon Jun 2 15:04:24 GMT 2025
* Sergey Kolosov:
> This test verifies that getaddrinfo returns a fully-qualified domain
> name in the ai_canonname field then AI_CANONNAME is set and search
> domains apply.
Overall the new test case looks good.
Does the test reproduce the original bug? I think you can re-introduce
it with t his change:
diff --git a/nss/getaddrinfo.c b/nss/getaddrinfo.c
index 6726ace6fd..4150553bd7 100644
--- a/nss/getaddrinfo.c
+++ b/nss/getaddrinfo.c
@@ -977,7 +977,7 @@ try_simple_gethostbyname (const char *name, const struct addrinfo *req,
{
res->at = NULL;
- if (req->ai_family != AF_INET || (req->ai_flags & AI_CANONNAME) != 0)
+ if (req->ai_family != AF_INET)
return 0;
int rc;
As far as I can tell, the upstream fix was this one:
commit b957ced8890a4438c8efe2c15e5abf4e327f25cf
Author: Andreas Schwab <schwab@suse.de>
Date: Tue Oct 15 10:21:13 2013 +0200
Don't use gethostbyaddr to determine canonical name
So please reference bug 15218 in the test case.
> diff --git a/resolv/tst-resolv-getaddrinfo-fqdn.c b/resolv/tst-resolv-getaddrinfo-fqdn.c
> new file mode 100644
> index 0000000000..18a71d6acf
> --- /dev/null
> +++ b/resolv/tst-resolv-getaddrinfo-fqdn.c
> @@ -0,0 +1,156 @@
> +/* Verify that getaddrinfo returns FQDN in ai_canonname,
> + when AI_CANONNAME is requested and search domain apply.
> + Copyright (C) 2025 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, see
> + <https://www.gnu.org/licenses/>. */
> +
> +#include <resolv.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <support/check.h>
> +#include <support/check_nss.h>
> +#include <support/resolv_test.h>
> +#include <support/support.h>
> +
> +static void
> +response (const struct resolv_response_context *ctx,
> + struct resolv_response_builder *b,
> + const char *qname, uint16_t qclass, uint16_t qtype)
> +{
> + if (strcmp (qname, "foo.site.example") == 0 ||
> + strcmp (qname, "bar.foo.site.example") == 0 ||
> + strcmp (qname, "site.example") == 0)
Style nit: Operators should be at the start of the following line, not
the end of the line.
> +char *
> +query_host (const char *host_name)
Could be static as well.
> +{
> + int family[] = { AF_INET, AF_INET6, AF_UNSPEC };
> + const char *family_names[] = { "AF_INET", "AF_INET6", "AF_UNSPEC" };
> + char *canonname = NULL;
> +
> + for (int i = 0; i < 3; i++)
> + {
> + struct addrinfo hints = {
> + .ai_socktype = 0,
> + .ai_protocol = 0,
> + .ai_family = family[i],
> + .ai_flags = AI_CANONNAME,
> + };
> + struct addrinfo *result, *current;
> + int res = getaddrinfo (host_name, NULL, &hints, &result);
> + if (res != 0)
> + {
> + FAIL_EXIT1 ("getaddrinfo(%s, %s): %s\n", host_name, family_names[i],
> + gai_strerror (res));
> + }
The braces are unnecessary here, but I don't mind including them.
> + else
> + {
> + int count = 0;
> + for (current = result;
> + current != NULL && current->ai_canonname != NULL;
> + current = current->ai_next)
> + {
> + if (count > 0)
> + FAIL_EXIT1 ("Exected exactly one cannoname\n");
Spelling: can[]o[n]name
> + canonname =
> + strndup (current->ai_canonname,
> + strlen (current->ai_canonname));
Please use xstrdup (strndup + strlen is strdup). But see below.
> + count++;
> + }
It might be clearer to check count after the loop has run to completion.
You could also include the count in the error message.
> +/* test with site.example domain. */
> +void
> +test_search_with_site_example_domain (void)
> +{
> + struct resolv_test *aux = resolv_test_start
> + ((struct resolv_redirect_config)
> + {
> + .response_callback = response,
> + .search = {"site.example"},
> + });
> +
> + TEST_COMPARE_STRING (query_host ("foo"), "foo.site.example");
> + TEST_COMPARE_STRING (query_host ("bar.foo"), "bar.foo.site.example");
>From an interface perspective, it's easier to pass the expected
canonical name to the query_host function. Then it's not necessary to
make a copy of the string at all. You can also check that the name is
on the first struct addrinfo result (which is also required by the
interface).
Thanks,
Florian
More information about the Libc-alpha
mailing list