about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2017-05-11 11:32:16 +0200
committerFlorian Weimer <fweimer@redhat.com>2017-05-11 11:51:34 +0200
commit8ec69bb7ecf3ca5edde5b7d9d7d5d3a5f8b6c405 (patch)
tree7c8875439ed455ff72491a5f73c4099afe83272c
parent46ce8881ade788db56079622f47f648d4aaa003b (diff)
downloadglibc-8ec69bb7ecf3ca5edde5b7d9d7d5d3a5f8b6c405.tar.gz
glibc-8ec69bb7ecf3ca5edde5b7d9d7d5d3a5f8b6c405.tar.xz
glibc-8ec69bb7ecf3ca5edde5b7d9d7d5d3a5f8b6c405.zip
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.
-rw-r--r--ChangeLog16
-rw-r--r--resolv/tst-resolv-basic.c71
-rw-r--r--support/support_format_addrinfo.c69
3 files changed, 136 insertions, 20 deletions
diff --git a/ChangeLog b/ChangeLog
index 4231a68860..d3137e73e7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,21 @@
 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.
 	(gaih_inet): Likewise.
 
diff --git a/resolv/tst-resolv-basic.c b/resolv/tst-resolv-basic.c
index f2b1fc7490..92f912beed 100644
--- a/resolv/tst-resolv-basic.c
+++ b/resolv/tst-resolv-basic.c
@@ -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"
diff --git a/support/support_format_addrinfo.c b/support/support_format_addrinfo.c
index 262e0df737..eedb030591 100644
--- a/support/support_format_addrinfo.c
+++ b/support/support_format_addrinfo.c
@@ -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);