diff options
author | Adam <Adam@anope.org> | 2012-03-27 19:01:29 -0400 |
---|---|---|
committer | Adam <Adam@anope.org> | 2012-03-27 19:01:29 -0400 |
commit | 31a0e673b2028f3dad67cd1e6f0f5410d0dde56d (patch) | |
tree | 32483487f9fbacb3c92361cb769894c89afaa48e /src | |
parent | 88fd1da803fd144f9eae4213eb4903d7c1ade9ad (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.cpp | 64 |
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; |