6ca6e8
commit bb8adbba4f5d9237a144786ba8e504039beff161
6ca6e8
Author: Florian Weimer <fweimer@redhat.com>
6ca6e8
Date:   Tue Aug 30 10:02:49 2022 +0200
6ca6e8
6ca6e8
    resolv: Add the __ns_samebinaryname function
6ca6e8
    
6ca6e8
    During packet parsing, only the binary name is available.  If the name
6ca6e8
    equality check is performed before conversion to text, we can sometimes
6ca6e8
    skip the last step.
6ca6e8
    
6ca6e8
    Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
6ca6e8
    (cherry picked from commit 394085a34d25a51513019a4dc411acd3527fbd33)
6ca6e8
6ca6e8
diff --git a/include/arpa/nameser.h b/include/arpa/nameser.h
6ca6e8
index 53f1dbc7c3f659e9..bb1dede187cf1500 100644
6ca6e8
--- a/include/arpa/nameser.h
6ca6e8
+++ b/include/arpa/nameser.h
6ca6e8
@@ -55,6 +55,12 @@ int __ns_name_ntop (const unsigned char *, char *, size_t) __THROW;
6ca6e8
 int __ns_name_unpack (const unsigned char *, const unsigned char *,
6ca6e8
 		      const unsigned char *, unsigned char *, size_t) __THROW;
6ca6e8
 
6ca6e8
+/* Like ns_samename, but for uncompressed binary names.  Return true
6ca6e8
+   if the two arguments compare are equal as case-insensitive domain
6ca6e8
+   names.  */
6ca6e8
+_Bool __ns_samebinaryname (const unsigned char *, const unsigned char *)
6ca6e8
+  attribute_hidden;
6ca6e8
+
6ca6e8
 #define ns_msg_getflag(handle, flag) \
6ca6e8
   (((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift)
6ca6e8
 
6ca6e8
diff --git a/resolv/Makefile b/resolv/Makefile
6ca6e8
index 567f4c2dcf5749df..0b4fa30716af3b8a 100644
6ca6e8
--- a/resolv/Makefile
6ca6e8
+++ b/resolv/Makefile
6ca6e8
@@ -46,6 +46,7 @@ routines := \
6ca6e8
   ns_name_skip \
6ca6e8
   ns_name_uncompress \
6ca6e8
   ns_name_unpack \
6ca6e8
+  ns_samebinaryname \
6ca6e8
   ns_samename \
6ca6e8
   nsap_addr \
6ca6e8
   nss_dns_functions \
6ca6e8
@@ -107,6 +108,10 @@ tests += \
6ca6e8
 tests-internal += tst-resolv-txnid-collision
6ca6e8
 tests-static += tst-resolv-txnid-collision
6ca6e8
 
6ca6e8
+# Likewise for __ns_samebinaryname.
6ca6e8
+tests-internal += tst-ns_samebinaryname
6ca6e8
+tests-static += tst-ns_samebinaryname
6ca6e8
+
6ca6e8
 # These tests need libdl.
6ca6e8
 ifeq (yes,$(build-shared))
6ca6e8
 tests += \
6ca6e8
diff --git a/resolv/ns_samebinaryname.c b/resolv/ns_samebinaryname.c
6ca6e8
new file mode 100644
6ca6e8
index 0000000000000000..9a47d8e97a84c759
6ca6e8
--- /dev/null
6ca6e8
+++ b/resolv/ns_samebinaryname.c
6ca6e8
@@ -0,0 +1,55 @@
6ca6e8
+/* Compare two binary domain names for quality.
6ca6e8
+   Copyright (C) 2022 Free Software Foundation, Inc.
6ca6e8
+   This file is part of the GNU C Library.
6ca6e8
+
6ca6e8
+   The GNU C Library is free software; you can redistribute it and/or
6ca6e8
+   modify it under the terms of the GNU Lesser General Public
6ca6e8
+   License as published by the Free Software Foundation; either
6ca6e8
+   version 2.1 of the License, or (at your option) any later version.
6ca6e8
+
6ca6e8
+   The GNU C Library is distributed in the hope that it will be useful,
6ca6e8
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
6ca6e8
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
6ca6e8
+   Lesser General Public License for more details.
6ca6e8
+
6ca6e8
+   You should have received a copy of the GNU Lesser General Public
6ca6e8
+   License along with the GNU C Library; if not, see
6ca6e8
+   <https://www.gnu.org/licenses/>.  */
6ca6e8
+
6ca6e8
+#include <arpa/nameser.h>
6ca6e8
+#include <stdbool.h>
6ca6e8
+
6ca6e8
+/* Convert ASCII letters to upper case.  */
6ca6e8
+static inline int
6ca6e8
+ascii_toupper (unsigned char ch)
6ca6e8
+{
6ca6e8
+  if (ch >= 'a' && ch <= 'z')
6ca6e8
+    return ch - 'a' + 'A';
6ca6e8
+  else
6ca6e8
+    return ch;
6ca6e8
+}
6ca6e8
+
6ca6e8
+bool
6ca6e8
+__ns_samebinaryname (const unsigned char *a, const unsigned char *b)
6ca6e8
+{
6ca6e8
+  while (*a != 0 && *b != 0)
6ca6e8
+    {
6ca6e8
+      if (*a != *b)
6ca6e8
+        /* Different label length.  */
6ca6e8
+        return false;
6ca6e8
+      int labellen = *a;
6ca6e8
+      ++a;
6ca6e8
+      ++b;
6ca6e8
+      for (int i = 0; i < labellen; ++i)
6ca6e8
+        {
6ca6e8
+          if (*a != *b && ascii_toupper (*a) != ascii_toupper (*b))
6ca6e8
+            /* Different character in label.  */
6ca6e8
+            return false;
6ca6e8
+          ++a;
6ca6e8
+          ++b;
6ca6e8
+        }
6ca6e8
+    }
6ca6e8
+
6ca6e8
+  /* Match if both names are at the root label.  */
6ca6e8
+  return *a == 0 && *b == 0;
6ca6e8
+}
6ca6e8
diff --git a/resolv/tst-ns_samebinaryname.c b/resolv/tst-ns_samebinaryname.c
6ca6e8
new file mode 100644
6ca6e8
index 0000000000000000..b06ac610b4cde8be
6ca6e8
--- /dev/null
6ca6e8
+++ b/resolv/tst-ns_samebinaryname.c
6ca6e8
@@ -0,0 +1,62 @@
6ca6e8
+/* Test the __ns_samebinaryname function.
6ca6e8
+   Copyright (C) 2022 Free Software Foundation, Inc.
6ca6e8
+   This file is part of the GNU C Library.
6ca6e8
+
6ca6e8
+   The GNU C Library is free software; you can redistribute it and/or
6ca6e8
+   modify it under the terms of the GNU Lesser General Public
6ca6e8
+   License as published by the Free Software Foundation; either
6ca6e8
+   version 2.1 of the License, or (at your option) any later version.
6ca6e8
+
6ca6e8
+   The GNU C Library is distributed in the hope that it will be useful,
6ca6e8
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
6ca6e8
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
6ca6e8
+   Lesser General Public License for more details.
6ca6e8
+
6ca6e8
+   You should have received a copy of the GNU Lesser General Public
6ca6e8
+   License along with the GNU C Library; if not, see
6ca6e8
+   <https://www.gnu.org/licenses/>.  */
6ca6e8
+
6ca6e8
+#include <arpa/nameser.h>
6ca6e8
+#include <array_length.h>
6ca6e8
+#include <stdbool.h>
6ca6e8
+#include <stdio.h>
6ca6e8
+#include <support/check.h>
6ca6e8
+
6ca6e8
+/* First character denotes the comparison group: All names with the
6ca6e8
+   same first character are expected to compare equal.  */
6ca6e8
+static const char *const cases[] =
6ca6e8
+  {
6ca6e8
+    " ",
6ca6e8
+    "1\001a", "1\001A",
6ca6e8
+    "2\002ab", "2\002aB", "2\002Ab", "2\002AB",
6ca6e8
+    "3\001a\002ab", "3\001A\002ab",
6ca6e8
+    "w\003www\007example\003com", "w\003Www\007Example\003Com",
6ca6e8
+    "w\003WWW\007EXAMPLE\003COM",
6ca6e8
+    "W\003WWW", "W\003www",
6ca6e8
+  };
6ca6e8
+
6ca6e8
+static int
6ca6e8
+do_test (void)
6ca6e8
+{
6ca6e8
+  for (int i = 0; i < array_length (cases); ++i)
6ca6e8
+    for (int j = 0; j < array_length (cases); ++j)
6ca6e8
+      {
6ca6e8
+        unsigned char *a = (unsigned char *) &cases[i][1];
6ca6e8
+        unsigned char *b = (unsigned char *) &cases[j][1];
6ca6e8
+        bool actual = __ns_samebinaryname (a, b);
6ca6e8
+        bool expected = cases[i][0] == cases[j][0];
6ca6e8
+        if (actual != expected)
6ca6e8
+          {
6ca6e8
+            char a1[NS_MAXDNAME];
6ca6e8
+            TEST_VERIFY (ns_name_ntop (a, a1, sizeof (a1)) > 0);
6ca6e8
+            char b1[NS_MAXDNAME];
6ca6e8
+            TEST_VERIFY (ns_name_ntop (b, b1, sizeof (b1)) > 0);
6ca6e8
+            printf ("error: \"%s\" \"%s\": expected %s\n",
6ca6e8
+                    a1, b1, expected ? "equal" : "unqueal");
6ca6e8
+            support_record_failure ();
6ca6e8
+          }
6ca6e8
+      }
6ca6e8
+  return 0;
6ca6e8
+}
6ca6e8
+
6ca6e8
+#include <support/test-driver.c>