mirror of https://github.com/oxen-io/lokinet
handle subdomains
This commit is contained in:
parent
353021b671
commit
fea64eaf12
|
@ -10,7 +10,7 @@ namespace llarp
|
|||
namespace dns
|
||||
{
|
||||
bool
|
||||
DecodeName(llarp_buffer_t* buf, Name_t& name)
|
||||
DecodeName(llarp_buffer_t* buf, Name_t& name, bool trimTrailingDot)
|
||||
{
|
||||
if(buf->size_left() < 1)
|
||||
return false;
|
||||
|
@ -37,6 +37,9 @@ namespace llarp
|
|||
buf->cur = buf->cur + l;
|
||||
} while(l);
|
||||
name = ss.str();
|
||||
/// trim off last dot
|
||||
if(trimTrailingDot)
|
||||
name = name.substr(0, name.find_last_of('.'));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace llarp
|
|||
|
||||
/// decode name from buffer
|
||||
bool
|
||||
DecodeName(llarp_buffer_t* buf, Name_t& name);
|
||||
DecodeName(llarp_buffer_t* buf, Name_t& name, bool trimTrailingDot = false);
|
||||
|
||||
/// encode name to buffer
|
||||
bool
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
@ -349,11 +347,10 @@ namespace llarp
|
|||
else if(addr.FromString(qname, ".snode"))
|
||||
{
|
||||
dns::Message *replyMsg = new dns::Message(std::move(msg));
|
||||
EnsurePathToSNode(addr.as_array(),
|
||||
[=](const RouterID &remote, exit::BaseSession *s) {
|
||||
SendDNSReply(remote, s, replyMsg, reply, true,
|
||||
isV6);
|
||||
});
|
||||
EnsurePathToSNode(
|
||||
addr.as_array(), [=](const RouterID &, exit::BaseSession * s) {
|
||||
SendDNSReply(addr, s, replyMsg, reply, true, isV6);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
@ -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…
Reference in New Issue