#include #include #include #include #include #include namespace llarp::dns { static std::vector MessageToBuffer(Message msg) { std::array tmp = {{0}}; llarp_buffer_t buf{tmp}; if (not msg.Encode(&buf)) throw std::runtime_error("cannot encode dns message"); std::vector pkt; pkt.resize(buf.cur - buf.base); std::copy_n(tmp.data(), pkt.size(), pkt.data()); return pkt; } PacketHandler::PacketHandler(Logic_ptr logic, IQueryHandler* h) : m_QueryHandler{h}, m_Logic{logic} {} Proxy::Proxy(llarp_ev_loop_ptr loop, Logic_ptr logic, IQueryHandler* h) : PacketHandler{logic, h}, m_Loop(std::move(loop)) { m_Server.user = this; m_Server.tick = nullptr; m_Server.recvfrom = &HandleUDP; } void PacketHandler::Stop() { if (m_UnboundResolver) m_UnboundResolver->Stop(); } bool Proxy::Start(SockAddr addr, std::vector resolvers) { if (not PacketHandler::Start(addr, std::move(resolvers))) return false; return (llarp_ev_add_udp(m_Loop, &m_Server, addr) == 0); } static Proxy::Buffer_t CopyBuffer(const llarp_buffer_t& buf) { std::vector msgbuf(buf.sz); std::copy_n(buf.base, buf.sz, msgbuf.data()); return msgbuf; } void Proxy::HandleUDP(llarp_udp_io* u, const SockAddr& from, ManagedBuffer buf) { Buffer_t msgbuf = CopyBuffer(buf.underlying); auto self = static_cast(u->user); self->HandlePacket(from, from, std::move(msgbuf)); } void PacketHandler::Restart() { if (m_UnboundResolver) { LogInfo("reset libunbound's internal stuff"); m_UnboundResolver->Init(); } } bool PacketHandler::Start(SockAddr, std::vector resolvers) { return SetupUnboundResolver(std::move(resolvers)); } bool PacketHandler::SetupUnboundResolver(std::vector resolvers) { auto failFunc = [self = weak_from_this()](SockAddr from, SockAddr to, Message msg) { auto this_ptr = self.lock(); if (this_ptr) { this_ptr->SendServerMessageBufferTo(from, to, MessageToBuffer(std::move(msg))); } }; auto replyFunc = [self = weak_from_this()]( SockAddr from, SockAddr to, std::vector buf) { auto this_ptr = self.lock(); if (this_ptr) { this_ptr->SendServerMessageBufferTo(from, to, std::move(buf)); } }; m_UnboundResolver = std::make_shared(m_Logic, std::move(replyFunc), std::move(failFunc)); if (not m_UnboundResolver->Init()) { llarp::LogError("Failed to initialize upstream DNS resolver."); m_UnboundResolver = nullptr; return false; } for (const auto& resolver : resolvers) { if (not m_UnboundResolver->AddUpstreamResolver(resolver.toHost())) { llarp::LogError("Failed to add upstream DNS server: ", resolver.toHost()); m_UnboundResolver = nullptr; return false; } m_Resolvers.emplace(resolver); } return true; } void Proxy::SendServerMessageBufferTo(SockAddr, SockAddr to, Buffer_t buf) { if (llarp_ev_udp_sendto(&m_Server, to, buf) < 0) llarp::LogError("dns reply failed"); } bool PacketHandler::ShouldHandlePacket(SockAddr to, SockAddr from, Buffer_t buf) const { (void)from; MessageHeader hdr; llarp_buffer_t pkt{buf}; if (not hdr.Decode(&pkt)) { return false; } Message msg{hdr}; if (not msg.Decode(&pkt)) { return false; } if (m_QueryHandler and m_QueryHandler->ShouldHookDNSMessage(msg)) return true; if (m_Resolvers.find(to) != m_Resolvers.end()) { return false; } return true; } void PacketHandler::HandlePacket(SockAddr resolver, SockAddr from, Buffer_t buf) { MessageHeader hdr; llarp_buffer_t pkt{buf}; if (not hdr.Decode(&pkt)) { llarp::LogWarn("failed to parse dns header from ", from); return; } Message msg(hdr); if (not msg.Decode(&pkt)) { llarp::LogWarn("failed to parse dns message from ", from); return; } // we don't provide a DoH resolver because it requires verified TLS // TLS needs X509/ASN.1-DER and opting into the Root CA Cabal // thankfully mozilla added a backdoor that allows ISPs to turn it off // so we disable DoH for firefox using mozilla's ISP backdoor // see: https://github.com/loki-project/loki-network/issues/832 for (const auto& q : msg.questions) { // is this firefox looking for their backdoor record? if (q.IsName("use-application-dns.net")) { // yea it is, let's turn off DoH because god is dead. msg.AddNXReply(); // press F to pay respects SendServerMessageBufferTo(resolver, from, MessageToBuffer(std::move(msg))); return; } } if (m_QueryHandler && m_QueryHandler->ShouldHookDNSMessage(msg)) { auto reply = [self = shared_from_this(), to = from, resolver](dns::Message msg) { self->SendServerMessageBufferTo(resolver, to, MessageToBuffer(std::move(msg))); }; if (!m_QueryHandler->HandleHookedDNSMessage(std::move(msg), reply)) { llarp::LogWarn("failed to handle hooked dns"); } } else if (not m_UnboundResolver) { // no upstream resolvers // let's serv fail it msg.AddServFail(); SendServerMessageBufferTo(resolver, from, MessageToBuffer(std::move(msg))); } else { m_UnboundResolver->Lookup(resolver, from, std::move(msg)); } } } // namespace llarp::dns