handle subdomains

pull/576/head
Jeff Becker 5 years ago
parent 0529e45ebe
commit d20ba9ceab
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05

@ -49,6 +49,22 @@ namespace llarp
return true; return true;
} }
bool
Question::IsName(const std::string& other) const
{
// does other have a . at the end?
if(other.find_last_of('.') == (other.size() - 1))
return other == qname;
else // no, add it and retry
return IsName(other + ".");
}
std::string
Question::Name() const
{
return qname.substr(0, qname.find_last_of('.'));
}
std::ostream& std::ostream&
Question::print(std::ostream& stream, int level, int spaces) const Question::print(std::ostream& stream, int level, int spaces) const
{ {

@ -36,6 +36,14 @@ namespace llarp
Name_t qname; Name_t qname;
QType_t qtype; QType_t qtype;
QClass_t qclass; QClass_t qclass;
/// determine if we match a name
bool
IsName(const std::string& other) const;
/// return qname with no trailing .
std::string
Name() const;
}; };
inline std::ostream& inline std::ostream&

@ -73,12 +73,11 @@ namespace llarp
|| msg.questions[0].qtype == dns::qTypeCNAME || msg.questions[0].qtype == dns::qTypeCNAME
|| msg.questions[0].qtype == dns::qTypeAAAA) || msg.questions[0].qtype == dns::qTypeAAAA)
{ {
// hook for forward dns or cname when using snode tld if(msg.questions[0].IsName("localhost.loki")
if(msg.questions[0].qname.find(".snode.") || msg.questions[0].IsName("random.snode"))
== (msg.questions[0].qname.size() - 7))
return true; return true;
return msg.questions[0].qname == "localhost.loki" service::Address addr;
|| msg.questions[0].qname == "localhost.loki."; return addr.FromString(msg.questions[0].Name(), ".snode");
} }
else else
return false; return false;
@ -113,8 +112,7 @@ namespace llarp
} }
else if(msg.questions[0].qtype == dns::qTypeCNAME) else if(msg.questions[0].qtype == dns::qTypeCNAME)
{ {
if(msg.questions[0].qname == "random.snode" if(msg.questions[0].IsName("random.snode"))
|| msg.questions[0].qname == "random.snode.")
{ {
RouterID random; RouterID random;
if(GetRouter()->GetRandomGoodRouter(random)) if(GetRouter()->GetRandomGoodRouter(random))
@ -122,8 +120,7 @@ namespace llarp
else else
msg.AddNXReply(); msg.AddNXReply();
} }
else if(msg.questions[0].qname == "localhost.loki" else if(msg.questions[0].IsName("localhost.loki"))
|| msg.questions[0].qname == "localhost.loki.")
{ {
RouterID us = m_Router->pubkey(); RouterID us = m_Router->pubkey();
msg.AddAReply(us.ToString(), 1); msg.AddAReply(us.ToString(), 1);
@ -135,8 +132,7 @@ namespace llarp
|| msg.questions[0].qtype == dns::qTypeAAAA) || msg.questions[0].qtype == dns::qTypeAAAA)
{ {
const bool isV6 = msg.questions[0].qtype == dns::qTypeAAAA; const bool isV6 = msg.questions[0].qtype == dns::qTypeAAAA;
if(msg.questions[0].qname == "random.snode" if(msg.questions[0].IsName("random.snode"))
|| msg.questions[0].qname == "random.snode.")
{ {
RouterID random; RouterID random;
if(GetRouter()->GetRandomGoodRouter(random)) if(GetRouter()->GetRandomGoodRouter(random))
@ -146,8 +142,7 @@ namespace llarp
reply(msg); reply(msg);
return true; return true;
} }
if(msg.questions[0].qname == "localhost.loki." if(msg.questions[0].IsName("localhost.loki"))
|| msg.questions[0].qname == "localhost.loki")
{ {
msg.AddINReply(GetIfAddr(), isV6); msg.AddINReply(GetIfAddr(), isV6);
reply(msg); reply(msg);
@ -155,7 +150,7 @@ namespace llarp
} }
// forward dns for snode // forward dns for snode
RouterID r; RouterID r;
if(r.FromString(msg.questions[0].qname)) if(r.FromString(msg.questions[0].Name()))
{ {
huint32_t ip; huint32_t ip;
PubKey pubKey(r); PubKey pubKey(r);

@ -233,15 +233,13 @@ namespace llarp
static bool static bool
is_random_snode(const dns::Message &msg) is_random_snode(const dns::Message &msg)
{ {
return msg.questions[0].qname == "random.snode" return msg.questions[0].IsName("random.snode");
|| msg.questions[0].qname == "random.snode.";
} }
static bool static bool
is_localhost_loki(const dns::Message &msg) is_localhost_loki(const dns::Message &msg)
{ {
return msg.questions[0].qname == "localhost.loki" return msg.questions[0].IsName("localhost.loki");
|| msg.questions[0].qname == "localhost.loki.";
} }
bool bool
@ -255,7 +253,7 @@ namespace llarp
llarp::LogWarn("bad number of dns questions: ", msg.questions.size()); llarp::LogWarn("bad number of dns questions: ", msg.questions.size());
return false; return false;
} }
std::string qname = msg.questions[0].qname; const std::string qname = msg.questions[0].Name();
if(msg.questions[0].qtype == dns::qTypeMX) if(msg.questions[0].qtype == dns::qTypeMX)
{ {
// mx record // mx record
@ -340,8 +338,8 @@ namespace llarp
using service::OutboundContext; using service::OutboundContext;
return EnsurePathToService( return EnsurePathToService(
addr, addr,
[=](const Address &remote, OutboundContext *ctx) { [=](const Address &, OutboundContext *ctx) {
SendDNSReply(remote, ctx, replyMsg, reply, false, isV6); SendDNSReply(addr, ctx, replyMsg, reply, false, isV6);
}, },
2000); 2000);
} }
@ -350,9 +348,8 @@ namespace llarp
{ {
dns::Message *replyMsg = new dns::Message(std::move(msg)); dns::Message *replyMsg = new dns::Message(std::move(msg));
EnsurePathToSNode( EnsurePathToSNode(
addr.as_array(), addr.as_array(), [=](const RouterID &, exit::BaseSession_ptr s) {
[=](const RouterID &remote, exit::BaseSession_ptr s) { SendDNSReply(addr, s, replyMsg, reply, true, isV6);
SendDNSReply(remote, s, replyMsg, reply, true, isV6);
}); });
return true; return true;
} }
@ -407,18 +404,17 @@ namespace llarp
if(msg.questions.size() == 1) if(msg.questions.size() == 1)
{ {
// hook random.snode // hook random.snode
if(msg.questions[0].qname == "random.snode" if(msg.questions[0].IsName("random.snode"))
|| msg.questions[0].qname == "random.snode.")
return true; return true;
// hook localhost.loki // hook localhost.loki
if(msg.questions[0].qname == "localhost.loki" if(msg.questions[0].IsName("localhost.loki"))
|| msg.questions[0].qname == "localhost.loki.")
return true; return true;
const std::string name = msg.questions[0].Name();
// hook .loki // hook .loki
if(addr.FromString(msg.questions[0].qname, ".loki")) if(addr.FromString(name, ".loki"))
return true; return true;
// hook .snode // hook .snode
if(addr.FromString(msg.questions[0].qname, ".snode")) if(addr.FromString(name, ".snode"))
return true; return true;
// hook any ranges we own // hook any ranges we own
if(msg.questions[0].qtype == llarp::dns::qTypePTR) if(msg.questions[0].qtype == llarp::dns::qTypePTR)

@ -6,25 +6,62 @@ namespace llarp
{ {
namespace service namespace service
{ {
const std::vector< std::string > Address::AllowedTLDs = {".loki", ".snode"};
bool
Address::PermitTLD(const char* tld)
{
std::string gtld(tld);
std::transform(gtld.begin(), gtld.end(), gtld.begin(), ::tolower);
for(const auto& allowed : AllowedTLDs)
if(allowed == tld)
return true;
return false;
}
std::string std::string
Address::ToString(const char* tld) const Address::ToString(const char* tld) const
{ {
if(!PermitTLD(tld))
return "";
char tmp[(1 + 32) * 2] = {0}; char tmp[(1 + 32) * 2] = {0};
std::string str = Base32Encode(*this, tmp); std::string str = Base32Encode(*this, tmp);
if(subdomain.size())
str = subdomain + "." + str;
return str + tld; return str + tld;
} }
bool bool
Address::FromString(const std::string& str, const char* tld) Address::FromString(const std::string& str, const char* tld)
{ {
auto pos = str.find(tld); if(!PermitTLD(tld))
return false;
static auto lowercase = [](const std::string s,
bool stripDots) -> std::string {
std::string ret(s.size(), ' ');
std::transform(s.begin(), s.end(), ret.begin(),
[stripDots](const char& ch) -> char {
if(ch == '.' && stripDots)
return 0;
return ::tolower(ch);
});
return ret.substr(0, ret.find_last_of(' '));
};
const auto pos = str.find_last_of('.');
if(pos == std::string::npos) if(pos == std::string::npos)
return false; return false;
if(str.substr(pos) != tld)
return false;
auto sub = str.substr(0, pos); auto sub = str.substr(0, pos);
// set subdomains if they are there
const auto idx = sub.find_last_of('.');
if(idx != std::string::npos)
{
subdomain = lowercase(sub.substr(0, idx), false);
sub = sub.substr(idx + 1);
}
// make sure it's lowercase // make sure it's lowercase
std::transform(sub.begin(), sub.end(), sub.begin(), ::tolower); return Base32Decode(lowercase(sub, true), *this);
return Base32Decode(sub, *this);
} }
} // namespace service } // namespace service
} // namespace llarp } // namespace llarp

@ -16,6 +16,18 @@ namespace llarp
/// Snapp/Snode Address /// Snapp/Snode Address
struct Address : public AlignedBuffer< 32 > struct Address : public AlignedBuffer< 32 >
{ {
/// if parsed using FromString this contains the subdomain
/// this member is not used when comparing it's extra data for dns
std::string subdomain;
/// list of whitelisted gtld to permit
static const std::vector< std::string > AllowedTLDs;
/// return true if we permit using this tld
/// otherwise return false
static bool
PermitTLD(const char* tld);
std::string std::string
ToString(const char* tld = ".loki") const; ToString(const char* tld = ".loki") const;
@ -30,7 +42,8 @@ namespace llarp
{ {
} }
Address(const Address& other) : AlignedBuffer< SIZE >(other.as_array()) Address(const Address& other)
: AlignedBuffer< SIZE >(other.as_array()), subdomain(other.subdomain)
{ {
} }

@ -42,9 +42,9 @@ namespace llarp
Base32Decode(const Stack& stack, V& value) Base32Decode(const Stack& stack, V& value)
{ {
int tmp = 0, bits = 0; int tmp = 0, bits = 0;
size_t ret = 0; size_t idx = 0;
size_t len = Base32DecodeSize(value.size()); const size_t len = Base32DecodeSize(value.size());
size_t outLen = value.size(); const size_t outLen = value.size();
for(size_t i = 0; i < len; i++) for(size_t i = 0; i < len; i++)
{ {
char ch = stack[i]; char ch = stack[i];
@ -57,21 +57,21 @@ namespace llarp
} }
else else
{ {
return ret == outLen; return idx == outLen;
} }
tmp |= ch; tmp |= ch;
bits += 5; bits += 5;
if(bits >= 8) if(bits >= 8)
{ {
if(ret >= outLen) if(idx >= outLen)
return false; return false;
value[ret] = tmp >> (bits - 8); value[idx] = tmp >> (bits - 8);
bits -= 8; bits -= 8;
ret++; idx++;
} }
tmp <<= 5; tmp <<= 5;
} }
return true; return idx == outLen;
} }
/// adapted from i2pd /// adapted from i2pd

@ -8,8 +8,32 @@ struct ServiceAddressTest : public ::testing::Test
"8zfiwpgonsu5zpddpxwdurxyb19x6r96xy4qbikff99jwsziws9y.snode"; "8zfiwpgonsu5zpddpxwdurxyb19x6r96xy4qbikff99jwsziws9y.snode";
const std::string loki = const std::string loki =
"7okic5x5do3uh3usttnqz9ek3uuoemdrwzto1hciwim9f947or6y.loki"; "7okic5x5do3uh3usttnqz9ek3uuoemdrwzto1hciwim9f947or6y.loki";
const std::string sub = "lokinet.test";
const std::string invalid =
"7okic5x5do3uh3usttnqz9ek3uuoemdrwzto1hciwim9f947or6y.net";
}; };
TEST_F(ServiceAddressTest, TestParseBadTLD)
{
llarp::service::Address addr;
ASSERT_FALSE(addr.FromString(snode, ".net"));
ASSERT_FALSE(addr.FromString(invalid, ".net"));
}
TEST_F(ServiceAddressTest, TestParseBadTLDAppenedOnEnd)
{
llarp::service::Address addr;
const std::string bad = loki + ".net";
ASSERT_FALSE(addr.FromString(bad, ".net"));
}
TEST_F(ServiceAddressTest, TestParseBadTLDAppenedOnEndWithSubdomain)
{
llarp::service::Address addr;
const std::string bad = sub + "." + loki + ".net";
ASSERT_FALSE(addr.FromString(bad, ".net"));
}
TEST_F(ServiceAddressTest, TestParseSNodeNotLoki) TEST_F(ServiceAddressTest, TestParseSNodeNotLoki)
{ {
llarp::service::Address addr; llarp::service::Address addr;
@ -23,3 +47,21 @@ TEST_F(ServiceAddressTest, TestParseLokiNotSNode)
ASSERT_FALSE(addr.FromString(loki, ".snode")); ASSERT_FALSE(addr.FromString(loki, ".snode"));
ASSERT_TRUE(addr.FromString(loki, ".loki")); ASSERT_TRUE(addr.FromString(loki, ".loki"));
} }
TEST_F(ServiceAddressTest, TestParseLokiWithSubdomain)
{
llarp::service::Address addr;
const std::string addr_str = sub + "." + loki;
ASSERT_TRUE(addr.FromString(addr_str, ".loki"));
ASSERT_EQ(addr.subdomain, sub);
ASSERT_EQ(addr.ToString(), addr_str);
};
TEST_F(ServiceAddressTest, TestParseSnodeWithSubdomain)
{
llarp::service::Address addr;
const std::string addr_str = sub + "." + snode;
ASSERT_TRUE(addr.FromString(addr_str, ".snode"));
ASSERT_EQ(addr.subdomain, sub);
ASSERT_EQ(addr.ToString(".snode"), addr_str);
};

Loading…
Cancel
Save