lokinet/llarp/handlers/tun.cpp

1190 lines
34 KiB
C++
Raw Normal View History

2018-10-10 12:06:28 +00:00
#include <algorithm>
#include "net/net.hpp"
// harmless on other platforms
#define __USE_MINGW_ANSI_STDIO 1
2018-12-12 01:12:59 +00:00
#include <handlers/tun.hpp>
#include <sys/types.h>
2018-09-25 08:31:29 +00:00
#ifndef _WIN32
#include <sys/socket.h>
#include <netdb.h>
2018-09-25 08:31:29 +00:00
#endif
2018-08-15 15:36:34 +00:00
#include <dns/dns.hpp>
2019-01-11 01:19:36 +00:00
#include <ev/ev.hpp>
#include <router/abstractrouter.hpp>
#include <service/context.hpp>
#include <service/outbound_context.hpp>
2020-05-21 14:18:23 +00:00
#include <service/endpoint_state.hpp>
#include <service/outbound_context.hpp>
#include <service/name.hpp>
2019-09-01 12:38:03 +00:00
#include <util/meta/memfn.hpp>
2019-09-01 13:26:16 +00:00
#include <util/thread/logic.hpp>
#include <nodedb.hpp>
2020-06-02 21:10:42 +00:00
#include <rpc/endpoint_rpc.hpp>
#include <util/str.hpp>
#include <dns/srv_data.hpp>
2018-08-15 15:36:34 +00:00
namespace llarp
{
2018-08-16 14:34:15 +00:00
namespace handlers
2018-08-15 15:36:34 +00:00
{
void
TunEndpoint::FlushToUser(std::function<bool(const net::IPPacket&)> send)
{
// flush network to user
while (not m_NetworkToUserPktQueue.empty())
{
send(m_NetworkToUserPktQueue.top().pkt);
m_NetworkToUserPktQueue.pop();
}
}
2019-11-29 18:37:19 +00:00
bool
TunEndpoint::ShouldFlushNow(llarp_time_t now) const
{
2020-02-24 19:40:45 +00:00
static constexpr auto FlushInterval = 25ms;
2019-11-29 18:37:19 +00:00
return now >= m_LastFlushAt + FlushInterval;
}
2019-11-20 19:45:23 +00:00
void
TunEndpoint::tunifTick(llarp_tun_io* tun)
2018-12-15 16:56:35 +00:00
{
llarp::LogTrace("TunEndpoint::tunifTick()");
auto* self = static_cast<TunEndpoint*>(tun->user);
2020-05-21 14:18:23 +00:00
self->Flush();
2018-12-15 16:56:35 +00:00
}
TunEndpoint::TunEndpoint(AbstractRouter* r, service::Context* parent, bool lazyVPN)
: service::Endpoint(r, parent)
, m_UserToNetworkPktQueue("endpoint_sendq", r->netloop(), r->netloop())
, m_Resolver(std::make_shared<dns::Proxy>(
2019-05-23 12:22:48 +00:00
r->netloop(), r->logic(), r->netloop(), r->logic(), this))
2018-08-15 15:36:34 +00:00
{
if (not lazyVPN)
{
tunif.reset(new llarp_tun_io());
std::fill(tunif->ifaddr, tunif->ifaddr + sizeof(tunif->ifaddr), 0);
std::fill(tunif->ifname, tunif->ifname + sizeof(tunif->ifname), 0);
tunif->netmask = 0;
tunif->get_fd_promise = nullptr;
tunif->user = this;
// eh this shouldn't do anything on windows anyway
tunif->tick = &tunifTick;
tunif->before_write = &tunifBeforeWrite;
tunif->recvpkt = &tunifRecvPkt;
}
2018-08-16 14:34:15 +00:00
}
2019-02-11 17:14:43 +00:00
util::StatusObject
TunEndpoint::ExtractStatus() const
2019-02-08 19:43:25 +00:00
{
auto obj = service::Endpoint::ExtractStatus();
obj["ifaddr"] = m_OurRange.ToString();
if (tunif)
{
obj["ifname"] = tunif->ifname;
}
std::vector<std::string> resolvers;
for (const auto& addr : m_UpstreamResolvers)
2020-05-06 20:38:44 +00:00
resolvers.emplace_back(addr.toString());
obj["ustreamResolvers"] = resolvers;
2020-05-06 20:38:44 +00:00
obj["localResolver"] = m_LocalResolverAddr.toString();
2019-02-11 17:14:43 +00:00
util::StatusObject ips{};
for (const auto& item : m_IPActivity)
2019-02-08 19:43:25 +00:00
{
util::StatusObject ipObj{{"lastActive", to_json(item.second)}};
2019-02-08 19:43:25 +00:00
std::string remoteStr;
AlignedBuffer<32> addr = m_IPToAddr.at(item.first);
if (m_SNodes.at(addr))
2019-02-08 19:43:25 +00:00
remoteStr = RouterID(addr.as_array()).ToString();
else
remoteStr = service::Address(addr.as_array()).ToString();
ipObj["remote"] = remoteStr;
2019-02-08 19:43:25 +00:00
std::string ipaddr = item.first.ToString();
ips[ipaddr] = ipObj;
2019-02-08 19:43:25 +00:00
}
obj["addrs"] = ips;
obj["ourIP"] = m_OurIP.ToString();
obj["nextIP"] = m_NextIP.ToString();
obj["maxIP"] = m_MaxIP.ToString();
2019-02-11 17:14:43 +00:00
return obj;
2019-02-08 19:43:25 +00:00
}
2018-08-16 14:34:15 +00:00
bool
TunEndpoint::Configure(const NetworkConfig& conf, const DnsConfig& dnsConf)
2018-08-16 14:34:15 +00:00
{
if (conf.m_reachable)
{
2020-05-04 16:51:57 +00:00
m_PublishIntroSet = true;
LogInfo(Name(), " setting to be reachable by default");
}
else
{
m_PublishIntroSet = false;
LogInfo(Name(), " setting to be not reachable by default");
}
if (conf.m_AuthType != service::AuthType::eAuthTypeNone)
2020-06-02 21:10:42 +00:00
{
std::string url, method;
if (conf.m_AuthUrl.has_value() and conf.m_AuthMethod.has_value())
{
url = *conf.m_AuthUrl;
method = *conf.m_AuthMethod;
}
2020-06-02 21:10:42 +00:00
auto auth = std::make_shared<rpc::EndpointAuthRPC>(
url, method, conf.m_AuthWhitelist, Router()->lmq(), shared_from_this());
2020-06-02 21:10:42 +00:00
auth->Start();
m_AuthPolicy = std::move(auth);
}
/*
* TODO: reinstate this option (it's not even clear what section this came from...)
*
if (k == "isolate-network" && IsTrueValue(v.c_str()))
{
2019-05-22 16:20:50 +00:00
#if defined(__linux__)
LogInfo(Name(), " isolating network...");
if (!SpawnIsolatedNetwork())
2019-05-22 16:20:50 +00:00
{
LogError(Name(), " failed to spawn isolated network");
return false;
2019-05-22 16:20:50 +00:00
}
LogInfo(Name(), " booyeah network isolation succeeded");
return true;
#else
LogError(Name(), " network isolation is not supported on your platform");
2019-05-22 16:20:50 +00:00
return false;
#endif
}
*/
/*
* TODO: this is currently defined for [router] / RouterConfig, but is clearly an [endpoint]
* option. either move it to [endpoint] or plumb RouterConfig through
*
if (k == "strict-connect")
{
RouterID connect;
if (!connect.FromString(v))
{
LogError(Name(), " invalid snode for strict-connect: ", v);
return false;
}
RouterContact rc;
if (!m_router->nodedb()->Get(connect, rc))
{
LogError(
Name(), " we don't have the RC for ", v, " so we can't use it in strict-connect");
return false;
}
for (const auto& ai : rc.addrs)
{
m_StrictConnectAddrs.emplace_back(ai);
LogInfo(Name(), " added ", m_StrictConnectAddrs.back(), " to strict connect");
}
return true;
}
*/
m_LocalResolverAddr = dnsConf.m_bind;
m_UpstreamResolvers = dnsConf.m_upstreamDNS;
2020-05-21 14:18:23 +00:00
for (const auto& item : conf.m_mapAddrs)
2018-08-22 15:52:10 +00:00
{
2020-05-21 14:18:23 +00:00
if (not MapAddress(item.second, item.first, false))
return false;
2018-08-22 15:52:10 +00:00
}
std::string ifname = conf.m_ifname;
if (ifname.empty())
{
const auto maybe = llarp::FindFreeTun();
if (not maybe.has_value())
throw std::runtime_error("cannot find free interface name");
ifname = *maybe;
}
if (tunif)
2018-08-16 14:34:15 +00:00
{
if (ifname.length() >= sizeof(tunif->ifname))
2018-12-28 15:10:05 +00:00
{
llarp::LogError(Name() + " ifname '", ifname, "' is too long");
2018-12-28 15:10:05 +00:00
return false;
}
strncpy(tunif->ifname, ifname.c_str(), sizeof(tunif->ifname) - 1);
llarp::LogInfo(Name() + " setting ifname to ", tunif->ifname);
m_OurRange = conf.m_ifaddr;
if (!m_OurRange.addr.h)
{
const auto maybe = llarp::FindFreeRange();
if (not maybe.has_value())
{
throw std::runtime_error("cannot find free address range");
}
m_OurRange = *maybe;
}
m_UseV6 = not m_OurRange.IsV4();
tunif->netmask = m_OurRange.HostmaskBits();
const auto addr = m_OurRange.BaseAddressString();
llarp::LogInfo(Name() + " set ifaddr to ", addr, " with netmask ", tunif->netmask);
strncpy(tunif->ifaddr, addr.c_str(), sizeof(tunif->ifaddr) - 1);
2018-08-16 14:34:15 +00:00
}
return Endpoint::Configure(conf, dnsConf);
2018-08-16 14:34:15 +00:00
}
2018-11-14 12:23:08 +00:00
bool
TunEndpoint::HasLocalIP(const huint128_t& ip) const
2018-11-14 12:23:08 +00:00
{
return m_IPToAddr.find(ip) != m_IPToAddr.end();
}
2018-12-15 16:56:35 +00:00
void
TunEndpoint::Flush()
{
2020-05-21 14:18:23 +00:00
FlushSend();
Pump(Now());
2018-12-15 16:56:35 +00:00
}
static bool
is_random_snode(const dns::Message& msg)
{
2019-04-26 12:11:34 +00:00
return msg.questions[0].IsName("random.snode");
}
static bool
is_localhost_loki(const dns::Message& msg)
{
return msg.questions[0].IsLocalhost();
}
2019-11-29 00:37:58 +00:00
template <>
bool
TunEndpoint::FindAddrForIP(service::Address& addr, huint128_t ip)
2019-11-29 00:37:58 +00:00
{
auto itr = m_IPToAddr.find(ip);
if (itr != m_IPToAddr.end() and not m_SNodes[itr->second])
2019-11-29 00:37:58 +00:00
{
addr = service::Address(itr->second.as_array());
return true;
}
return false;
}
template <>
bool
TunEndpoint::FindAddrForIP(RouterID& addr, huint128_t ip)
2019-11-29 00:37:58 +00:00
{
auto itr = m_IPToAddr.find(ip);
if (itr != m_IPToAddr.end() and m_SNodes[itr->second])
2019-11-29 00:37:58 +00:00
{
addr = RouterID(itr->second.as_array());
return true;
}
return false;
}
static dns::Message&
clear_dns_message(dns::Message& msg)
{
msg.authorities.resize(0);
msg.additional.resize(0);
msg.answers.resize(0);
msg.hdr_fields &= ~dns::flags_RCODENameError;
return msg;
}
2018-12-03 22:22:59 +00:00
bool
TunEndpoint::HandleHookedDNSMessage(dns::Message msg, std::function<void(dns::Message)> reply)
2018-12-03 22:22:59 +00:00
{
auto ReplyToSNodeDNSWhenReady = [self = this, reply = reply](
RouterID snode, auto msg, bool isV6) -> bool {
return self->EnsurePathToSNode(snode, [=](const RouterID&, exit::BaseSession_ptr s) {
self->SendDNSReply(snode, s, msg, reply, true, isV6);
});
};
auto ReplyToLokiDNSWhenReady = [self = this, reply = reply](
service::Address addr, auto msg, bool isV6) -> bool {
using service::Address;
using service::OutboundContext;
return self->EnsurePathToService(
addr,
[=](const Address&, OutboundContext* ctx) {
self->SendDNSReply(addr, ctx, msg, reply, false, isV6);
},
2s);
};
auto ReplyToLokiSRVWhenReady = [self = this, reply = reply](
service::Address addr, auto msg) -> bool {
using service::Address;
using service::OutboundContext;
return self->EnsurePathToService(
addr,
[=](const Address&, OutboundContext* ctx) {
if (ctx == nullptr)
return;
const auto& introset = ctx->GetCurrentIntroSet();
msg->AddSRVReply(introset.GetMatchingSRVRecords(addr.subdomain));
reply(*msg);
},
2s);
};
if (msg.answers.size() > 0)
{
const auto& answer = msg.answers[0];
if (answer.HasCNameForTLD(".snode"))
{
dns::Name_t qname;
llarp_buffer_t buf(answer.rData);
if (not dns::DecodeName(&buf, qname, true))
return false;
RouterID addr;
if (not addr.FromString(qname))
return false;
auto replyMsg = std::make_shared<dns::Message>(clear_dns_message(msg));
return ReplyToSNodeDNSWhenReady(addr, std::move(replyMsg), false);
}
else if (answer.HasCNameForTLD(".loki"))
{
dns::Name_t qname;
llarp_buffer_t buf(answer.rData);
if (not dns::DecodeName(&buf, qname, true))
return false;
service::Address addr;
if (not addr.FromString(qname))
return false;
auto replyMsg = std::make_shared<dns::Message>(clear_dns_message(msg));
return ReplyToLokiDNSWhenReady(addr, replyMsg, false);
}
}
if (msg.questions.size() != 1)
2018-12-03 22:22:59 +00:00
{
llarp::LogWarn("bad number of dns questions: ", msg.questions.size());
return false;
}
std::string qname = msg.questions[0].Name();
2020-09-19 14:38:57 +00:00
const auto nameparts = split(qname, ".");
std::string lnsName;
if (nameparts.size() >= 2 and ends_with(qname, ".loki"))
{
lnsName = nameparts[nameparts.size() - 2];
lnsName += ".loki"sv;
}
if (msg.questions[0].qtype == dns::qTypeTXT)
{
RouterID snode;
if (snode.FromString(qname))
{
m_router->LookupRouter(snode, [reply, msg = std::move(msg)](const auto& found) mutable {
if (found.empty())
{
msg.AddNXReply();
}
else
{
std::stringstream ss;
for (const auto& rc : found)
rc.ToTXTRecord(ss);
msg.AddTXTReply(ss.str());
}
reply(msg);
});
return true;
}
else if (msg.questions[0].IsLocalhost() and msg.questions[0].HasSubdomains())
{
const auto subdomain = msg.questions[0].Subdomains();
if (subdomain == "exit")
{
if (HasExit())
{
std::stringstream ss;
m_ExitMap.ForEachEntry([&ss](const auto& range, const auto& exit) {
ss << range.ToString() << "=" << exit.ToString() << "; ";
});
msg.AddTXTReply(ss.str());
}
else
{
msg.AddNXReply();
}
}
else if (subdomain == "netid")
{
std::stringstream ss;
ss << "netid=" << m_router->rc().netID.ToString() << ";";
msg.AddTXTReply(ss.str());
}
else
{
msg.AddNXReply();
}
}
else
{
msg.AddNXReply();
}
reply(msg);
}
else if (msg.questions[0].qtype == dns::qTypeMX)
2018-12-07 21:52:19 +00:00
{
// mx record
2019-02-05 14:23:51 +00:00
service::Address addr;
if (addr.FromString(qname, ".loki") || addr.FromString(qname, ".snode")
|| is_random_snode(msg) || is_localhost_loki(msg))
2018-12-07 21:52:19 +00:00
msg.AddMXReply(qname, 1);
else
msg.AddNXReply();
2018-12-07 22:08:23 +00:00
reply(msg);
2018-12-07 21:52:19 +00:00
}
else if (msg.questions[0].qtype == dns::qTypeCNAME)
2019-01-10 15:49:08 +00:00
{
if (is_random_snode(msg))
2019-01-10 15:49:08 +00:00
{
RouterID random;
if (Router()->GetRandomGoodRouter(random))
{
2019-01-10 15:49:08 +00:00
msg.AddCNAMEReply(random.ToString(), 1);
}
2019-01-10 15:49:08 +00:00
else
msg.AddNXReply();
}
else if (is_localhost_loki(msg))
{
size_t counter = 0;
context->ForEachService(
[&](const std::string&, const std::shared_ptr<service::Endpoint>& service) -> bool {
2019-07-05 14:41:26 +00:00
const service::Address addr = service->GetIdentity().pub.Addr();
msg.AddCNAMEReply(addr.ToString(), 1);
++counter;
return true;
});
if (counter == 0)
msg.AddNXReply();
}
2019-01-10 15:49:08 +00:00
else
msg.AddNXReply();
2019-02-05 14:03:38 +00:00
reply(msg);
2019-01-10 15:49:08 +00:00
}
else if (msg.questions[0].qtype == dns::qTypeA || msg.questions[0].qtype == dns::qTypeAAAA)
2018-12-03 22:22:59 +00:00
{
const bool isV6 = msg.questions[0].qtype == dns::qTypeAAAA;
2019-06-11 16:44:05 +00:00
const bool isV4 = msg.questions[0].qtype == dns::qTypeA;
2018-12-03 22:22:59 +00:00
llarp::service::Address addr;
if (isV6 && !SupportsV6())
{ // empty reply but not a NXDOMAIN so that client can retry IPv4
msg.AddNSReply("localhost.loki.");
}
2019-02-05 03:19:06 +00:00
// on MacOS this is a typeA query
else if (is_random_snode(msg))
2019-02-05 03:19:06 +00:00
{
2019-02-05 21:04:30 +00:00
RouterID random;
if (Router()->GetRandomGoodRouter(random))
{
2019-02-05 21:04:30 +00:00
msg.AddCNAMEReply(random.ToString(), 1);
return ReplyToSNodeDNSWhenReady(random, std::make_shared<dns::Message>(msg), isV6);
}
2019-02-05 21:04:30 +00:00
else
msg.AddNXReply();
2019-02-05 03:19:06 +00:00
}
else if (is_localhost_loki(msg))
2018-12-13 00:03:19 +00:00
{
size_t counter = 0;
context->ForEachService(
[&](const std::string&, const std::shared_ptr<service::Endpoint>& service) -> bool {
if (!service->HasIfAddr())
2019-07-01 13:44:25 +00:00
return true;
2019-06-11 16:44:05 +00:00
huint128_t ip = service->GetIfAddr();
if (ip.h)
{
msg.AddINReply(ip, isV6);
++counter;
}
return true;
});
if (counter == 0)
2018-12-13 00:03:19 +00:00
msg.AddNXReply();
}
else if (addr.FromString(qname, ".loki"))
2018-12-03 22:22:59 +00:00
{
if (isV4 && SupportsV6())
{
2019-06-11 18:23:53 +00:00
msg.hdr_fields |= dns::flags_QR | dns::flags_AA | dns::flags_RA;
2019-06-11 16:44:05 +00:00
}
else
{
return ReplyToLokiDNSWhenReady(addr, std::make_shared<dns::Message>(msg), isV6);
}
2018-12-03 22:22:59 +00:00
}
else if (addr.FromString(qname, ".snode"))
2018-12-03 22:22:59 +00:00
{
if (isV4 && SupportsV6())
2019-06-12 13:48:14 +00:00
{
msg.hdr_fields |= dns::flags_QR | dns::flags_AA | dns::flags_RA;
}
else
{
return ReplyToSNodeDNSWhenReady(
addr.as_array(), std::make_shared<dns::Message>(msg), isV6);
2019-06-12 13:48:14 +00:00
}
2018-12-03 22:22:59 +00:00
}
2020-09-19 14:38:57 +00:00
else if (service::NameIsValid(lnsName))
{
return LookupNameAsync(
2020-09-19 14:38:57 +00:00
lnsName,
[msg = std::make_shared<dns::Message>(msg),
name = Name(),
2020-09-19 14:38:57 +00:00
lnsName,
isV6,
reply,
ReplyToLokiDNSWhenReady](auto maybe) {
if (not maybe.has_value())
{
2020-09-19 14:38:57 +00:00
LogWarn(name, " lns name ", lnsName, " not resolved");
msg->AddNXReply();
reply(*msg);
return;
}
2020-09-19 14:38:57 +00:00
LogInfo(name, " ", lnsName, " resolved to ", maybe->ToString());
ReplyToLokiDNSWhenReady(*maybe, msg, isV6);
});
}
2018-12-03 22:22:59 +00:00
else
2018-12-04 16:16:43 +00:00
msg.AddNXReply();
reply(msg);
2018-12-03 22:22:59 +00:00
}
else if (msg.questions[0].qtype == dns::qTypePTR)
2018-12-03 22:22:59 +00:00
{
2018-12-04 16:16:43 +00:00
// reverse dns
2019-06-12 13:48:14 +00:00
huint128_t ip = {0};
if (!dns::DecodePTR(msg.questions[0].qname, ip))
2018-12-03 22:22:59 +00:00
{
2018-12-04 16:16:43 +00:00
msg.AddNXReply();
reply(msg);
2018-12-03 22:22:59 +00:00
return true;
}
2019-11-29 00:37:58 +00:00
RouterID snodeAddr;
if (FindAddrForIP(snodeAddr, ip))
2018-12-03 22:22:59 +00:00
{
2019-11-29 00:37:58 +00:00
msg.AddAReply(snodeAddr.ToString());
2018-12-04 16:16:43 +00:00
reply(msg);
2018-12-03 22:22:59 +00:00
return true;
}
2019-11-29 00:37:58 +00:00
service::Address lokiAddr;
if (FindAddrForIP(lokiAddr, ip))
2018-12-03 22:22:59 +00:00
{
2019-11-29 00:37:58 +00:00
msg.AddAReply(lokiAddr.ToString());
2018-12-04 16:16:43 +00:00
reply(msg);
2018-12-03 22:22:59 +00:00
return true;
}
2018-12-04 16:16:43 +00:00
msg.AddNXReply();
reply(msg);
2018-12-03 22:22:59 +00:00
return true;
}
else if (msg.questions[0].qtype == dns::qTypeSRV)
{
llarp::service::Address addr;
if (is_localhost_loki(msg))
{
msg.AddSRVReply(introSet().GetMatchingSRVRecords(msg.questions[0].Subdomains()));
reply(msg);
return true;
}
else if (addr.FromString(qname, ".loki"))
{
llarp::LogDebug("SRV request for: ", qname);
return ReplyToLokiSRVWhenReady(addr, std::make_shared<dns::Message>(msg));
}
}
2018-12-03 22:22:59 +00:00
else
2018-12-04 16:16:43 +00:00
{
msg.AddNXReply();
reply(msg);
}
2018-12-03 22:22:59 +00:00
return true;
}
2019-05-07 17:46:38 +00:00
void
TunEndpoint::ResetInternalState()
{
service::Endpoint::ResetInternalState();
}
2019-06-11 16:44:05 +00:00
bool
TunEndpoint::SupportsV6() const
{
return m_UseV6;
}
2019-03-20 03:18:38 +00:00
// FIXME: pass in which question it should be addressing
2018-12-03 22:22:59 +00:00
bool
TunEndpoint::ShouldHookDNSMessage(const dns::Message& msg) const
2018-12-03 22:22:59 +00:00
{
llarp::service::Address addr;
if (msg.questions.size() == 1)
2018-12-03 22:22:59 +00:00
{
/// hook every .loki
if (msg.questions[0].HasTLD(".loki"))
2018-12-13 00:03:19 +00:00
return true;
/// hook every .snode
if (msg.questions[0].HasTLD(".snode"))
2018-12-03 22:22:59 +00:00
return true;
2019-01-10 15:49:08 +00:00
// hook any ranges we own
if (msg.questions[0].qtype == llarp::dns::qTypePTR)
2018-12-03 22:22:59 +00:00
{
2019-06-12 13:48:14 +00:00
huint128_t ip = {0};
if (!dns::DecodePTR(msg.questions[0].qname, ip))
2018-12-03 22:22:59 +00:00
return false;
2019-06-12 13:48:14 +00:00
return m_OurRange.Contains(ip);
2018-12-03 22:22:59 +00:00
}
}
for (const auto& answer : msg.answers)
{
if (answer.HasCNameForTLD(".loki"))
return true;
if (answer.HasCNameForTLD(".snode"))
return true;
}
2018-12-03 22:22:59 +00:00
return false;
}
2018-08-22 15:52:10 +00:00
bool
TunEndpoint::MapAddress(const service::Address& addr, huint128_t ip, bool SNode)
2018-08-22 15:52:10 +00:00
{
auto itr = m_IPToAddr.find(ip);
if (itr != m_IPToAddr.end())
2018-08-22 15:52:10 +00:00
{
llarp::LogWarn(
ip, " already mapped to ", service::Address(itr->second.as_array()).ToString());
2018-08-22 15:52:10 +00:00
return false;
}
2018-11-03 13:19:18 +00:00
llarp::LogInfo(Name() + " map ", addr.ToString(), " to ", ip);
2018-10-19 15:04:14 +00:00
m_IPToAddr[ip] = addr;
m_AddrToIP[addr] = ip;
m_SNodes[addr] = SNode;
2018-09-10 11:08:09 +00:00
MarkIPActiveForever(ip);
2018-08-22 15:52:10 +00:00
return true;
}
2020-08-21 15:07:37 +00:00
std::string
TunEndpoint::GetIfName() const
{
2020-09-28 22:43:31 +00:00
#ifdef _WIN32
return net::TruncateV6(GetIfAddr()).ToString();
#else
if (tunif)
return tunif->ifname;
2020-08-21 15:07:37 +00:00
return m_IfName;
2020-09-28 22:43:31 +00:00
#endif
2020-08-21 15:07:37 +00:00
}
2018-08-16 14:34:15 +00:00
bool
TunEndpoint::Start()
{
if (!Endpoint::Start())
{
llarp::LogWarn("Couldn't start endpoint");
2018-08-16 14:34:15 +00:00
return false;
}
2018-08-21 18:39:18 +00:00
return SetupNetworking();
2018-08-16 14:34:15 +00:00
}
bool
TunEndpoint::IsSNode() const
{
// TODO : implement me
return false;
}
2018-08-16 14:34:15 +00:00
bool
TunEndpoint::SetupTun()
{
lazy_vpn vpn;
huint32_t ip;
2019-04-08 12:01:52 +00:00
auto loop = EndpointNetLoop();
if (tunif == nullptr)
{
llarp::LogInfo(Name(), " waiting for vpn to start");
vpn = m_LazyVPNPromise.get_future().get();
vpnif = vpn.io;
if (vpnif == nullptr)
{
llarp::LogError(Name(), " failed to recieve vpn interface");
return false;
}
llarp::LogInfo(Name(), " got vpn interface");
auto self = shared_from_this();
// function to queue a packet to send to vpn interface
auto sendpkt = [self](const net::IPPacket& pkt) -> bool {
// drop if no endpoint
auto impl = self->GetVPNImpl();
// drop if no vpn interface
if (impl == nullptr)
return true;
// drop if queue to vpn not enabled
if (not impl->reader.queue.enabled())
return true;
// drop if queue to vpn full
if (impl->reader.queue.full())
return true;
// queue to reader
impl->reader.queue.pushBack(pkt);
return false;
};
// event loop ticker
auto ticker = [self, sendpkt]() {
llarp::LogTrace("TunEndpoint ticker() start");
TunEndpoint* ep = self.get();
const bool running = not ep->IsStopped();
auto impl = ep->GetVPNImpl();
if (impl)
{
/// get packets from vpn
while (not impl->writer.queue.empty())
{
// queue it to be sent over lokinet
auto pkt = impl->writer.queue.popFront();
if (running)
ep->m_UserToNetworkPktQueue.Emplace(pkt);
}
}
// process packets queued from vpn
if (running)
{
ep->Flush();
ep->FlushToUser(sendpkt);
}
// if impl has a tick function call it
if (impl && impl->parent && impl->parent->tick)
impl->parent->tick(impl->parent);
llarp::LogTrace("TunEndpoint ticker() end");
};
if (not loop->add_ticker(ticker))
{
llarp::LogError(Name(), " failed to add vpn to event loop");
if (vpnif->injected)
vpnif->injected(vpnif, false);
return false;
}
2019-06-11 16:44:05 +00:00
}
else
{
if (!llarp_ev_add_tun(loop.get(), tunif.get()))
2019-06-11 16:44:05 +00:00
{
llarp::LogError(
Name(), " failed to set up tun interface: ", tunif->ifaddr, " on ", tunif->ifname);
2019-06-11 16:44:05 +00:00
return false;
}
}
const char* ifname;
const char* ifaddr;
unsigned char netmask;
if (tunif)
{
ifname = tunif->ifname;
ifaddr = tunif->ifaddr;
netmask = tunif->netmask;
}
else
{
ifname = vpn.info.ifname;
ifaddr = vpn.info.ifaddr;
netmask = vpn.info.netmask;
}
2020-08-21 15:07:37 +00:00
m_IfName = ifname;
if (ip.FromString(ifaddr))
2019-06-11 16:44:05 +00:00
{
m_OurIP = net::ExpandV4(ip);
m_OurRange.netmask_bits = netmask_ipv6_bits(netmask + 96);
2019-06-11 16:44:05 +00:00
}
else if (m_OurIP.FromString(ifaddr))
2019-06-11 16:44:05 +00:00
{
m_OurRange.netmask_bits = netmask_ipv6_bits(netmask);
m_UseV6 = true;
}
else
{
LogError(Name(), " invalid interface address given, ifaddr=", ifaddr);
if (vpnif && vpnif->injected)
vpnif->injected(vpnif, false);
return false;
}
m_NextIP = m_OurIP;
2019-06-11 16:44:05 +00:00
m_OurRange.addr = m_OurIP;
m_MaxIP = m_OurRange.HighestAddr();
llarp::LogInfo(Name(), " set ", ifname, " to have address ", m_OurIP);
llarp::LogInfo(Name(), " allocated up to ", m_MaxIP, " on range ", m_OurRange);
2019-06-11 16:44:05 +00:00
2019-11-29 00:37:58 +00:00
const service::Address ourAddr = m_Identity.pub.Addr();
if (not MapAddress(ourAddr, GetIfAddr(), false))
2019-11-29 00:37:58 +00:00
{
return false;
}
if (m_OnUp)
{
2019-04-22 14:00:59 +00:00
m_OnUp->NotifyAsync(NotifyParams());
}
if (vpnif && vpnif->injected)
{
vpnif->injected(vpnif, true);
}
2019-11-29 00:37:58 +00:00
return HasAddress(ourAddr);
2018-08-16 14:34:15 +00:00
}
std::unordered_map<std::string, std::string>
2019-04-22 14:00:59 +00:00
TunEndpoint::NotifyParams() const
{
auto env = Endpoint::NotifyParams();
env.emplace("IP_ADDR", m_OurIP.ToString());
env.emplace("IF_ADDR", m_OurRange.ToString());
if (tunif)
env.emplace("IF_NAME", tunif->ifname);
std::string strictConnect;
for (const auto& addr : m_StrictConnectAddrs)
2020-05-06 20:38:44 +00:00
strictConnect += addr.toString() + " ";
env.emplace("STRICT_CONNECT_ADDRS", strictConnect);
2019-04-22 14:00:59 +00:00
return env;
}
2018-08-16 14:34:15 +00:00
bool
TunEndpoint::SetupNetworking()
{
llarp::LogInfo("Set Up networking for ", Name());
if (!SetupTun())
2018-10-04 13:42:22 +00:00
{
2018-12-03 22:22:59 +00:00
llarp::LogError(Name(), " failed to set up network interface");
return false;
2018-10-04 13:42:22 +00:00
}
if (!m_Resolver->Start(m_LocalResolverAddr, m_UpstreamResolvers))
{
llarp::LogError(Name(), " failed to start DNS server");
return false;
}
2018-12-03 22:22:59 +00:00
return true;
2018-08-16 14:34:15 +00:00
}
void
TunEndpoint::Tick(llarp_time_t now)
{
2019-11-20 19:45:23 +00:00
Endpoint::Tick(now);
2018-08-16 14:34:15 +00:00
}
bool
TunEndpoint::Stop()
{
return llarp::service::Endpoint::Stop();
}
2018-08-22 15:52:10 +00:00
void
TunEndpoint::FlushSend()
{
m_UserToNetworkPktQueue.Process([&](net::IPPacket& pkt) {
std::function<bool(const llarp_buffer_t&)> sendFunc;
2019-06-11 16:44:05 +00:00
2020-05-21 14:18:23 +00:00
huint128_t dst, src;
if (pkt.IsV4())
2020-05-21 14:18:23 +00:00
{
dst = pkt.dst4to6();
src = pkt.src4to6();
}
2019-06-11 16:44:05 +00:00
else
2020-05-21 14:18:23 +00:00
{
2019-06-11 16:44:05 +00:00
dst = pkt.dstv6();
2020-05-21 14:18:23 +00:00
src = pkt.srcv6();
}
2019-06-11 16:44:05 +00:00
auto itr = m_IPToAddr.find(dst);
if (itr == m_IPToAddr.end())
2018-08-22 15:52:10 +00:00
{
const auto exits = m_ExitMap.FindAll(dst);
if (IsBogon(dst) or exits.empty())
2019-06-11 19:48:21 +00:00
{
2020-05-21 14:18:23 +00:00
// send icmp unreachable
const auto icmp = pkt.MakeICMPUnreachable();
if (icmp.has_value())
{
HandleWriteIPPacket(icmp->ConstBuffer(), dst, src, 0);
}
2019-06-11 16:44:05 +00:00
}
2020-05-21 14:18:23 +00:00
else
{
const auto addr = *exits.begin();
2020-05-21 14:18:23 +00:00
pkt.ZeroSourceAddress();
MarkAddressOutbound(addr);
2020-05-21 14:18:23 +00:00
EnsurePathToService(
addr,
[addr, pkt, self = this](service::Address, service::OutboundContext* ctx) {
if (ctx)
{
ctx->sendTimeout = 5s;
}
self->SendToServiceOrQueue(addr, pkt.ConstBuffer(), service::eProtocolExit);
2020-05-21 14:18:23 +00:00
},
1s);
}
2019-06-11 16:44:05 +00:00
return;
2018-08-22 15:52:10 +00:00
}
if (m_SNodes.at(itr->second))
2018-11-29 13:12:35 +00:00
{
sendFunc = std::bind(
&TunEndpoint::SendToSNodeOrQueue,
this,
itr->second.as_array(),
std::placeholders::_1);
2018-11-29 13:12:35 +00:00
}
2020-05-21 14:18:23 +00:00
else if (m_state->m_ExitEnabled)
{
sendFunc = std::bind(
&TunEndpoint::SendToServiceOrQueue,
this,
service::Address(itr->second.as_array()),
std::placeholders::_1,
service::eProtocolExit);
}
else
2018-11-29 13:12:35 +00:00
{
sendFunc = std::bind(
&TunEndpoint::SendToServiceOrQueue,
this,
service::Address(itr->second.as_array()),
std::placeholders::_1,
pkt.ServiceProtocol());
2018-11-29 13:12:35 +00:00
}
// prepare packet for insertion into network
// this includes clearing IP addresses, recalculating checksums, etc
2020-05-21 14:18:23 +00:00
if (not m_state->m_ExitEnabled)
{
if (pkt.IsV4())
pkt.UpdateIPv4Address({0}, {0});
else
pkt.UpdateIPv6Address({0}, {0});
}
if (sendFunc && sendFunc(pkt.Buffer()))
{
MarkIPActive(dst);
2019-06-11 16:44:05 +00:00
return;
}
2018-11-29 13:12:35 +00:00
llarp::LogWarn(Name(), " did not flush packets");
2018-08-22 15:52:10 +00:00
});
}
bool
2020-05-21 14:18:23 +00:00
TunEndpoint::HandleInboundPacket(
const service::ConvoTag tag,
const llarp_buffer_t& buf,
service::ProtocolType t,
uint64_t seqno)
2020-05-21 14:18:23 +00:00
{
if (t != service::eProtocolTrafficV4 && t != service::eProtocolTrafficV6
&& t != service::eProtocolExit)
return false;
AlignedBuffer<32> addr;
bool snode = false;
if (!GetEndpointWithConvoTag(tag, addr, snode))
return false;
huint128_t src, dst;
net::IPPacket pkt;
if (not pkt.Load(buf))
return false;
if (m_state->m_ExitEnabled)
2020-05-21 14:18:23 +00:00
{
// exit side from exit
src = ObtainIPForAddr(addr, snode);
if (pkt.IsV4())
dst = pkt.dst4to6();
else if (pkt.IsV6())
dst = pkt.dstv6();
}
else if (t == service::eProtocolExit)
{
// client side exit traffic from exit
if (pkt.IsV4())
src = pkt.src4to6();
else if (pkt.IsV6())
src = pkt.srcv6();
dst = m_OurIP;
// find what exit we think this should be for
const auto mapped = m_ExitMap.FindAll(src);
if (mapped.count(service::Address{addr}) == 0 or IsBogon(src))
{
// we got exit traffic from someone who we should not have gotten it from
return false;
}
}
2020-05-21 14:18:23 +00:00
else
{
// snapp traffic
src = ObtainIPForAddr(addr, snode);
dst = m_OurIP;
}
HandleWriteIPPacket(buf, src, dst, seqno);
2020-05-21 14:18:23 +00:00
return true;
}
bool
TunEndpoint::HandleWriteIPPacket(
const llarp_buffer_t& b, huint128_t src, huint128_t dst, uint64_t seqno)
2018-08-18 14:01:21 +00:00
{
2019-02-03 00:48:10 +00:00
ManagedBuffer buf(b);
WritePacket write;
write.seqno = seqno;
auto& pkt = write.pkt;
// load
if (!pkt.Load(buf))
return false;
if (pkt.IsV4())
{
pkt.UpdateIPv4Address(xhtonl(net::TruncateV6(src)), xhtonl(net::TruncateV6(dst)));
}
else if (pkt.IsV6())
{
pkt.UpdateIPv6Address(src, dst);
}
m_NetworkToUserPktQueue.push(std::move(write));
return true;
2018-08-20 19:12:12 +00:00
}
2018-10-19 15:04:14 +00:00
2019-06-11 16:44:05 +00:00
huint128_t
2018-11-14 12:23:08 +00:00
TunEndpoint::GetIfAddr() const
{
2018-11-14 12:23:08 +00:00
return m_OurIP;
}
2018-08-20 19:12:12 +00:00
2019-06-11 16:44:05 +00:00
huint128_t
TunEndpoint::ObtainIPForAddr(const AlignedBuffer<32>& ident, bool snode)
2018-08-20 19:12:12 +00:00
{
llarp_time_t now = Now();
2019-06-11 16:44:05 +00:00
huint128_t nextIP = {0};
{
// previously allocated address
2018-11-14 20:56:54 +00:00
auto itr = m_AddrToIP.find(ident);
if (itr != m_AddrToIP.end())
2018-08-22 15:52:10 +00:00
{
// mark ip active
2018-09-16 12:25:17 +00:00
MarkIPActive(itr->second);
return itr->second;
2018-08-22 15:52:10 +00:00
}
}
// allocate new address
if (m_NextIP < m_MaxIP)
{
do
{
nextIP = ++m_NextIP;
} while (m_IPToAddr.find(nextIP) != m_IPToAddr.end() && m_NextIP < m_MaxIP);
if (nextIP < m_MaxIP)
{
m_AddrToIP[ident] = nextIP;
2018-11-14 21:40:44 +00:00
m_IPToAddr[nextIP] = ident;
m_SNodes[ident] = snode;
2018-11-14 20:56:54 +00:00
llarp::LogInfo(Name(), " mapped ", ident, " to ", nextIP);
MarkIPActive(nextIP);
return nextIP;
}
}
// we are full
// expire least active ip
// TODO: prevent DoS
std::pair<huint128_t, llarp_time_t> oldest = {huint128_t{0}, 0s};
// find oldest entry
auto itr = m_IPActivity.begin();
while (itr != m_IPActivity.end())
{
if (itr->second <= now)
{
if ((now - itr->second) > oldest.second)
{
oldest.first = itr->first;
oldest.second = itr->second;
}
}
++itr;
}
// remap address
2018-11-14 21:47:58 +00:00
m_IPToAddr[oldest.first] = ident;
m_AddrToIP[ident] = oldest.first;
m_SNodes[ident] = snode;
nextIP = oldest.first;
// mark ip active
m_IPActivity[nextIP] = std::max(m_IPActivity[nextIP], now);
2018-08-20 19:12:12 +00:00
return nextIP;
}
bool
2019-06-11 16:44:05 +00:00
TunEndpoint::HasRemoteForIP(huint128_t ip) const
2018-08-20 19:12:12 +00:00
{
return m_IPToAddr.find(ip) != m_IPToAddr.end();
2018-08-18 14:01:21 +00:00
}
void
2019-06-11 16:44:05 +00:00
TunEndpoint::MarkIPActive(huint128_t ip)
{
2019-06-11 21:28:55 +00:00
llarp::LogDebug(Name(), " address ", ip, " is active");
2018-10-29 16:48:36 +00:00
m_IPActivity[ip] = std::max(Now(), m_IPActivity[ip]);
}
2018-09-10 11:08:09 +00:00
void
2019-06-11 16:44:05 +00:00
TunEndpoint::MarkIPActiveForever(huint128_t ip)
2018-09-10 11:08:09 +00:00
{
m_IPActivity[ip] = std::numeric_limits<llarp_time_t>::max();
2018-09-10 11:08:09 +00:00
}
void
TunEndpoint::TickTun(__attribute__((unused)) llarp_time_t now)
{
// called in the isolated thread
}
void
TunEndpoint::tunifBeforeWrite(llarp_tun_io* tun)
{
// called in the isolated network thread
auto* self = static_cast<TunEndpoint*>(tun->user);
2020-06-04 21:25:34 +00:00
self->Flush();
self->FlushToUser([self, tun](const net::IPPacket& pkt) -> bool {
if (not llarp_ev_tun_async_write(tun, pkt.ConstBuffer()))
{
2020-05-21 14:18:23 +00:00
llarp::LogWarn(self->Name(), " packet dropped");
}
2020-05-21 14:18:23 +00:00
return false;
});
2020-05-21 14:18:23 +00:00
} // namespace handlers
2018-08-22 15:52:10 +00:00
void
TunEndpoint::tunifRecvPkt(llarp_tun_io* tun, const llarp_buffer_t& b)
{
// called for every packet read from user in isolated network thread
auto* self = static_cast<TunEndpoint*>(tun->user);
2020-05-21 14:18:23 +00:00
self->m_UserToNetworkPktQueue.EmplaceIf([&](net::IPPacket& pkt) { return pkt.Load(b); });
}
2019-07-30 23:42:13 +00:00
TunEndpoint::~TunEndpoint() = default;
2018-08-15 15:36:34 +00:00
2018-08-16 14:34:15 +00:00
} // namespace handlers
} // namespace llarp