From 1d1bde2e88cd3870d889f646bbc2f6f2b3c0f54e Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 3 Dec 2018 17:22:59 -0500 Subject: [PATCH] add dnslib --- CMakeLists.txt | 11 ++ daemon/dns.cpp | 6 +- include/llarp/dns/dns.hpp | 5 + include/llarp/dns/message.hpp | 60 ++++++++ include/llarp/dns/name.hpp | 28 ++++ include/llarp/dns/query.hpp | 4 + include/llarp/dns/question.hpp | 29 ++++ include/llarp/dns/rr.hpp | 35 +++++ include/llarp/dns/serialize.hpp | 39 ++++++ include/llarp/dns/server.hpp | 93 +++++++++++++ include/llarp/dns/string.hpp | 23 ++++ include/llarp/dns_dotlokilookup.hpp | 35 ++--- include/llarp/handlers/tun.hpp | 47 ++++--- include/llarp/net.hpp | 192 +------------------------- include/llarp/net_int.hpp | 199 +++++++++++++++++++++++++++ include/llarp/service/address.hpp | 6 +- llarp/context.cpp | 6 +- llarp/dns/message.cpp | 162 ++++++++++++++++++++++ llarp/dns/name.cpp | 82 +++++++++++ llarp/dns/question.cpp | 27 ++++ llarp/dns/rr.cpp | 35 +++++ llarp/dns/serialize.cpp | 76 +++++++++++ llarp/dns/server.cpp | 112 +++++++++++++++ llarp/dns_dotlokilookup.cpp | 84 +++--------- llarp/handlers/tun.cpp | 205 ++++++++++++++++------------ llarp/service/address.cpp | 8 +- test/test_dnslib.cpp | 84 ++++++++++++ 27 files changed, 1293 insertions(+), 400 deletions(-) create mode 100644 include/llarp/dns/dns.hpp create mode 100644 include/llarp/dns/message.hpp create mode 100644 include/llarp/dns/name.hpp create mode 100644 include/llarp/dns/query.hpp create mode 100644 include/llarp/dns/question.hpp create mode 100644 include/llarp/dns/rr.hpp create mode 100644 include/llarp/dns/serialize.hpp create mode 100644 include/llarp/dns/server.hpp create mode 100644 include/llarp/dns/string.hpp create mode 100644 include/llarp/net_int.hpp create mode 100644 llarp/dns/message.cpp create mode 100644 llarp/dns/name.cpp create mode 100644 llarp/dns/question.cpp create mode 100644 llarp/dns/rr.cpp create mode 100644 llarp/dns/serialize.cpp create mode 100644 llarp/dns/server.cpp create mode 100644 test/test_dnslib.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a6f32518..da801b364 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -416,8 +416,18 @@ if(WIN32) set(UTP_SRC ${UTP_SRC} libutp/libutp_inet_ntop.cpp) endif() +set(DNSLIB_SRC + llarp/dns/message.cpp + llarp/dns/name.cpp + llarp/dns/question.cpp + llarp/dns/rr.cpp + llarp/dns/serialize.cpp + llarp/dns/server.cpp +) + set(LIB_SRC + ${DNSLIB_SRC} ${UTP_SRC} llarp/address_info.cpp llarp/bencode.cpp @@ -521,6 +531,7 @@ set(TEST_SRC test/test_dns_unit.cpp test/test_dnsc_unit.cpp test/test_dnsd_unit.cpp + test/test_dnslib.cpp test/test_llarp_queue.cpp test/test_llarp_queue_manager.cpp test/test_llarp_thread_pool.cpp diff --git a/daemon/dns.cpp b/daemon/dns.cpp index 4611ddd5b..ca65f8688 100644 --- a/daemon/dns.cpp +++ b/daemon/dns.cpp @@ -191,7 +191,8 @@ main(int argc, char *argv[]) return 0; } // Configure intercept - dnsd.intercept = &llarp_dotlokilookup_handler; + dnsd.intercept = nullptr; + // dnsd.intercept = &llarp_dotlokilookup_handler; llarp::LogInfo("singlethread start"); llarp_ev_loop_run_single_process(netloop, worker, logic); @@ -219,7 +220,8 @@ main(int argc, char *argv[]) return 0; } // Configure intercept - dnsd.intercept = &llarp_dotlokilookup_handler; + dnsd.intercept = nullptr; + // dnsd.intercept = &llarp_dotlokilookup_handler; struct sockaddr_in m_address; int m_sockfd; diff --git a/include/llarp/dns/dns.hpp b/include/llarp/dns/dns.hpp new file mode 100644 index 000000000..aa91377c2 --- /dev/null +++ b/include/llarp/dns/dns.hpp @@ -0,0 +1,5 @@ +#include +#include +#include +#include +#include diff --git a/include/llarp/dns/message.hpp b/include/llarp/dns/message.hpp new file mode 100644 index 000000000..4f9915f93 --- /dev/null +++ b/include/llarp/dns/message.hpp @@ -0,0 +1,60 @@ +#ifndef LLARP_DNS_MESSAGE_HPP +#define LLARP_DNS_MESSAGE_HPP +#include +#include +#include + +namespace llarp +{ + namespace dns + { + using MsgID_t = uint16_t; + using Fields_t = uint16_t; + using Count_t = uint16_t; + + struct MessageHeader : public Serialize + { + MsgID_t id; + Fields_t fields; + Count_t qd_count; + Count_t an_count; + Count_t ns_count; + Count_t ar_count; + + bool + Encode(llarp_buffer_t* buf) const override; + + bool + Decode(llarp_buffer_t* buf) override; + }; + + struct Message : public Serialize + { + void + UpdateHeader(); + + Message& + AddNXReply(); + + Message& + AddINReply(llarp::huint32_t addr); + + Message& + AddAReply(std::string name); + + bool + Encode(llarp_buffer_t* buf) const override; + + bool + Decode(llarp_buffer_t* buf) override; + + MessageHeader hdr; + std::vector< Question > questions; + std::vector< ResourceRecord > answers; + std::vector< ResourceRecord > authorities; + std::vector< ResourceRecord > additional; + }; + } // namespace dns +} // namespace llarp + +#endif diff --git a/include/llarp/dns/name.hpp b/include/llarp/dns/name.hpp new file mode 100644 index 000000000..e974fb923 --- /dev/null +++ b/include/llarp/dns/name.hpp @@ -0,0 +1,28 @@ +#ifndef LLARP_DNS_NAME_HPP +#define LLARP_DNS_NAME_HPP + +#include +#include +#include + +namespace llarp +{ + namespace dns + { + using Name_t = std::string; + + /// decode name from buffer + bool + DecodeName(llarp_buffer_t* buf, Name_t& name); + + /// encode name to buffer + bool + EncodeName(llarp_buffer_t* buf, const Name_t& name); + + bool + DecodePTR(const Name_t& name, huint32_t& ip); + + } // namespace dns +} // namespace llarp + +#endif diff --git a/include/llarp/dns/query.hpp b/include/llarp/dns/query.hpp new file mode 100644 index 000000000..665e98e2f --- /dev/null +++ b/include/llarp/dns/query.hpp @@ -0,0 +1,4 @@ +#ifndef LLARP_DNS_QUERY_HPP +#define LLARP_DNS_QUERY_HPP + +#endif diff --git a/include/llarp/dns/question.hpp b/include/llarp/dns/question.hpp new file mode 100644 index 000000000..b44130b4d --- /dev/null +++ b/include/llarp/dns/question.hpp @@ -0,0 +1,29 @@ +#ifndef LLARP_DNS_QUESTION_HPP +#define LLARP_DNS_QUESTION_HPP +#include +#include +#include + +namespace llarp +{ + namespace dns + { + using QType_t = llarp::huint16_t; + using QClass_t = llarp::huint16_t; + + struct Question : public Serialize + { + bool + Encode(llarp_buffer_t* buf) const override; + + bool + Decode(llarp_buffer_t* buf) override; + + Name_t qname; + QType_t qtype; + QClass_t qclass; + }; + } // namespace dns +} // namespace llarp + +#endif diff --git a/include/llarp/dns/rr.hpp b/include/llarp/dns/rr.hpp new file mode 100644 index 000000000..4fde191c8 --- /dev/null +++ b/include/llarp/dns/rr.hpp @@ -0,0 +1,35 @@ +#ifndef LLARP_DNS_RR_HPP +#define LLARP_DNS_RR_HPP +#include +#include +#include +#include +#include + +namespace llarp +{ + namespace dns + { + using RRClass_t = llarp::huint16_t; + using RRType_t = llarp::huint16_t; + using RR_RData_t = std::vector< byte_t >; + using RR_TTL_t = llarp::huint32_t; + + struct ResourceRecord : public Serialize + { + bool + Encode(llarp_buffer_t* buf) const override; + + bool + Decode(llarp_buffer_t* buf) override; + + Name_t rr_name; + RRType_t rr_type; + RRClass_t rr_class; + RR_TTL_t ttl; + RR_RData_t rData; + }; + } // namespace dns +} // namespace llarp + +#endif diff --git a/include/llarp/dns/serialize.hpp b/include/llarp/dns/serialize.hpp new file mode 100644 index 000000000..e76ee5c71 --- /dev/null +++ b/include/llarp/dns/serialize.hpp @@ -0,0 +1,39 @@ +#ifndef LLARP_DNS_SERIALIZE_HPP +#define LLARP_DNS_SERIALIZE_HPP +#include +#include + +namespace llarp +{ + namespace dns + { + /// base type for serializable dns entities + struct Serialize + { + /// encode entity to buffer + virtual bool + Encode(llarp_buffer_t* buf) const = 0; + + /// decode entity from buffer + virtual bool + Decode(llarp_buffer_t* buf) = 0; + }; + + template < typename Int_t > + bool + EncodeInt(llarp_buffer_t* buf, const Int_t& i); + + template < typename Int_t > + bool + DecodeInt(llarp_buffer_t* buf, Int_t& i); + + bool + EncodeRData(llarp_buffer_t* buf, const std::vector< byte_t >& rdata); + + bool + DecodeRData(llarp_buffer_t* buf, std::vector< byte_t >& rdata); + + } // namespace dns +} // namespace llarp + +#endif diff --git a/include/llarp/dns/server.hpp b/include/llarp/dns/server.hpp new file mode 100644 index 000000000..8b0dbf771 --- /dev/null +++ b/include/llarp/dns/server.hpp @@ -0,0 +1,93 @@ +#ifndef LLARP_DNS_SERVER_HPP +#define LLARP_DNS_SERVER_HPP +#include +#include + +#include +#include + +#include + +namespace llarp +{ + namespace dns + { + /// handler of dns query hooking + struct IQueryHandler + { + /// return true if we should hook this message + virtual bool + ShouldHookDNSMessage(const Message& msg) const = 0; + + /// handle a hooked message + virtual bool + HandleHookedDNSMessage(Message query, + std::function< void(Message) > sendReply) = 0; + }; + + struct Proxy + { + Proxy(llarp_ev_loop* loop, IQueryHandler* handler); + + bool + Start(const llarp::Addr& addr, + const std::vector< llarp::Addr >& resolvers); + + void + Stop(); + + private: + /// low level packet handler + static void + HandleUDPRecv(llarp_udp_io*, const struct sockaddr*, llarp_buffer_t); + + /// low level ticker + static void + HandleTick(llarp_udp_io*); + + void + Tick(llarp_time_t now); + + void + HandlePkt(llarp::Addr from, llarp_buffer_t* buf); + + void + SendMessageTo(llarp::Addr to, Message msg); + + llarp::Addr + PickRandomResolver() const; + + private: + llarp_udp_io m_UDP; + llarp_ev_loop* m_Loop; + IQueryHandler* m_QueryHandler; + std::vector< llarp::Addr > m_Resolvers; + + struct TX + { + MsgID_t txid; + llarp::Addr from; + + bool + operator==(const TX& other) const + { + return txid == other.txid && from == other.from; + } + + struct Hash + { + size_t + operator()(const TX& t) const noexcept + { + return t.txid ^ llarp::Addr::Hash()(t.from); + } + }; + }; + + // maps tx to who to send reply to + std::unordered_map< TX, llarp::Addr, TX::Hash > m_Forwarded; + }; + } // namespace dns +} // namespace llarp + +#endif diff --git a/include/llarp/dns/string.hpp b/include/llarp/dns/string.hpp new file mode 100644 index 000000000..d3ce75c9c --- /dev/null +++ b/include/llarp/dns/string.hpp @@ -0,0 +1,23 @@ +#ifndef LLARP_DNS_STRING_HPP +#define LLARP_DNS_STRING_HPP + +#include + +namespace llarp +{ + namespace dns + { + using name_t = std::string; + + /// decode name from buffer + bool + decode_name(llarp_buffer_t* buf, name_t& name); + + /// encode name to buffer + bool + encode_name(llarp_buffer_t* buf, const name_t& name); + + } // namespace dns +} // namespace llarp + +#endif diff --git a/include/llarp/dns_dotlokilookup.hpp b/include/llarp/dns_dotlokilookup.hpp index cef0cb9e2..f621580c9 100644 --- a/include/llarp/dns_dotlokilookup.hpp +++ b/include/llarp/dns_dotlokilookup.hpp @@ -5,36 +5,25 @@ #include "dnsd.hpp" -using map_address_hook_func = - std::function< bool(const byte_t *addr, bool isSNode, uint32_t ip) >; +struct dotLokiLookup; + +using obtain_address_func = + std::function< bool(struct dotLokiLookup *, const byte_t *addr, + bool isSNode, llarp::huint32_t &ip) >; /// dotLokiLookup context/config struct dotLokiLookup { - /// for timers (MAYBEFIXME? maybe we decouple this, yes pls have a generic - /// passed in) - // we can use DNSc for access to the logic - struct llarp_logic *logic; - - /// which ip tracker to use struct dns_iptracker *ip_tracker; - - /// tunEndpoint - // llarp::handlers::TunEndpoint *tunEndpoint; // is this even needed here? - void *user; // well dotLokiLookup current uses it to access the tun if - // pointer to tunendpoint properties? - // llarp::service::Context *hiddenServiceContext; - - // need a way to reference - // 1. mapaddress - map_address_hook_func map_address_handler; - // std::function< bool(const llarp::service::Address &addr, uint32_t ip), - // llarp::handlers::TunEndpoint * > callback; - // 2. prefetch + /// opaque user data + void *user; + /// get address for lookup + obtain_address_func obtainAddress; }; -dnsd_query_hook_response * +void llarp_dotlokilookup_handler(std::string name, - const dnsd_question_request *request); + const dnsd_question_request *request, + struct dnsd_query_hook_response *result); #endif diff --git a/include/llarp/handlers/tun.hpp b/include/llarp/handlers/tun.hpp index 7c5e3bcd9..0e9c8ff72 100644 --- a/include/llarp/handlers/tun.hpp +++ b/include/llarp/handlers/tun.hpp @@ -5,9 +5,8 @@ #include #include #include -#include // for relay -#include // for lookup -#include // for tracker +#include +#include namespace llarp { @@ -18,7 +17,7 @@ namespace llarp static const char DefaultTunDstAddr[] = "10.10.0.1"; static const char DefaultTunSrcAddr[] = "10.10.0.2"; - struct TunEndpoint : public service::Endpoint + struct TunEndpoint : public service::Endpoint, public dns::IQueryHandler { TunEndpoint(const std::string& nickname, llarp_router* r); ~TunEndpoint(); @@ -29,6 +28,14 @@ namespace llarp virtual void Tick(llarp_time_t now); + bool + ShouldHookDNSMessage(const dns::Message& msg) const override; + + bool + HandleHookedDNSMessage( + dns::Message query, + std::function< void(dns::Message) > sendreply) override; + void TickTun(llarp_time_t now); @@ -66,16 +73,6 @@ namespace llarp bool HasLocalIP(const huint32_t& ip) const; -#ifndef WIN32 - /// overrides Endpoint - bool - IsolationFailed() - { - m_TunSetupResult.set_value(false); - return false; - } -#endif - llarp_tun_io tunif; std::unique_ptr< llarp_fd_promise > Promise; @@ -173,18 +170,18 @@ namespace llarp }); } + void + SendDNSReply(service::Address addr, + service::Endpoint::OutboundContext* ctx, dns::Message query, + std::function< void(dns::Message) > reply); + #ifndef WIN32 - /// handles setup, given value true on success and false on failure to set - /// up interface - std::promise< bool > m_TunSetupResult; /// handles fd injection force android std::promise< int > m_VPNPromise; #endif - /// DNS server per tun - struct dnsd_context dnsd; - /// DNS loki lookup subsystem configuration (also holds optional iptracker - /// for netns) - struct dotLokiLookup dll; + + /// our dns resolver + dns::Proxy m_Resolver; /// maps ip address to timestamp last active std::unordered_map< huint32_t, llarp_time_t, huint32_t::Hash > @@ -195,8 +192,10 @@ namespace llarp huint32_t m_NextIP; /// highest ip address to allocate (host byte order) huint32_t m_MaxIP; - /// upstream dns - llarp::Addr m_UpstreamDNSAddr; + /// our ip range we are using + llarp::IPRange m_OurRange; + /// upstream dns resolver list + std::vector< llarp::Addr > m_UpstreamResolvers; /// local dns llarp::Addr m_LocalResolverAddr; }; diff --git a/include/llarp/net.hpp b/include/llarp/net.hpp index d8fb21bc1..7426f4c8f 100644 --- a/include/llarp/net.hpp +++ b/include/llarp/net.hpp @@ -3,25 +3,12 @@ #include #include #include -#include #include "logger.hpp" #include "mem.hpp" #include +#include #include -#include // for itoa - -// for addrinfo -#ifndef _WIN32 -#include -#include -#include -#else -#include -#include -#define inet_aton(x, y) inet_pton(AF_INET, x, y) -#endif - bool operator==(const sockaddr& a, const sockaddr& b); @@ -54,183 +41,6 @@ llarp_getPrivateIfs(); namespace llarp { - // clang-format off - - struct huint32_t - { - uint32_t h; - - constexpr huint32_t - operator &(huint32_t x) const { return huint32_t{uint32_t(h & x.h)}; } - constexpr huint32_t - operator |(huint32_t x) const { return huint32_t{uint32_t(h | x.h)}; } - constexpr huint32_t - operator ^(huint32_t x) const { return huint32_t{uint32_t(h ^ x.h)}; } - - constexpr huint32_t - operator ~() const { return huint32_t{uint32_t(~h)}; } - - inline huint32_t operator ++() { ++h; return *this; } - inline huint32_t operator --() { --h; return *this; } - - constexpr bool operator <(huint32_t x) const { return h < x.h; } - constexpr bool operator ==(huint32_t x) const { return h == x.h; } - - friend std::ostream& - operator<<(std::ostream& out, const huint32_t& a) - { - uint32_t n = htonl(a.h); - char tmp[INET_ADDRSTRLEN] = {0}; - if(inet_ntop(AF_INET, (void*)&n, tmp, sizeof(tmp))) - { - out << tmp; - } - return out; - } - - struct Hash - { - inline size_t - operator ()(huint32_t x) const - { - return std::hash< uint32_t >{}(x.h); - } - }; - }; - - struct nuint32_t - { - uint32_t n; - - constexpr nuint32_t - operator &(nuint32_t x) const { return nuint32_t{uint32_t(n & x.n)}; } - constexpr nuint32_t - operator |(nuint32_t x) const { return nuint32_t{uint32_t(n | x.n)}; } - constexpr nuint32_t - operator ^(nuint32_t x) const { return nuint32_t{uint32_t(n ^ x.n)}; } - - constexpr nuint32_t - operator ~() const { return nuint32_t{uint32_t(~n)}; } - - inline nuint32_t operator ++() { ++n; return *this; } - inline nuint32_t operator --() { --n; return *this; } - - constexpr bool operator <(nuint32_t x) const { return n < x.n; } - constexpr bool operator ==(nuint32_t x) const { return n == x.n; } - - friend std::ostream& - operator<<(std::ostream& out, const nuint32_t& a) - { - char tmp[INET_ADDRSTRLEN] = {0}; - if(inet_ntop(AF_INET, (void*)&a.n, tmp, sizeof(tmp))) - { - out << tmp; - } - return out; - } - - struct Hash - { - inline size_t - operator ()(nuint32_t x) const - { - return std::hash< uint32_t >{}(x.n); - } - }; - }; - - struct huint16_t - { - uint16_t h; - - constexpr huint16_t - operator &(huint16_t x) const { return huint16_t{uint16_t(h & x.h)}; } - constexpr huint16_t - operator |(huint16_t x) const { return huint16_t{uint16_t(h | x.h)}; } - constexpr huint16_t - operator ~() const { return huint16_t{uint16_t(~h)}; } - - inline huint16_t operator ++() { ++h; return *this; } - inline huint16_t operator --() { --h; return *this; } - - constexpr bool operator <(huint16_t x) const { return h < x.h; } - constexpr bool operator ==(huint16_t x) const { return h == x.h; } - - friend std::ostream& - operator<<(std::ostream& out, const huint16_t& a) - { - return out << a.h; - } - - struct Hash - { - inline size_t - operator ()(huint16_t x) const - { - return std::hash< uint16_t >{}(x.h); - } - }; - }; - - struct nuint16_t - { - uint16_t n; - - constexpr nuint16_t - operator &(nuint16_t x) const { return nuint16_t{uint16_t(n & x.n)}; } - constexpr nuint16_t - operator |(nuint16_t x) const { return nuint16_t{uint16_t(n | x.n)}; } - constexpr nuint16_t - operator ~() const { return nuint16_t{uint16_t(~n)}; } - - inline nuint16_t operator ++() { ++n; return *this; } - inline nuint16_t operator --() { --n; return *this; } - - constexpr bool operator <(nuint16_t x) const { return n < x.n; } - constexpr bool operator ==(nuint16_t x) const { return n == x.n; } - - friend std::ostream& - operator<<(std::ostream& out, const nuint16_t& a) - { - return out << ntohs(a.n); - } - - struct Hash - { - inline size_t - operator ()(nuint16_t x) const - { - return std::hash< uint16_t >{}(x.n); - } - }; - }; - - // clang-format on - - static inline nuint32_t - xhtonl(huint32_t x) - { - return nuint32_t{htonl(x.h)}; - } - - static inline huint32_t - xntohl(nuint32_t x) - { - return huint32_t{ntohl(x.n)}; - } - - static inline nuint16_t - xhtons(huint16_t x) - { - return nuint16_t{htons(x.h)}; - } - - static inline huint16_t - xntohs(nuint16_t x) - { - return huint16_t{ntohs(x.n)}; - } - struct IPRange { huint32_t addr; diff --git a/include/llarp/net_int.hpp b/include/llarp/net_int.hpp new file mode 100644 index 000000000..822182f43 --- /dev/null +++ b/include/llarp/net_int.hpp @@ -0,0 +1,199 @@ +#ifndef LLARP_NET_INT_HPP +#define LLARP_NET_INT_HPP + +// for addrinfo +#ifndef _WIN32 +#include +#include +#include +#else +#include +#include +#define inet_aton(x, y) inet_pton(AF_INET, x, y) +#endif + +#include // for itoa +#include +#include + +namespace llarp +{ + // clang-format off + + struct huint32_t + { + uint32_t h; + + constexpr huint32_t + operator &(huint32_t x) const { return huint32_t{uint32_t(h & x.h)}; } + constexpr huint32_t + operator |(huint32_t x) const { return huint32_t{uint32_t(h | x.h)}; } + constexpr huint32_t + operator ^(huint32_t x) const { return huint32_t{uint32_t(h ^ x.h)}; } + + constexpr huint32_t + operator ~() const { return huint32_t{uint32_t(~h)}; } + + inline huint32_t operator ++() { ++h; return *this; } + inline huint32_t operator --() { --h; return *this; } + + constexpr bool operator <(huint32_t x) const { return h < x.h; } + constexpr bool operator ==(huint32_t x) const { return h == x.h; } + + friend std::ostream& + operator<<(std::ostream& out, const huint32_t& a) + { + uint32_t n = htonl(a.h); + char tmp[INET_ADDRSTRLEN] = {0}; + if(inet_ntop(AF_INET, (void*)&n, tmp, sizeof(tmp))) + { + out << tmp; + } + return out; + } + + struct Hash + { + inline size_t + operator ()(huint32_t x) const + { + return std::hash< uint32_t >{}(x.h); + } + }; + }; + + struct nuint32_t + { + uint32_t n; + + constexpr nuint32_t + operator &(nuint32_t x) const { return nuint32_t{uint32_t(n & x.n)}; } + constexpr nuint32_t + operator |(nuint32_t x) const { return nuint32_t{uint32_t(n | x.n)}; } + constexpr nuint32_t + operator ^(nuint32_t x) const { return nuint32_t{uint32_t(n ^ x.n)}; } + + constexpr nuint32_t + operator ~() const { return nuint32_t{uint32_t(~n)}; } + + inline nuint32_t operator ++() { ++n; return *this; } + inline nuint32_t operator --() { --n; return *this; } + + constexpr bool operator <(nuint32_t x) const { return n < x.n; } + constexpr bool operator ==(nuint32_t x) const { return n == x.n; } + + friend std::ostream& + operator<<(std::ostream& out, const nuint32_t& a) + { + char tmp[INET_ADDRSTRLEN] = {0}; + if(inet_ntop(AF_INET, (void*)&a.n, tmp, sizeof(tmp))) + { + out << tmp; + } + return out; + } + + struct Hash + { + inline size_t + operator ()(nuint32_t x) const + { + return std::hash< uint32_t >{}(x.n); + } + }; + }; + + struct huint16_t + { + uint16_t h; + + constexpr huint16_t + operator &(huint16_t x) const { return huint16_t{uint16_t(h & x.h)}; } + constexpr huint16_t + operator |(huint16_t x) const { return huint16_t{uint16_t(h | x.h)}; } + constexpr huint16_t + operator ~() const { return huint16_t{uint16_t(~h)}; } + + inline huint16_t operator ++() { ++h; return *this; } + inline huint16_t operator --() { --h; return *this; } + + constexpr bool operator <(huint16_t x) const { return h < x.h; } + constexpr bool operator ==(huint16_t x) const { return h == x.h; } + + friend std::ostream& + operator<<(std::ostream& out, const huint16_t& a) + { + return out << a.h; + } + + struct Hash + { + inline size_t + operator ()(huint16_t x) const + { + return std::hash< uint16_t >{}(x.h); + } + }; + }; + + struct nuint16_t + { + uint16_t n; + + constexpr nuint16_t + operator &(nuint16_t x) const { return nuint16_t{uint16_t(n & x.n)}; } + constexpr nuint16_t + operator |(nuint16_t x) const { return nuint16_t{uint16_t(n | x.n)}; } + constexpr nuint16_t + operator ~() const { return nuint16_t{uint16_t(~n)}; } + + inline nuint16_t operator ++() { ++n; return *this; } + inline nuint16_t operator --() { --n; return *this; } + + constexpr bool operator <(nuint16_t x) const { return n < x.n; } + constexpr bool operator ==(nuint16_t x) const { return n == x.n; } + + friend std::ostream& + operator<<(std::ostream& out, const nuint16_t& a) + { + return out << ntohs(a.n); + } + + struct Hash + { + inline size_t + operator ()(nuint16_t x) const + { + return std::hash< uint16_t >{}(x.n); + } + }; + }; + + // clang-format on + + static inline nuint32_t + xhtonl(huint32_t x) + { + return nuint32_t{htonl(x.h)}; + } + + static inline huint32_t + xntohl(nuint32_t x) + { + return huint32_t{ntohl(x.n)}; + } + + static inline nuint16_t + xhtons(huint16_t x) + { + return nuint16_t{htons(x.h)}; + } + + static inline huint16_t + xntohs(nuint16_t x) + { + return huint16_t{ntohs(x.n)}; + } +} // namespace llarp + +#endif diff --git a/include/llarp/service/address.hpp b/include/llarp/service/address.hpp index 389bba336..bd8f3bc56 100644 --- a/include/llarp/service/address.hpp +++ b/include/llarp/service/address.hpp @@ -9,14 +9,14 @@ namespace llarp { namespace service { - /// Snapp Address + /// Snapp/Snode Address struct Address { std::string - ToString() const; + ToString(const char* tld = ".loki") const; bool - FromString(const std::string& str); + FromString(const std::string& str, const char* tld = ".loki"); Address() { diff --git a/llarp/context.cpp b/llarp/context.cpp index 3c7020800..f8f0eb262 100644 --- a/llarp/context.cpp +++ b/llarp/context.cpp @@ -341,8 +341,10 @@ extern "C" llarp_main_init_dotLokiLookup(struct llarp_main *ptr, struct dotLokiLookup *dll) { - dll->logic = ptr->ctx->logic; - return true; + (void)ptr; + (void)dll; + // TODO: gutt me + return false; } void diff --git a/llarp/dns/message.cpp b/llarp/dns/message.cpp new file mode 100644 index 000000000..b9f209a47 --- /dev/null +++ b/llarp/dns/message.cpp @@ -0,0 +1,162 @@ +#include +#include +namespace llarp +{ + namespace dns + { + bool + MessageHeader::Encode(llarp_buffer_t* buf) const + { + if(!EncodeInt(buf, id)) + return false; + if(!EncodeInt(buf, fields)) + return false; + if(!EncodeInt(buf, qd_count)) + return false; + if(!EncodeInt(buf, an_count)) + return false; + if(!EncodeInt(buf, ns_count)) + return false; + return EncodeInt(buf, ar_count); + } + + bool + MessageHeader::Decode(llarp_buffer_t* buf) + { + if(!DecodeInt(buf, id)) + return false; + if(!DecodeInt(buf, fields)) + return false; + if(!DecodeInt(buf, qd_count)) + return false; + if(!DecodeInt(buf, an_count)) + return false; + if(!DecodeInt(buf, ns_count)) + return false; + return DecodeInt(buf, ar_count); + } + + bool + Message::Encode(llarp_buffer_t* buf) const + { + if(!hdr.Encode(buf)) + return false; + + for(const auto& question : questions) + if(!question.Encode(buf)) + return false; + + for(const auto& answer : answers) + if(!answer.Encode(buf)) + return false; + + for(const auto& auth : authorities) + if(!auth.Encode(buf)) + return false; + + for(const auto& rr : additional) + if(!rr.Encode(buf)) + return false; + + return true; + } + + bool + Message::Decode(llarp_buffer_t* buf) + { + if(!hdr.Decode(buf)) + return false; + questions.resize(hdr.qd_count); + answers.resize(hdr.an_count); + authorities.resize(hdr.ns_count); + additional.resize(hdr.ar_count); + + for(auto& qd : questions) + if(!qd.Decode(buf)) + return false; + + for(auto& an : answers) + if(!an.Decode(buf)) + return false; + + for(auto& ns : authorities) + if(!ns.Decode(buf)) + return false; + + for(auto& ar : additional) + if(!ar.Decode(buf)) + return false; + return true; + } + + void + Message::UpdateHeader() + { + hdr.qd_count = questions.size(); + hdr.an_count = answers.size(); + hdr.ns_count = authorities.size(); + hdr.ar_count = additional.size(); + } + + Message& + Message::AddINReply(llarp::huint32_t ip) + { + if(questions.size()) + { + hdr.fields |= (1 << 15); + const auto& question = questions[0]; + answers.emplace_back(); + auto& rec = answers.back(); + rec.rr_name = question.qname; + rec.rr_type.h = 1; + rec.rr_class = question.qclass; + rec.ttl.h = 1; + rec.rData.resize(4); + htobe32buf(rec.rData.data(), ip.h); + UpdateHeader(); + } + return *this; + } + + Message& + Message::AddAReply(std::string name) + { + if(questions.size()) + { + hdr.fields |= (1 << 15); + const auto& question = questions[0]; + answers.emplace_back(); + auto& rec = answers.back(); + rec.rr_name = question.qname; + rec.rr_type = question.qtype; + rec.rr_class.h = 1; + rec.ttl.h = 1; + rec.rData.resize(name.size()); + memcpy(rec.rData.data(), name.c_str(), rec.rData.size()); + UpdateHeader(); + } + return *this; + } + + Message& + Message::AddNXReply() + { + if(questions.size()) + { + hdr.fields |= (1 << 15) | (1 << 3); + const auto& question = questions[0]; + answers.emplace_back(); + auto& nx = answers.back(); + nx.rr_name = question.qname; + nx.rr_type = question.qtype; + nx.rr_class = question.qclass; + nx.ttl.h = 1; + nx.rData.resize(1); + nx.rData.data()[0] = 0; + UpdateHeader(); + } + return *this; + } + + } // namespace dns +} // namespace llarp diff --git a/llarp/dns/name.cpp b/llarp/dns/name.cpp new file mode 100644 index 000000000..c0561395f --- /dev/null +++ b/llarp/dns/name.cpp @@ -0,0 +1,82 @@ +#include +#include +#include +#include + +namespace llarp +{ + namespace dns + { + bool + DecodeName(llarp_buffer_t* buf, Name_t& name) + { + if(llarp_buffer_size_left(*buf) < 1) + return false; + std::stringstream ss; + size_t l; + do + { + l = *buf->cur; + buf->cur++; + if(llarp_buffer_size_left(*buf) < l) + return false; + if(l) + ss << Name_t((const char*)buf->cur, l); + ss << "."; + } while(l); + name = ss.str(); + return true; + } + + bool + EncodeName(llarp_buffer_t* buf, const Name_t& name) + { + std::stringstream ss(name); + if(name.size() == 0 || name[name.size() - 1] != '.') + ss << "."; + std::string part; + while(std::getline(ss, part, '.')) + { + uint8_t l; + if(part.size() > 63) + return false; + l = part.size(); + *buf->cur = l; + buf->cur++; + if(llarp_buffer_size_left(*buf) < l) + return false; + memcpy(buf->cur, part.c_str(), l); + } + return true; + } + + bool + DecodePTR(const Name_t& name, huint32_t& ip) + { + auto pos = name.find(".in-addr.arpa."); + if(pos == Name_t::npos) + return false; + std::string sub = name.substr(0, pos - 1); + if(std::count(sub.begin(), sub.end(), '.') == 4) + { + uint8_t a, b, c, d; + pos = sub.find('.'); + d = atoi(sub.substr(0, pos).c_str()); + sub = sub.substr(pos); + pos = sub.find('.'); + c = atoi(sub.substr(0, pos).c_str()); + sub = sub.substr(pos); + pos = sub.find('.'); + b = atoi(sub.substr(0, pos).c_str()); + sub = sub.substr(pos); + pos = sub.find('.'); + a = atoi(sub.substr(0, pos).c_str()); + ip = llarp::ipaddr_ipv4_bits(a, b, c, d); + return true; + } + else + return false; + } + + } // namespace dns +} // namespace llarp diff --git a/llarp/dns/question.cpp b/llarp/dns/question.cpp new file mode 100644 index 000000000..8b89bebf2 --- /dev/null +++ b/llarp/dns/question.cpp @@ -0,0 +1,27 @@ +#include + +namespace llarp +{ + namespace dns + { + bool + Question::Encode(llarp_buffer_t* buf) const + { + if(!EncodeName(buf, qname)) + return false; + if(!EncodeInt(buf, qtype)) + return false; + return EncodeInt(buf, qclass); + } + + bool + Question::Decode(llarp_buffer_t* buf) + { + if(!DecodeName(buf, qname)) + return false; + if(!DecodeInt(buf, qtype)) + return false; + return DecodeInt(buf, qclass); + } + } // namespace dns +} // namespace llarp diff --git a/llarp/dns/rr.cpp b/llarp/dns/rr.cpp new file mode 100644 index 000000000..959a8a757 --- /dev/null +++ b/llarp/dns/rr.cpp @@ -0,0 +1,35 @@ +#include + +namespace llarp +{ + namespace dns + { + bool + ResourceRecord::Encode(llarp_buffer_t* buf) const + { + if(!EncodeName(buf, rr_name)) + return false; + if(!EncodeInt(buf, rr_type)) + return false; + if(!EncodeInt(buf, rr_class)) + return false; + if(!EncodeInt(buf, ttl)) + return false; + return EncodeRData(buf, rData); + } + + bool + ResourceRecord::Decode(llarp_buffer_t* buf) + { + if(!DecodeName(buf, rr_name)) + return false; + if(!DecodeInt(buf, rr_type)) + return false; + if(!DecodeInt(buf, rr_class)) + return false; + if(!DecodeInt(buf, ttl)) + return false; + return DecodeRData(buf, rData); + } + } // namespace dns +} // namespace llarp diff --git a/llarp/dns/serialize.cpp b/llarp/dns/serialize.cpp new file mode 100644 index 000000000..7f485e10c --- /dev/null +++ b/llarp/dns/serialize.cpp @@ -0,0 +1,76 @@ +#include +#include + +namespace llarp +{ + namespace dns + { + template <> + bool + DecodeInt(llarp_buffer_t* buf, llarp::huint32_t& i) + { + return llarp_buffer_read_uint32(buf, &i.h); + } + + template <> + bool + EncodeInt(llarp_buffer_t* buf, const llarp::huint32_t& i) + { + return llarp_buffer_put_uint32(buf, i.h); + } + + template <> + bool + DecodeInt(llarp_buffer_t* buf, llarp::huint16_t& i) + { + return llarp_buffer_read_uint16(buf, &i.h); + } + + template <> + bool + EncodeInt(llarp_buffer_t* buf, const llarp::huint16_t& i) + { + return llarp_buffer_put_uint16(buf, i.h); + } + + template <> + bool + DecodeInt(llarp_buffer_t* buf, uint16_t& i) + { + return llarp_buffer_read_uint16(buf, &i); + } + + template <> + bool + EncodeInt(llarp_buffer_t* buf, const uint16_t& i) + { + return llarp_buffer_put_uint16(buf, i); + } + + bool + EncodeRData(llarp_buffer_t* buf, const std::vector< byte_t >& v) + { + if(v.size() > 65536) + return false; + llarp::huint16_t len; + len.h = v.size(); + return EncodeInt(buf, len) && llarp_buffer_write(buf, v.data(), v.size()); + } + + bool + DecodeRData(llarp_buffer_t* buf, std::vector< byte_t >& v) + { + llarp::huint16_t len = {0}; + if(!DecodeInt(buf, len)) + return false; + size_t left = llarp_buffer_size_left(*buf); + if(left < len.h) + return false; + v.resize(size_t(len.h)); + memcpy(v.data(), buf->cur, len.h); + buf->cur += len.h; + return true; + } + + } // namespace dns +} // namespace llarp diff --git a/llarp/dns/server.cpp b/llarp/dns/server.cpp new file mode 100644 index 000000000..f3dab2b57 --- /dev/null +++ b/llarp/dns/server.cpp @@ -0,0 +1,112 @@ +#include + +namespace llarp +{ + namespace dns + { + Proxy::Proxy(llarp_ev_loop* loop, IQueryHandler* h) + : m_Loop(loop), m_QueryHandler(h) + { + m_UDP.user = this; + m_UDP.tick = &HandleTick; + m_UDP.recvfrom = &HandleUDPRecv; + } + + void + Proxy::Stop() + { + } + + bool + Proxy::Start(const llarp::Addr& addr, + const std::vector< llarp::Addr >& resolvers) + { + m_Resolvers.clear(); + m_Resolvers = resolvers; + if(m_Resolvers.size() == 0) + { + llarp::LogError("no upstream dns provide specified"); + return false; + } + return llarp_ev_add_udp(m_Loop, &m_UDP, addr) == 0; + } + + void + Proxy::HandleUDPRecv(llarp_udp_io* u, const sockaddr* from, + llarp_buffer_t buf) + { + static_cast< Proxy* >(u->user)->HandlePkt(*from, &buf); + } + + llarp::Addr + Proxy::PickRandomResolver() const + { + size_t sz = m_Resolvers.size(); + if(sz == 0) + return llarp::Addr("1.1.1.1", 52); + if(sz == 1) + return m_Resolvers[0]; + auto itr = m_Resolvers.begin(); + std::advance(itr, llarp_randint() % sz); + return *itr; + } + + void + Proxy::HandleTick(llarp_udp_io*) + { + } + + void + Proxy::SendMessageTo(llarp::Addr to, Message msg) + { + byte_t tmp[1500] = {0}; + auto buf = llarp::StackBuffer< decltype(tmp) >(tmp); + if(msg.Encode(&buf)) + { + buf.sz = buf.cur - buf.base; + buf.cur = buf.base; + llarp_ev_udp_sendto(&m_UDP, to, buf); + } + else + llarp::LogWarn("failed to encode dns message when sending"); + } + + void + Proxy::HandlePkt(llarp::Addr from, llarp_buffer_t* pkt) + { + Message msg; + if(!msg.Decode(pkt)) + { + llarp::LogWarn("failed to handle dns message from ", from); + llarp::DumpBuffer(*pkt); + return; + } + if(m_QueryHandler && m_QueryHandler->ShouldHookDNSMessage(msg)) + { + if(!m_QueryHandler->HandleHookedDNSMessage( + msg, + std::bind(&Proxy::SendMessageTo, this, from, + std::placeholders::_1))) + { + llarp::LogWarn("failed to handle hooked dns"); + } + return; + } + TX tx = {msg.hdr.id, from}; + auto itr = m_Forwarded.find(tx); + if(itr == m_Forwarded.end()) + { + // new forwarded query + tx.from = PickRandomResolver(); + m_Forwarded[tx] = from; + SendMessageTo(tx.from, msg); + } + else + { + SendMessageTo(itr->second, msg); + m_Forwarded.erase(itr); + } + } + + } // namespace dns +} // namespace llarp diff --git a/llarp/dns_dotlokilookup.cpp b/llarp/dns_dotlokilookup.cpp index 2d940729b..ec19d13f0 100644 --- a/llarp/dns_dotlokilookup.cpp +++ b/llarp/dns_dotlokilookup.cpp @@ -70,47 +70,8 @@ llarp_dotlokilookup_checkQuery(void *u, __attribute__((unused)) uint64_t orig, // check_query_request * >(u); struct check_query_simple_request *qr = static_cast< struct check_query_simple_request * >(u); - dotLokiLookup *dll = (dotLokiLookup *)qr->request->context->user; - if(!dll) - { - llarp::LogError("DNSd dotLokiLookup is not configured"); - write404_dnss_response(qr->request); - delete qr; - return; - } + dotLokiLookup *lookup = (dotLokiLookup *)qr->request->context->user; - // we do have result - // if so send that - // else - // if we have a free private ip, send that - - /* - // cache hit - auto itr = loki_tld_lookup_cache.find(addr.ToString()); - if(itr != loki_tld_lookup_cache.end()) - { - llarp::LogDebug("Found in .loki lookup cache"); - writesend_dnss_response(itr->second->returnThis, qr->from, qr->request); - delete qr; - return; - } - - struct dns_pointer *free_private = dns_iptracker_get_free(dll->ip_tracker); - if(free_private) - { - */ - - // in_addr ip_address = ((sockaddr_in *)free_private->hostResult)->sin_addr; - - llarp::service::Context *routerHiddenServiceContext = - (llarp::service::Context *)dll->user; - if(!routerHiddenServiceContext) - { - llarp::LogWarn("dotLokiLookup user isnt a service::Context: ", dll->user); - write404_dnss_response(qr->request); - delete qr; - return; - } llarp::huint32_t serviceIP; llarp::AlignedBuffer< 32 > addr; bool isSNode = false; @@ -121,7 +82,7 @@ llarp_dotlokilookup_checkQuery(void *u, __attribute__((unused)) uint64_t orig, delete qr; return; } - if(!routerHiddenServiceContext->FindBestAddressFor(addr, isSNode, serviceIP)) + if(!lookup->obtainAddress(lookup, addr, isSNode, serviceIP)) { llarp::LogWarn("dotLokiLookup failed to map address"); write404_dnss_response(qr->request); @@ -168,6 +129,7 @@ llarp_dotlokilookup_checkQuery(void *u, __attribute__((unused)) uint64_t orig, return; } */ + /* llarp::huint32_t foundAddr; if(!routerHiddenServiceContext->FindBestAddressFor(addr, isSNode, foundAddr)) { @@ -175,7 +137,7 @@ llarp_dotlokilookup_checkQuery(void *u, __attribute__((unused)) uint64_t orig, delete qr; return; } - + */ // make a dnsd_query_hook_response for the cache /* dnsd_query_hook_response *response = new dnsd_query_hook_response; @@ -189,7 +151,7 @@ llarp_dotlokilookup_checkQuery(void *u, __attribute__((unused)) uint64_t orig, // saddr.sin_addr.s_addr = llarp::xhtonl(foundAddr).n; // FIXME: flush cache to disk // on crash we'll need to bring up all the same IPs we assigned before... - writesend_dnss_response(&foundAddr, qr->request); + // writesend_dnss_response(&foundAddr, qr->request); delete qr; return; } @@ -324,14 +286,14 @@ should_intercept_query_with_name(const std::string &lName) return false; } -dnsd_query_hook_response * +void llarp_dotlokilookup_handler(std::string name, - const dnsd_question_request *request) + const dnsd_question_request *request, + struct dnsd_query_hook_response *response) { - dnsd_query_hook_response *response = new dnsd_query_hook_response; - response->dontLookUp = false; - response->dontSendResponse = false; - response->returnThis.h = 0; + response->dontLookUp = false; + response->dontSendResponse = false; + response->returnThis.h = 0; llarp::LogDebug("Hooked ", name); std::string lName = name; std::transform(lName.begin(), lName.end(), lName.begin(), ::tolower); @@ -341,14 +303,7 @@ llarp_dotlokilookup_handler(std::string name, if(lName.find(".in-addr.arpa") != std::string::npos) { // llarp::LogDebug("Checking ", lName); - dotLokiLookup *dll = (dotLokiLookup *)request->context->user; - llarp::service::Context *routerHiddenServiceContext = - (llarp::service::Context *)dll->user; - if(!routerHiddenServiceContext) - { - llarp::LogWarn("dotLokiLookup user isnt a service::Context: ", dll->user); - return response; - } + // dotLokiLookup *dll = (dotLokiLookup *)request->context->user; // llarp::LogDebug("Starting rev iter for ", lName); // which range? // for each tun interface @@ -361,7 +316,9 @@ llarp_dotlokilookup_handler(std::string name, i.user = &context; i.index = 0; i.visit = &ReverseHandlerIter; - bool res = routerHiddenServiceContext->iterate(i); + bool res = true; + (void)i; + // bool res = routerHiddenServiceContext->iterate(i); if(!res) { llarp::LogDebug("Reverse is ours"); @@ -382,8 +339,7 @@ llarp_dotlokilookup_handler(std::string name, // was in cache llarp::LogInfo("Reused address from LokiLookupCache"); // FIXME: avoid the response allocation if you could - delete response; - return cache_check->second; + return; } // decode address @@ -392,7 +348,6 @@ llarp_dotlokilookup_handler(std::string name, if(!decode_request_name(lName, addr, isSNode)) { response->dontLookUp = true; - return response; } dotLokiLookup *dll = (dotLokiLookup *)request->context->user; @@ -401,7 +356,6 @@ llarp_dotlokilookup_handler(std::string name, if(!routerHiddenServiceContext) { llarp::LogWarn("dotLokiLookup user isnt a service::Context: ", dll->user); - return response; } // start path build early (if you're looking it up, you're probably going to @@ -420,7 +374,7 @@ llarp_dotlokilookup_handler(std::string name, { llarp_dotlokilookup_checkQuery(qr, 0, 0); response->dontSendResponse = true; // will send it shortly - return response; + return; } } else @@ -429,7 +383,7 @@ llarp_dotlokilookup_handler(std::string name, { llarp_dotlokilookup_checkQuery(qr, 0, 0); response->dontSendResponse = true; // will send it shortly - return response; + return; } } @@ -439,5 +393,5 @@ llarp_dotlokilookup_handler(std::string name, response->dontSendResponse = true; // will send it shortly } - return response; + return; } diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index ff661db57..83167bb77 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -24,6 +24,7 @@ namespace llarp : service::Endpoint(nickname, r) , m_UserToNetworkPktQueue(nickname + "_sendq", r->netloop, r->netloop) , m_NetworkToUserPktQueue(nickname + "_recvq", r->netloop, r->netloop) + , m_Resolver(r->netloop, this) { #ifdef ANDROID tunif.get_fd_promise = &get_tun_fd_promise; @@ -40,12 +41,9 @@ namespace llarp strncpy(tunif.ifaddr, DefaultTunSrcAddr, sizeof(tunif.ifaddr) - 1); strncpy(tunif.ifname, DefaultTunIfname, sizeof(tunif.ifname) - 1); #endif - tunif.tick = nullptr; - tunif.before_write = &tunifBeforeWrite; - tunif.recvpkt = &tunifRecvPkt; - this->dll.ip_tracker = nullptr; - this->dll.user = &r->hiddenServiceContext; - // this->dll.callback = std::bind(&TunEndpoint::MapAddress, this); + tunif.tick = nullptr; + tunif.before_write = &tunifBeforeWrite; + tunif.recvpkt = &tunifRecvPkt; } bool @@ -89,8 +87,9 @@ namespace llarp resolverAddr = v.substr(0, pos); dnsport = std::atoi(v.substr(pos + 1).c_str()); } - m_UpstreamDNSAddr = llarp::Addr(resolverAddr, dnsport); - llarp::LogInfo(Name(), " upstream dns set to ", m_UpstreamDNSAddr); + m_UpstreamResolvers.emplace_back(resolverAddr, dnsport); + llarp::LogInfo(Name(), "adding upstream dns set to ", resolverAddr, ":", + dnsport); } if(k == "mapaddr") { @@ -156,15 +155,6 @@ namespace llarp llarp::LogInfo(Name() + " set ifaddr to ", addr, " with netmask ", tunif.netmask); strncpy(tunif.ifaddr, addr.c_str(), sizeof(tunif.ifaddr) - 1); - - // set up address in dotLokiLookup - // llarp::Addr tunIp(tunif.ifaddr); - llarp::huint32_t tunIpV4; - tunIpV4.h = inet_addr(tunif.ifaddr); - // related to dns_iptracker_setup_dotLokiLookup(&this->dll, tunIp); - dns_iptracker_setup( - this->dll.ip_tracker, - tunIpV4); // claim GW IP to make sure it's not inuse return true; } return Endpoint::SetOption(k, v); @@ -184,6 +174,102 @@ namespace llarp std::move(pkt)); } + bool + TunEndpoint::HandleHookedDNSMessage( + dns::Message msg, std::function< void(dns::Message) > reply) + { + if(msg.questions.size() != 1) + { + llarp::LogWarn("bad number of dns questions: ", msg.questions.size()); + return false; + } + std::string qname = msg.questions[0].qname; + if(msg.questions[0].qtype.h == 1) + { + llarp::service::Address addr; + + if(addr.FromString(qname, ".loki")) + { + return EnsurePathToService( + addr, + std::bind(&TunEndpoint::SendDNSReply, this, std::placeholders::_1, + std::placeholders::_2, msg, reply), + 2000); + } + else if(addr.FromString(qname, ".snode")) + { + EnsurePathToSNode(addr.data()); + huint32_t ip = ObtainIPForAddr(addr.data(), true); + reply(msg.AddINReply(ip)); + } + else + reply(msg.AddNXReply()); + } + else if(msg.questions[0].qtype.h == 12) + { + huint32_t ip = {0}; + if(!dns::DecodePTR(msg.questions[0].qname, ip)) + { + reply(msg.AddNXReply()); + return true; + } + llarp::service::Address addr = + ObtainAddrForIP< llarp::service::Address >(ip, true); + if(!addr.IsZero()) + { + reply(msg.AddAReply(addr.ToString(".snode"))); + return true; + } + addr = ObtainAddrForIP< llarp::service::Address >(ip, false); + if(!addr.IsZero()) + { + reply(msg.AddAReply(addr.ToString(".loki"))); + return true; + } + reply(msg.AddNXReply()); + return true; + } + else + reply(msg.AddNXReply()); + return true; + } + + bool + TunEndpoint::ShouldHookDNSMessage(const dns::Message &msg) const + { + llarp::service::Address addr; + if(msg.questions.size() == 1) + { + if(addr.FromString(msg.questions[0].qname, ".loki")) + return true; + if(addr.FromString(msg.questions[0].qname, ".snode")) + return true; + if(msg.questions[0].qtype.h == 12) + { + huint32_t ip = {0}; + if(!dns::DecodePTR(msg.questions[0].qname, ip)) + return false; + return m_OurRange.Contains(ip); + } + } + return false; + } + + void + TunEndpoint::SendDNSReply(service::Address addr, + service::Endpoint::OutboundContext *ctx, + dns::Message request, + std::function< void(dns::Message) > reply) + { + if(ctx) + { + huint32_t ip = ObtainIPForAddr(addr.data(), false); + reply(request.AddINReply(ip)); + } + else + reply(request.AddNXReply()); + } + bool TunEndpoint::MapAddress(const service::Address &addr, huint32_t ip, bool SNode) @@ -208,44 +294,9 @@ namespace llarp bool TunEndpoint::Start() { - // do network isolation first if(!Endpoint::Start()) return false; -#ifdef WIN32 return SetupNetworking(); -#else - if(!NetworkIsIsolated()) - { - llarp::LogInfo("Setting up global DNS IP tracker"); - llarp::huint32_t tunIpV4; - tunIpV4.h = inet_addr(tunif.ifaddr); - dns_iptracker_setup_dotLokiLookup( - &this->dll, tunIpV4); // just set ups dll to use global iptracker - dns_iptracker_setup( - this->dll.ip_tracker, - tunIpV4); // claim GW IP to make sure it's not inuse - - // set up networking in currrent thread if we are not isolated - if(!SetupNetworking()) - return false; - } - else - { - llarp::LogInfo("Setting up per netns DNS IP tracker"); - llarp::huint32_t tunIpV4; - tunIpV4.h = inet_addr(tunif.ifaddr); - llarp::Addr tunIp(tunif.ifaddr); - this->dll.ip_tracker = new dns_iptracker; - dns_iptracker_setup_dotLokiLookup( - &this->dll, tunIpV4); // just set ups dll to use global iptracker - dns_iptracker_setup( - this->dll.ip_tracker, - tunIpV4); // claim GW IP to make sure it's not inuse - } - // wait for result for network setup - llarp::LogInfo("waiting for tun interface..."); - return m_TunSetupResult.get_future().get(); -#endif } bool @@ -288,8 +339,8 @@ namespace llarp int s = inet_pton(res->ai_family, tunif.ifaddr, buf); if (s <= 0) { - llarp::LogError(Name(), " failed to set up tun interface, cant parse ", - tunif.ifaddr); return false; + llarp::LogError(Name(), " failed to set up tun interface, cant parse + ", tunif.ifaddr); return false; } */ if(res->ai_family == AF_INET6) @@ -311,13 +362,15 @@ namespace llarp llarp::Addr lAddr(tunif.ifaddr); - m_OurIP = lAddr.xtohl(); - m_NextIP = m_OurIP; - auto xmask = netmask_ipv4_bits(tunif.netmask); - m_MaxIP = m_OurIP ^ (~xmask); + m_OurIP = lAddr.xtohl(); + m_NextIP = m_OurIP; + m_OurRange.netmask_bits = netmask_ipv4_bits(tunif.netmask); + m_OurRange.addr = m_OurIP; + m_MaxIP = m_OurIP | (~m_OurRange.netmask_bits); llarp::LogInfo(Name(), " set ", tunif.ifname, " to have address ", lAddr); - llarp::LogInfo(Name(), " allocated up to ", m_MaxIP); + llarp::LogInfo(Name(), " allocated up to ", m_MaxIP, " on range ", + m_OurRange); MapAddress(m_Identity.pub.Addr(), m_OurIP, IsSNode()); return true; } @@ -326,37 +379,17 @@ namespace llarp TunEndpoint::SetupNetworking() { llarp::LogInfo("Set Up networking for ", Name()); - bool result = SetupTun(); -#ifndef WIN32 - m_TunSetupResult.set_value( - result); // now that NT has tun, we don't need the CPP guard -#endif - if(!NetworkIsIsolated()) + if(!SetupTun()) { - // need to check to see if we have more than one hidden service - // well we'll only use the primary - // FIXME: detect number of hidden services - llarp::LogWarn( - "Only utilizing first hidden service for .loki look ups"); - // because we can't find to the tun interface because we don't want it - // accessible on lokinet we can only bind one to loopback, and we can't - // really utilize anything other than port 53 we can't bind to our - // public interface, don't want it exploitable maybe we could detect if - // you have a private interface + llarp::LogError(Name(), " failed to set up network interface"); + return false; } - - llarp::LogInfo("TunDNS set up ", m_LocalResolverAddr, " to ", - m_UpstreamDNSAddr); - if(!llarp_dnsd_init(&this->dnsd, EndpointLogic(), EndpointNetLoop(), - m_LocalResolverAddr, m_UpstreamDNSAddr)) + if(!m_Resolver.Start(m_LocalResolverAddr, m_UpstreamResolvers)) { - llarp::LogError("Couldnt init dns daemon"); + llarp::LogError(Name(), " failed to start dns server"); + return false; } - // configure hook for .loki lookup - dnsd.intercept = &llarp_dotlokilookup_handler; - // set dotLokiLookup (this->dll) configuration - dnsd.user = &this->dll; - return result; + return true; } void diff --git a/llarp/service/address.cpp b/llarp/service/address.cpp index 386bb1c4a..c1ed792e5 100644 --- a/llarp/service/address.cpp +++ b/llarp/service/address.cpp @@ -6,17 +6,17 @@ namespace llarp namespace service { std::string - Address::ToString() const + Address::ToString(const char* tld) const { char tmp[(1 + 32) * 2] = {0}; std::string str = Base32Encode(*this, tmp); - return str + ".loki"; + return str + tld; } bool - Address::FromString(const std::string& str) + Address::FromString(const std::string& str, const char* tld) { - auto pos = str.find(".loki"); + auto pos = str.find(tld); if(pos == std::string::npos) return false; auto sub = str.substr(0, pos); diff --git a/test/test_dnslib.cpp b/test/test_dnslib.cpp new file mode 100644 index 000000000..d750554f3 --- /dev/null +++ b/test/test_dnslib.cpp @@ -0,0 +1,84 @@ +#include +#include +#include + +struct DNSLibTest : public ::testing::Test +{ + byte_t mem[1500] = {0}; + llarp_buffer_t buf; + + void + SetUp() + { + buf = llarp::StackBuffer< decltype(mem) >(mem); + } + + void + TearDown() + { + Rewind(); + } + + void + Rewind() + { + buf.cur = buf.base; + } +}; + +TEST_F(DNSLibTest, TestEncodeDecode_RData) +{ + static constexpr size_t rdatasize = 32; + llarp::dns::RR_RData_t rdata(rdatasize); + std::fill(rdata.begin(), rdata.end(), 'a'); + + llarp::dns::RR_RData_t other_rdata; + + ASSERT_TRUE(llarp::dns::EncodeRData(&buf, rdata)); + ASSERT_TRUE(buf.cur - buf.base == rdatasize + sizeof(uint16_t)); + Rewind(); + ASSERT_TRUE(llarp::dns::DecodeRData(&buf, other_rdata)); + ASSERT_TRUE(rdata == other_rdata); +}; + +TEST_F(DNSLibTest, TestEncode_huint16) +{ + llarp::huint16_t i = {0x1122}; + ASSERT_TRUE(llarp::dns::EncodeInt(&buf, i)); + ASSERT_TRUE(buf.cur - buf.base == sizeof(uint16_t)); + ASSERT_TRUE(buf.base[0] == 0x11); + ASSERT_TRUE(buf.base[1] == 0x22); +}; + +TEST_F(DNSLibTest, TestEncode_huint32) +{ + llarp::huint32_t i = {0x11223344}; + ASSERT_TRUE(llarp::dns::EncodeInt(&buf, i)); + ASSERT_TRUE(buf.cur - buf.base == sizeof(uint32_t)); + ASSERT_TRUE(buf.base[0] == 0x11); + ASSERT_TRUE(buf.base[1] == 0x22); + ASSERT_TRUE(buf.base[2] == 0x33); + ASSERT_TRUE(buf.base[3] == 0x44); +}; + +TEST_F(DNSLibTest, TestDecode_huint16) +{ + llarp::huint16_t i = {0}; + buf.base[0] = 0x11; + buf.base[1] = 0x22; + ASSERT_TRUE(llarp::dns::DecodeInt(&buf, i)); + ASSERT_TRUE(buf.cur - buf.base == sizeof(uint16_t)); + ASSERT_TRUE(i.h == 0x1122); +}; + +TEST_F(DNSLibTest, TestDecode_huint32) +{ + llarp::huint32_t i = {0}; + buf.base[0] = 0x11; + buf.base[1] = 0x22; + buf.base[2] = 0x33; + buf.base[3] = 0x44; + ASSERT_TRUE(llarp::dns::DecodeInt(&buf, i)); + ASSERT_TRUE(buf.cur - buf.base == sizeof(uint32_t)); + ASSERT_TRUE(i.h == 0x11223344); +};