summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdam <Adam@anope.org>2012-03-27 19:01:29 -0400
committerAdam <Adam@anope.org>2012-03-27 19:01:29 -0400
commit31a0e673b2028f3dad67cd1e6f0f5410d0dde56d (patch)
tree32483487f9fbacb3c92361cb769894c89afaa48e /src
parent88fd1da803fd144f9eae4213eb4903d7c1ade9ad (diff)
Fixed unpacking multiple names from dns packets when one has multiple compression pointers.
Currently this will just fail at unpacking the later name due to offsets being invalid. Also cleaned up the existing code and made unpacking error messages more helpful.
Diffstat (limited to 'src')
-rw-r--r--src/dns.cpp64
1 files changed, 37 insertions, 27 deletions
diff --git a/src/dns.cpp b/src/dns.cpp
index 0a016624b..ad9c01c7f 100644
--- a/src/dns.cpp
+++ b/src/dns.cpp
@@ -144,44 +144,54 @@ void DNSPacket::PackName(unsigned char *output, unsigned short output_size, unsi
Anope::string DNSPacket::UnpackName(const unsigned char *input, unsigned short input_size, unsigned short &pos)
{
Anope::string name;
- unsigned short pos_ptr = pos;
+ unsigned short pos_ptr = pos, lowest_ptr = input_size;
+ bool compressed = false;
if (pos_ptr >= input_size)
- throw SocketException("Unable to unpack name");
+ throw SocketException("Unable to unpack name - no input");
- unsigned short offset;
- do
+ while (input[pos_ptr] > 0)
{
- offset = input[pos_ptr];
+ unsigned short offset = input[pos_ptr];
if (offset & DNS_POINTER)
{
+ if ((offset & DNS_POINTER) != DNS_POINTER)
+ throw SocketException("Unable to unpack name - bogus compression header");
if (pos_ptr + 1 >= input_size)
- throw SocketException("Unable to unpack name");
- offset = (offset & DNS_LABEL) << 8 | input[++pos_ptr];
- pos_ptr = offset;
- if (pos_ptr >= input_size)
- throw SocketException("Unable to unpack name");
- offset = input[pos_ptr];
- ++pos;
- }
+ throw SocketException("Unable to unpack name - bogus compression header");
+
+ /* Place pos at the second byte of the first (farthest) compression pointer */
+ if (compressed == false)
+ {
+ ++pos;
+ compressed = true;
+ }
- if (pos_ptr + offset >= input_size)
- throw SocketException("Unable to unpack name");
- if (!name.empty())
- name += ".";
- for (unsigned i = 1; i <= offset; ++i)
- name += input[pos_ptr + i];
-
- pos_ptr += offset + 1;
- if (pos_ptr >= input_size)
- throw SocketException("Unable to unpack name");
- offset = input[pos_ptr];
- if (pos_ptr > pos)
- pos = pos_ptr;
+ pos_ptr = (offset & DNS_LABEL) << 8 | input[pos_ptr + 1];
+
+ /* Pointers can only go back */
+ if (pos_ptr >= lowest_ptr)
+ throw SocketException("Unable to unpack name - bogus compression pointer");
+ lowest_ptr = pos_ptr;
+ }
+ else
+ {
+ if (pos_ptr + offset + 1 >= input_size)
+ throw SocketException("Unable to unpack name - offset too large");
+ if (!name.empty())
+ name += ".";
+ for (unsigned i = 1; i <= offset; ++i)
+ name += input[pos_ptr + i];
+
+ pos_ptr += offset + 1;
+ if (compressed == false)
+ /* Move up pos */
+ pos = pos_ptr;
+ }
}
- while (offset);
+ /* +1 pos either to one byte after the compression pointer or one byte after the ending \0 */
++pos;
Log(LOG_DEBUG_2) << "Resolver: UnpackName successfully unpacked " << name;