diff options
-rw-r--r-- | Userland/Services/LookupServer/DNSName.cpp | 33 | ||||
-rw-r--r-- | Userland/Services/LookupServer/DNSName.h | 4 | ||||
-rw-r--r-- | Userland/Services/LookupServer/DNSPacket.cpp | 39 |
3 files changed, 41 insertions, 35 deletions
diff --git a/Userland/Services/LookupServer/DNSName.cpp b/Userland/Services/LookupServer/DNSName.cpp index 7385868076..ce9ad68f56 100644 --- a/Userland/Services/LookupServer/DNSName.cpp +++ b/Userland/Services/LookupServer/DNSName.cpp @@ -1,4 +1,5 @@ /* + * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> * Copyright (c) 2021, Sergey Bugaev <bugaevc@serenityos.org> * All rights reserved. * @@ -36,4 +37,36 @@ DNSName::DNSName(const String& name) m_name = name; } +DNSName DNSName::parse(const u8* data, size_t& offset, size_t max_offset, size_t recursion_level) +{ + if (recursion_level > 4) + return DNSName({}); + + StringBuilder builder; + while (true) { + if (offset >= max_offset) + return DNSName({}); + u8 b = data[offset++]; + if (b == '\0') { + // This terminates the name. + return builder.to_string(); + } else if ((b & 0xc0) == 0xc0) { + // The two bytes tell us the offset when to continue from. + if (offset >= max_offset) + return DNSName({}); + size_t dummy = (b & 0x3f) << 8 | data[offset++]; + auto rest_of_name = parse(data, dummy, max_offset, recursion_level + 1); + builder.append(rest_of_name.as_string()); + return builder.to_string(); + } else { + // This is the length of a part. + if (offset + b >= max_offset) + return DNSName({}); + builder.append((const char*)&data[offset], (size_t)b); + builder.append('.'); + offset += b; + } + } +} + } diff --git a/Userland/Services/LookupServer/DNSName.h b/Userland/Services/LookupServer/DNSName.h index 20f1c91fba..21d1b88e47 100644 --- a/Userland/Services/LookupServer/DNSName.h +++ b/Userland/Services/LookupServer/DNSName.h @@ -1,4 +1,5 @@ /* + * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> * Copyright (c) 2021, Sergey Bugaev <bugaevc@serenityos.org> * All rights reserved. * @@ -33,6 +34,9 @@ namespace LookupServer { class DNSName { public: DNSName(const String&); + + static DNSName parse(const u8* data, size_t& offset, size_t max_offset, size_t recursion_level = 0); + const String& as_string() const { return m_name; } private: diff --git a/Userland/Services/LookupServer/DNSPacket.cpp b/Userland/Services/LookupServer/DNSPacket.cpp index 6248318640..0bf84d5ac3 100644 --- a/Userland/Services/LookupServer/DNSPacket.cpp +++ b/Userland/Services/LookupServer/DNSPacket.cpp @@ -26,6 +26,7 @@ */ #include "DNSPacket.h" +#include "DNSName.h" #include "DNSPacketHeader.h" #include <AK/IPv4Address.h> #include <AK/MemoryStream.h> @@ -108,8 +109,6 @@ ByteBuffer DNSPacket::to_byte_buffer() const return stream.copy_into_contiguous_buffer(); } -static String parse_dns_name(const u8* data, size_t& offset, size_t max_offset, size_t recursion_level = 0); - class [[gnu::packed]] DNSRecordWithoutName { public: DNSRecordWithoutName() { } @@ -159,7 +158,7 @@ Optional<DNSPacket> DNSPacket::from_raw_packet(const u8* raw_data, size_t raw_si size_t offset = sizeof(DNSPacketHeader); for (u16 i = 0; i < header.question_count(); i++) { - auto name = parse_dns_name(raw_data, offset, raw_size); + auto name = DNSName::parse(raw_data, offset, raw_size); struct RawDNSAnswerQuestion { NetworkOrdered<u16> record_type; NetworkOrdered<u16> class_code; @@ -174,7 +173,7 @@ Optional<DNSPacket> DNSPacket::from_raw_packet(const u8* raw_data, size_t raw_si } for (u16 i = 0; i < header.answer_count(); ++i) { - auto name = parse_dns_name(raw_data, offset, raw_size); + auto name = DNSName::parse(raw_data, offset, raw_size); auto& record = *(const DNSRecordWithoutName*)(&raw_data[offset]); @@ -184,7 +183,7 @@ Optional<DNSPacket> DNSPacket::from_raw_packet(const u8* raw_data, size_t raw_si if (record.type() == T_PTR) { size_t dummy_offset = offset; - data = parse_dns_name(raw_data, dummy_offset, raw_size); + data = DNSName::parse(raw_data, dummy_offset, raw_size).as_string(); } else if (record.type() == T_A) { data = { record.data(), record.data_length() }; } else { @@ -201,34 +200,4 @@ Optional<DNSPacket> DNSPacket::from_raw_packet(const u8* raw_data, size_t raw_si return packet; } -String parse_dns_name(const u8* data, size_t& offset, size_t max_offset, size_t recursion_level) -{ - if (recursion_level > 4) - return {}; - Vector<char, 128> buf; - while (offset < max_offset) { - u8 ch = data[offset]; - if (ch == '\0') { - ++offset; - break; - } - if ((ch & 0xc0) == 0xc0) { - if ((offset + 1) >= max_offset) - return {}; - size_t dummy = (ch & 0x3f) << 8 | data[offset + 1]; - offset += 2; - StringBuilder builder; - builder.append(buf.data(), buf.size()); - auto okay = parse_dns_name(data, dummy, max_offset, recursion_level + 1); - builder.append(okay); - return builder.to_string(); - } - for (size_t i = 0; i < ch; ++i) - buf.append(data[offset + i + 1]); - buf.append('.'); - offset += ch + 1; - } - return String::copy(buf); -} - } |