diff --git a/Base/etc/LookupServer.ini b/Base/etc/LookupServer.ini index 9fedd22837..b7185e689b 100644 --- a/Base/etc/LookupServer.ini +++ b/Base/etc/LookupServer.ini @@ -1,2 +1,3 @@ [DNS] Nameservers=1.1.1.1,1.0.0.1 +EnableServer=0 diff --git a/Userland/Services/LookupServer/CMakeLists.txt b/Userland/Services/LookupServer/CMakeLists.txt index 5b99be3de8..7831df7481 100644 --- a/Userland/Services/LookupServer/CMakeLists.txt +++ b/Userland/Services/LookupServer/CMakeLists.txt @@ -5,6 +5,7 @@ set(SOURCES DNSAnswer.cpp DNSName.cpp DNSPacket.cpp + DNSServer.cpp LookupServer.cpp LookupServerEndpoint.h LookupClientEndpoint.h diff --git a/Userland/Services/LookupServer/DNSPacket.cpp b/Userland/Services/LookupServer/DNSPacket.cpp index afd2b745b4..0d30ac6761 100644 --- a/Userland/Services/LookupServer/DNSPacket.cpp +++ b/Userland/Services/LookupServer/DNSPacket.cpp @@ -44,6 +44,13 @@ void DNSPacket::add_question(const DNSQuestion& question) ASSERT(m_questions.size() <= UINT16_MAX); } +void DNSPacket::add_answer(const DNSAnswer& answer) +{ + m_answers.empend(answer); + + ASSERT(m_answers.size() <= UINT16_MAX); +} + ByteBuffer DNSPacket::to_byte_buffer() const { DNSPacketHeader header; @@ -54,6 +61,7 @@ ByteBuffer DNSPacket::to_byte_buffer() const header.set_is_response(); // FIXME: What should this be? header.set_opcode(0); + header.set_response_code(m_code); header.set_truncated(false); // hopefully... header.set_recursion_desired(true); // FIXME: what should the be for requests? diff --git a/Userland/Services/LookupServer/DNSPacket.h b/Userland/Services/LookupServer/DNSPacket.h index 41912c9f2d..bfda9cd5e9 100644 --- a/Userland/Services/LookupServer/DNSPacket.h +++ b/Userland/Services/LookupServer/DNSPacket.h @@ -80,6 +80,7 @@ public: } void add_question(const DNSQuestion&); + void add_answer(const DNSAnswer&); enum class Code : u8 { NOERROR = 0, diff --git a/Userland/Services/LookupServer/DNSServer.cpp b/Userland/Services/LookupServer/DNSServer.cpp new file mode 100644 index 0000000000..81ff783a53 --- /dev/null +++ b/Userland/Services/LookupServer/DNSServer.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2021, Sergey Bugaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "DNSServer.h" +#include "DNSPacket.h" +#include "LookupServer.h" +#include + +namespace LookupServer { + +DNSServer::DNSServer(Object* parent) + : Core::UDPServer(parent) +{ + bind(IPv4Address(), 53); + on_ready_to_receive = [this]() { + handle_client(); + }; +} + +void DNSServer::handle_client() +{ + sockaddr_in client_address; + auto buffer = receive(1024, client_address); + auto optional_request = DNSPacket::from_raw_packet(buffer.data(), buffer.size()); + if (!optional_request.has_value()) { + dbgln("Got an invalid DNS packet"); + return; + } + auto& request = optional_request.value(); + + if (!request.is_query()) { + dbgln("It's not a request"); + return; + } + + LookupServer& lookup_server = LookupServer::the(); + + DNSPacket response; + response.set_is_response(); + response.set_id(request.id()); + + for (auto& question : request.questions()) { + if (question.class_code() != C_IN) + continue; + response.add_question(question); + auto answers = lookup_server.lookup(question.name(), question.record_type()); + for (auto& answer : answers) { + response.add_answer(answer); + } + } + + if (response.answer_count() == 0) + response.set_code(DNSPacket::Code::NXDOMAIN); + else + response.set_code(DNSPacket::Code::NOERROR); + + buffer = response.to_byte_buffer(); + sendto(fd(), buffer.data(), buffer.size(), 0, (const sockaddr*)&client_address, sizeof(client_address)); +} + +} diff --git a/Userland/Services/LookupServer/DNSServer.h b/Userland/Services/LookupServer/DNSServer.h new file mode 100644 index 0000000000..24a055e586 --- /dev/null +++ b/Userland/Services/LookupServer/DNSServer.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021, Sergey Bugaev + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include + +namespace LookupServer { + +class DNSServer : public Core::UDPServer { + C_OBJECT(DNSServer) + +private: + explicit DNSServer(Object* parent = nullptr); + + void handle_client(); +}; + +} diff --git a/Userland/Services/LookupServer/LookupServer.cpp b/Userland/Services/LookupServer/LookupServer.cpp index 75d9aa124c..2185c4fea1 100644 --- a/Userland/Services/LookupServer/LookupServer.cpp +++ b/Userland/Services/LookupServer/LookupServer.cpp @@ -62,6 +62,11 @@ LookupServer::LookupServer() load_etc_hosts(); + if (config->read_bool_entry("DNS", "EnableServer")) { + m_dns_server = DNSServer::construct(this); + // TODO: drop root privileges here. + } + m_local_server = Core::LocalServer::construct(this); m_local_server->on_ready_to_accept = [this]() { auto socket = m_local_server->accept(); diff --git a/Userland/Services/LookupServer/LookupServer.h b/Userland/Services/LookupServer/LookupServer.h index 7c01a2a432..f19ec7ed09 100644 --- a/Userland/Services/LookupServer/LookupServer.h +++ b/Userland/Services/LookupServer/LookupServer.h @@ -26,8 +26,9 @@ #pragma once -#include "DNSPacket.h" #include "DNSName.h" +#include "DNSPacket.h" +#include "DNSServer.h" #include namespace LookupServer { @@ -49,8 +50,8 @@ private: Vector lookup(const DNSName& hostname, const String& nameserver, bool& did_get_response, unsigned short record_type, ShouldRandomizeCase = ShouldRandomizeCase::Yes); - RefPtr m_local_server; + RefPtr m_dns_server; Vector m_nameservers; HashMap, DNSName::Traits> m_etc_hosts; HashMap, DNSName::Traits> m_lookup_cache;