support_format_addrinfo: Fix flags and canonname formatting

The address family splitting via format_ai_family made unpredictable
the place where the canonname field was printed.  This commit adjusts
the implementation so that the ai_flags is checked for consistency
across the list, and ai_canonname must only be present on the first
list element.

Tests for AI_CANONNAME are added to resolv/tst-resolv-basic.
This commit is contained in:
Florian Weimer 2017-05-11 11:32:16 +02:00
parent 46ce8881ad
commit 8ec69bb7ec
3 changed files with 136 additions and 20 deletions

View File

@ -1,3 +1,19 @@
2017-05-11 Florian Weimer <fweimer@redhat.com>
* support/support_format_addrinfo.c (format_ai_flags_1): Renamed
from format_ai_flags.
(format_ai_flags): New function. Incorporate flag formatting code
from format_ai_one.
(format_ai_canonname): New function.
(format_ai_one): Remove flags parameter.
(format_ai_family): Likewise.
(support_format_addrinfo): Call format_ai_flags,
format_ai_canonname.
* resolv/tst-resolv-basic.c (check_ai_hints): Extracted from
check_ai.
(check_ai): Call check_ai_hints.
(do_test): Add AI_CANONNAME tests.
2017-05-11 Florian Weimer <fweimer@redhat.com>
* sysdeps/posix/getaddrinfo.c (gethosts): Remove malloc_addrmem.

View File

@ -182,12 +182,12 @@ check_h (const char *name, int family, const char *expected)
}
static void
check_ai (const char *name, const char *service,
int family, const char *expected)
check_ai_hints (const char *name, const char *service,
struct addrinfo hints, const char *expected)
{
struct addrinfo hints = {.ai_family = family};
struct addrinfo *ai;
char *query = xasprintf ("%s:%s [%d]", name, service, family);
char *query = xasprintf ("%s:%s [%d]/0x%x", name, service,
hints.ai_family, hints.ai_flags);
int ret = getaddrinfo (name, service, &hints, &ai);
check_addrinfo (query, ai, ret, expected);
if (ret == 0)
@ -195,6 +195,15 @@ check_ai (const char *name, const char *service,
free (query);
}
static void
check_ai (const char *name, const char *service,
int family, const char *expected)
{
return check_ai_hints (name, service,
(struct addrinfo) { .ai_family = family, },
expected);
}
static int
do_test (void)
{
@ -229,6 +238,17 @@ do_test (void)
"address: STREAM/TCP 2001:db8::1 80\n"
"address: DGRAM/UDP 2001:db8::1 80\n"
"address: RAW/IP 2001:db8::1 80\n");
check_ai_hints ("www.example", "80",
(struct addrinfo) { .ai_family = AF_UNSPEC,
.ai_flags = AI_CANONNAME, },
"flags: AI_CANONNAME\n"
"canonname: www.example\n"
"address: STREAM/TCP 192.0.2.17 80\n"
"address: DGRAM/UDP 192.0.2.17 80\n"
"address: RAW/IP 192.0.2.17 80\n"
"address: STREAM/TCP 2001:db8::1 80\n"
"address: DGRAM/UDP 2001:db8::1 80\n"
"address: RAW/IP 2001:db8::1 80\n");
check_ai ("alias.example", "80", AF_UNSPEC,
"address: STREAM/TCP 192.0.2.18 80\n"
"address: DGRAM/UDP 192.0.2.18 80\n"
@ -236,6 +256,17 @@ do_test (void)
"address: STREAM/TCP 2001:db8::2 80\n"
"address: DGRAM/UDP 2001:db8::2 80\n"
"address: RAW/IP 2001:db8::2 80\n");
check_ai_hints ("alias.example", "80",
(struct addrinfo) { .ai_family = AF_UNSPEC,
.ai_flags = AI_CANONNAME, },
"flags: AI_CANONNAME\n"
"canonname: www.example\n"
"address: STREAM/TCP 192.0.2.18 80\n"
"address: DGRAM/UDP 192.0.2.18 80\n"
"address: RAW/IP 192.0.2.18 80\n"
"address: STREAM/TCP 2001:db8::2 80\n"
"address: DGRAM/UDP 2001:db8::2 80\n"
"address: RAW/IP 2001:db8::2 80\n");
check_ai (LONG_NAME, "80", AF_UNSPEC,
"address: STREAM/TCP 192.0.2.20 80\n"
"address: DGRAM/UDP 192.0.2.20 80\n"
@ -247,10 +278,26 @@ do_test (void)
"address: STREAM/TCP 192.0.2.17 80\n"
"address: DGRAM/UDP 192.0.2.17 80\n"
"address: RAW/IP 192.0.2.17 80\n");
check_ai_hints ("www.example", "80",
(struct addrinfo) { .ai_family = AF_INET,
.ai_flags = AI_CANONNAME, },
"flags: AI_CANONNAME\n"
"canonname: www.example\n"
"address: STREAM/TCP 192.0.2.17 80\n"
"address: DGRAM/UDP 192.0.2.17 80\n"
"address: RAW/IP 192.0.2.17 80\n");
check_ai ("alias.example", "80", AF_INET,
"address: STREAM/TCP 192.0.2.18 80\n"
"address: DGRAM/UDP 192.0.2.18 80\n"
"address: RAW/IP 192.0.2.18 80\n");
check_ai_hints ("alias.example", "80",
(struct addrinfo) { .ai_family = AF_INET,
.ai_flags = AI_CANONNAME, },
"flags: AI_CANONNAME\n"
"canonname: www.example\n"
"address: STREAM/TCP 192.0.2.18 80\n"
"address: DGRAM/UDP 192.0.2.18 80\n"
"address: RAW/IP 192.0.2.18 80\n");
check_ai (LONG_NAME, "80", AF_INET,
"address: STREAM/TCP 192.0.2.20 80\n"
"address: DGRAM/UDP 192.0.2.20 80\n"
@ -259,10 +306,26 @@ do_test (void)
"address: STREAM/TCP 2001:db8::1 80\n"
"address: DGRAM/UDP 2001:db8::1 80\n"
"address: RAW/IP 2001:db8::1 80\n");
check_ai_hints ("www.example", "80",
(struct addrinfo) { .ai_family = AF_INET6,
.ai_flags = AI_CANONNAME, },
"flags: AI_CANONNAME\n"
"canonname: www.example\n"
"address: STREAM/TCP 2001:db8::1 80\n"
"address: DGRAM/UDP 2001:db8::1 80\n"
"address: RAW/IP 2001:db8::1 80\n");
check_ai ("alias.example", "80", AF_INET6,
"address: STREAM/TCP 2001:db8::2 80\n"
"address: DGRAM/UDP 2001:db8::2 80\n"
"address: RAW/IP 2001:db8::2 80\n");
check_ai_hints ("alias.example", "80",
(struct addrinfo) { .ai_family = AF_INET6,
.ai_flags = AI_CANONNAME, },
"flags: AI_CANONNAME\n"
"canonname: www.example\n"
"address: STREAM/TCP 2001:db8::2 80\n"
"address: DGRAM/UDP 2001:db8::2 80\n"
"address: RAW/IP 2001:db8::2 80\n");
check_ai (LONG_NAME, "80", AF_INET6,
"address: STREAM/TCP 2001:db8::4 80\n"
"address: DGRAM/UDP 2001:db8::4 80\n"

View File

@ -39,8 +39,8 @@ socket_address_length (int family)
}
static void
format_ai_flags (FILE *out, struct addrinfo *ai, int flag, const char *name,
int * flags_printed)
format_ai_flags_1 (FILE *out, struct addrinfo *ai, int flag, const char *name,
int * flags_printed)
{
if ((ai->ai_flags & flag) != 0)
fprintf (out, " %s", name);
@ -48,14 +48,16 @@ format_ai_flags (FILE *out, struct addrinfo *ai, int flag, const char *name,
}
static void
format_ai_one (FILE *out, struct addrinfo *ai, int *flags)
format_ai_flags (FILE *out, struct addrinfo *ai)
{
/* ai_flags */
if (ai->ai_flags != *flags)
if (ai == NULL)
return;
if (ai->ai_flags != 0)
{
fprintf (out, "flags:");
int flags_printed = 0;
#define FLAG(flag) format_ai_flags (out, ai, flag, #flag, &flags_printed)
#define FLAG(flag) format_ai_flags_1 (out, ai, flag, #flag, &flags_printed)
FLAG (AI_PASSIVE);
FLAG (AI_CANONNAME);
FLAG (AI_NUMERICHOST);
@ -72,9 +74,47 @@ format_ai_one (FILE *out, struct addrinfo *ai, int *flags)
if (remaining != 0)
fprintf (out, " %08x", remaining);
fprintf (out, "\n");
*flags = ai->ai_flags;
}
/* Report flag mismatches within the list. */
int flags = ai->ai_flags;
int index = 1;
ai = ai->ai_next;
while (ai != NULL)
{
if (ai->ai_flags != flags)
fprintf (out, "error: flags at %d: 0x%x expected, 0x%x actual\n",
index, flags, ai->ai_flags);
ai = ai->ai_next;
++index;
}
}
static void
format_ai_canonname (FILE *out, struct addrinfo *ai)
{
if (ai == NULL)
return;
if (ai->ai_canonname != NULL)
fprintf (out, "canonname: %s\n", ai->ai_canonname);
/* Report incorrectly set ai_canonname fields on subsequent list
entries. */
int index = 1;
ai = ai->ai_next;
while (ai != NULL)
{
if (ai->ai_canonname != NULL)
fprintf (out, "error: canonname set at %d: %s\n",
index, ai->ai_canonname);
ai = ai->ai_next;
++index;
}
}
static void
format_ai_one (FILE *out, struct addrinfo *ai)
{
{
char type_buf[32];
const char *type_str;
@ -156,20 +196,16 @@ format_ai_one (FILE *out, struct addrinfo *ai, int *flags)
else
fprintf (out, " %s %u\n", buf, ntohs (port));
}
/* ai_canonname */
if (ai->ai_canonname != NULL)
fprintf (out, "canonname: %s\n", ai->ai_canonname);
}
/* Format all the addresses in one address family. */
static void
format_ai_family (FILE *out, struct addrinfo *ai, int family, int *flags)
format_ai_family (FILE *out, struct addrinfo *ai, int family)
{
while (ai)
{
if (ai->ai_family == family)
format_ai_one (out, ai, flags);
format_ai_one (out, ai);
ai = ai->ai_next;
}
}
@ -192,9 +228,10 @@ support_format_addrinfo (struct addrinfo *ai, int ret)
}
else
{
int flags = 0;
format_ai_family (mem.out, ai, AF_INET, &flags);
format_ai_family (mem.out, ai, AF_INET6, &flags);
format_ai_flags (mem.out, ai);
format_ai_canonname (mem.out, ai);
format_ai_family (mem.out, ai, AF_INET);
format_ai_family (mem.out, ai, AF_INET6);
}
xfclose_memstream (&mem);