diff --git a/llarp/dns/question.cpp b/llarp/dns/question.cpp index 83ff57262..f5be6f551 100644 --- a/llarp/dns/question.cpp +++ b/llarp/dns/question.cpp @@ -2,6 +2,7 @@ #include #include +#include namespace llarp { @@ -59,6 +60,31 @@ namespace llarp return IsName(other + "."); } + bool + Question::IsLocalhost() const + { + return (qname == "localhost.loki." or llarp::ends_with(qname, ".localhost.loki.")); + } + + std::string + Question::Subdomains() const + { + if (qname.size() < 2) + return ""; + + size_t pos; + + pos = qname.rfind('.', qname.size() - 2); + if (pos == std::string::npos or pos == 0) + return ""; + + pos = qname.rfind('.', pos - 1); + if (pos == std::string::npos or pos == 0) + return ""; + + return qname.substr(0, pos); + } + std::string Question::Name() const { diff --git a/llarp/dns/question.hpp b/llarp/dns/question.hpp index 2f4f19fa5..98b6ba60a 100644 --- a/llarp/dns/question.hpp +++ b/llarp/dns/question.hpp @@ -40,6 +40,14 @@ namespace llarp bool IsName(const std::string& other) const; + /// is the name [something.]localhost.loki. ? + bool + IsLocalhost() const; + + /// get subdomain(s), if any, from qname + std::string + Subdomains() const; + /// return qname with no trailing . std::string Name() const; diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index 70e44ab3e..9dd308ea0 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -245,7 +245,7 @@ namespace llarp static bool is_localhost_loki(const dns::Message& msg) { - return msg.questions[0].IsName("localhost.loki"); + return msg.questions[0].IsLocalhost(); } template <> @@ -324,17 +324,7 @@ namespace llarp return; const auto& introset = ctx->GetCurrentIntroSet(); - std::vector records; - size_t numRecords = introset.SRVs.size(); - if (numRecords > 0) - { - records.reserve(numRecords); - for (const auto& record : introset.SRVs) - { - records.push_back(std::move(llarp::dns::SRVData::fromTuple(record))); - } - } - msg->AddSRVReply(records); + msg->AddSRVReply(introset.GetMatchingSRVRecords(addr.subdomain)); reply(*msg); }, 2s); @@ -511,20 +501,20 @@ namespace llarp reply(msg); return true; } - // TODO: SRV Record else if (msg.questions[0].qtype == dns::qTypeSRV) { llarp::service::Address addr; if (is_localhost_loki(msg)) { - msg.AddNXReply(); + msg.AddSRVReply(introSet().GetMatchingSRVRecords(msg.questions[0].Subdomains())); reply(msg); return true; } else if (addr.FromString(qname, ".loki")) { - llarp::LogWarn("SRV request for: ", qname); + llarp::LogDebug("SRV request for: ", qname); + return ReplyToLokiSRVWhenReady(addr, std::make_shared(msg)); } } diff --git a/llarp/service/endpoint.hpp b/llarp/service/endpoint.hpp index a36fb2a2a..d9911a0ab 100644 --- a/llarp/service/endpoint.hpp +++ b/llarp/service/endpoint.hpp @@ -459,7 +459,6 @@ namespace llarp std::shared_ptr m_AuthPolicy; std::unordered_map m_RemoteAuthInfos; - private: void FlushRecvData(); diff --git a/llarp/service/intro_set.cpp b/llarp/service/intro_set.cpp index 214e47340..ee5d5c1ec 100644 --- a/llarp/service/intro_set.cpp +++ b/llarp/service/intro_set.cpp @@ -282,6 +282,22 @@ namespace llarp return GetNewestIntroExpiration() < now; } + std::vector + IntroSet::GetMatchingSRVRecords(std::string_view service_proto) const + { + std::vector records; + + for (const auto& tuple : SRVs) + { + if (std::get<0>(tuple) == service_proto) + { + records.push_back(llarp::dns::SRVData::fromTuple(tuple)); + } + } + + return records; + } + bool IntroSet::Verify(llarp_time_t now) const { diff --git a/llarp/service/intro_set.hpp b/llarp/service/intro_set.hpp index d1e7dd8eb..99b68b8f9 100644 --- a/llarp/service/intro_set.hpp +++ b/llarp/service/intro_set.hpp @@ -58,6 +58,9 @@ namespace llarp bool IsExpired(llarp_time_t now) const; + std::vector + GetMatchingSRVRecords(std::string_view service_proto) const; + bool BEncode(llarp_buffer_t* buf) const; diff --git a/test/dns/test_llarp_dns_dns.cpp b/test/dns/test_llarp_dns_dns.cpp index d18468215..8cd62f484 100644 --- a/test/dns/test_llarp_dns_dns.cpp +++ b/test/dns/test_llarp_dns_dns.cpp @@ -48,6 +48,64 @@ TEST_F(DNSLibTest, TestHasTLD) ASSERT_FALSE(question.HasTLD(tld)); }; +TEST_F(DNSLibTest, TestIsLocalhost) +{ + llarp::dns::Question question; + + question.qname = "localhost.loki."; + ASSERT_TRUE(question.IsLocalhost()); + question.qname = "foo.localhost.loki."; + ASSERT_TRUE(question.IsLocalhost()); + question.qname = "foo.bar.localhost.loki."; + ASSERT_TRUE(question.IsLocalhost()); + + question.qname = "something.loki."; + ASSERT_FALSE(question.IsLocalhost()); + question.qname = "localhost.something.loki."; + ASSERT_FALSE(question.IsLocalhost()); + question.qname = "notlocalhost.loki."; + ASSERT_FALSE(question.IsLocalhost()); +}; + +TEST_F(DNSLibTest, TestGetSubdomains) +{ + llarp::dns::Question question; + std::string expected; + + question.qname = "localhost.loki."; + expected = ""; + ASSERT_EQ(question.Subdomains(), expected); + + question.qname = "foo.localhost.loki."; + expected = "foo"; + ASSERT_EQ(question.Subdomains(), expected); + + question.qname = "foo.bar.localhost.loki."; + expected = "foo.bar"; + ASSERT_EQ(question.Subdomains(), expected); + + // not legal, but test it anyway + question.qname = ".localhost.loki."; + expected = ""; + ASSERT_EQ(question.Subdomains(), expected); + + question.qname = ".loki."; + expected = ""; + ASSERT_EQ(question.Subdomains(), expected); + + question.qname = "loki."; + expected = ""; + ASSERT_EQ(question.Subdomains(), expected); + + question.qname = "."; + expected = ""; + ASSERT_EQ(question.Subdomains(), expected); + + question.qname = ""; + expected = ""; + ASSERT_EQ(question.Subdomains(), expected); +}; + TEST_F(DNSLibTest, TestPTR) { llarp::huint128_t ip = {0};