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