mirror of https://github.com/oxen-io/lokinet
initial commit for #1595
This commit is contained in:
parent
545021aa3d
commit
fedc56e3f1
|
@ -154,6 +154,7 @@ add_library(liblokinet
|
||||||
messages/relay_status.cpp
|
messages/relay_status.cpp
|
||||||
net/address_info.cpp
|
net/address_info.cpp
|
||||||
net/exit_info.cpp
|
net/exit_info.cpp
|
||||||
|
net/traffic_policy.cpp
|
||||||
nodedb.cpp
|
nodedb.cpp
|
||||||
path/ihophandler.cpp
|
path/ihophandler.cpp
|
||||||
path/path_context.cpp
|
path/path_context.cpp
|
||||||
|
@ -212,6 +213,7 @@ add_library(liblokinet
|
||||||
service/name.cpp
|
service/name.cpp
|
||||||
service/outbound_context.cpp
|
service/outbound_context.cpp
|
||||||
service/protocol.cpp
|
service/protocol.cpp
|
||||||
|
service/protocol_type.cpp
|
||||||
service/router_lookup_job.cpp
|
service/router_lookup_job.cpp
|
||||||
service/sendcontext.cpp
|
service/sendcontext.cpp
|
||||||
service/session.cpp
|
service/session.cpp
|
||||||
|
|
|
@ -415,19 +415,25 @@ namespace llarp
|
||||||
"on the server and may pose liability concerns. Enable at your own risk.",
|
"on the server and may pose liability concerns. Enable at your own risk.",
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: not implemented yet!
|
conf.defineOption<std::string>(
|
||||||
// TODO: define the order of precedence (e.g. is whitelist applied before blacklist?)
|
"network",
|
||||||
// additionally, what's default? What if I don't whitelist anything?
|
"traffic-whitelist",
|
||||||
/*
|
MultiValue,
|
||||||
conf.defineOption<std::string>("network", "exit-whitelist", MultiValue, Comment{
|
Comment{
|
||||||
"List of destination protocol:port pairs to whitelist, example: udp:*",
|
"List of ip traffic whitelist, anything not specified will be dropped by us."
|
||||||
"or tcp:80. Multiple values supported.",
|
"examples:",
|
||||||
}, FIXME-acceptor);
|
"tcp for all tcp traffic regardless of port",
|
||||||
|
"0x69 for all packets using ip protocol 0x69"
|
||||||
|
"udp/53 for udp port 53",
|
||||||
|
"tcp/smtp for smtp port",
|
||||||
|
},
|
||||||
|
[this](std::string arg) {
|
||||||
|
if (not m_TrafficPolicy)
|
||||||
|
m_TrafficPolicy = net::TrafficPolicy{};
|
||||||
|
|
||||||
conf.defineOption<std::string>("network", "exit-blacklist", MultiValue, Comment{
|
// this will throw on error
|
||||||
"Blacklist of destinations (same format as whitelist).",
|
m_TrafficPolicy->protocols.emplace(arg);
|
||||||
}, FIXME-acceptor);
|
});
|
||||||
*/
|
|
||||||
|
|
||||||
conf.defineOption<std::string>(
|
conf.defineOption<std::string>(
|
||||||
"network",
|
"network",
|
||||||
|
|
|
@ -122,6 +122,9 @@ namespace llarp
|
||||||
|
|
||||||
std::optional<huint128_t> m_baseV6Address;
|
std::optional<huint128_t> m_baseV6Address;
|
||||||
|
|
||||||
|
std::set<IPRange> m_AdvertisedRanges;
|
||||||
|
std::optional<net::TrafficPolicy> m_TrafficPolicy;
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// on-up
|
// on-up
|
||||||
// on-down
|
// on-down
|
||||||
|
|
|
@ -158,56 +158,6 @@ namespace llarp
|
||||||
m_AuthPolicy = std::move(auth);
|
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()))
|
|
||||||
{
|
|
||||||
#if defined(__linux__)
|
|
||||||
LogInfo(Name(), " isolating network...");
|
|
||||||
if (!SpawnIsolatedNetwork())
|
|
||||||
{
|
|
||||||
LogError(Name(), " failed to spawn isolated network");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
LogInfo(Name(), " booyeah network isolation succeeded");
|
|
||||||
return true;
|
|
||||||
#else
|
|
||||||
LogError(Name(), " network isolation is not supported on your platform");
|
|
||||||
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_LocalResolverAddr = dnsConf.m_bind;
|
||||||
m_UpstreamResolvers = dnsConf.m_upstreamDNS;
|
m_UpstreamResolvers = dnsConf.m_upstreamDNS;
|
||||||
|
|
||||||
|
@ -916,34 +866,46 @@ namespace llarp
|
||||||
auto itr = m_IPToAddr.find(dst);
|
auto itr = m_IPToAddr.find(dst);
|
||||||
if (itr == m_IPToAddr.end())
|
if (itr == m_IPToAddr.end())
|
||||||
{
|
{
|
||||||
const auto exits = m_ExitMap.FindAll(dst);
|
// find all ranges that match the destination ip
|
||||||
if (IsBogon(dst) or exits.empty())
|
const auto exitEntries = m_ExitMap.FindAllEntries(dst);
|
||||||
|
if (exitEntries.empty())
|
||||||
{
|
{
|
||||||
// send icmp unreachable
|
// send icmp unreachable as we dont have any exits for this ip
|
||||||
const auto icmp = pkt.MakeICMPUnreachable();
|
if (const auto icmp = pkt.MakeICMPUnreachable())
|
||||||
if (icmp.has_value())
|
|
||||||
{
|
{
|
||||||
HandleWriteIPPacket(icmp->ConstBuffer(), dst, src, 0);
|
HandleWriteIPPacket(icmp->ConstBuffer(), dst, src, 0);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
service::Address addr{};
|
||||||
|
for (const auto& [range, exitAddr] : exitEntries)
|
||||||
{
|
{
|
||||||
const auto addr = *exits.begin();
|
if (range.BogonRange() and range.Contains(dst))
|
||||||
if (addr.IsZero()) // drop
|
{
|
||||||
return;
|
// we permit this because it matches our rules and we allow bogons
|
||||||
pkt.ZeroSourceAddress();
|
addr = exitAddr;
|
||||||
MarkAddressOutbound(addr);
|
}
|
||||||
EnsurePathToService(
|
else if (not IsBogon(dst))
|
||||||
addr,
|
{
|
||||||
[addr, pkt, self = this](service::Address, service::OutboundContext* ctx) {
|
// allow because the destination is not a bogon and the mapped range is not a bogon
|
||||||
if (ctx)
|
addr = exitAddr;
|
||||||
{
|
}
|
||||||
ctx->sendTimeout = 5s;
|
// we do not permit bogons when they don't explicitly match a permitted bogon range
|
||||||
}
|
|
||||||
self->SendToOrQueue(addr, pkt.ConstBuffer(), service::ProtocolType::Exit);
|
|
||||||
},
|
|
||||||
1s);
|
|
||||||
}
|
}
|
||||||
|
if (addr.IsZero()) // drop becase no exit was found that matches our rules
|
||||||
|
return;
|
||||||
|
pkt.ZeroSourceAddress();
|
||||||
|
MarkAddressOutbound(addr);
|
||||||
|
EnsurePathToService(
|
||||||
|
addr,
|
||||||
|
[addr, pkt, self = this](service::Address, service::OutboundContext* ctx) {
|
||||||
|
if (ctx)
|
||||||
|
{
|
||||||
|
ctx->sendTimeout = 5s;
|
||||||
|
}
|
||||||
|
self->SendToOrQueue(addr, pkt.ConstBuffer(), service::ProtocolType::Exit);
|
||||||
|
},
|
||||||
|
1s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bool rewriteAddrs = true;
|
bool rewriteAddrs = true;
|
||||||
|
@ -979,6 +941,18 @@ namespace llarp
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TunEndpoint::ShouldAllowTraffic(const net::IPPacket& pkt) const
|
||||||
|
{
|
||||||
|
if (const auto exitPolicy = GetExitPolicy())
|
||||||
|
{
|
||||||
|
if (not exitPolicy->AllowsTraffic(pkt))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TunEndpoint::HandleInboundPacket(
|
TunEndpoint::HandleInboundPacket(
|
||||||
const service::ConvoTag tag,
|
const service::ConvoTag tag,
|
||||||
|
@ -1024,6 +998,11 @@ namespace llarp
|
||||||
if (m_state->m_ExitEnabled)
|
if (m_state->m_ExitEnabled)
|
||||||
{
|
{
|
||||||
// exit side from exit
|
// exit side from exit
|
||||||
|
|
||||||
|
// check packet against exit policy and if as needed
|
||||||
|
if (not ShouldAllowTraffic(pkt))
|
||||||
|
return false;
|
||||||
|
|
||||||
src = ObtainIPForAddr(addr);
|
src = ObtainIPForAddr(addr);
|
||||||
if (t == service::ProtocolType::Exit)
|
if (t == service::ProtocolType::Exit)
|
||||||
{
|
{
|
||||||
|
@ -1055,18 +1034,22 @@ namespace llarp
|
||||||
src = pkt.srcv6();
|
src = pkt.srcv6();
|
||||||
}
|
}
|
||||||
// find what exit we think this should be for
|
// find what exit we think this should be for
|
||||||
const auto mapped = m_ExitMap.FindAll(src);
|
const auto mapped = m_ExitMap.FindAllEntries(src);
|
||||||
if (IsBogon(src))
|
bool allow = false;
|
||||||
return false;
|
for (const auto& [range, exitAddr] : mapped)
|
||||||
|
|
||||||
if (const auto ptr = std::get_if<service::Address>(&addr))
|
|
||||||
{
|
{
|
||||||
if (mapped.count(*ptr) == 0)
|
if ((range.BogonRange() and range.Contains(src)) or not IsBogon(src))
|
||||||
{
|
{
|
||||||
// we got exit traffic from someone who we should not have gotten it from
|
// this range is either not a bogon or is a bogon we are explicitly allowing
|
||||||
return false;
|
if (const auto* ptr = std::get_if<service::Address>(&addr))
|
||||||
|
{
|
||||||
|
// allow if this address matches the endpoint we think it should be
|
||||||
|
allow = exitAddr == *ptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (not allow)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -123,6 +123,18 @@ namespace llarp
|
||||||
bool
|
bool
|
||||||
HasLocalIP(const huint128_t& ip) const;
|
HasLocalIP(const huint128_t& ip) const;
|
||||||
|
|
||||||
|
std::optional<net::TrafficPolicy>
|
||||||
|
GetExitPolicy() const override
|
||||||
|
{
|
||||||
|
return m_ExitPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ip packet against any exit policies we have
|
||||||
|
/// returns false if this traffic is disallowed by any of those policies
|
||||||
|
/// returns true otherwise
|
||||||
|
bool
|
||||||
|
ShouldAllowTraffic(const net::IPPacket& pkt) const;
|
||||||
|
|
||||||
/// get a key for ip address
|
/// get a key for ip address
|
||||||
std::optional<std::variant<service::Address, RouterID>>
|
std::optional<std::variant<service::Address, RouterID>>
|
||||||
ObtainAddrForIP(huint128_t ip) const override;
|
ObtainAddrForIP(huint128_t ip) const override;
|
||||||
|
@ -245,6 +257,8 @@ namespace llarp
|
||||||
std::shared_ptr<vpn::NetworkInterface> m_NetIf;
|
std::shared_ptr<vpn::NetworkInterface> m_NetIf;
|
||||||
|
|
||||||
std::unique_ptr<vpn::PacketRouter> m_PacketRouter;
|
std::unique_ptr<vpn::PacketRouter> m_PacketRouter;
|
||||||
|
|
||||||
|
std::optional<net::TrafficPolicy> m_ExitPolicy;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace handlers
|
} // namespace handlers
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
/// Exit info model
|
/// Exit info model
|
||||||
namespace llarp
|
namespace llarp
|
||||||
{
|
{
|
||||||
|
/// deprecated don't use me , this is only for backwards compat
|
||||||
struct ExitInfo
|
struct ExitInfo
|
||||||
{
|
{
|
||||||
IpAddress ipAddress;
|
IpAddress ipAddress;
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include <llarp/util/buffer.hpp>
|
#include <llarp/util/buffer.hpp>
|
||||||
#include <llarp/util/endian.hpp>
|
#include <llarp/util/endian.hpp>
|
||||||
#include <llarp/util/mem.hpp>
|
#include <llarp/util/mem.hpp>
|
||||||
|
#include <llarp/util/str.hpp>
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -32,6 +32,33 @@ namespace llarp
|
||||||
{
|
{
|
||||||
namespace net
|
namespace net
|
||||||
{
|
{
|
||||||
|
std::string
|
||||||
|
IPProtocolName(IPProtocol proto)
|
||||||
|
{
|
||||||
|
if (const auto* ent = ::getprotobynumber(static_cast<uint8_t>(proto)))
|
||||||
|
{
|
||||||
|
return ent->p_name;
|
||||||
|
}
|
||||||
|
throw std::invalid_argument{
|
||||||
|
"cannot determine protocol name for ip proto '" + std::to_string(static_cast<int>(proto))
|
||||||
|
+ "'"};
|
||||||
|
}
|
||||||
|
|
||||||
|
IPProtocol
|
||||||
|
ParseIPProtocol(std::string data)
|
||||||
|
{
|
||||||
|
if (const auto* ent = ::getprotobyname(data.c_str()))
|
||||||
|
{
|
||||||
|
return static_cast<IPProtocol>(ent->p_proto);
|
||||||
|
}
|
||||||
|
if (starts_with(data, "0x"))
|
||||||
|
{
|
||||||
|
if (const int intVal = std::stoi(data.substr(2), nullptr, 16); intVal > 0)
|
||||||
|
return static_cast<IPProtocol>(intVal);
|
||||||
|
}
|
||||||
|
throw std::invalid_argument{"no such ip protocol: '" + data + "'"};
|
||||||
|
}
|
||||||
|
|
||||||
inline static uint32_t*
|
inline static uint32_t*
|
||||||
in6_uint32_ptr(in6_addr& addr)
|
in6_uint32_ptr(in6_addr& addr)
|
||||||
{
|
{
|
||||||
|
@ -88,6 +115,19 @@ namespace llarp
|
||||||
return ManagedBuffer(b);
|
return ManagedBuffer(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<nuint16_t>
|
||||||
|
IPPacket::DstPort() const
|
||||||
|
{
|
||||||
|
switch (IPProtocol{Header()->protocol})
|
||||||
|
{
|
||||||
|
case IPProtocol::TCP:
|
||||||
|
case IPProtocol::UDP:
|
||||||
|
return nuint16_t{*reinterpret_cast<const uint16_t*>(buf + (Header()->ihl * 4) + 2)};
|
||||||
|
default:
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
huint32_t
|
huint32_t
|
||||||
IPPacket::srcv4() const
|
IPPacket::srcv4() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -112,6 +112,31 @@ namespace llarp
|
||||||
{
|
{
|
||||||
namespace net
|
namespace net
|
||||||
{
|
{
|
||||||
|
/// "well known" ip protocols
|
||||||
|
/// TODO: extend this to non "well known values"
|
||||||
|
enum class IPProtocol : uint8_t
|
||||||
|
{
|
||||||
|
ICMP = 0x01,
|
||||||
|
IGMP = 0x02,
|
||||||
|
IPIP = 0x04,
|
||||||
|
TCP = 0x06,
|
||||||
|
UDP = 0x11,
|
||||||
|
GRE = 0x2F,
|
||||||
|
ICMP6 = 0x3A,
|
||||||
|
OSFP = 0x59,
|
||||||
|
PGM = 0x71,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// get string representation of this protocol
|
||||||
|
/// throws std::invalid_argument if we don't know the name of this ip protocol
|
||||||
|
std::string
|
||||||
|
IPProtocolName(IPProtocol proto);
|
||||||
|
|
||||||
|
/// parse a string to an ip protocol
|
||||||
|
/// throws std::invalid_argument if cannot be parsed
|
||||||
|
IPProtocol
|
||||||
|
ParseIPProtocol(std::string data);
|
||||||
|
|
||||||
/// an Packet
|
/// an Packet
|
||||||
struct IPPacket
|
struct IPPacket
|
||||||
{
|
{
|
||||||
|
@ -264,6 +289,10 @@ namespace llarp
|
||||||
huint128_t
|
huint128_t
|
||||||
dst4to6Lan() const;
|
dst4to6Lan() const;
|
||||||
|
|
||||||
|
/// get destination port if applicable
|
||||||
|
std::optional<nuint16_t>
|
||||||
|
DstPort() const;
|
||||||
|
|
||||||
void
|
void
|
||||||
UpdateIPv4Address(nuint32_t src, nuint32_t dst);
|
UpdateIPv4Address(nuint32_t src, nuint32_t dst);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,38 @@
|
||||||
#include "ip_range.hpp"
|
#include "ip_range.hpp"
|
||||||
|
|
||||||
|
#include "oxenmq/bt_serialize.h"
|
||||||
|
|
||||||
|
#include "llarp/util/bencode.h"
|
||||||
|
|
||||||
namespace llarp
|
namespace llarp
|
||||||
{
|
{
|
||||||
|
bool
|
||||||
|
IPRange::BEncode(llarp_buffer_t* buf) const
|
||||||
|
{
|
||||||
|
const auto str = oxenmq::bt_serialize(ToString());
|
||||||
|
return buf->write(str.begin(), str.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IPRange::BDecode(llarp_buffer_t* buf)
|
||||||
|
{
|
||||||
|
const auto* start = buf->cur;
|
||||||
|
if (not bencode_discard(buf))
|
||||||
|
return false;
|
||||||
|
std::string_view data{
|
||||||
|
reinterpret_cast<const char*>(start), static_cast<size_t>(buf->cur - start)};
|
||||||
|
std::string str;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
oxenmq::bt_deserialize(data, str);
|
||||||
|
}
|
||||||
|
catch (std::exception&)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return FromString(str);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
IPRange::FromString(std::string str)
|
IPRange::FromString(std::string str)
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,11 +3,16 @@
|
||||||
#include "ip.hpp"
|
#include "ip.hpp"
|
||||||
#include "net_bits.hpp"
|
#include "net_bits.hpp"
|
||||||
#include <llarp/util/bits.hpp>
|
#include <llarp/util/bits.hpp>
|
||||||
|
#include <llarp/util/buffer.hpp>
|
||||||
#include <llarp/util/types.hpp>
|
#include <llarp/util/types.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace llarp
|
namespace llarp
|
||||||
{
|
{
|
||||||
|
/// forward declare
|
||||||
|
bool
|
||||||
|
IsBogon(huint128_t ip);
|
||||||
|
|
||||||
struct IPRange
|
struct IPRange
|
||||||
{
|
{
|
||||||
using Addr_t = huint128_t;
|
using Addr_t = huint128_t;
|
||||||
|
@ -34,6 +39,19 @@ namespace llarp
|
||||||
return ipv4_map.Contains(addr);
|
return ipv4_map.Contains(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// return true if we intersect with a bogon range
|
||||||
|
constexpr bool
|
||||||
|
BogonRange() const
|
||||||
|
{
|
||||||
|
// special case for 0.0.0.0/0
|
||||||
|
if (IsV4() and netmask_bits == netmask_ipv6_bits(96))
|
||||||
|
return false;
|
||||||
|
// special case for ::/0
|
||||||
|
if (netmask_bits == huint128_t{0})
|
||||||
|
return false;
|
||||||
|
return IsBogon(addr) or IsBogon(HighestAddr());
|
||||||
|
}
|
||||||
|
|
||||||
/// return the number of bits set in the hostmask
|
/// return the number of bits set in the hostmask
|
||||||
constexpr int
|
constexpr int
|
||||||
HostmaskBits() const
|
HostmaskBits() const
|
||||||
|
@ -106,6 +124,12 @@ namespace llarp
|
||||||
|
|
||||||
bool
|
bool
|
||||||
FromString(std::string str);
|
FromString(std::string str);
|
||||||
|
|
||||||
|
bool
|
||||||
|
BEncode(llarp_buffer_t* buf) const;
|
||||||
|
|
||||||
|
bool
|
||||||
|
BDecode(llarp_buffer_t* buf);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace llarp
|
} // namespace llarp
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
#include "ip_range.hpp"
|
#include "ip_range.hpp"
|
||||||
#include <llarp/util/status.hpp>
|
#include <llarp/util/status.hpp>
|
||||||
#include <list>
|
#include <vector>
|
||||||
|
|
||||||
namespace llarp
|
namespace llarp
|
||||||
{
|
{
|
||||||
|
@ -19,7 +19,7 @@ namespace llarp
|
||||||
using IP_t = Range_t::Addr_t;
|
using IP_t = Range_t::Addr_t;
|
||||||
|
|
||||||
using Entry_t = std::pair<Range_t, Value_t>;
|
using Entry_t = std::pair<Range_t, Value_t>;
|
||||||
using Container_t = std::list<Entry_t>;
|
using Container_t = std::vector<Entry_t>;
|
||||||
|
|
||||||
/// get a set of all values
|
/// get a set of all values
|
||||||
std::set<Value_t>
|
std::set<Value_t>
|
||||||
|
@ -89,15 +89,15 @@ namespace llarp
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// return a set of all values who's range contains this IP
|
/// return a set of all entries who's range contains this IP
|
||||||
std::set<Value_t>
|
std::set<Entry_t>
|
||||||
FindAll(const IP_t& addr) const
|
FindAllEntries(const IP_t& addr) const
|
||||||
{
|
{
|
||||||
std::set<Value_t> found;
|
std::set<Entry_t> found;
|
||||||
for (const auto& entry : m_Entries)
|
for (const auto& entry : m_Entries)
|
||||||
{
|
{
|
||||||
if (entry.first.Contains(addr))
|
if (entry.first.Contains(addr))
|
||||||
found.insert(entry.second);
|
found.insert(entry);
|
||||||
}
|
}
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
@ -114,8 +114,7 @@ namespace llarp
|
||||||
void
|
void
|
||||||
Insert(const Range_t& addr, const Value_t& val)
|
Insert(const Range_t& addr, const Value_t& val)
|
||||||
{
|
{
|
||||||
m_Entries.emplace_front(addr, val);
|
m_Entries.emplace_back(addr, val);
|
||||||
m_Entries.sort(CompareEntry{});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Visit_t>
|
template <typename Visit_t>
|
||||||
|
|
|
@ -0,0 +1,213 @@
|
||||||
|
#include "traffic_policy.hpp"
|
||||||
|
#include "llarp/util/str.hpp"
|
||||||
|
|
||||||
|
namespace llarp::net
|
||||||
|
{
|
||||||
|
ProtocolInfo::ProtocolInfo(std::string_view data)
|
||||||
|
{
|
||||||
|
const auto parts = split(data, "/");
|
||||||
|
protocol = ParseIPProtocol(std::string{parts[0]});
|
||||||
|
if (parts.size() == 2)
|
||||||
|
{
|
||||||
|
huint16_t portHost{};
|
||||||
|
std::string portStr{parts[1]};
|
||||||
|
std::string protoName = IPProtocolName(protocol);
|
||||||
|
if (const auto* serv = ::getservbyname(portStr.c_str(), protoName.c_str()))
|
||||||
|
{
|
||||||
|
portHost.h = serv->s_port;
|
||||||
|
}
|
||||||
|
else if (const auto portInt = std::stoi(portStr); portInt > 0)
|
||||||
|
{
|
||||||
|
portHost.h = portInt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw std::invalid_argument{"invalid port in protocol info: " + portStr};
|
||||||
|
port = ToNet(portHost);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
port = std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ProtocolInfo::MatchesPacket(const IPPacket& pkt) const
|
||||||
|
{
|
||||||
|
if (pkt.Header()->protocol != static_cast<std::underlying_type_t<IPProtocol>>(protocol))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (not port)
|
||||||
|
return true;
|
||||||
|
if (const auto maybe = pkt.DstPort())
|
||||||
|
{
|
||||||
|
return *port == *maybe;
|
||||||
|
}
|
||||||
|
// we can't tell what the port is but the protocol matches and that's good enough
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TrafficPolicy::AllowsTraffic(const IPPacket& pkt) const
|
||||||
|
{
|
||||||
|
if (protocols.empty() and ranges.empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (const auto& proto : protocols)
|
||||||
|
{
|
||||||
|
if (proto.MatchesPacket(pkt))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (const auto& range : ranges)
|
||||||
|
{
|
||||||
|
huint128_t dst;
|
||||||
|
if (pkt.IsV6())
|
||||||
|
dst = pkt.dstv6();
|
||||||
|
else if (pkt.IsV4())
|
||||||
|
dst = pkt.dst4to6();
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
if (range.Contains(dst))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ProtocolInfo::BDecode(llarp_buffer_t* buf)
|
||||||
|
{
|
||||||
|
port = std::nullopt;
|
||||||
|
std::vector<uint64_t> vals;
|
||||||
|
if (not bencode_read_list(
|
||||||
|
[&vals](llarp_buffer_t* buf, bool more) {
|
||||||
|
if (more)
|
||||||
|
{
|
||||||
|
uint64_t intval;
|
||||||
|
if (not bencode_read_integer(buf, &intval))
|
||||||
|
return false;
|
||||||
|
vals.push_back(intval);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
buf))
|
||||||
|
return false;
|
||||||
|
if (vals.empty())
|
||||||
|
return false;
|
||||||
|
if (vals.size() >= 1)
|
||||||
|
{
|
||||||
|
if (vals[0] > 255)
|
||||||
|
return false;
|
||||||
|
protocol = static_cast<IPProtocol>(vals[0]);
|
||||||
|
}
|
||||||
|
if (vals.size() >= 2)
|
||||||
|
{
|
||||||
|
if (vals[1] > 65536)
|
||||||
|
return false;
|
||||||
|
port = ToNet(huint16_t{static_cast<uint16_t>(vals[1])});
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ProtocolInfo::BEncode(llarp_buffer_t* buf) const
|
||||||
|
{
|
||||||
|
if (not bencode_start_list(buf))
|
||||||
|
return false;
|
||||||
|
if (not bencode_write_uint64(buf, static_cast<std::underlying_type_t<IPProtocol>>(protocol)))
|
||||||
|
return false;
|
||||||
|
if (port)
|
||||||
|
{
|
||||||
|
const auto hostint = ToHost(*port);
|
||||||
|
if (not bencode_write_uint64(buf, hostint.h))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return bencode_end(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TrafficPolicy::BEncode(llarp_buffer_t* buf) const
|
||||||
|
{
|
||||||
|
if (not bencode_start_dict(buf))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (not bencode_write_bytestring(buf, "p", 1))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (not bencode_start_list(buf))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (const auto& item : protocols)
|
||||||
|
{
|
||||||
|
if (not item.BEncode(buf))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not bencode_end(buf))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (not bencode_write_bytestring(buf, "r", 1))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (not bencode_start_list(buf))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (const auto& item : ranges)
|
||||||
|
{
|
||||||
|
if (not item.BEncode(buf))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not bencode_end(buf))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return bencode_end(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
TrafficPolicy::BDecode(llarp_buffer_t* buf)
|
||||||
|
{
|
||||||
|
return bencode_read_dict(
|
||||||
|
[&](llarp_buffer_t* buffer, llarp_buffer_t* key) -> bool {
|
||||||
|
if (key == nullptr)
|
||||||
|
return true;
|
||||||
|
if (*key == "p")
|
||||||
|
{
|
||||||
|
return BEncodeReadSet(protocols, buffer);
|
||||||
|
}
|
||||||
|
if (*key == "r")
|
||||||
|
{
|
||||||
|
return BEncodeReadSet(ranges, buffer);
|
||||||
|
}
|
||||||
|
return bencode_discard(buffer);
|
||||||
|
},
|
||||||
|
buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
util::StatusObject
|
||||||
|
ProtocolInfo::ExtractStatus() const
|
||||||
|
{
|
||||||
|
util::StatusObject status{
|
||||||
|
{"protocol", static_cast<uint>(protocol)},
|
||||||
|
};
|
||||||
|
if (port)
|
||||||
|
status["port"] = ToHost(*port).h;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
util::StatusObject
|
||||||
|
TrafficPolicy::ExtractStatus() const
|
||||||
|
{
|
||||||
|
std::vector<util::StatusObject> rangesStatus;
|
||||||
|
std::transform(
|
||||||
|
ranges.begin(), ranges.end(), std::back_inserter(rangesStatus), [](const auto& range) {
|
||||||
|
return range.ToString();
|
||||||
|
});
|
||||||
|
|
||||||
|
std::vector<util::StatusObject> protosStatus;
|
||||||
|
std::transform(
|
||||||
|
protocols.begin(),
|
||||||
|
protocols.end(),
|
||||||
|
std::back_inserter(protosStatus),
|
||||||
|
[](const auto& proto) { return proto.ExtractStatus(); });
|
||||||
|
|
||||||
|
return util::StatusObject{{"ranges", rangesStatus}, {"protocols", protosStatus}};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace llarp::net
|
|
@ -0,0 +1,70 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ip_range.hpp"
|
||||||
|
#include "ip_packet.hpp"
|
||||||
|
#include "llarp/util/status.hpp"
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
namespace llarp::net
|
||||||
|
{
|
||||||
|
/// information about an IP protocol
|
||||||
|
struct ProtocolInfo
|
||||||
|
{
|
||||||
|
/// ip protocol byte of this protocol
|
||||||
|
IPProtocol protocol;
|
||||||
|
/// the layer 3 port if applicable
|
||||||
|
std::optional<nuint16_t> port;
|
||||||
|
|
||||||
|
bool
|
||||||
|
BEncode(llarp_buffer_t* buf) const;
|
||||||
|
|
||||||
|
bool
|
||||||
|
BDecode(llarp_buffer_t* buf);
|
||||||
|
|
||||||
|
util::StatusObject
|
||||||
|
ExtractStatus() const;
|
||||||
|
|
||||||
|
/// returns true if an ip packet looks like it matches this protocol info
|
||||||
|
/// returns false otherwise
|
||||||
|
bool
|
||||||
|
MatchesPacket(const IPPacket& pkt) const;
|
||||||
|
|
||||||
|
bool
|
||||||
|
operator<(const ProtocolInfo& other) const
|
||||||
|
{
|
||||||
|
if (port and other.port)
|
||||||
|
{
|
||||||
|
return protocol < other.protocol or *port < *other.port;
|
||||||
|
}
|
||||||
|
return protocol < other.protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtocolInfo() = default;
|
||||||
|
|
||||||
|
explicit ProtocolInfo(std::string_view spec);
|
||||||
|
};
|
||||||
|
|
||||||
|
/// information about what traffic an endpoint will carry
|
||||||
|
struct TrafficPolicy
|
||||||
|
{
|
||||||
|
/// ranges that are explicitly allowed
|
||||||
|
std::set<IPRange> ranges;
|
||||||
|
|
||||||
|
/// protocols that are explicity allowed
|
||||||
|
std::set<ProtocolInfo> protocols;
|
||||||
|
|
||||||
|
bool
|
||||||
|
BEncode(llarp_buffer_t* buf) const;
|
||||||
|
|
||||||
|
bool
|
||||||
|
BDecode(llarp_buffer_t* buf);
|
||||||
|
util::StatusObject
|
||||||
|
ExtractStatus() const;
|
||||||
|
|
||||||
|
/// returns true if we allow the traffic in this ip packet
|
||||||
|
/// returns false otherwise
|
||||||
|
bool
|
||||||
|
AllowsTraffic(const IPPacket& pkt) const;
|
||||||
|
};
|
||||||
|
} // namespace llarp::net
|
|
@ -131,6 +131,13 @@ namespace llarp::quic
|
||||||
void
|
void
|
||||||
receive_packet(const service::ConvoTag& tag, const llarp_buffer_t& buf);
|
receive_packet(const service::ConvoTag& tag, const llarp_buffer_t& buf);
|
||||||
|
|
||||||
|
/// return true if we have any listeners added
|
||||||
|
inline bool
|
||||||
|
hasListeners() const
|
||||||
|
{
|
||||||
|
return not incoming_handlers_.empty();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EndpointBase& service_endpoint_;
|
EndpointBase& service_endpoint_;
|
||||||
|
|
||||||
|
|
|
@ -113,12 +113,41 @@ namespace llarp
|
||||||
BuildOne();
|
BuildOne();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
introSet().I.clear();
|
|
||||||
|
// add supported ethertypes
|
||||||
|
if (HasIfAddr())
|
||||||
|
{
|
||||||
|
const auto ourIP = net::HUIntToIn6(GetIfAddr());
|
||||||
|
if (ipv6_is_mapped_ipv4(ourIP))
|
||||||
|
{
|
||||||
|
introSet().supportedProtocols.push_back(ProtocolType::TrafficV4);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
introSet().supportedProtocols.push_back(ProtocolType::TrafficV6);
|
||||||
|
}
|
||||||
|
|
||||||
|
// exit related stuffo
|
||||||
|
if (m_state->m_ExitEnabled)
|
||||||
|
{
|
||||||
|
introSet().supportedProtocols.push_back(ProtocolType::Exit);
|
||||||
|
introSet().exitTrafficPolicy = GetExitPolicy();
|
||||||
|
introSet().ownedRanges = GetOwnedRanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// add quic ethertype if we have listeners set up
|
||||||
|
if (auto* quic = GetQUICTunnel())
|
||||||
|
{
|
||||||
|
if (quic->hasListeners())
|
||||||
|
introSet().supportedProtocols.push_back(ProtocolType::QUIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
introSet().intros.clear();
|
||||||
for (auto& intro : introset)
|
for (auto& intro : introset)
|
||||||
{
|
{
|
||||||
introSet().I.emplace_back(std::move(intro));
|
introSet().intros.emplace_back(std::move(intro));
|
||||||
}
|
}
|
||||||
if (introSet().I.size() == 0)
|
if (introSet().intros.empty())
|
||||||
{
|
{
|
||||||
LogWarn("not enough intros to publish introset for ", Name());
|
LogWarn("not enough intros to publish introset for ", Name());
|
||||||
if (ShouldBuildMore(now))
|
if (ShouldBuildMore(now))
|
||||||
|
@ -145,7 +174,7 @@ namespace llarp
|
||||||
Endpoint::IsReady() const
|
Endpoint::IsReady() const
|
||||||
{
|
{
|
||||||
const auto now = Now();
|
const auto now = Now();
|
||||||
if (introSet().I.size() == 0)
|
if (introSet().intros.empty())
|
||||||
return false;
|
return false;
|
||||||
if (introSet().IsExpired(now))
|
if (introSet().IsExpired(now))
|
||||||
return false;
|
return false;
|
||||||
|
@ -716,7 +745,7 @@ namespace llarp
|
||||||
void
|
void
|
||||||
Endpoint::PutNewOutboundContext(const service::IntroSet& introset, llarp_time_t left)
|
Endpoint::PutNewOutboundContext(const service::IntroSet& introset, llarp_time_t left)
|
||||||
{
|
{
|
||||||
Address addr{introset.A.Addr()};
|
Address addr{introset.addressKeys.Addr()};
|
||||||
|
|
||||||
auto& remoteSessions = m_state->m_RemoteSessions;
|
auto& remoteSessions = m_state->m_RemoteSessions;
|
||||||
auto& serviceLookups = m_state->m_PendingServiceLookups;
|
auto& serviceLookups = m_state->m_PendingServiceLookups;
|
||||||
|
|
|
@ -113,6 +113,22 @@ namespace llarp
|
||||||
return {0};
|
return {0};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// get the exit policy for our exit if we have one
|
||||||
|
/// override me
|
||||||
|
virtual std::optional<net::TrafficPolicy>
|
||||||
|
GetExitPolicy() const
|
||||||
|
{
|
||||||
|
return std::nullopt;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// get the ip ranges we claim to own
|
||||||
|
/// override me
|
||||||
|
virtual std::vector<IPRange>
|
||||||
|
GetOwnedRanges() const
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
virtual void
|
virtual void
|
||||||
Thaw(){};
|
Thaw(){};
|
||||||
|
|
||||||
|
|
|
@ -155,31 +155,31 @@ namespace llarp
|
||||||
{
|
{
|
||||||
EncryptedIntroSet encrypted;
|
EncryptedIntroSet encrypted;
|
||||||
|
|
||||||
if (other_i.I.size() == 0)
|
if (other_i.intros.empty())
|
||||||
return {};
|
return std::nullopt;
|
||||||
IntroSet i(other_i);
|
IntroSet i{other_i};
|
||||||
encrypted.nounce.Randomize();
|
encrypted.nounce.Randomize();
|
||||||
// set timestamp
|
// set timestamp
|
||||||
// TODO: round to nearest 1000 ms
|
// TODO: round to nearest 1000 ms
|
||||||
i.T = now;
|
i.timestampSignedAt = now;
|
||||||
encrypted.signedAt = now;
|
encrypted.signedAt = now;
|
||||||
// set service info
|
// set service info
|
||||||
i.A = pub;
|
i.addressKeys = pub;
|
||||||
// set public encryption key
|
// set public encryption key
|
||||||
i.K = pq_keypair_to_public(pq);
|
i.sntrupKey = pq_keypair_to_public(pq);
|
||||||
std::array<byte_t, MAX_INTROSET_SIZE> tmp;
|
std::array<byte_t, MAX_INTROSET_SIZE> tmp;
|
||||||
llarp_buffer_t buf(tmp);
|
llarp_buffer_t buf{tmp};
|
||||||
if (not i.BEncode(&buf))
|
if (not i.BEncode(&buf))
|
||||||
return {};
|
return std::nullopt;
|
||||||
// rewind and resize buffer
|
// rewind and resize buffer
|
||||||
buf.sz = buf.cur - buf.base;
|
buf.sz = buf.cur - buf.base;
|
||||||
buf.cur = buf.base;
|
buf.cur = buf.base;
|
||||||
const SharedSecret k(i.A.Addr());
|
const SharedSecret k{i.addressKeys.Addr()};
|
||||||
CryptoManager::instance()->xchacha20(buf, k, encrypted.nounce);
|
CryptoManager::instance()->xchacha20(buf, k, encrypted.nounce);
|
||||||
encrypted.introsetPayload.resize(buf.sz);
|
encrypted.introsetPayload = buf.copy();
|
||||||
std::copy_n(buf.base, buf.sz, encrypted.introsetPayload.data());
|
|
||||||
if (not encrypted.Sign(derivedSignKey))
|
if (not encrypted.Sign(derivedSignKey))
|
||||||
return {};
|
return std::nullopt;
|
||||||
return encrypted;
|
return encrypted;
|
||||||
}
|
}
|
||||||
} // namespace service
|
} // namespace service
|
||||||
|
|
|
@ -90,7 +90,7 @@ namespace llarp::service
|
||||||
llarp_buffer_t buf(payload);
|
llarp_buffer_t buf(payload);
|
||||||
CryptoManager::instance()->xchacha20(buf, k, nounce);
|
CryptoManager::instance()->xchacha20(buf, k, nounce);
|
||||||
if (not i.BDecode(&buf))
|
if (not i.BDecode(&buf))
|
||||||
return std::nullopt;
|
return {};
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,16 +139,39 @@ namespace llarp::service
|
||||||
util::StatusObject
|
util::StatusObject
|
||||||
IntroSet::ExtractStatus() const
|
IntroSet::ExtractStatus() const
|
||||||
{
|
{
|
||||||
util::StatusObject obj{{"published", to_json(T)}};
|
util::StatusObject obj{{"published", to_json(timestampSignedAt)}};
|
||||||
std::vector<util::StatusObject> introsObjs;
|
std::vector<util::StatusObject> introsObjs;
|
||||||
std::transform(
|
std::transform(
|
||||||
I.begin(),
|
intros.begin(),
|
||||||
I.end(),
|
intros.end(),
|
||||||
std::back_inserter(introsObjs),
|
std::back_inserter(introsObjs),
|
||||||
[](const auto& intro) -> util::StatusObject { return intro.ExtractStatus(); });
|
[](const auto& intro) -> util::StatusObject { return intro.ExtractStatus(); });
|
||||||
obj["intros"] = introsObjs;
|
obj["intros"] = introsObjs;
|
||||||
if (!topic.IsZero())
|
if (!topic.IsZero())
|
||||||
obj["topic"] = topic.ToString();
|
obj["topic"] = topic.ToString();
|
||||||
|
|
||||||
|
std::vector<util::StatusObject> protocols;
|
||||||
|
std::transform(
|
||||||
|
supportedProtocols.begin(),
|
||||||
|
supportedProtocols.end(),
|
||||||
|
std::back_inserter(protocols),
|
||||||
|
[](const auto& proto) -> util::StatusObject {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << proto;
|
||||||
|
return ss.str();
|
||||||
|
});
|
||||||
|
obj["protos"] = protocols;
|
||||||
|
std::vector<util::StatusObject> ranges;
|
||||||
|
std::transform(
|
||||||
|
ownedRanges.begin(),
|
||||||
|
ownedRanges.end(),
|
||||||
|
std::back_inserter(ranges),
|
||||||
|
[](const auto& range) -> util::StatusObject { return range.ToString(); });
|
||||||
|
|
||||||
|
obj["advertisedRanges"] = ranges;
|
||||||
|
if (exitTrafficPolicy)
|
||||||
|
obj["exitPolicy"] = exitTrafficPolicy->ExtractStatus();
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,19 +179,49 @@ namespace llarp::service
|
||||||
IntroSet::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf)
|
IntroSet::DecodeKey(const llarp_buffer_t& key, llarp_buffer_t* buf)
|
||||||
{
|
{
|
||||||
bool read = false;
|
bool read = false;
|
||||||
if (!BEncodeMaybeReadDictEntry("a", A, read, key, buf))
|
if (!BEncodeMaybeReadDictEntry("a", addressKeys, read, key, buf))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (key == "e")
|
||||||
|
{
|
||||||
|
net::TrafficPolicy policy;
|
||||||
|
if (not policy.BDecode(buf))
|
||||||
|
return false;
|
||||||
|
exitTrafficPolicy = policy;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (key == "i")
|
if (key == "i")
|
||||||
{
|
{
|
||||||
return BEncodeReadList(I, buf);
|
return BEncodeReadList(intros, buf);
|
||||||
}
|
}
|
||||||
if (!BEncodeMaybeReadDictEntry("k", K, read, key, buf))
|
if (!BEncodeMaybeReadDictEntry("k", sntrupKey, read, key, buf))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!BEncodeMaybeReadDictEntry("n", topic, read, key, buf))
|
if (!BEncodeMaybeReadDictEntry("n", topic, read, key, buf))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (key == "p")
|
||||||
|
{
|
||||||
|
return bencode_read_list(
|
||||||
|
[&](llarp_buffer_t* buf, bool more) {
|
||||||
|
if (more)
|
||||||
|
{
|
||||||
|
uint64_t protoval;
|
||||||
|
if (not bencode_read_integer(buf, &protoval))
|
||||||
|
return false;
|
||||||
|
supportedProtocols.emplace_back(static_cast<ProtocolType>(protoval));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == "r")
|
||||||
|
{
|
||||||
|
return BEncodeReadList(ownedRanges, buf);
|
||||||
|
}
|
||||||
|
|
||||||
if (key == "s")
|
if (key == "s")
|
||||||
{
|
{
|
||||||
byte_t* begin = buf->cur;
|
byte_t* begin = buf->cur;
|
||||||
|
@ -177,8 +230,8 @@ namespace llarp::service
|
||||||
|
|
||||||
byte_t* end = buf->cur;
|
byte_t* end = buf->cur;
|
||||||
|
|
||||||
std::string_view srvString{
|
std::string_view srvString(
|
||||||
reinterpret_cast<char*>(begin), static_cast<std::size_t>(end - begin)};
|
reinterpret_cast<const char*>(begin), static_cast<size_t>(end - begin));
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -192,53 +245,71 @@ namespace llarp::service
|
||||||
read = true;
|
read = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!BEncodeMaybeReadDictInt("t", T, read, key, buf))
|
if (!BEncodeMaybeReadDictInt("t", timestampSignedAt, read, key, buf))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (key == "w")
|
|
||||||
{
|
|
||||||
W.emplace();
|
|
||||||
return bencode_decode_dict(*W, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!BEncodeMaybeReadDictInt("v", version, read, key, buf))
|
if (!BEncodeMaybeReadDictInt("v", version, read, key, buf))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!BEncodeMaybeReadDictEntry("z", Z, read, key, buf))
|
if (!BEncodeMaybeReadDictEntry("z", signature, read, key, buf))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (read)
|
return read or bencode_discard(buf);
|
||||||
return true;
|
|
||||||
|
|
||||||
return bencode_discard(buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
IntroSet::BEncode(llarp_buffer_t* buf) const
|
IntroSet::BEncode(llarp_buffer_t* buf) const
|
||||||
{
|
{
|
||||||
if (!bencode_start_dict(buf))
|
if (not bencode_start_dict(buf))
|
||||||
return false;
|
return false;
|
||||||
if (!BEncodeWriteDictEntry("a", A, buf))
|
if (not BEncodeWriteDictEntry("a", addressKeys, buf))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// exit policy if applicable
|
||||||
|
if (exitTrafficPolicy)
|
||||||
|
{
|
||||||
|
if (not BEncodeWriteDictEntry("e", *exitTrafficPolicy, buf))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// start introduction list
|
// start introduction list
|
||||||
if (!bencode_write_bytestring(buf, "i", 1))
|
if (not bencode_write_bytestring(buf, "i", 1))
|
||||||
return false;
|
return false;
|
||||||
if (!BEncodeWriteList(I.begin(), I.end(), buf))
|
if (not BEncodeWriteList(intros.begin(), intros.end(), buf))
|
||||||
return false;
|
return false;
|
||||||
// end introduction list
|
// end introduction list
|
||||||
|
|
||||||
// pq pubkey
|
// pq pubkey
|
||||||
if (!BEncodeWriteDictEntry("k", K, buf))
|
if (not BEncodeWriteDictEntry("k", sntrupKey, buf))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// topic tag
|
// topic tag
|
||||||
if (topic.ToString().size())
|
if (not topic.ToString().empty())
|
||||||
{
|
{
|
||||||
if (!BEncodeWriteDictEntry("n", topic, buf))
|
if (not BEncodeWriteDictEntry("n", topic, buf))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SRVs.size())
|
// supported ethertypes
|
||||||
|
if (not supportedProtocols.empty())
|
||||||
|
{
|
||||||
|
if (not bencode_write_bytestring(buf, "p", 1))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (not bencode_start_list(buf))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (const auto& proto : supportedProtocols)
|
||||||
|
{
|
||||||
|
if (not bencode_write_uint64(buf, static_cast<uint64_t>(proto)))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not bencode_end(buf))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// srv records
|
||||||
|
if (not SRVs.empty())
|
||||||
{
|
{
|
||||||
std::string serial = oxenmq::bt_serialize(SRVs);
|
std::string serial = oxenmq::bt_serialize(SRVs);
|
||||||
if (!bencode_write_bytestring(buf, "s", 1))
|
if (!bencode_write_bytestring(buf, "s", 1))
|
||||||
|
@ -247,19 +318,22 @@ namespace llarp::service
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timestamp published
|
// owned ranges
|
||||||
if (!BEncodeWriteDictInt("t", T.count(), buf))
|
if (not ownedRanges.empty())
|
||||||
|
{
|
||||||
|
if (not BEncodeWriteDictArray("r", ownedRanges, buf))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// timestamp
|
||||||
|
if (!BEncodeWriteDictInt("t", timestampSignedAt.count(), buf))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// write version
|
// write version
|
||||||
if (!BEncodeWriteDictInt("v", version, buf))
|
if (!BEncodeWriteDictInt("v", version, buf))
|
||||||
return false;
|
return false;
|
||||||
if (W)
|
|
||||||
{
|
if (!BEncodeWriteDictEntry("z", signature, buf))
|
||||||
if (!BEncodeWriteDictEntry("w", *W, buf))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!BEncodeWriteDictEntry("z", Z, buf))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return bencode_end(buf);
|
return bencode_end(buf);
|
||||||
|
@ -268,8 +342,8 @@ namespace llarp::service
|
||||||
bool
|
bool
|
||||||
IntroSet::HasExpiredIntros(llarp_time_t now) const
|
IntroSet::HasExpiredIntros(llarp_time_t now) const
|
||||||
{
|
{
|
||||||
for (const auto& i : I)
|
for (const auto& intro : intros)
|
||||||
if (now >= i.expiresAt)
|
if (now >= intro.expiresAt)
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -300,10 +374,10 @@ namespace llarp::service
|
||||||
IntroSet::Verify(llarp_time_t now) const
|
IntroSet::Verify(llarp_time_t now) const
|
||||||
{
|
{
|
||||||
std::array<byte_t, MAX_INTROSET_SIZE> tmp;
|
std::array<byte_t, MAX_INTROSET_SIZE> tmp;
|
||||||
llarp_buffer_t buf(tmp);
|
llarp_buffer_t buf{tmp};
|
||||||
IntroSet copy;
|
IntroSet copy;
|
||||||
copy = *this;
|
copy = *this;
|
||||||
copy.Z.Zero();
|
copy.signature.Zero();
|
||||||
if (!copy.BEncode(&buf))
|
if (!copy.BEncode(&buf))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -311,57 +385,39 @@ namespace llarp::service
|
||||||
// rewind and resize buffer
|
// rewind and resize buffer
|
||||||
buf.sz = buf.cur - buf.base;
|
buf.sz = buf.cur - buf.base;
|
||||||
buf.cur = buf.base;
|
buf.cur = buf.base;
|
||||||
if (!A.Verify(buf, Z))
|
if (!addressKeys.Verify(buf, signature))
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// validate PoW
|
|
||||||
if (W && !W->IsValid(now))
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// valid timestamps
|
// valid timestamps
|
||||||
// add max clock skew
|
// add max clock skew
|
||||||
now += MAX_INTROSET_TIME_DELTA;
|
now += MAX_INTROSET_TIME_DELTA;
|
||||||
for (const auto& intro : I)
|
for (const auto& intro : intros)
|
||||||
{
|
{
|
||||||
if (intro.expiresAt > now && intro.expiresAt - now > path::default_lifetime)
|
if (intro.expiresAt > now && intro.expiresAt - now > path::default_lifetime)
|
||||||
{
|
{
|
||||||
if (!W)
|
return false;
|
||||||
{
|
|
||||||
LogWarn("intro has too high expire time");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (intro.expiresAt - W->extendedLifetime > path::default_lifetime)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (IsExpired(now))
|
return not IsExpired(now);
|
||||||
{
|
|
||||||
LogWarn("introset expired: ", *this);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
llarp_time_t
|
llarp_time_t
|
||||||
IntroSet::GetNewestIntroExpiration() const
|
IntroSet::GetNewestIntroExpiration() const
|
||||||
{
|
{
|
||||||
llarp_time_t t = 0s;
|
llarp_time_t maxTime = 0s;
|
||||||
for (const auto& intro : I)
|
for (const auto& intro : intros)
|
||||||
t = std::max(intro.expiresAt, t);
|
maxTime = std::max(intro.expiresAt, maxTime);
|
||||||
return t;
|
return maxTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream&
|
std::ostream&
|
||||||
IntroSet::print(std::ostream& stream, int level, int spaces) const
|
IntroSet::print(std::ostream& stream, int level, int spaces) const
|
||||||
{
|
{
|
||||||
Printer printer(stream, level, spaces);
|
Printer printer(stream, level, spaces);
|
||||||
printer.printAttribute("A", A);
|
printer.printAttribute("addressKeys", addressKeys);
|
||||||
printer.printAttribute("I", I);
|
printer.printAttribute("intros", intros);
|
||||||
printer.printAttribute("K", K);
|
printer.printAttribute("sntrupKey", sntrupKey);
|
||||||
|
|
||||||
std::string _topic = topic.ToString();
|
std::string _topic = topic.ToString();
|
||||||
|
|
||||||
|
@ -374,17 +430,10 @@ namespace llarp::service
|
||||||
printer.printAttribute("topic", topic);
|
printer.printAttribute("topic", topic);
|
||||||
}
|
}
|
||||||
|
|
||||||
printer.printAttribute("T", T.count());
|
printer.printAttribute("signedAt", timestampSignedAt.count());
|
||||||
if (W)
|
|
||||||
{
|
printer.printAttribute("version", version);
|
||||||
printer.printAttribute("W", *W);
|
printer.printAttribute("sig", signature);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printer.printAttribute("W", "NULL");
|
|
||||||
}
|
|
||||||
printer.printAttribute("V", version);
|
|
||||||
printer.printAttribute("Z", Z);
|
|
||||||
|
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,15 @@
|
||||||
#include "info.hpp"
|
#include "info.hpp"
|
||||||
#include "intro.hpp"
|
#include "intro.hpp"
|
||||||
#include "tag.hpp"
|
#include "tag.hpp"
|
||||||
|
#include "protocol_type.hpp"
|
||||||
#include <llarp/util/bencode.hpp>
|
#include <llarp/util/bencode.hpp>
|
||||||
#include <llarp/util/time.hpp>
|
#include <llarp/util/time.hpp>
|
||||||
#include <llarp/util/status.hpp>
|
#include <llarp/util/status.hpp>
|
||||||
#include <llarp/dns/srv_data.hpp>
|
#include <llarp/dns/srv_data.hpp>
|
||||||
|
|
||||||
|
#include <llarp/net/ip_range.hpp>
|
||||||
|
#include <llarp/net/traffic_policy.hpp>
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
@ -26,20 +30,31 @@ namespace llarp
|
||||||
|
|
||||||
struct IntroSet
|
struct IntroSet
|
||||||
{
|
{
|
||||||
ServiceInfo A;
|
ServiceInfo addressKeys;
|
||||||
std::vector<Introduction> I;
|
std::vector<Introduction> intros;
|
||||||
PQPubKey K;
|
PQPubKey sntrupKey;
|
||||||
Tag topic;
|
Tag topic;
|
||||||
std::vector<llarp::dns::SRVTuple> SRVs;
|
std::vector<llarp::dns::SRVTuple> SRVs;
|
||||||
llarp_time_t T = 0s;
|
llarp_time_t timestampSignedAt = 0s;
|
||||||
std::optional<PoW> W;
|
|
||||||
Signature Z;
|
/// ethertypes we advertise that we speak
|
||||||
|
std::vector<ProtocolType> supportedProtocols;
|
||||||
|
/// aonnuce that these ranges are reachable via our endpoint
|
||||||
|
/// only set when we support exit traffic ethertype is supported
|
||||||
|
std::vector<IPRange> ownedRanges;
|
||||||
|
|
||||||
|
/// policies about traffic that we are willing to carry
|
||||||
|
/// a protocol/range whitelist or blacklist
|
||||||
|
/// only set when we support exit traffic ethertype
|
||||||
|
std::optional<net::TrafficPolicy> exitTrafficPolicy;
|
||||||
|
|
||||||
|
Signature signature;
|
||||||
uint64_t version = LLARP_PROTO_VERSION;
|
uint64_t version = LLARP_PROTO_VERSION;
|
||||||
|
|
||||||
bool
|
bool
|
||||||
OtherIsNewer(const IntroSet& other) const
|
OtherIsNewer(const IntroSet& other) const
|
||||||
{
|
{
|
||||||
return T < other.T;
|
return timestampSignedAt < other.timestampSignedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream&
|
std::ostream&
|
||||||
|
@ -82,14 +97,28 @@ namespace llarp
|
||||||
inline bool
|
inline bool
|
||||||
operator<(const IntroSet& lhs, const IntroSet& rhs)
|
operator<(const IntroSet& lhs, const IntroSet& rhs)
|
||||||
{
|
{
|
||||||
return lhs.A < rhs.A;
|
return lhs.addressKeys < rhs.addressKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
operator==(const IntroSet& lhs, const IntroSet& rhs)
|
operator==(const IntroSet& lhs, const IntroSet& rhs)
|
||||||
{
|
{
|
||||||
return std::tie(lhs.A, lhs.I, lhs.K, lhs.T, lhs.version, lhs.topic, lhs.W, lhs.Z)
|
return std::tie(
|
||||||
== std::tie(rhs.A, rhs.I, rhs.K, rhs.T, rhs.version, rhs.topic, rhs.W, rhs.Z);
|
lhs.addressKeys,
|
||||||
|
lhs.intros,
|
||||||
|
lhs.sntrupKey,
|
||||||
|
lhs.timestampSignedAt,
|
||||||
|
lhs.version,
|
||||||
|
lhs.topic,
|
||||||
|
lhs.signature)
|
||||||
|
== std::tie(
|
||||||
|
rhs.addressKeys,
|
||||||
|
rhs.intros,
|
||||||
|
rhs.sntrupKey,
|
||||||
|
rhs.timestampSignedAt,
|
||||||
|
rhs.version,
|
||||||
|
rhs.topic,
|
||||||
|
rhs.signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
|
|
|
@ -56,13 +56,13 @@ namespace llarp
|
||||||
|
|
||||||
OutboundContext::OutboundContext(const IntroSet& introset, Endpoint* parent)
|
OutboundContext::OutboundContext(const IntroSet& introset, Endpoint* parent)
|
||||||
: path::Builder(parent->Router(), 4, parent->numHops)
|
: path::Builder(parent->Router(), 4, parent->numHops)
|
||||||
, SendContext(introset.A, {}, this, parent)
|
, SendContext(introset.addressKeys, {}, this, parent)
|
||||||
, location(introset.A.Addr().ToKey())
|
, location(introset.addressKeys.Addr().ToKey())
|
||||||
, currentIntroSet(introset)
|
, currentIntroSet(introset)
|
||||||
|
|
||||||
{
|
{
|
||||||
updatingIntroSet = false;
|
updatingIntroSet = false;
|
||||||
for (const auto& intro : introset.I)
|
for (const auto& intro : introset.intros)
|
||||||
{
|
{
|
||||||
if (intro.expiresAt > m_NextIntro.expiresAt)
|
if (intro.expiresAt > m_NextIntro.expiresAt)
|
||||||
m_NextIntro = intro;
|
m_NextIntro = intro;
|
||||||
|
@ -80,7 +80,7 @@ namespace llarp
|
||||||
if (remoteIntro != m_NextIntro)
|
if (remoteIntro != m_NextIntro)
|
||||||
{
|
{
|
||||||
remoteIntro = m_NextIntro;
|
remoteIntro = m_NextIntro;
|
||||||
m_DataHandler->PutSenderFor(currentConvoTag, currentIntroSet.A, false);
|
m_DataHandler->PutSenderFor(currentConvoTag, currentIntroSet.addressKeys, false);
|
||||||
m_DataHandler->PutIntroFor(currentConvoTag, remoteIntro);
|
m_DataHandler->PutIntroFor(currentConvoTag, remoteIntro);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,12 +94,12 @@ namespace llarp
|
||||||
updatingIntroSet = false;
|
updatingIntroSet = false;
|
||||||
if (foundIntro)
|
if (foundIntro)
|
||||||
{
|
{
|
||||||
if (foundIntro->T == 0s)
|
if (foundIntro->timestampSignedAt == 0s)
|
||||||
{
|
{
|
||||||
LogWarn(Name(), " got introset with zero timestamp: ", *foundIntro);
|
LogWarn(Name(), " got introset with zero timestamp: ", *foundIntro);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (currentIntroSet.T > foundIntro->T)
|
if (currentIntroSet.timestampSignedAt > foundIntro->timestampSignedAt)
|
||||||
{
|
{
|
||||||
LogInfo("introset is old, dropping");
|
LogInfo("introset is old, dropping");
|
||||||
return true;
|
return true;
|
||||||
|
@ -136,7 +136,7 @@ namespace llarp
|
||||||
{
|
{
|
||||||
const auto now = Now();
|
const auto now = Now();
|
||||||
Introduction selectedIntro;
|
Introduction selectedIntro;
|
||||||
for (const auto& intro : currentIntroSet.I)
|
for (const auto& intro : currentIntroSet.intros)
|
||||||
{
|
{
|
||||||
if (intro.expiresAt > selectedIntro.expiresAt && intro.router != r)
|
if (intro.expiresAt > selectedIntro.expiresAt && intro.router != r)
|
||||||
{
|
{
|
||||||
|
@ -215,7 +215,7 @@ namespace llarp
|
||||||
m_Endpoint->Loop(),
|
m_Endpoint->Loop(),
|
||||||
remoteIdent,
|
remoteIdent,
|
||||||
m_Endpoint->GetIdentity(),
|
m_Endpoint->GetIdentity(),
|
||||||
currentIntroSet.K,
|
currentIntroSet.sntrupKey,
|
||||||
remoteIntro,
|
remoteIntro,
|
||||||
m_DataHandler,
|
m_DataHandler,
|
||||||
currentConvoTag,
|
currentConvoTag,
|
||||||
|
@ -236,7 +236,8 @@ namespace llarp
|
||||||
std::string
|
std::string
|
||||||
OutboundContext::Name() const
|
OutboundContext::Name() const
|
||||||
{
|
{
|
||||||
return "OBContext:" + m_Endpoint->Name() + "-" + currentIntroSet.A.Addr().ToString();
|
return "OBContext:" + m_Endpoint->Name() + "-"
|
||||||
|
+ currentIntroSet.addressKeys.Addr().ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -244,7 +245,7 @@ namespace llarp
|
||||||
{
|
{
|
||||||
if (updatingIntroSet || markedBad)
|
if (updatingIntroSet || markedBad)
|
||||||
return;
|
return;
|
||||||
const auto addr = currentIntroSet.A.Addr();
|
const auto addr = currentIntroSet.addressKeys.Addr();
|
||||||
// we want to use the parent endpoint's paths because outbound context
|
// we want to use the parent endpoint's paths because outbound context
|
||||||
// does not implement path::PathSet::HandleGotIntroMessage
|
// does not implement path::PathSet::HandleGotIntroMessage
|
||||||
const auto paths = GetManyPathsWithUniqueEndpoints(m_Endpoint, 2);
|
const auto paths = GetManyPathsWithUniqueEndpoints(m_Endpoint, 2);
|
||||||
|
@ -453,7 +454,7 @@ namespace llarp
|
||||||
if (now - lastShift < MIN_SHIFT_INTERVAL)
|
if (now - lastShift < MIN_SHIFT_INTERVAL)
|
||||||
return false;
|
return false;
|
||||||
bool shifted = false;
|
bool shifted = false;
|
||||||
std::vector<Introduction> intros = currentIntroSet.I;
|
std::vector<Introduction> intros = currentIntroSet.intros;
|
||||||
if (intros.size() > 1)
|
if (intros.size() > 1)
|
||||||
{
|
{
|
||||||
std::shuffle(intros.begin(), intros.end(), CSRNG{});
|
std::shuffle(intros.begin(), intros.end(), CSRNG{});
|
||||||
|
@ -543,7 +544,7 @@ namespace llarp
|
||||||
// hop off it
|
// hop off it
|
||||||
Introduction picked;
|
Introduction picked;
|
||||||
// get the latest intro that isn't on that endpoint
|
// get the latest intro that isn't on that endpoint
|
||||||
for (const auto& intro : currentIntroSet.I)
|
for (const auto& intro : currentIntroSet.intros)
|
||||||
{
|
{
|
||||||
if (intro.router == endpoint)
|
if (intro.router == endpoint)
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -12,19 +12,6 @@ namespace llarp
|
||||||
{
|
{
|
||||||
namespace service
|
namespace service
|
||||||
{
|
{
|
||||||
std::ostream&
|
|
||||||
operator<<(std::ostream& o, ProtocolType t)
|
|
||||||
{
|
|
||||||
return o
|
|
||||||
<< (t == ProtocolType::Control ? "Control"
|
|
||||||
: t == ProtocolType::TrafficV4 ? "TrafficV4"
|
|
||||||
: t == ProtocolType::TrafficV6 ? "TrafficV6"
|
|
||||||
: t == ProtocolType::Exit ? "Exit"
|
|
||||||
: t == ProtocolType::Auth ? "Auth"
|
|
||||||
: t == ProtocolType::QUIC ? "QUIC"
|
|
||||||
: "(unknown-protocol-type)");
|
|
||||||
}
|
|
||||||
|
|
||||||
ProtocolMessage::ProtocolMessage()
|
ProtocolMessage::ProtocolMessage()
|
||||||
{
|
{
|
||||||
tag.Zero();
|
tag.Zero();
|
||||||
|
|
|
@ -31,9 +31,6 @@ namespace llarp
|
||||||
|
|
||||||
constexpr std::size_t MAX_PROTOCOL_MESSAGE_SIZE = 2048 * 2;
|
constexpr std::size_t MAX_PROTOCOL_MESSAGE_SIZE = 2048 * 2;
|
||||||
|
|
||||||
std::ostream&
|
|
||||||
operator<<(std::ostream& o, ProtocolType t);
|
|
||||||
|
|
||||||
/// inner message
|
/// inner message
|
||||||
struct ProtocolMessage
|
struct ProtocolMessage
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
#include "protocol_type.hpp"
|
||||||
|
|
||||||
|
namespace llarp::service
|
||||||
|
{
|
||||||
|
std::ostream&
|
||||||
|
operator<<(std::ostream& o, ProtocolType t)
|
||||||
|
{
|
||||||
|
return o
|
||||||
|
<< (t == ProtocolType::Control ? "Control"
|
||||||
|
: t == ProtocolType::TrafficV4 ? "TrafficV4"
|
||||||
|
: t == ProtocolType::TrafficV6 ? "TrafficV6"
|
||||||
|
: t == ProtocolType::Exit ? "Exit"
|
||||||
|
: t == ProtocolType::Auth ? "Auth"
|
||||||
|
: t == ProtocolType::QUIC ? "QUIC"
|
||||||
|
: "(unknown-protocol-type)");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace llarp::service
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
namespace llarp::service
|
namespace llarp::service
|
||||||
{
|
{
|
||||||
// Supported protocol types; the values are given explicitly because they are specifically used
|
// Supported protocol types; the values are given explicitly because they are specifically used
|
||||||
|
@ -14,5 +16,10 @@ namespace llarp::service
|
||||||
Exit = 3UL,
|
Exit = 3UL,
|
||||||
Auth = 4UL,
|
Auth = 4UL,
|
||||||
QUIC = 5UL,
|
QUIC = 5UL,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::ostream&
|
||||||
|
operator<<(std::ostream& o, ProtocolType t);
|
||||||
|
|
||||||
} // namespace llarp::service
|
} // namespace llarp::service
|
||||||
|
|
|
@ -260,7 +260,6 @@ namespace llarp
|
||||||
},
|
},
|
||||||
buf);
|
buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename List_t>
|
template <typename List_t>
|
||||||
bool
|
bool
|
||||||
BEncodeReadList(List_t& result, llarp_buffer_t* buf)
|
BEncodeReadList(List_t& result, llarp_buffer_t* buf)
|
||||||
|
@ -279,6 +278,46 @@ namespace llarp
|
||||||
buf);
|
buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// read a std::set of decodable entities and deny duplicates
|
||||||
|
template <typename Set_t>
|
||||||
|
bool
|
||||||
|
BEncodeReadSet(Set_t& set, llarp_buffer_t* buffer)
|
||||||
|
{
|
||||||
|
return bencode_read_list(
|
||||||
|
[&set](llarp_buffer_t* buf, bool more) {
|
||||||
|
if (more)
|
||||||
|
{
|
||||||
|
typename Set_t::value_type item;
|
||||||
|
if (not item.BDecode(buf))
|
||||||
|
return false;
|
||||||
|
// deny duplicates
|
||||||
|
return set.emplace(std::move(item)).second;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// read a std::set of decodable entities and deny duplicates
|
||||||
|
template <typename Set_t>
|
||||||
|
bool
|
||||||
|
BEncodeWriteSet(Set_t& set, llarp_buffer_t* buffer)
|
||||||
|
{
|
||||||
|
return bencode_read_list(
|
||||||
|
[&set](llarp_buffer_t* buf, bool more) {
|
||||||
|
if (more)
|
||||||
|
{
|
||||||
|
typename Set_t::value_type item;
|
||||||
|
if (not item.BDecode(buf))
|
||||||
|
return false;
|
||||||
|
// deny duplicates
|
||||||
|
return set.emplace(std::move(item)).second;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
buffer);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename List_t>
|
template <typename List_t>
|
||||||
bool
|
bool
|
||||||
BEncodeWriteDictList(const char* k, List_t& list, llarp_buffer_t* buf)
|
BEncodeWriteDictList(const char* k, List_t& list, llarp_buffer_t* buf)
|
||||||
|
|
|
@ -210,19 +210,19 @@ TEST_CASE("Test sign and encrypt introset", "[crypto]")
|
||||||
ident.RegenerateKeys();
|
ident.RegenerateKeys();
|
||||||
service::Address addr;
|
service::Address addr;
|
||||||
CHECK(ident.pub.CalculateAddress(addr.as_array()));
|
CHECK(ident.pub.CalculateAddress(addr.as_array()));
|
||||||
service::IntroSet I;
|
service::IntroSet introset;
|
||||||
auto now = time_now_ms();
|
auto now = time_now_ms();
|
||||||
I.T = now;
|
introset.timestampSignedAt = now;
|
||||||
while(I.I.size() < 10)
|
while(introset.intros.size() < 10)
|
||||||
{
|
{
|
||||||
service::Introduction intro;
|
service::Introduction intro;
|
||||||
intro.expiresAt = now + (path::default_lifetime / 2);
|
intro.expiresAt = now + (path::default_lifetime / 2);
|
||||||
intro.router.Randomize();
|
intro.router.Randomize();
|
||||||
intro.pathID.Randomize();
|
intro.pathID.Randomize();
|
||||||
I.I.emplace_back(std::move(intro));
|
introset.intros.emplace_back(std::move(intro));
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto maybe = ident.EncryptAndSignIntroSet(I, now);
|
const auto maybe = ident.EncryptAndSignIntroSet(introset, now);
|
||||||
CHECK(maybe.has_value());
|
CHECK(maybe.has_value());
|
||||||
CHECK(maybe->Verify(now));
|
CHECK(maybe->Verify(now));
|
||||||
PubKey blind_key;
|
PubKey blind_key;
|
||||||
|
|
Loading…
Reference in New Issue