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;
}
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&
Question::print(std::ostream& stream, int level, int spaces) const
{

@ -36,6 +36,14 @@ namespace llarp
Name_t qname;
QType_t qtype;
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&

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

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

@ -6,25 +6,62 @@ namespace llarp
{
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
Address::ToString(const char* tld) const
{
if(!PermitTLD(tld))
return "";
char tmp[(1 + 32) * 2] = {0};
std::string str = Base32Encode(*this, tmp);
if(subdomain.size())
str = subdomain + "." + str;
return str + tld;
}
bool
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)
return false;
if(str.substr(pos) != tld)
return false;
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
std::transform(sub.begin(), sub.end(), sub.begin(), ::tolower);
return Base32Decode(sub, *this);
return Base32Decode(lowercase(sub, true), *this);
}
} // namespace service
} // namespace llarp

@ -16,6 +16,18 @@ namespace llarp
/// Snapp/Snode Address
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
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)
{
int tmp = 0, bits = 0;
size_t ret = 0;
size_t len = Base32DecodeSize(value.size());
size_t outLen = value.size();
size_t idx = 0;
const size_t len = Base32DecodeSize(value.size());
const size_t outLen = value.size();
for(size_t i = 0; i < len; i++)
{
char ch = stack[i];
@ -57,21 +57,21 @@ namespace llarp
}
else
{
return ret == outLen;
return idx == outLen;
}
tmp |= ch;
bits += 5;
if(bits >= 8)
{
if(ret >= outLen)
if(idx >= outLen)
return false;
value[ret] = tmp >> (bits - 8);
value[idx] = tmp >> (bits - 8);
bits -= 8;
ret++;
idx++;
}
tmp <<= 5;
}
return true;
return idx == outLen;
}
/// adapted from i2pd

@ -8,8 +8,32 @@ struct ServiceAddressTest : public ::testing::Test
"8zfiwpgonsu5zpddpxwdurxyb19x6r96xy4qbikff99jwsziws9y.snode";
const std::string 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)
{
llarp::service::Address addr;
@ -23,3 +47,21 @@ TEST_F(ServiceAddressTest, TestParseLokiNotSNode)
ASSERT_FALSE(addr.FromString(loki, ".snode"));
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