Serenity Operating System
at master 181 lines 6.4 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2021, Sergey Bugaev <bugaevc@serenityos.org> 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include "Packet.h" 9#include "Name.h" 10#include "PacketHeader.h" 11#include <AK/Debug.h> 12#include <AK/MemoryStream.h> 13#include <AK/StringBuilder.h> 14#include <arpa/inet.h> 15 16namespace DNS { 17 18void Packet::add_question(Question const& question) 19{ 20 m_questions.empend(question); 21 22 VERIFY(m_questions.size() <= UINT16_MAX); 23} 24 25void Packet::add_answer(Answer const& answer) 26{ 27 m_answers.empend(answer); 28 29 VERIFY(m_answers.size() <= UINT16_MAX); 30} 31 32ErrorOr<ByteBuffer> Packet::to_byte_buffer() const 33{ 34 PacketHeader header; 35 header.set_id(m_id); 36 if (is_query()) 37 header.set_is_query(); 38 else 39 header.set_is_response(); 40 header.set_authoritative_answer(m_authoritative_answer); 41 // FIXME: What should this be? 42 header.set_opcode(0); 43 header.set_response_code(m_code); 44 header.set_truncated(false); // hopefully... 45 header.set_recursion_desired(m_recursion_desired); 46 // FIXME: what should the be for requests? 47 header.set_recursion_available(m_recursion_available); 48 header.set_question_count(m_questions.size()); 49 header.set_answer_count(m_answers.size()); 50 51 AllocatingMemoryStream stream; 52 53 TRY(stream.write_value(header)); 54 for (auto& question : m_questions) { 55 TRY(stream.write_value(question.name())); 56 TRY(stream.write_value(htons((u16)question.record_type()))); 57 TRY(stream.write_value(htons(question.raw_class_code()))); 58 } 59 for (auto& answer : m_answers) { 60 TRY(stream.write_value(answer.name())); 61 TRY(stream.write_value(htons((u16)answer.type()))); 62 TRY(stream.write_value(htons(answer.raw_class_code()))); 63 TRY(stream.write_value(htonl(answer.ttl()))); 64 if (answer.type() == RecordType::PTR) { 65 Name name { answer.record_data() }; 66 TRY(stream.write_value(htons(name.serialized_size()))); 67 TRY(stream.write_value(name)); 68 } else { 69 TRY(stream.write_value(htons(answer.record_data().length()))); 70 TRY(stream.write_until_depleted(answer.record_data().bytes())); 71 } 72 } 73 74 auto buffer = TRY(ByteBuffer::create_uninitialized(stream.used_buffer_size())); 75 TRY(stream.read_until_filled(buffer)); 76 return buffer; 77} 78 79class [[gnu::packed]] DNSRecordWithoutName { 80public: 81 DNSRecordWithoutName() = default; 82 83 u16 type() const { return m_type; } 84 u16 record_class() const { return m_class; } 85 u32 ttl() const { return m_ttl; } 86 u16 data_length() const { return m_data_length; } 87 88 void* data() { return this + 1; } 89 void const* data() const { return this + 1; } 90 91private: 92 NetworkOrdered<u16> m_type; 93 NetworkOrdered<u16> m_class; 94 NetworkOrdered<u32> m_ttl; 95 NetworkOrdered<u16> m_data_length; 96}; 97 98static_assert(sizeof(DNSRecordWithoutName) == 10); 99 100Optional<Packet> Packet::from_raw_packet(u8 const* raw_data, size_t raw_size) 101{ 102 if (raw_size < sizeof(PacketHeader)) { 103 dbgln("DNS response not large enough ({} out of {}) to be a DNS packet.", raw_size, sizeof(PacketHeader)); 104 return {}; 105 } 106 107 auto& header = *(PacketHeader const*)(raw_data); 108 dbgln_if(LOOKUPSERVER_DEBUG, "Got packet (ID: {})", header.id()); 109 dbgln_if(LOOKUPSERVER_DEBUG, " Question count: {}", header.question_count()); 110 dbgln_if(LOOKUPSERVER_DEBUG, " Answer count: {}", header.answer_count()); 111 dbgln_if(LOOKUPSERVER_DEBUG, " Authority count: {}", header.authority_count()); 112 dbgln_if(LOOKUPSERVER_DEBUG, "Additional count: {}", header.additional_count()); 113 114 Packet packet; 115 packet.m_id = header.id(); 116 packet.m_query_or_response = header.is_response(); 117 packet.m_code = header.response_code(); 118 119 // FIXME: Should we parse further in this case? 120 if (packet.code() != Code::NOERROR) 121 return packet; 122 123 size_t offset = sizeof(PacketHeader); 124 125 for (u16 i = 0; i < header.question_count(); i++) { 126 auto name = Name::parse(raw_data, offset, raw_size); 127 struct RawDNSAnswerQuestion { 128 NetworkOrdered<u16> record_type; 129 NetworkOrdered<u16> class_code; 130 }; 131 auto& record_and_class = *(RawDNSAnswerQuestion const*)&raw_data[offset]; 132 u16 class_code = record_and_class.class_code & ~MDNS_WANTS_UNICAST_RESPONSE; 133 bool mdns_wants_unicast_response = record_and_class.class_code & MDNS_WANTS_UNICAST_RESPONSE; 134 packet.m_questions.empend(name, (RecordType)(u16)record_and_class.record_type, (RecordClass)class_code, mdns_wants_unicast_response); 135 offset += 4; 136 auto& question = packet.m_questions.last(); 137 dbgln_if(LOOKUPSERVER_DEBUG, "Question #{}: name=_{}_, type={}, class={}", i, question.name(), question.record_type(), question.class_code()); 138 } 139 140 for (u16 i = 0; i < header.answer_count(); ++i) { 141 auto name = Name::parse(raw_data, offset, raw_size); 142 143 auto& record = *(DNSRecordWithoutName const*)(&raw_data[offset]); 144 145 DeprecatedString data; 146 147 offset += sizeof(DNSRecordWithoutName); 148 149 switch ((RecordType)record.type()) { 150 case RecordType::PTR: { 151 size_t dummy_offset = offset; 152 data = Name::parse(raw_data, dummy_offset, raw_size).as_string(); 153 break; 154 } 155 case RecordType::CNAME: 156 // Fall through 157 case RecordType::A: 158 // Fall through 159 case RecordType::TXT: 160 // Fall through 161 case RecordType::AAAA: 162 // Fall through 163 case RecordType::SRV: 164 data = { record.data(), record.data_length() }; 165 break; 166 default: 167 // FIXME: Parse some other record types perhaps? 168 dbgln("data=(unimplemented record type {})", (u16)record.type()); 169 } 170 171 dbgln_if(LOOKUPSERVER_DEBUG, "Answer #{}: name=_{}_, type={}, ttl={}, length={}, data=_{}_", i, name, record.type(), record.ttl(), record.data_length(), data); 172 u16 class_code = record.record_class() & ~MDNS_CACHE_FLUSH; 173 bool mdns_cache_flush = record.record_class() & MDNS_CACHE_FLUSH; 174 packet.m_answers.empend(name, (RecordType)record.type(), (RecordClass)class_code, record.ttl(), data, mdns_cache_flush); 175 offset += record.data_length(); 176 } 177 178 return packet; 179} 180 181}