d1bb17
From 4bde615c5fa2a6a6f61ca533e46a062691d83f45 Mon Sep 17 00:00:00 2001
d1bb17
From: bradh352 <brad@brad-house.com>
d1bb17
Date: Fri, 11 Jun 2021 11:27:45 -0400
d1bb17
Subject: [PATCH 1/2] ares_expand_name() should escape more characters
d1bb17
d1bb17
RFC1035 5.1 specifies some reserved characters and escaping sequences
d1bb17
that are allowed to be specified.  Expand the list of reserved characters
d1bb17
and also escape non-printable characters using the \DDD format as
d1bb17
specified in the RFC.
d1bb17
d1bb17
Bug Reported By: philipp.jeitner@sit.fraunhofer.de
d1bb17
Fix By: Brad House (@bradh352)
d1bb17
---
d1bb17
 ares_expand_name.c | 41 ++++++++++++++++++++++++++++++++++++++---
d1bb17
 1 file changed, 38 insertions(+), 3 deletions(-)
d1bb17
d1bb17
diff --git a/ares_expand_name.c b/ares_expand_name.c
d1bb17
index 3a38e67..8604543 100644
d1bb17
--- a/ares_expand_name.c
d1bb17
+++ b/ares_expand_name.c
d1bb17
@@ -38,6 +38,26 @@
d1bb17
 static int name_length(const unsigned char *encoded, const unsigned char *abuf,
d1bb17
                        int alen);
d1bb17
 
d1bb17
+/* Reserved characters for names that need to be escaped */
d1bb17
+static int is_reservedch(int ch)
d1bb17
+{
d1bb17
+  switch (ch) {
d1bb17
+    case '"':
d1bb17
+    case '.':
d1bb17
+    case ';':
d1bb17
+    case '\\':
d1bb17
+    case '(':
d1bb17
+    case ')':
d1bb17
+    case '@':
d1bb17
+    case '$':
d1bb17
+      return 1;
d1bb17
+    default:
d1bb17
+      break;
d1bb17
+  }
d1bb17
+
d1bb17
+  return 0;
d1bb17
+}
d1bb17
+
d1bb17
 /* Expand an RFC1035-encoded domain name given by encoded.  The
d1bb17
  * containing message is given by abuf and alen.  The result given by
d1bb17
  * *s, which is set to a NUL-terminated allocated buffer.  *enclen is
d1bb17
@@ -117,9 +137,18 @@ int ares_expand_name(const unsigned char *encoded, const unsigned char *abuf,
d1bb17
           p++;
d1bb17
           while (len--)
d1bb17
             {
d1bb17
-              if (*p == '.' || *p == '\\')
d1bb17
+              if (!isprint(*p)) {
d1bb17
+                /* Output as \DDD for consistency with RFC1035 5.1 */
d1bb17
+                *q++ = '\\';
d1bb17
+                *q++ = '0' + *p / 100;
d1bb17
+                *q++ = '0' + (*p % 100) / 10;
d1bb17
+                *q++ = '0' + (*p % 10);
d1bb17
+              } else if (is_reservedch(*p)) {
d1bb17
                 *q++ = '\\';
d1bb17
-              *q++ = *p;
d1bb17
+                *q++ = *p;
d1bb17
+              } else {
d1bb17
+                *q++ = *p;
d1bb17
+              }
d1bb17
               p++;
d1bb17
             }
d1bb17
           *q++ = '.';
d1bb17
@@ -177,7 +206,13 @@ static int name_length(const unsigned char *encoded, const unsigned char *abuf,
d1bb17
           encoded++;
d1bb17
           while (offset--)
d1bb17
             {
d1bb17
-              n += (*encoded == '.' || *encoded == '\\') ? 2 : 1;
d1bb17
+              if (!isprint(*encoded)) {
d1bb17
+                n += 4;
d1bb17
+              } else if (is_reservedch(*encoded)) {
d1bb17
+                n += 2;
d1bb17
+              } else {
d1bb17
+                n += 1;
d1bb17
+              }
d1bb17
               encoded++;
d1bb17
             }
d1bb17
           n++;
d1bb17
-- 
d1bb17
2.26.3
d1bb17
d1bb17
d1bb17
From 86cc9241f89c1155111b992ccc03bf76d8ae634a Mon Sep 17 00:00:00 2001
d1bb17
From: bradh352 <brad@brad-house.com>
d1bb17
Date: Fri, 11 Jun 2021 12:39:24 -0400
d1bb17
Subject: [PATCH 2/2] ares_expand_name(): fix formatting and handling of root
d1bb17
 name response
d1bb17
d1bb17
Fixes issue introduced in prior commit with formatting and handling
d1bb17
of parsing a root name response which should not be escaped.
d1bb17
d1bb17
Fix By: Brad House
d1bb17
---
d1bb17
 ares_expand_name.c | 62 ++++++++++++++++++++++++++++++----------------
d1bb17
 1 file changed, 40 insertions(+), 22 deletions(-)
d1bb17
d1bb17
diff --git a/ares_expand_name.c b/ares_expand_name.c
d1bb17
index 8604543..f89ee3f 100644
d1bb17
--- a/ares_expand_name.c
d1bb17
+++ b/ares_expand_name.c
d1bb17
@@ -133,27 +133,37 @@ int ares_expand_name(const unsigned char *encoded, const unsigned char *abuf,
d1bb17
         }
d1bb17
       else
d1bb17
         {
d1bb17
-          len = *p;
d1bb17
+          int name_len = *p;
d1bb17
+          len = name_len;
d1bb17
           p++;
d1bb17
+
d1bb17
           while (len--)
d1bb17
             {
d1bb17
-              if (!isprint(*p)) {
d1bb17
-                /* Output as \DDD for consistency with RFC1035 5.1 */
d1bb17
-                *q++ = '\\';
d1bb17
-                *q++ = '0' + *p / 100;
d1bb17
-                *q++ = '0' + (*p % 100) / 10;
d1bb17
-                *q++ = '0' + (*p % 10);
d1bb17
-              } else if (is_reservedch(*p)) {
d1bb17
-                *q++ = '\\';
d1bb17
-                *q++ = *p;
d1bb17
-              } else {
d1bb17
-                *q++ = *p;
d1bb17
-              }
d1bb17
+              /* Output as \DDD for consistency with RFC1035 5.1, except
d1bb17
+               * for the special case of a root name response  */
d1bb17
+              if (!isprint(*p) && !(name_len == 1 && *p == 0))
d1bb17
+                {
d1bb17
+
d1bb17
+                  *q++ = '\\';
d1bb17
+                  *q++ = '0' + *p / 100;
d1bb17
+                  *q++ = '0' + (*p % 100) / 10;
d1bb17
+                  *q++ = '0' + (*p % 10);
d1bb17
+                }
d1bb17
+              else if (is_reservedch(*p))
d1bb17
+                {
d1bb17
+                  *q++ = '\\';
d1bb17
+                  *q++ = *p;
d1bb17
+                }
d1bb17
+              else
d1bb17
+                {
d1bb17
+                  *q++ = *p;
d1bb17
+                }
d1bb17
               p++;
d1bb17
             }
d1bb17
           *q++ = '.';
d1bb17
         }
d1bb17
-    }
d1bb17
+     }
d1bb17
+
d1bb17
   if (!indir)
d1bb17
     *enclen = aresx_uztosl(p + 1U - encoded);
d1bb17
 
d1bb17
@@ -200,21 +210,29 @@ static int name_length(const unsigned char *encoded, const unsigned char *abuf,
d1bb17
         }
d1bb17
       else if (top == 0x00)
d1bb17
         {
d1bb17
-          offset = *encoded;
d1bb17
+          int name_len = *encoded;
d1bb17
+          offset = name_len;
d1bb17
           if (encoded + offset + 1 >= abuf + alen)
d1bb17
             return -1;
d1bb17
           encoded++;
d1bb17
+
d1bb17
           while (offset--)
d1bb17
             {
d1bb17
-              if (!isprint(*encoded)) {
d1bb17
-                n += 4;
d1bb17
-              } else if (is_reservedch(*encoded)) {
d1bb17
-                n += 2;
d1bb17
-              } else {
d1bb17
-                n += 1;
d1bb17
-              }
d1bb17
+              if (!isprint(*encoded) && !(name_len == 1 && *encoded == 0))
d1bb17
+                {
d1bb17
+                  n += 4;
d1bb17
+                }
d1bb17
+              else if (is_reservedch(*encoded))
d1bb17
+                {
d1bb17
+                  n += 2;
d1bb17
+                }
d1bb17
+              else
d1bb17
+                {
d1bb17
+                  n += 1;
d1bb17
+                }
d1bb17
               encoded++;
d1bb17
             }
d1bb17
+
d1bb17
           n++;
d1bb17
         }
d1bb17
       else
d1bb17
-- 
d1bb17
2.26.3
d1bb17