Prefiguring, deprecation

- TunEndpoint and LocalEndpoint prefiguring
- Fully removed service::Address and all uses of AddressVariant_t in favor of the improved NetworkAddress type
- Fully removed exit/* and most of service/*
This commit is contained in:
dr7ana 2024-04-09 14:32:20 -07:00
parent 791155d1c9
commit 078d0dfc23
55 changed files with 158 additions and 3550 deletions

View File

@ -1,5 +1,5 @@
#pragma once
#include "lokinet_context.h"
#include "context.h"
#ifdef __cplusplus
extern "C"

View File

@ -1,6 +1,6 @@
#pragma once
#include "lokinet_export.h"
#include "export.h"
#include <stdbool.h>
#include <stdint.h>

View File

@ -1,21 +0,0 @@
#pragma once
#include "lokinet_context.h"
#include "lokinet_os.h"
#ifdef __cplusplus
extern "C"
{
#endif
/// poll many sockets for activity
/// each pollfd.fd should be set to the socket id
/// returns 0 on sucess
int EXPORT lokinet_poll(struct pollfd* poll, nfds_t numsockets, struct lokinet_context* ctx);
/// close a udp socket or a stream socket by its id
void EXPORT lokinet_close_socket(int id, struct lokinet_context* ctx);
#ifdef __cplusplus
}
#endif

View File

@ -1,5 +1,5 @@
#pragma once
#include "lokinet_export.h"
#include "export.h"
#ifdef __cplusplus
extern "C"
{

View File

@ -1,6 +1,6 @@
#pragma once
#include "lokinet_context.h"
#include "context.h"
#ifdef __cplusplus
extern "C"

View File

@ -1,6 +1,6 @@
#pragma once
#include "lokinet_context.h"
#include "context.h"
#ifdef __cplusplus
extern "C"

View File

@ -1,6 +1,6 @@
#pragma once
#include "lokinet_context.h"
#include "context.h"
#ifdef __cplusplus
extern "C"

View File

@ -30,17 +30,10 @@ lokinet_add_library(lokinet-core-utils
handlers/remote.cpp
handlers/tun.cpp
# deprecated for handlers/{endpoint,remote}.cpp
# exit/handler.cpp
# exit/endpoint.cpp
# service/handler.cpp # link/ exit/
# service/endpoint.cpp
service/identity.cpp
service/info.cpp
service/intro.cpp # path
service/intro_set.cpp
service/lns_tracker.cpp
service/name.cpp
vpn/egres_packet_router.cpp
@ -50,19 +43,13 @@ lokinet_add_library(lokinet-core
context.cpp
consensus/reachability_testing.cpp
# handlers/tun.cpp
link/link_manager.cpp
router/router.cpp
router/route_poker.cpp
# service/async_key_exchange.cpp
service/types.cpp
service/endpoint_state.cpp
service/protocol.cpp
service/session.cpp
session/outbound_session.cpp
session/inbound_session.cpp
@ -119,7 +106,6 @@ lokinet_add_library(lokinet-time-place
router_id.cpp
router_version.cpp # to be deleted shortly
service/address.cpp
service/tag.cpp
)

View File

@ -59,6 +59,11 @@ namespace llarp
bool operator==(const NetworkAddress& other) const;
bool operator!=(const NetworkAddress& other) const;
bool is_empty() const
{
return _pubkey.is_zero() and _tld.empty();
}
// Will throw invalid_argument with bad input. Assumes that the network address terminates in either '.loki'
// or '.snode'
static std::optional<NetworkAddress> from_network_addr(std::string arg);
@ -78,7 +83,7 @@ namespace llarp
return _pubkey;
}
PubKey pubkey()
PubKey& pubkey()
{
return _pubkey;
}

View File

@ -78,6 +78,11 @@ namespace llarp
return ret;
}
bool has_remote(const net_addr_t& remote) const
{
return _remote_to_local.contains(remote);
}
void unmap(const net_addr_t& remote)
{
auto name = remote.name();

View File

@ -4,8 +4,7 @@
#include <llarp/address/address.hpp>
#include <llarp/crypto/types.hpp>
#include <llarp/service/address.hpp>
#include <llarp/service/protocol.hpp>
#include <llarp/router_id.hpp>
#include <llarp/service/tag.hpp>
#include <llarp/util/str.hpp>
#include <llarp/util/thread/threading.hpp>
@ -20,11 +19,6 @@
namespace llarp
{
struct Router;
namespace service
{
struct Endpoint;
}
} // namespace llarp
namespace llarp::auth
@ -52,14 +46,6 @@ namespace llarp::auth
{
return _router;
}
/// asynchronously determine if we accept new convotag from remote service, call hook with
/// result later
virtual void authenticate_async(
std::shared_ptr<service::ProtocolMessage> msg, std::function<void(std::string, bool)> hook) = 0;
/// return true if we are asynchronously processing authentication on this sessiontag
virtual bool auth_async_pending(service::SessionTag tag) const = 0;
};
struct SessionAuthPolicy final : public AuthPolicy, public std::enable_shared_from_this<SessionAuthPolicy>
@ -101,11 +87,6 @@ namespace llarp::auth
{
return shared_from_this();
}
void authenticate_async(
std::shared_ptr<service::ProtocolMessage> msg, std::function<void(std::string, bool)> hook) override;
bool auth_async_pending(service::SessionTag tag) const override;
};
struct FileAuthPolicy final : public AuthPolicy, public std::enable_shared_from_this<FileAuthPolicy>
@ -124,11 +105,6 @@ namespace llarp::auth
return shared_from_this();
}
void authenticate_async(
std::shared_ptr<service::ProtocolMessage> msg, std::function<void(std::string, bool)> hook) override;
bool auth_async_pending(service::SessionTag tag) const override;
private:
const std::set<fs::path> _files;
const AuthFileType _type;
@ -147,10 +123,9 @@ namespace llarp::auth
Router& r,
std::string url,
std::string method,
std::unordered_set<llarp::service::Address> addr_whitelist,
std::unordered_set<NetworkAddress> addr_whitelist,
std::unordered_set<std::string> token_whitelist,
std::shared_ptr<oxenmq::OxenMQ> lmq,
std::shared_ptr<service::Endpoint> endpoint);
std::shared_ptr<oxenmq::OxenMQ> lmq);
~RPCAuthPolicy() override = default;
@ -166,19 +141,13 @@ namespace llarp::auth
void start();
void authenticate_async(
std::shared_ptr<llarp::service::ProtocolMessage> msg, std::function<void(std::string, bool)> hook) override;
bool auth_async_pending(service::SessionTag tag) const override;
private:
const std::string _url;
const std::string _method;
const std::unordered_set<llarp::service::Address> _whitelist;
const std::unordered_set<NetworkAddress> _whitelist;
const std::unordered_set<std::string> _static_tokens;
std::shared_ptr<oxenmq::OxenMQ> _omq;
std::shared_ptr<service::Endpoint> _ep;
std::optional<oxenmq::ConnectionID> _omq_conn;
std::unordered_set<service::SessionTag> _pending_sessions;
};

View File

@ -1,7 +1,6 @@
#include "auth.hpp"
#include <llarp/router/router.hpp>
#include <llarp/service/protocol.hpp>
#include <llarp/util/str.hpp>
namespace llarp::auth
@ -42,43 +41,4 @@ namespace llarp::auth
}
}
void FileAuthPolicy::authenticate_async(
std::shared_ptr<service::ProtocolMessage> msg, std::function<void(std::string, bool)> hook)
{
auto reply = router().loop()->make_caller([tag = msg->tag, hook, self = shared_from_this()](AuthResult result) {
{
util::Lock _lock{self->_m};
self->_pending.erase(tag);
}
hook(result.reason, result.code == AuthCode::ACCEPTED);
});
{
util::Lock _lock{_m};
_pending.emplace(msg->tag);
}
if (msg->proto == service::ProtocolType::Auth)
{
router().queue_disk_io(
[self = shared_from_this(),
auth = AuthInfo{std::string{reinterpret_cast<const char*>(msg->payload.data()), msg->payload.size()}},
reply]() {
try
{
reply(self->check_files(auth));
}
catch (std::exception& ex)
{
reply(AuthResult{AuthCode::FAILED, ex.what()});
}
});
}
else
reply(AuthResult{AuthCode::REJECTED, "protocol error"});
}
bool FileAuthPolicy::auth_async_pending(service::SessionTag tag) const
{
util::Lock _lock{_m};
return _pending.count(tag);
}
} // namespace llarp::auth

View File

@ -1,7 +1,6 @@
#include "auth.hpp"
#include <llarp/router/router.hpp>
#include <llarp/service/endpoint.hpp>
namespace llarp::auth
{
@ -11,17 +10,15 @@ namespace llarp::auth
Router& r,
std::string url,
std::string method,
std::unordered_set<llarp::service::Address> whitelist_addrs,
std::unordered_set<NetworkAddress> whitelist_addrs,
std::unordered_set<std::string> whitelist_tokens,
std::shared_ptr<oxenmq::OxenMQ> lmq,
std::shared_ptr<service::Endpoint> endpoint)
std::shared_ptr<oxenmq::OxenMQ> lmq)
: AuthPolicy{r},
_url{std::move(url)},
_method{std::move(method)},
_whitelist{std::move(whitelist_addrs)},
_static_tokens{std::move(whitelist_tokens)},
_omq{std::move(lmq)},
_ep{std::move(endpoint)}
_omq{std::move(lmq)}
{}
void RPCAuthPolicy::start()
@ -41,86 +38,4 @@ namespace llarp::auth
});
}
bool RPCAuthPolicy::auth_async_pending(service::SessionTag tag) const
{
return _pending_sessions.count(tag) > 0;
}
void RPCAuthPolicy::authenticate_async(
std::shared_ptr<llarp::service::ProtocolMessage> msg, std::function<void(std::string, bool)> hook)
{
service::SessionTag tag = msg->tag;
_pending_sessions.insert(tag);
const auto from = msg->sender.address();
auto reply = _ep->loop()->make_caller([this, tag, hook](std::string code, bool success) {
_pending_sessions.erase(tag);
hook(code, success);
});
if (_whitelist.count(from))
{
// explicitly whitelisted source
reply("explicitly whitelisted", true);
return;
}
if (msg->proto != llarp::service::ProtocolType::Auth)
{
// not an auth message, reject
reply("protocol error", false);
return;
}
std::string payload{(char*)msg->payload.data(), msg->payload.size()};
if (_static_tokens.count(payload))
{
reply("explicitly whitelisted", true);
return;
}
if (not _omq_conn.has_value())
{
if (_static_tokens.empty())
{
// we don't have a connection to the backend so it's failed
reply("remote has no connection to auth backend", false);
}
else
{
// static auth mode
reply("access not permitted", true);
}
return;
}
const auto authinfo = msg->encode_auth_info();
std::string_view metainfo{authinfo.data(), authinfo.size()};
// call method with 2 parameters: metainfo and userdata
_omq->request(
*_omq_conn,
_method,
[self = shared_from_this(), reply = std::move(reply)](bool success, std::vector<std::string> data) {
AuthResult result{AuthCode::FAILED, "no reason given"};
if (success and not data.empty())
{
if (const auto maybe = parse_auth_code(data[0]))
{
result.code = *maybe;
}
if (result.code == AuthCode::ACCEPTED)
{
result.reason = "OK";
}
if (data.size() > 1)
{
result.reason = data[1];
}
}
reply(result.reason, success);
},
metainfo,
payload);
}
} // namespace llarp::auth

View File

@ -824,7 +824,7 @@ namespace llarp
if (auto maybe_netaddr = NetworkAddress::from_network_addr(*arg))
{
_persisting_addrs.emplace(std::move(*maybe_netaddr), std::move(addr));
_reserved_local_addrs.emplace(std::move(*maybe_netaddr), std::move(addr));
}
else
log::warning(logcat, "{}: {}", addrmap_errorstr, *arg);

View File

@ -14,7 +14,6 @@
#include <llarp/net/net_int.hpp>
#include <llarp/net/traffic_policy.hpp>
#include <llarp/router_contact.hpp>
#include <llarp/service/address.hpp>
#include <llarp/util/fs.hpp>
#include <llarp/util/logging.hpp>
#include <llarp/util/str.hpp>
@ -141,11 +140,9 @@ namespace llarp
/* TESTNET: Under modification */
// Contents of this file are read directly into ::_reserved_local_addrs
std::optional<fs::path> addr_map_persist_file;
// Pass to TunEndpoint -- combine with _reserved_local_addrs
std::unordered_map<NetworkAddress, oxen::quic::Address> _persisting_addrs;
// the only member that refers to an actual interface
std::optional<std::string> _if_name;
@ -158,8 +155,7 @@ namespace llarp
// Remote exit or hidden service addresses mapped to fixed local IP addresses
// TODO:
// - pass to TunEndpoint
// - create separate "reserved_ips" mapping or load directly into TunEndpoint mapping (probably better)
// - pass to TunEndpoint, load directly into TunEndpoint mapping
// - when a session is created, check here when assigning IP's
std::unordered_map<NetworkAddress, oxen::quic::Address> _reserved_local_addrs;

View File

@ -5,7 +5,6 @@
#include <llarp/dns/srv_data.hpp>
#include <llarp/ev/loop.hpp>
#include <llarp/link/tunnel.hpp>
#include <llarp/service/address.hpp>
#include <llarp/service/tag.hpp>
#include <llarp/service/types.hpp>
#include <llarp/session/map.hpp>
@ -38,7 +37,7 @@ namespace llarp
std::unordered_set<dns::SRVData> _srv_records;
public:
bool _publish_introset{true};
bool should_publish_introset{true};
// TODO: replace with session_map type
// std::unordered_map<service::SessionTag, RouterID> _session_lookup;

View File

@ -1,10 +0,0 @@
#include "endpoint.hpp"
#include <llarp/path/path_context.hpp>
#include <llarp/router/router.hpp>
#include <llarp/service/handler.hpp>
namespace llarp::exit
{
//
} // namespace llarp::exit

View File

@ -1,37 +0,0 @@
#pragma once
#include <llarp/address/ip_range.hpp>
#include <llarp/crypto/types.hpp>
#include <llarp/endpoint_base.hpp>
#include <llarp/service/types.hpp>
#include <llarp/util/time.hpp>
#include <queue>
namespace llarp::exit
{
/**
TONUKE: all of this
*/
/** This class is the counterpart to service::Endpoint. While service::Endpoint manages hidden
services ran locally, exit::Endpoint manages locally operated client exit nodes
*/
struct Endpoint /* final */ : public path::PathHandler,
/* public EndpointBase, */
public std::enable_shared_from_this<Endpoint>
{
std::shared_ptr<path::PathHandler> get_self() override
{
return shared_from_this();
}
std::weak_ptr<path::PathHandler> get_weak() override
{
return weak_from_this();
}
std::unordered_map<IPRange, service::Address> _exit_map;
std::set<IPRange> _owned_ranges;
};
} // namespace llarp::exit

View File

@ -1,15 +0,0 @@
#include "handler.hpp"
#include <llarp/router/router.hpp>
#include <memory>
#include <stdexcept>
namespace llarp::exit
{
Handler::Handler(std::string /* name */, Router& /* r */) /* : handlers::RemoteHandler{std::move(name), r} */
{}
void Handler::_configure()
{}
} // namespace llarp::exit

View File

@ -1,25 +0,0 @@
#pragma once
// #include <llarp/dns/server.hpp>
#include <llarp/endpoint_base.hpp>
#include <llarp/handlers/remote.hpp>
#include <llarp/session/session.hpp>
#include <string>
#include <unordered_map>
namespace llarp::exit
{
/** This class is the counterpart to service::Handler. While service::Handler manages sessions
to remote hidden services, exit::Handler manages sessions to remote exit nodes
*/
struct Handler final : /* public handlers::RemoteHandler, */ public std::enable_shared_from_this<Handler>
{
private:
void _configure();
public:
Handler(std::string name, Router& r);
~Handler() = default;
};
} // namespace llarp::exit

View File

@ -4,7 +4,6 @@
#include <llarp/dns/server.hpp>
#include <llarp/ev/loop.hpp>
#include <llarp/net/net.hpp>
#include <llarp/service/address.hpp>
#include <llarp/service/identity.hpp>
#include <llarp/service/name.hpp>
#include <llarp/session/session.hpp>
@ -56,7 +55,7 @@ namespace llarp::handlers
virtual bool supports_ipv6() const = 0;
virtual bool configure(const NetworkConfig& conf, const DnsConfig& dnsConf) = 0;
virtual bool configure() = 0;
virtual bool setup_networking() = 0;

View File

@ -2,20 +2,23 @@
namespace llarp::handlers
{
static auto logcat = log::Cat("Null");
static auto logcat = log::Cat("EmbeddedEndpoint");
EmbeddedEndpoint::EmbeddedEndpoint(Router& r)
: BaseHandler{r}, _packet_router{new vpn::EgresPacketRouter{[](AddressVariant_t from, IPPacket pkt) {
var::visit(
[&pkt](AddressVariant_t&& from) {
log::error(logcat, "Unhandled traffic from {} (pkt size:{}B)", from, pkt.size());
},
from);
: BaseHandler{r}, _packet_router{new vpn::EgresPacketRouter{[](NetworkAddress from, IPPacket pkt) {
(void)from;
(void)pkt;
// TODO: something smart here!
}}}
{
// r->loop()->add_ticker([this] { Pump(Now()); });
}
bool EmbeddedEndpoint::configure()
{
return true;
}
bool EmbeddedEndpoint::handle_inbound_packet(
const service::SessionTag tag, const llarp_buffer_t& buf, service::ProtocolType t, uint64_t)
{

View File

@ -51,12 +51,7 @@ namespace llarp::handlers
}
// TODO: this
bool configure(const NetworkConfig& conf, const DnsConfig& dnsConf) override
{
(void)conf;
(void)dnsConf;
return true;
}
bool configure() override;
bool handle_inbound_packet(
const service::SessionTag tag, const llarp_buffer_t& buf, service::ProtocolType t, uint64_t) override;

View File

@ -48,27 +48,30 @@ namespace llarp::handlers
void LocalEndpoint::configure()
{
// auto _dns_config = _router.config()->dns;
auto _net_config = _router.config()->network;
auto net_config = _router.config()->network;
if (net_config.is_reachable)
should_publish_introset = true;
_is_exit_node = _router.is_exit_node();
_is_snode_service = _router.is_service_node();
if (_is_exit_node)
{
if (not _net_config._routed_ranges.empty())
if (not net_config._routed_ranges.empty())
{
_routed_ranges.merge(_net_config._routed_ranges);
_routed_ranges.merge(net_config._routed_ranges);
_local_introset._routed_ranges = _routed_ranges;
}
_exit_policy = _net_config.traffic_policy;
_exit_policy = net_config.traffic_policy;
_local_introset.exit_policy = _exit_policy;
}
_if_name = *_net_config._if_name;
_local_range = *_net_config._local_ip_range;
_local_addr = *_net_config._local_addr;
_local_ip = *_net_config._local_ip;
_if_name = *net_config._if_name;
_local_range = *net_config._local_ip_range;
_local_addr = *net_config._local_addr;
_local_ip = *net_config._local_ip;
_is_v4 = _local_range.is_ipv4();
}

View File

@ -1,10 +1,10 @@
#pragma once
#include <llarp/address/ip_range.hpp>
#include <llarp/address/map.hpp>
#include <llarp/auth/auth.hpp>
#include <llarp/config/config.hpp>
#include <llarp/endpoint_base.hpp>
#include <llarp/service/intro_set.hpp>
#include <llarp/session/session.hpp>
namespace llarp

View File

@ -14,7 +14,6 @@
#include <llarp/nodedb.hpp>
#include <llarp/router/route_poker.hpp>
#include <llarp/router/router.hpp>
#include <llarp/service/endpoint_state.hpp>
#include <llarp/service/name.hpp>
#include <llarp/service/types.hpp>
#include <llarp/util/str.hpp>
@ -139,10 +138,12 @@ namespace llarp::handlers
void TunEndpoint::setup_dns()
{
auto& dns_config = _router.config()->dns;
const auto& info = get_vpn_interface()->Info();
if (_dns_config.raw)
if (dns_config.raw)
{
auto dns = std::make_shared<TunDNS>(this, _dns_config);
auto dns = std::make_shared<TunDNS>(this, dns_config);
_dns = dns;
_packet_router->add_udp_handler(uint16_t{53}, [this, dns](UDPPacket pkt) {
@ -164,12 +165,12 @@ namespace llarp::handlers
});
}
else
_dns = std::make_shared<dns::Server>(router().loop(), _dns_config, info.index);
_dns = std::make_shared<dns::Server>(router().loop(), dns_config, info.index);
_dns->add_resolver(weak_from_this());
_dns->start();
if (_dns_config.raw)
if (dns_config.raw)
{
if (auto vpn = router().vpn_platform())
{
@ -260,31 +261,22 @@ namespace llarp::handlers
}
}
bool TunEndpoint::configure(const NetworkConfig& conf, const DnsConfig& dnsConf)
bool TunEndpoint::configure()
{
// if (conf.is_reachable)
// {
// _publish_introset = true;
// log::info(logcat, "TunEndpoint setting to be reachable by default");
// }
// else
// {
// _publish_introset = false;
// log::info(logcat, "TunEndpoint setting to be not reachable by default");
// }
auto& net_conf = _router.config()->network;
if (conf.auth_type == auth::AuthType::FILE)
if (net_conf.auth_type == auth::AuthType::FILE)
{
// _auth_policy = auth::make_auth_policy<auth::FileAuthPolicy>(router(),
// conf.auth_files, conf.auth_file_type);
}
else if (conf.auth_type != auth::AuthType::NONE)
else if (net_conf.auth_type != auth::AuthType::NONE)
{
std::string url, method;
if (conf.auth_url.has_value() and conf.auth_method.has_value())
if (net_conf.auth_url.has_value() and net_conf.auth_method.has_value())
{
url = *conf.auth_url;
method = *conf.auth_method;
url = *net_conf.auth_url;
method = *net_conf.auth_method;
}
// TODO:
// auto auth = auth::make_auth_policy<auth::RPCAuthPolicy>(
@ -299,155 +291,32 @@ namespace llarp::handlers
// _auth_policy = std::move(auth);
}
_dns_config = dnsConf;
_traffic_policy = conf.traffic_policy;
_traffic_policy = net_conf.traffic_policy;
_base_ipv6_range = conf._base_ipv6_range;
_base_ipv6_range = net_conf._base_ipv6_range;
if (conf.path_alignment_timeout)
if (net_conf.path_alignment_timeout)
{
_path_alignment_timeout = *conf.path_alignment_timeout;
}
else
_path_alignment_timeout = service::DEFAULT_PATH_ALIGN_TIMEOUT;
if (is_service_node())
throw std::runtime_error{"Service nodes cannot specify path alignment timeout!"};
for (const auto& item : conf._reserved_local_addrs)
{
(void)item;
// if (not map_address(item.second, item.first, false))
// return false;
_path_alignment_timeout = *net_conf.path_alignment_timeout;
}
_if_name = *conf._if_name;
_local_range = *conf._local_ip_range;
_local_addr = *conf._local_addr;
_local_ip = *conf._local_ip;
_if_name = *net_conf._if_name;
_local_range = *net_conf._local_ip_range;
_local_addr = *net_conf._local_addr;
_local_ip = *net_conf._local_ip;
_use_v6 = not _local_range.is_ipv4();
_persisting_addr_file = conf.addr_map_persist_file;
_persisting_addr_file = net_conf.addr_map_persist_file;
if (conf.addr_map_persist_file and not conf._persisting_addrs.empty())
if (not net_conf._reserved_local_addrs.empty())
{
}
if (_persisting_addr_file)
{
const auto& file = *_persisting_addr_file;
if (fs::exists(file))
for (auto& [remote, local] : net_conf._reserved_local_addrs)
{
bool load_file = true;
{
constexpr auto LastModifiedWindow = 1min;
const auto lastmodified = fs::last_write_time(file);
const auto now = decltype(lastmodified)::clock::now();
if (now < lastmodified or now - lastmodified > LastModifiedWindow)
{
load_file = false;
}
}
std::vector<char> data;
if (auto maybe = util::OpenFileStream<fs::ifstream>(file, std::ios_base::binary); maybe and load_file)
{
log::info(logcat, "{} loading persisting address map file from path:{}", name(), file);
maybe->seekg(0, std::ios_base::end);
const size_t len = maybe->tellg();
maybe->seekg(0, std::ios_base::beg);
data.resize(len);
log::debug(logcat, "{} reading {}B", name(), len);
maybe->read(data.data(), data.size());
}
else
{
auto err = "{} could not load persisting address map file from path:{} --"_format(name(), file);
log::info(logcat, "{} {}", err, load_file ? "NOT FOUND" : "STALE");
if (load_file)
{
log::info(logcat, "{} NOT FOUND", err);
}
else
log::info(logcat, "{} STALE", err);
}
if (not data.empty())
{
std::string_view bdata{data.data(), data.size()};
log::trace(logcat, "{} parsing address map data: {}", name(), bdata);
const auto parsed = oxenc::bt_deserialize<oxenc::bt_dict>(bdata);
for (const auto& [key, value] : parsed)
{
ip ip{};
// if (not ip.FromString(key))
// {
// log::warning(logcat, "{} malformed IP in addr map data: {}", name(), key);
// continue;
// }
if (_local_ip == ip)
continue;
if (not _local_range.contains(ip))
{
// log::warning(logcat, "{} out of range IP in addr map data", name(), ip);
continue;
}
AddressVariant_t addr;
if (const auto* str = std::get_if<std::string>(&value))
{
if (auto maybe = parse_address(*str))
{
addr = *maybe;
}
else
{
log::warning(logcat, "{} invalid address in addr map: {}", name(), *str);
continue;
}
}
else
{
log::warning(logcat, "{} invalid first entry in addr map: not a string!", name());
continue;
}
if (const auto* loki = std::get_if<service::Address>(&addr))
{
_ip_to_addr.emplace(ip, loki->data());
_addr_to_ip.emplace(loki->data(), ip);
_is_snode_map[*loki] = false;
log::info(logcat, "{} remapped {} to {}", name(), ip, *loki);
}
if (const auto* snode = std::get_if<RouterID>(&addr))
{
_ip_to_addr.emplace(ip, snode->data());
_addr_to_ip.emplace(snode->data(), ip);
_is_snode_map[*snode] = true;
log::info(logcat, "{} remapped {} to {}", name(), ip, *snode);
}
if (_next_ip < ip)
_next_ip = ip;
// make sure we dont unmap this guy
mark_ip_active(ip);
}
}
}
else
{
log::info(logcat, "{} skipping loading addr map at {} as it does not currently exist", name(), file);
local_ip_mapping.insert_or_assign(local, remote);
}
}
@ -461,11 +330,6 @@ namespace llarp::handlers
return true;
}
bool TunEndpoint::has_local_ip(const ip& ip) const
{
return _ip_to_addr.find(ip) != _ip_to_addr.end();
}
static bool is_random_snode(const dns::Message& msg)
{
return msg.questions[0].IsName("random.snode");
@ -875,7 +739,7 @@ namespace llarp::handlers
// FIXME: pass in which question it should be addressing
bool TunEndpoint::should_hook_dns_message(const dns::Message& msg) const
{
llarp::service::Address addr;
// llarp::service::Address addr;
if (msg.questions.size() == 1)
{
/// hook every .loki
@ -916,10 +780,14 @@ namespace llarp::handlers
return setup_networking();
}
bool TunEndpoint::is_snode() const
bool TunEndpoint::is_service_node() const
{
// TODO : implement me
return false;
return _router.is_service_node();
}
bool TunEndpoint::is_exit_node() const
{
return _router.is_exit_node();
}
bool TunEndpoint::setup_tun()
@ -929,12 +797,9 @@ namespace llarp::handlers
log::info(logcat, "{} set {} to have address {}", name(), _if_name, _local_addr);
// log::info(logcat, "{} allocated up to {} on range {}", name(), _max_ip, _local_range);
const service::Address ourAddr = _identity.pub.address();
auto& local_netaddr = _identity.pub.address();
if (not map_address(ourAddr, get_if_addr(), false))
{
return false;
}
local_ip_mapping.insert_or_assign(get_if_addr(), local_netaddr);
vpn::InterfaceInfo info;
info.addrs.emplace_back(_local_range);
@ -990,7 +855,7 @@ namespace llarp::handlers
log::info(logcat, "{} setting up DNS...", name());
setup_dns();
// loop()->call_soon([this]() { router().route_poker()->set_dns_mode(false); });
return has_mapped_address(ourAddr);
return has_mapped_address(local_netaddr);
}
// std::unordered_map<std::string, std::string>
@ -1229,8 +1094,10 @@ namespace llarp::handlers
bool TunEndpoint::is_allowing_traffic(const IPPacket& pkt) const
{
if (auto exitPolicy = get_traffic_policy())
return exitPolicy->allow_ip_traffic(pkt);
// if (auto exitPolicy = get_traffic_policy())
// return exitPolicy->allow_ip_traffic(pkt);
(void)pkt;
return true;
}
@ -1263,7 +1130,7 @@ namespace llarp::handlers
if (t != service::ProtocolType::TrafficV4 && t != service::ProtocolType::TrafficV6
&& t != service::ProtocolType::Exit)
return false;
std::variant<service::Address, RouterID> addr;
// std::variant<service::Address, RouterID> addr;
// if (auto maybe = GetEndpointWithConvoTag(tag))
// {
// addr = *maybe;
@ -1344,9 +1211,8 @@ namespace llarp::handlers
bool TunEndpoint::handle_write_ip_packet(const llarp_buffer_t& b, huint128_t src, huint128_t dst, uint64_t seqno)
{
ManagedBuffer buf(b);
WritePacket write;
write.seqno = seqno;
auto& pkt = write.pkt;
IPPacket pkt;
// load
if (!pkt.load(buf.underlying.base))
{
@ -1362,6 +1228,7 @@ namespace llarp::handlers
// }
(void)src;
(void)dst;
(void)seqno;
// TODO: send this along but without a fucking huint182_t
// m_NetworkToUserPktQueue.push(std::move(write));
@ -1371,28 +1238,14 @@ namespace llarp::handlers
return true;
}
ip TunEndpoint::get_if_addr() const
bool TunEndpoint::has_mapped_address(const NetworkAddress& addr) const
{
return _local_ip;
return local_ip_mapping.has_remote(addr);
}
bool TunEndpoint::is_ip_mapped(ip ip) const
oxen::quic::Address TunEndpoint::get_if_addr() const
{
return _ip_to_addr.find(ip) != _ip_to_addr.end();
}
void TunEndpoint::mark_ip_active(ip ip)
{
log::debug(logcat, "{} marking address {} active", name(), ip);
// _ip_activity[ip] =
// std::max(llarp::time_now_ms(), _ip_activity[ip]);
}
void TunEndpoint::mark_ip_active_forever(ip ip)
{
log::debug(logcat, "{} marking address {} perpetually active", name(), ip);
// _ip_activity[ip] =
// std::numeric_limits<std::chrono::milliseconds>::max();
return _local_addr;
}
TunEndpoint::~TunEndpoint() = default;

View File

@ -3,6 +3,7 @@
#include "common.hpp"
#include <llarp/address/ip_packet.hpp>
#include <llarp/address/map.hpp>
#include <llarp/dns/server.hpp>
#include <llarp/net/ip.hpp>
#include <llarp/net/net.hpp>
@ -71,7 +72,7 @@ namespace llarp::handlers
// Reconfigures DNS servers and restarts libunbound with the new servers.
void reconfigure_dns(std::vector<oxen::quic::Address> servers);
bool configure(const NetworkConfig& conf, const DnsConfig& dnsConf) override;
bool configure() override;
std::string get_if_name() const override;
@ -92,7 +93,9 @@ namespace llarp::handlers
bool stop();
bool is_snode() const;
bool is_service_node() const;
bool is_exit_node() const;
/// set up tun interface, blocking
bool setup_tun();
@ -105,10 +108,10 @@ namespace llarp::handlers
// return _dns;
// };
/// overrides Endpoint
/// overrides BaseHandler
bool setup_networking() override;
/// overrides Endpoint
/// overrides BaseHandler
bool handle_inbound_packet(
const service::SessionTag tag, const llarp_buffer_t& pkt, service::ProtocolType t, uint64_t seqno) override;
@ -118,24 +121,21 @@ namespace llarp::handlers
/// we got a packet from the user
void handle_user_packet(llarp::IPPacket pkt);
// TODO: change this to the new IP type after changing the member
/// get the local interface's address
ip get_if_addr() const /* override */;
oxen::quic::Address get_if_addr() const;
/// we have an interface addr
bool has_if_addr() const /* override */
bool has_if_addr() const
{
return true;
}
bool has_local_ip(const ip& ip) const;
std::optional<net::TrafficPolicy> get_traffic_policy() const /* override */
std::optional<net::TrafficPolicy> get_traffic_policy() const
{
return _traffic_policy;
}
std::chrono::milliseconds get_path_alignment_timeout() const /* override */
std::chrono::milliseconds get_path_alignment_timeout() const
{
return _path_alignment_timeout;
}
@ -145,10 +145,7 @@ namespace llarp::handlers
/// returns true otherwise
bool is_allowing_traffic(const IPPacket& pkt) const;
bool has_mapped_address(const AlignedBuffer<32>& addr) const
{
return _addr_to_ip.find(addr) != _addr_to_ip.end();
}
bool has_mapped_address(const NetworkAddress& addr) const;
protected:
struct WritePacket
@ -162,32 +159,7 @@ namespace llarp::handlers
}
};
/// return true if we have a remote loki address for this ip address
bool is_ip_mapped(ip ipv4) const;
/// mark this address as active
void mark_ip_active(ip ip);
/// mark this address as active forever
void mark_ip_active_forever(ip ip);
/// flush writing ip packets to interface
void flush_write();
// TONUKE: errythang buddy (move to handlers)
/// maps ip to key (host byte order)
std::unordered_map<ip, AlignedBuffer<32>> _ip_to_addr;
/// maps key to ip (host byte order)
std::unordered_map<AlignedBuffer<32>, ip> _addr_to_ip;
/// maps key to true if key is a service node, maps key to false if key is
/// a hidden service
// TONUKE: this stupid POS
std::unordered_map<AlignedBuffer<32>, bool> _is_snode_map;
/// maps ip address to an exit endpoint, useful when we have multiple exits on a range
std::unordered_map<huint128_t, service::Address> _exit_to_ip;
address_map<oxen::quic::Address, NetworkAddress> local_ip_mapping;
private:
template <typename Addr_t, typename Endpoint_t>
@ -212,12 +184,6 @@ namespace llarp::handlers
/// dns subsystem for this endpoint
std::shared_ptr<dns::Server> _dns;
DnsConfig _dns_config;
// TODO: change the IP's to the variant IP type in address/ip_range.hpp
/// maps ip address to timestamp last active
std::unordered_map<huint128_t, std::chrono::milliseconds> _ip_activity;
/// our local address and ip
oxen::quic::Address _local_addr;
ip _local_ip;
@ -248,7 +214,7 @@ namespace llarp::handlers
std::optional<net::TrafficPolicy> _traffic_policy = std::nullopt;
/// how long to wait for path alignment
std::chrono::milliseconds _path_alignment_timeout;
std::chrono::milliseconds _path_alignment_timeout{30s};
/// a file to load / store the ephemeral address map to
std::optional<fs::path> _persisting_addr_file = std::nullopt;

View File

@ -523,7 +523,6 @@ namespace llarp
void Router::init_api()
{
auto& net_config = _config->network;
auto& dns_config = _config->dns;
auto& type = net_config.endpoint_type;
auto& key_file = net_config.keyfile;
@ -535,7 +534,7 @@ namespace llarp
throw std::runtime_error{"Failed to construct API endpoint of type {}"_format(type)};
_api->load_key_file(key_file, *this);
_api->configure(net_config, dns_config);
_api->configure();
}
else
throw std::runtime_error{"API endpoint of type {} does not exist"_format(type)};
@ -632,10 +631,7 @@ namespace llarp
// all snodes have Tun
//
// TODO: change this for snodes running hidden service
if (not is_service_node())
{
init_api();
}
init_api();
if (not ensure_identity())
throw std::runtime_error{"EnsureIdentity() failed"};

View File

@ -11,7 +11,8 @@ namespace llarp
{
static auto logcat = llarp::log::Cat("router_version");
RouterVersion::RouterVersion(const Version_t& router, uint64_t proto) : _version(router), _proto(proto)
RouterVersion::RouterVersion(const std::array<uint16_t, 3>& router, uint64_t proto)
: _version(router), _proto(proto)
{}
bool RouterVersion::is_compatible_with(const RouterVersion& other) const

View File

@ -13,11 +13,9 @@ namespace llarp
{
struct RouterVersion
{
using Version_t = std::array<uint16_t, 3>;
RouterVersion() = default;
explicit RouterVersion(const Version_t& routerVersion, uint64_t protoVersion);
explicit RouterVersion(const std::array<uint16_t, 3>& routerVersion, uint64_t protoVersion);
std::string bt_encode() const;
@ -51,7 +49,7 @@ namespace llarp
}
private:
Version_t _version = {{0, 0, 0}};
std::array<uint16_t, 3> _version = {{0, 0, 0}};
int64_t _proto = llarp::constants::proto_version;
};

View File

@ -1,48 +0,0 @@
#pragma once
#include <llarp/service/auth.hpp>
#include <llarp/service/convotag.hpp>
#include <oxenmq/oxenmq.h>
namespace llarp::service
{
struct Endpoint;
}
namespace llarp::rpc
{
struct EndpointAuthRPC : public llarp::service::IAuthPolicy, public std::enable_shared_from_this<EndpointAuthRPC>
{
using LMQ_ptr = std::shared_ptr<oxenmq::OxenMQ>;
using Endpoint_ptr = std::shared_ptr<llarp::service::Endpoint>;
using Whitelist_t = std::unordered_set<llarp::service::Address>;
explicit EndpointAuthRPC(
std::string url,
std::string method,
Whitelist_t addr_whitelist,
std::unordered_set<std::string> token_whitelist,
LMQ_ptr lmq,
Endpoint_ptr endpoint);
~EndpointAuthRPC() override = default;
void Start();
void authenticate_async(
std::shared_ptr<llarp::service::ProtocolMessage> msg, std::function<void(std::string, bool)> hook) override;
bool auth_async_pending(service::ConvoTag tag) const override;
private:
const std::string m_AuthURL;
const std::string m_AuthMethod;
const Whitelist_t m_AuthWhitelist;
const std::unordered_set<std::string> m_AuthStaticTokens;
LMQ_ptr m_LMQ;
Endpoint_ptr m_Endpoint;
std::optional<oxenmq::ConnectionID> m_Conn;
std::unordered_set<service::ConvoTag> m_PendingAuths;
};
} // namespace llarp::rpc

View File

@ -5,8 +5,6 @@
#include <llarp/address/ip_range.hpp>
#include <llarp/config/config.hpp>
#include <llarp/router/route_poker.hpp>
#include <llarp/service/address.hpp>
#include <llarp/service/endpoint.hpp>
#include <oxen/log/omq_logger.hpp>
#include <oxenmq/address.h>

View File

@ -5,7 +5,7 @@
#include <llarp/config/config.hpp>
#include <llarp/config/ini.hpp>
#include <llarp/constants/version.hpp>
#include <llarp/dns/dns.hpp>
#include <llarp/dns/server.hpp>
#include <llarp/endpoint_base.hpp>
#include <llarp/router/router.hpp>
#include <llarp/rpc/rpc_request_definitions.hpp>

View File

@ -1,73 +0,0 @@
#include "address.hpp"
#include <llarp/crypto/crypto.hpp>
#include <oxenc/base32z.h>
#include <algorithm>
namespace llarp::service
{
const std::set<std::string> Address::AllowedTLDs = {".loki", ".snode"};
bool Address::PermitTLD(const char* tld)
{
std::string gtld(tld);
std::transform(gtld.begin(), gtld.end(), gtld.begin(), ::tolower);
return AllowedTLDs.count(gtld) != 0;
}
std::string Address::to_string(const char* tld) const
{
if (!PermitTLD(tld))
return "";
std::string str;
if (subdomain.size())
{
str = subdomain;
str += '.';
}
str += oxenc::to_base32z(begin(), end());
str += tld;
return str;
}
bool Address::FromString(std::string_view str, const char* tld)
{
if (!PermitTLD(tld))
return false;
// Find, validate, and remove the .tld
const auto pos = str.find_last_of('.');
if (pos == std::string::npos)
return false;
if (str.substr(pos) != tld)
return false;
str = str.substr(0, pos);
// copy subdomains if they are there (and strip them off)
const auto idx = str.find_last_of('.');
if (idx != std::string::npos)
{
subdomain = str.substr(0, idx);
str.remove_prefix(idx + 1);
}
// Ensure we have something valid:
// - must end in a 1-bit value: 'o' or 'y' (i.e. 10000 or 00000)
// - must have 51 preceeding base32z chars
// - thus we get 51*5+1 = 256 bits = 32 bytes of output
if (str.size() != 52 || !oxenc::is_base32z(str) || !(str.back() == 'o' || str.back() == 'y'))
return false;
oxenc::from_base32z(str.begin(), str.end(), begin());
return true;
}
dht::Key_t Address::ToKey() const
{
PubKey k;
crypto::derive_subkey(k, PubKey(data()), 1);
return dht::Key_t{k.as_array()};
}
} // namespace llarp::service

View File

@ -1,105 +0,0 @@
#pragma once
#include <llarp/dht/key.hpp>
#include <llarp/router_id.hpp>
#include <llarp/util/aligned.hpp>
#include <functional>
#include <numeric>
#include <set>
#include <string>
#include <string_view>
#include <variant>
namespace llarp
{
namespace service
{
struct Address : public AlignedBuffer<32>
{
/// if parsed using FromString this contains the subdomain
/// this member is not used when comparing it's extra data for dns
std::string subdomain;
/// list of whitelisted gtld to permit
static const std::set<std::string> AllowedTLDs;
/// return true if we permit using this tld
/// otherwise return false
static bool PermitTLD(const char* tld);
std::string to_string(const char* tld = ".loki") const;
bool FromString(std::string_view str, const char* tld = ".loki");
Address() : AlignedBuffer<32>()
{}
explicit Address(const std::string& str) : AlignedBuffer<32>()
{
if (not FromString(str))
throw std::runtime_error("invalid address");
}
explicit Address(const std::array<uint8_t, SIZE>& buf) : AlignedBuffer<32>(buf)
{}
Address(const Address& other) : AlignedBuffer<32>(other.as_array()), subdomain(other.subdomain)
{}
explicit Address(const AlignedBuffer<32>& other) : AlignedBuffer<32>(other)
{}
bool operator<(const Address& other) const
{
return as_array() < other.as_array();
}
bool operator==(const Address& other) const
{
return as_array() == other.as_array();
}
bool operator!=(const Address& other) const
{
return as_array() != other.as_array();
}
Address& operator=(const Address& other) = default;
dht::Key_t ToKey() const;
RouterID ToRouter() const
{
return {as_array()};
}
};
} // namespace service
using AddressVariant_t = std::variant<service::Address, RouterID>;
inline std::optional<AddressVariant_t> parse_address(std::string_view lokinet_addr)
{
RouterID router{};
service::Address addr{};
if (router.from_snode_address(lokinet_addr))
return router;
if (addr.FromString(lokinet_addr))
return addr;
return std::nullopt;
}
} // namespace llarp
namespace std
{
template <>
struct hash<llarp::service::Address>
{
size_t operator()(const llarp::service::Address& addr) const
{
return std::accumulate(addr.begin(), addr.end(), 0, std::bit_xor{});
}
};
} // namespace std

View File

@ -1,74 +0,0 @@
#include "async_key_exchange.hpp"
#include "endpoint.hpp"
#include <llarp/crypto/crypto.hpp>
#include <llarp/crypto/types.hpp>
#include <utility>
namespace llarp::service
{
AsyncKeyExchange::AsyncKeyExchange(
ServiceInfo r,
const Identity& localident,
const PQPubKey& introsetPubKey,
const Introduction& remote,
Endpoint* h,
const SessionTag& t)
: m_remote(std::move(r)),
m_LocalIdentity(localident),
introPubKey(introsetPubKey),
remoteIntro(remote),
handler(h),
tag(t)
{}
void AsyncKeyExchange::Result(std::shared_ptr<AsyncKeyExchange> self, std::shared_ptr<ProtocolFrameMessage> frame)
{
// put values
// self->handler->PutSenderFor(self->msg.tag, self->m_remote, false);
// self->handler->PutCachedSessionKeyFor(self->msg.tag, self->sharedKey);
// self->handler->PutIntroFor(self->msg.tag, self->remoteIntro);
// self->handler->PutReplyIntroFor(self->msg.tag, self->msg.introReply);
self->hook(frame);
}
void AsyncKeyExchange::Encrypt(std::shared_ptr<AsyncKeyExchange> self, std::shared_ptr<ProtocolFrameMessage> frame)
{
(void)self;
(void)frame;
/* TODO: client<->client session ("conversation"/"convo") key exchange
// derive ntru session key component
SharedSecret secret;
crypto::pqe_encrypt(frame->cipher, secret, self->introPubKey);
// randomize Nonce
frame->nonce.Randomize();
// compute post handshake session key
// PKE (A, B, N)
SharedSecret sharedSecret;
if (!self->m_LocalIdentity.KeyExchange(
crypto::dh_client, sharedSecret, self->m_remote, frame->nonce))
{
log::error(logcat, "failed to derive x25519 shared key component");
}
auto buf = secret.bt_encode() + sharedSecret.bt_encode();
// H (K + PKE(A, B, N))
crypto::shorthash(self->sharedKey, reinterpret_cast<uint8_t*>(buf.data()), buf.size());
// set tag
self->msg.tag = self->tag;
// set sender
self->msg.sender = self->m_LocalIdentity.pub;
// encrypt and sign
if (frame->EncryptAndSign(self->msg, secret, self->m_LocalIdentity))
self->loop->call([self, frame] { AsyncKeyExchange::Result(self, frame); });
else
{
log::error(logcat, "failed to encrypt and sign");
}
*/
}
} // namespace llarp::service

View File

@ -1,37 +0,0 @@
#pragma once
#include "identity.hpp"
#include "protocol.hpp"
#include <llarp/crypto/types.hpp>
namespace llarp::service
{
struct AsyncKeyExchange : public std::enable_shared_from_this<AsyncKeyExchange>
{
SharedSecret sharedKey;
ServiceInfo m_remote;
const Identity& m_LocalIdentity;
ProtocolMessage msg;
Introduction intro;
const PQPubKey introPubKey;
Introduction remoteIntro;
std::function<void(std::shared_ptr<ProtocolFrameMessage>)> hook;
Endpoint* handler;
SessionTag tag;
AsyncKeyExchange(
ServiceInfo r,
const Identity& localident,
const PQPubKey& introsetPubKey,
const Introduction& remote,
Endpoint* h,
const SessionTag& t);
static void Result(std::shared_ptr<AsyncKeyExchange> user, std::shared_ptr<ProtocolFrameMessage> frame);
/// given protocol message make protocol frame
static void Encrypt(std::shared_ptr<AsyncKeyExchange> user, std::shared_ptr<ProtocolFrameMessage> frame);
};
} // namespace llarp::service

File diff suppressed because it is too large Load Diff

View File

@ -1,270 +0,0 @@
#pragma once
#include "address.hpp"
#include "identity.hpp"
#include "types.hpp"
#include <llarp/dns/server.hpp>
#include <llarp/endpoint_base.hpp>
#include <llarp/net/net.hpp>
#include <llarp/path/path_handler.hpp>
// #include <llarp/service/address.hpp>
// #include <llarp/service/identity.hpp>
// #include <llarp/service/protocol.hpp>
// #include <llarp/service/session.hpp>
#include <llarp/util/compare_ptr.hpp>
#include <llarp/vpn/egres_packet_router.hpp>
#include <oxenc/variant.h>
#include <optional>
#include <unordered_map>
#include <variant>
// minimum time between introset shifts
#ifndef MIN_SHIFT_INTERVAL
#define MIN_SHIFT_INTERVAL 5s
#endif
namespace llarp::quic
{
class TunnelManager;
}
namespace llarp::service
{
inline constexpr auto DEFAULT_PATH_ALIGN_TIMEOUT{30s};
/// minimum interval for publishing introsets
inline constexpr auto IntrosetPublishInterval = path::INTRO_PATH_SPREAD / 2;
/// how agressively should we retry publishing introset on failure
inline constexpr auto IntrosetPublishRetryCooldown = 1s;
/// how aggressively should we retry looking up introsets
inline constexpr auto IntrosetLookupCooldown = 250ms;
/// number of unique snodes we want to talk to do to ons lookups
inline constexpr size_t MIN_ONS_LOOKUP_ENDPOINTS{2};
inline constexpr size_t MAX_ONS_LOOKUP_ENDPOINTS{7};
/** Holds all local hidden service related functionality. One hidden service can be hosted per
client or relay instance, and is managed by this object.
*/
struct Endpoint final : public path::PathHandler,
/* public EndpointBase, */ public std::enable_shared_from_this<Endpoint>
{
Endpoint(Router& r);
~Endpoint() override = default;
std::shared_ptr<path::PathHandler> get_self() override
{
return shared_from_this();
}
std::weak_ptr<path::PathHandler> get_weak() override
{
return weak_from_this();
}
/// return true if we are ready to recv packets from the void.
/// really should be ReadyForInboundTraffic() but the diff is HUGE and we need to rewrite
/// this component anyways.
bool is_ready() const;
/// return true if our introset has expired intros
bool IntrosetIsStale() const;
/// construct parameters for notify hooks
// virtual std::unordered_map<std::string, std::string>
// NotifyParams() const;
virtual StatusObject ExtractStatus() const;
virtual bool Configure(const NetworkConfig& conf, const DnsConfig& dnsConf);
void Tick(std::chrono::milliseconds now) override;
/// return true if we have a resolvable ip address
virtual bool HasIfAddr() const
{
return false;
}
// std::optional<SessionTag> GetBestConvoTagFor(std::variant<Address, RouterID> addr) const
// override;
/// get our ifaddr if it is set
virtual huint128_t GetIfAddr() const
{
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;
};
void reset_path_state() override;
/// loop (via router)
/// use when sending any data on a path
const std::shared_ptr<EventLoop>& loop();
virtual bool Start();
std::string name() const override;
oxen::quic::Address local_address() const;
// bool should_publish_intro(std::chrono::milliseconds now) const;
// TODO:
void build_more(size_t n = 0) override;
void srv_records_changed();
void path_died(std::shared_ptr<path::Path> p) override;
virtual vpn::EgresPacketRouter* EgresPacketRouter()
{
return nullptr;
}
virtual vpn::NetworkInterface* GetVPNInterface()
{
return nullptr;
}
bool publish_introset(const EncryptedIntroSet& i);
bool HandleHiddenServiceFrame(std::shared_ptr<path::Path> p, const ProtocolFrameMessage& msg);
// virtual bool // HasServiceAddress(const AlignedBuffer< 32 >& addr) const = 0;
// bool HandleDataMessage(
// std::shared_ptr<path::Path> path,
// const PathID_t from,
// std::shared_ptr<ProtocolMessage> msg);
// virtual bool // HandleWriteIPPacket(const llarp_buffer_t& pkt,
// std::function< huint128_t(void) > getFromIP) = 0;
// bool ProcessDataMessage(std::shared_ptr<ProtocolMessage> msg);
// TODO: move these to endpoint_base
// "find name"
// void lookup_name(std::string name, std::function<void(std::string, bool)> func = nullptr)
// override;
// "find introset?"
// void LookupServiceAsync(
// std::string name,
// std::string service,
// std::function<void(std::vector<dns::SRVData>)> resultHandler) override;
const Identity& GetIdentity() const
{
return _identity;
}
bool HandleDataDrop(std::shared_ptr<path::Path> p, const HopID& dst, uint64_t s);
bool CheckPathIsDead(std::shared_ptr<path::Path> p, std::chrono::milliseconds latency);
size_t RemoveAllConvoTagsFor(service::Address remote);
// bool WantsOutboundSession(const Address&) const;
void blacklist_snode(const RouterID& snode) override;
virtual std::chrono::milliseconds PathAlignmentTimeout() const
{
return service::DEFAULT_PATH_ALIGN_TIMEOUT;
}
static constexpr auto DefaultPathEnsureTimeout = 2s;
void AsyncProcessAuthMessage(std::shared_ptr<ProtocolMessage> msg, std::function<void(std::string, bool)> hook);
void SendAuthResult(
std::shared_ptr<path::Path> path, HopID replyPath, SessionTag tag, std::string result, bool success);
uint64_t GenTXID();
const std::set<RouterID>& SnodeBlacklist() const;
protected:
void regen_and_publish_introset();
private:
bool DoNetworkIsolation(bool failed);
virtual bool SetupNetworking()
{
// XXX: override me
return true;
}
virtual bool IsolationFailed()
{
// XXX: override me
return false;
}
/// return true if we are ready to do outbound and inbound traffic
bool ReadyForNetwork() const;
protected:
bool ReadyToDoLookup(size_t num_paths) const;
auto GetUniqueEndpointsForLookup() const;
/** TESTNET: these are member attributes/functions moved to EndpointBase. This is to
spread commonly used members amongst all types deriving from EndpointBase, like
{Tun,Null}Endpoint. */
// bool _publish_introset = true;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/** TESTNET: these are member attributes/functions moved to service::Handler. This is
a result of a separation of concerns between managing locally operated services
vs our sessions to services operated remotely. service::Endpoint will manage the
former, while service::Handler will manage the latter. */
/// this MUST be called if you want to call EnsurePathTo on the given address
// void MarkAddressOutbound(service::Address) override;
// bool // EnsurePathTo(
// std::variant<Address, RouterID> addr,
// std::function<void(std::optional<ConvoTag>)> hook,
// std::chrono::milliseconds timeout) override;
// /// return false if we have already called this function before for this
// /// address
// bool // EnsurePathToService(
// const Address remote,
// std::function<void(Address, OutboundContext*)> h,
// std::chrono::milliseconds timeoutMS = DefaultPathEnsureTimeout);
// /// ensure a path to a service node by public key
// bool // EnsurePathToSNode(
// const RouterID remote,
// std::function<void(const RouterID, std::shared_ptr<session::BaseSession>, ConvoTag)>
// h);
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
Identity _identity;
std::unique_ptr<link::TunnelManager> _tunnel_manager;
private:
std::chrono::milliseconds _last_introset_regen_attempt = 0s;
std::set<RouterID> snode_blacklist;
protected:
friend struct EndpointUtil;
};
} // namespace llarp::service

View File

@ -1,43 +0,0 @@
#include "endpoint_state.hpp"
namespace llarp::service
{
StatusObject EndpointState::ExtractStatus(StatusObject& obj) const
{
obj["lastPublished"] = to_json(last_publish);
obj["lastPublishAttempt"] = to_json(last_publish_attempt);
obj["introset"] = local_introset.ExtractStatus();
// static auto getSecond = [](const auto& item) -> auto
// {
// return item.second.ExtractStatus();
// };
// std::transform(
// dead_sessions.begin(),
// dead_sessions.end(),
// std::back_inserter(obj["deadSessions"]),
// getSecond);
// std::transform(
// remote_sessions.begin(),
// remote_sessions.end(),
// std::back_inserter(obj["remoteSessions"]),
// getSecond);
// std::transform(
// snode_sessions.begin(),
// snode_sessions.end(),
// std::back_inserter(obj["snodeSessions"]),
// [](const auto& item) { return item.second->ExtractStatus(); });
StatusObject sessionObj{};
// TODO:
// for (const auto& item : m_Sessions)
// {
// std::string k = item.first.ToHex();
// sessionObj[k] = item.second.ExtractStatus();
// }
obj["converstations"] = sessionObj;
return obj;
}
} // namespace llarp::service

View File

@ -1,55 +0,0 @@
#pragma once
#include "address.hpp"
#include "intro_set.hpp"
#include "lns_tracker.hpp"
#include "tag.hpp"
#include "types.hpp"
#include <llarp/router_id.hpp>
#include <llarp/util/compare_ptr.hpp>
#include <llarp/util/decaying_hashtable.hpp>
#include <llarp/util/types.hpp>
#include <oxenc/variant.h>
#include <memory>
#include <queue>
#include <set>
#include <unordered_map>
namespace llarp::service
{
struct EndpointState
{
std::set<RouterID> snode_blacklist;
std::string key_file;
std::string name;
std::string net_NS;
bool is_exit_enabled = false;
// PendingTrafficMap pending_traffic;
// ConnectionMap remote_sessions;
// ConnectionMap dead_sessions;
// std::set<SessionTag> inbound_convotags;
// SNodeConnectionMap snode_sessions;
// PendingRoutersMap pending_routers;
std::chrono::milliseconds last_publish = 0s;
std::chrono::milliseconds last_publish_attempt = 0s;
/// our introset
IntroSet local_introset;
/// on initialize functions
std::list<std::function<bool(void)>> on_init_callbacks;
/// conversations
std::unordered_map<SessionTag, Session> m_Sessions;
llarp::util::DecayingHashTable<std::string, std::variant<Address, RouterID>, std::hash<std::string>> nameCache;
LNSLookupTracker lnsTracker;
StatusObject ExtractStatus(StatusObject& obj) const;
};
} // namespace llarp::service

View File

@ -1,313 +0,0 @@
#include "handler.hpp"
#include "types.hpp"
#include <llarp/dns/dns.hpp>
#include <llarp/messages/common.hpp>
#include <llarp/net/net.hpp>
#include <llarp/nodedb.hpp>
#include <llarp/path/path_context.hpp>
#include <llarp/router/router.hpp>
#include <cassert>
namespace llarp::service
{
Handler::Handler(std::string /* name */, Router& /* r */) /* : handlers::RemoteHandler{std::move(name), r} */
{}
Handler::~Handler() = default;
// bool Handler::EnsurePathTo(
// AddressVariant_t addr,
// std::function<void(std::optional<service::SessionTag>)> hook,
// std::chrono::milliseconds)
// {
// if (std::holds_alternative<service::Address>(addr))
// return false;
// if (auto* rid = std::get_if<RouterID>(&addr))
// {
// if (snode_keys.count(PubKey{*rid}) or _router.PathToRouterAllowed(*rid))
// {
// // ObtainSNodeSession(
// // *rid, [hook, routerID = *rid](std::shared_ptr<session::BaseSession> session) {
// // if (session and session->IsReady())
// // {
// // if (auto path = session->GetPathByRouter(routerID))
// // {
// // hook(service::ConvoTag{path->RXID().as_array()});
// // }
// // else
// // hook(std::nullopt);
// // }
// // else
// // hook(std::nullopt);
// // });
// }
// else
// {
// // probably a client
// hook(GetBestConvoTagFor(addr));
// }
// }
// return true;
// }
void Handler::_configure()
{}
StatusObject Handler::ExtractStatus() const
{
// StatusObject obj{{"permitExit", permit_exit}, {"ip", if_addr.to_string()}};
// StatusObject exitsObj{};
// for (const auto& item : active_exits)
// {
// exitsObj[item.first.to_string()] = item.second->ExtractStatus();
// }
// obj["exits"] = exitsObj;
return {};
}
// bool Handler::should_hook_dns_msg(const dns::Message& msg) const
// {
// if (msg.questions.size() == 0)
// return false;
// // always hook ptr for ranges we own
// if (msg.questions[0].qtype == dns::qTypePTR)
// {
// if (auto ip = dns::DecodePTR(msg.questions[0].qname))
// return ip_range.Contains(*ip);
// return false;
// }
// if (msg.questions[0].qtype == dns::qTypeA || msg.questions[0].qtype == dns::qTypeCNAME
// || msg.questions[0].qtype == dns::qTypeAAAA)
// {
// if (msg.questions[0].IsName("localhost.loki"))
// return true;
// if (msg.questions[0].HasTLD(".snode"))
// return true;
// }
// return false;
// }
// bool Handler::MaybeHookDNS(
// std::shared_ptr<dns::PacketSource_Base> source,
// const dns::Message& query,
// const SockAddr& to,
// const SockAddr& from)
// {
// if (not ShouldHookDNSMessage(query))
// return false;
// (void)source;
// (void)to;
// (void)from;
// // auto job = std::make_shared<dns::QueryJob>(source, query, to, from);
// // if (not HandleHookedDNSMessage(query, [job](auto msg) { job->SendReply(msg.ToBuffer());
// }))
// // job->Cancel();
// return true;
// }
// bool Handler::handle_hooked_dns_msg(dns::Message msg, std::function<void(dns::Message)>
// reply)
// {
// if (msg.questions[0].qtype == dns::qTypePTR)
// {
// auto ip = dns::DecodePTR(msg.questions[0].qname);
// if (not ip)
// return false;
// if (ip == _if_addr)
// {
// RouterID us = _router.pubkey();
// msg.AddAReply(us.to_string(), 300);
// }
// else
// {
// auto itr = ip_to_key.find(*ip);
// if (itr != ip_to_key.end() && snode_keys.find(itr->second) != snode_keys.end())
// {
// RouterID them{itr->second.data()};
// msg.AddAReply(them.to_string());
// }
// else
// msg.AddNXReply();
// }
// }
// else if (msg.questions[0].qtype == dns::qTypeCNAME)
// {
// if (msg.questions[0].IsName("random.snode"))
// {
// if (auto random = _router.GetRandomGoodRouter())
// msg.AddCNAMEReply(random->to_string(), 1);
// else
// msg.AddNXReply();
// }
// else if (msg.questions[0].IsName("localhost.loki"))
// {
// RouterID us = _router.pubkey();
// msg.AddAReply(us.to_string(), 1);
// }
// else
// msg.AddNXReply();
// }
// else if (msg.questions[0].qtype == dns::qTypeA || msg.questions[0].qtype == dns::qTypeAAAA)
// {
// const bool isV6 = msg.questions[0].qtype == dns::qTypeAAAA;
// const bool isV4 = msg.questions[0].qtype == dns::qTypeA;
// if (msg.questions[0].IsName("random.snode"))
// {
// if (auto random = _router.GetRandomGoodRouter())
// {
// // TODO:
// // msg.AddCNAMEReply(random->to_string(), 1);
// // auto ip = ObtainServiceNodeIP(*random);
// // msg.AddINReply(ip, false);
// }
// else
// msg.AddNXReply();
// reply(msg);
// return true;
// }
// if (msg.questions[0].IsName("localhost.loki"))
// {
// msg.AddINReply(if_addr(), isV6);
// reply(msg);
// return true;
// }
// // forward dns for snode
// RouterID r;
// if (r.from_snode_address(msg.questions[0].Name()))
// {
// huint128_t ip;
// PubKey pubKey(r);
// if (isV4 && supports_ipv6())
// {
// msg.hdr_fields |= dns::flags_QR | dns::flags_AA | dns::flags_RA;
// }
// else if (snode_keys.find(pubKey) == snode_keys.end())
// {
// // we do not have it mapped, async obtain it
// ObtainSNodeSession(
// r,
// [&, msg = std::make_shared<dns::Message>(msg), reply](
// std::shared_ptr<session::BaseSession> session) {
// if (session && session->IsReady())
// {
// msg->AddINReply(key_to_IP[pubKey], isV6);
// }
// else
// {
// msg->AddNXReply();
// }
// reply(*msg);
// });
// return true;
// }
// else
// {
// // we have it mapped already as a service node
// auto itr = key_to_IP.find(pubKey);
// if (itr != key_to_IP.end())
// {
// ip = itr->second;
// msg.AddINReply(ip, isV6);
// }
// else // fallback case that should never happen (probably)
// msg.AddNXReply();
// }
// }
// else
// msg.AddNXReply();
// }
// reply(msg);
// return true;
// }
// void Handler::ObtainSNodeSession(const RouterID& rid)
// {
// (void)rid;
// // if (not _router.node_db()->is_connection_allowed(rid))
// // {
// // obtain_cb(nullptr);
// // return;
// // }
// // ObtainServiceNodeIP(rid);
// // snode_sessions[rid]->AddReadyHook(obtain_cb);
// }
bool Handler::Start()
{
// map our address
// const PubKey us(_router.pubkey());
// const huint128_t ip = if_addr();
// key_to_IP[us] = ip;
// ip_to_key[ip] = us;
// ip_activity[ip] = std::numeric_limits<std::chrono::milliseconds>::max();
// snode_keys.insert(us);
// TODO: move this into router
// if (should_init_tun)
// {
// vpn::InterfaceInfo info;
// info.ifname = if_name;
// info.addrs.emplace_back(ip_range);
// if_net = _router.vpn_platform()->CreateInterface(std::move(info), _router);
// if (not if_net)
// {
// llarp::LogError("Could not create interface");
// return false;
// }
// if (not _router.loop()->add_network_interface(
// if_net, [this](net::IPPacket pkt) { OnInetPacket(std::move(pkt)); }))
// {
// llarp::LogWarn("Could not create tunnel for exit endpoint");
// return false;
// }
// // _router.loop()->add_ticker([this] { Flush(); });
// #ifndef _WIN32
// resolver =
// std::make_shared<dns::Server>(_router.loop(), dns_conf,
// if_nametoindex(if_name.c_str()));
// resolver->Start();
// #endif
// }
return true;
}
// bool Handler::HasLocalMappedAddrFor(const PubKey& pk) const
// {
// return key_to_IP.find(pk) != key_to_IP.end();
// }
// huint128_t
// Handler::ObtainServiceNodeIP(const RouterID& other) // "find router"
// {
// const PubKey pubKey{other};
// const PubKey us{_router.pubkey()};
// // just in case
// if (pubKey == us)
// return if_addr;
// huint128_t ip = GetIPForIdent(pubKey);
// // if (snode_keys.emplace(pubKey).second)
// // {
// // auto session = std::make_shared<exit::SNodeSession>(
// // other,
// // [this, ip](const auto& buf) { return QueueSNodePacket(buf, ip); },
// // _router,
// // 2,
// // 1,
// // true,
// // this);
// // // this is a new service node make an outbound session to them
// // snode_sessions[other] = session;
// // }
// return ip;
// }
} // namespace llarp::service

View File

@ -1,85 +0,0 @@
#pragma once
#include <llarp/endpoint_base.hpp>
#include <llarp/handlers/remote.hpp>
#include <llarp/session/session.hpp>
#include <unordered_map>
namespace llarp
{
struct Router;
}
namespace llarp::service
{
/** Will handle all sessions to remote hidden services operated by either a
client or a snode. This is NOT handling any thing related to clearnet
exit nodes.
*/
struct Handler final : /* public handlers::RemoteHandler, */ public std::enable_shared_from_this<Handler>
{
Handler(std::string name, Router& r);
~Handler();
// std::shared_ptr<PathHandler> get_self()
// {
// return shared_from_this();
// }
// std::weak_ptr<PathHandler> get_weak()
// {
// return weak_from_this();
// }
StatusObject ExtractStatus() const;
// bool should_hook_dns_msg(const dns::Message& msg) const;
// bool handle_hooked_dns_msg(dns::Message msg, std::function<void(dns::Message)>);
/// sets up networking and starts traffic
bool Start();
// bool HasLocalMappedAddrFor(const PubKey& pk) const;
// huint128_t GetIPForIdent(const PubKey pk);
private:
void _configure();
// huint128_t AllocateNewAddress();
/// obtain ip for service node session, creates a new session if one does
/// not existing already
// huint128_t ObtainServiceNodeIP(const RouterID& router);
// void MarkIPActive(huint128_t ip);
// void KickIdentOffExit(const PubKey& pk);
// bool should_init_tun;
// std::shared_ptr<dns::Server> resolver;
// std::unordered_map<PubKey, huint128_t> key_to_IP;
// /// set of pubkeys we treat as snodes
// std::set<PubKey> snode_keys;
// std::unordered_map<huint128_t, PubKey> ip_to_key;
// huint128_t _if_addr;
// huint128_t highest_addr;
// huint128_t next_addr;
// IPRange ip_range;
// std::string if_name;
// std::unordered_map<huint128_t, std::chrono::milliseconds> ip_activity;
// std::shared_ptr<vpn::NetworkInterface> if_net;
// SockAddr resolver_addr;
// std::vector<SockAddr> upstream_resolvers;
// std::shared_ptr<link::TunnelManager> tunnel_manager;
};
} // namespace llarp::service

View File

@ -162,7 +162,7 @@ namespace llarp::service
auto bte = i.bt_encode();
const SharedSecret k{i.address_keys.address()};
const SharedSecret k{i.address_keys.address().pubkey()};
crypto::xchacha20(reinterpret_cast<uint8_t*>(bte.data()), bte.size(), k, encrypted.nonce);
std::memcpy(encrypted.introset_payload.data(), bte.data(), bte.size());

View File

@ -21,6 +21,7 @@ namespace llarp::service
{
vanity = *nonce;
}
return update_address();
}
@ -69,27 +70,29 @@ namespace llarp::service
std::string ServiceInfo::name() const
{
if (_cached_addr.is_zero())
if (_cached_addr.is_empty())
{
Address addr;
calculate_address(addr.as_array());
return addr.to_string();
PubKey pk;
calculate_address(pk);
return pk.to_string();
}
return _cached_addr.to_string();
}
bool ServiceInfo::calculate_address(std::array<uint8_t, 32>& data) const
bool ServiceInfo::calculate_address(PubKey& data) const
{
data = signkey.as_array();
data = PubKey{signkey.as_array()};
return true;
}
bool ServiceInfo::update_address()
{
if (_cached_addr.is_zero())
if (_cached_addr.is_empty())
{
return calculate_address(_cached_addr.as_array());
return calculate_address(_cached_addr.pubkey());
}
return true;
}

View File

@ -1,8 +1,8 @@
#pragma once
#include "address.hpp"
#include "vanity.hpp"
#include <llarp/address/address.hpp>
#include <llarp/crypto/types.hpp>
#include <oxenc/bt.h>
@ -16,7 +16,7 @@ namespace llarp::service
private:
PubKey enckey;
PubKey signkey;
mutable Address _cached_addr;
mutable NetworkAddress _cached_addr;
public:
VanityNonce vanity;
@ -31,10 +31,9 @@ namespace llarp::service
const PubKey& encryption_pubkey() const
{
if (_cached_addr.is_zero())
{
calculate_address(_cached_addr.as_array());
}
if (_cached_addr.is_empty())
calculate_address(_cached_addr.pubkey());
return enckey;
}
@ -63,17 +62,16 @@ namespace llarp::service
bool update_address();
const Address& address() const
const NetworkAddress& address() const
{
if (_cached_addr.is_zero())
{
calculate_address(_cached_addr.as_array());
}
if (_cached_addr.is_empty())
calculate_address(_cached_addr.pubkey());
return _cached_addr;
}
/// calculate our address
bool calculate_address(std::array<uint8_t, 32>& data) const;
bool calculate_address(PubKey& data) const;
bool bt_decode(std::string_view buf);

View File

@ -1,43 +0,0 @@
#include "lns_tracker.hpp"
namespace llarp::service
{
std::function<void(std::optional<LNSLookupTracker::Addr_t>)> LNSLookupTracker::MakeResultHandler(
std::string name, std::size_t numPeers, std::function<void(std::optional<Addr_t>)> resultHandler)
{
m_PendingLookups.emplace(name, LookupInfo{numPeers, resultHandler});
return [name, this](std::optional<Addr_t> found) {
auto itr = m_PendingLookups.find(name);
if (itr == m_PendingLookups.end())
return;
itr->second.HandleOneResult(found);
if (itr->second.IsDone())
m_PendingLookups.erase(itr);
};
}
bool LNSLookupTracker::LookupInfo::IsDone() const
{
return m_ResultsGotten == m_ResultsNeeded;
}
void LNSLookupTracker::LookupInfo::HandleOneResult(std::optional<Addr_t> result)
{
if (result)
{
m_CurrentValues.insert(*result);
}
m_ResultsGotten++;
if (IsDone())
{
if (m_CurrentValues.size() == 1)
{
m_HandleResult(*m_CurrentValues.begin());
}
else
{
m_HandleResult(std::nullopt);
}
}
}
} // namespace llarp::service

View File

@ -1,50 +0,0 @@
#pragma once
#include "address.hpp"
#include <llarp/router_id.hpp>
#include <oxenc/variant.h>
#include <functional>
#include <optional>
#include <string>
#include <unordered_map>
#include <unordered_set>
namespace llarp::service
{
/// tracks and manages consensus of lns names we fetch from the network
class LNSLookupTracker
{
public:
using Addr_t = std::variant<Address, RouterID>;
private:
struct LookupInfo
{
std::unordered_set<Addr_t> m_CurrentValues;
std::function<void(std::optional<Addr_t>)> m_HandleResult;
std::size_t m_ResultsGotten = 0;
std::size_t m_ResultsNeeded;
LookupInfo(std::size_t wantResults, std::function<void(std::optional<Addr_t>)> resultHandler)
: m_HandleResult{std::move(resultHandler)}, m_ResultsNeeded{wantResults}
{}
bool IsDone() const;
void HandleOneResult(std::optional<Addr_t> result);
};
std::unordered_map<std::string, LookupInfo> m_PendingLookups;
public:
/// make a function that will handle consensus of an lns request
/// name is the name we are requesting
/// numPeers is the number of peers we asked
/// resultHandler is a function that we are wrapping that will handle the final result
std::function<void(std::optional<Addr_t>)> MakeResultHandler(
std::string name, std::size_t numPeers, std::function<void(std::optional<Addr_t>)> resultHandler);
};
} // namespace llarp::service

View File

@ -1,459 +0,0 @@
#include "protocol.hpp"
#include "endpoint.hpp"
#include <llarp/path/path.hpp>
#include <llarp/router/router.hpp>
#include <llarp/util/buffer.hpp>
#include <llarp/util/logging.hpp>
#include <utility>
namespace llarp::service
{
static auto logcat = log::Cat("Protocol");
ProtocolMessage::ProtocolMessage()
{
tag.zero();
}
ProtocolMessage::ProtocolMessage(const SessionTag& t) : tag(t)
{}
ProtocolMessage::~ProtocolMessage() = default;
void ProtocolMessage::put_buffer(std::string buf)
{
payload.resize(buf.size());
memcpy(payload.data(), buf.data(), buf.size());
}
void ProtocolMessage::process_async(
std::shared_ptr<path::Path> path, HopID from, std::shared_ptr<ProtocolMessage> self)
{
(void)path;
(void)from;
(void)self;
// if (!self->handler->HandleDataMessage(path, from, self))
// LogWarn("failed to handle data message from ", path->name());
}
bool ProtocolMessage::bt_decode(std::string_view buf)
{
try
{
oxenc::bt_dict_consumer btdc{buf};
bt_decode(btdc);
}
catch (const std::exception& e)
{
// DISCUSS: rethrow or print warning/return false...?
auto err = "ProtocolMessage parsing exception: {}"_format(e.what());
log::warning(logcat, "{}", err);
throw std::runtime_error{err};
}
return true;
}
void ProtocolMessage::bt_decode(oxenc::bt_dict_consumer& btdc)
{
try
{
proto = ProtocolType{btdc.require<uint64_t>("p")};
if (auto maybe_payload = btdc.maybe<ustring>("d"))
{
payload = std::vector<uint8_t>(*maybe_payload->data(), maybe_payload->size());
}
{
auto [key, subdict] = btdc.next_dict_consumer();
if (key != "i")
throw std::invalid_argument{"Unexpected key (expected:'i', actual:'{}')"_format(key)};
intro_reply.bt_decode(subdict);
}
{
auto [key, subdict] = btdc.next_dict_consumer();
if (key != "s")
throw std::invalid_argument{"Unexpected key (expected:'s', actual:'{}')"_format(key)};
sender.bt_decode(subdict);
}
tag.from_string(btdc.require<std::string>("t"));
}
catch (...)
{
log::critical(logcat, "ProtocolMessage failed to populate with bt encoded contents");
throw;
}
}
std::string ProtocolMessage::bt_encode() const
{
oxenc::bt_dict_producer btdp;
try
{
btdp.append("a", static_cast<uint64_t>(proto));
if (not payload.empty())
btdp.append("d", std::string_view{reinterpret_cast<const char*>(payload.data()), payload.size()});
{
auto subdict = btdp.append_dict("i");
intro_reply.bt_encode(subdict);
}
{
auto subdict = btdp.append_dict("s");
sender.bt_encode(subdict);
}
btdp.append("t", tag.to_view());
}
catch (...)
{
log::critical(logcat, "Error: ProtocolMessage failed to bt encode contents!");
}
return std::move(btdp).str();
}
std::vector<char> ProtocolMessage::encode_auth_info() const
{
oxenc::bt_dict_producer btdp;
try
{
// btdp.append("a", static_cast<uint64_t>(proto));
{
auto subdict = btdp.append_dict("s");
sender.bt_encode(subdict);
}
btdp.append("t", tag.to_view());
}
catch (...)
{
log::critical(logcat, "Error: ProtocolMessage failed to bt encode auth info");
}
auto view = btdp.view();
std::vector<char> data;
data.resize(view.size());
std::copy_n(view.data(), view.size(), data.data());
return data;
}
std::string ProtocolFrameMessage::bt_encode() const
{
oxenc::bt_dict_producer btdp;
try
{
btdp.append("A", "H");
btdp.append("C", cipher.to_view());
btdp.append("D", std::string_view{reinterpret_cast<const char*>(enc.data()), enc.size()});
btdp.append("F", hop_id.to_view());
btdp.append("N", nonce.to_view());
btdp.append("R", flag);
btdp.append("T", convo_tag.to_view());
btdp.append("Z", sig.to_view());
}
catch (...)
{
log::critical(logcat, "Error: ProtocolFrameMessage failed to bt encode contents!");
}
return std::move(btdp).str();
}
bool ProtocolFrameMessage::decrypt_payload_to_message(const SharedSecret& sharedkey, ProtocolMessage& msg) const
{
Encrypted<2048> tmp = enc;
crypto::xchacha20(tmp.data(), tmp.size(), sharedkey, nonce);
auto buf = tmp.to_string();
return msg.bt_decode(buf);
}
bool ProtocolFrameMessage::sign(const Identity& localIdent)
{
sig.zero();
std::array<uint8_t, MAX_PROTOCOL_MESSAGE_SIZE> tmp;
llarp_buffer_t buf(tmp);
// encode
auto bte = bt_encode();
buf.write(bte.begin(), bte.end());
// rewind
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
// sign
return localIdent.Sign(sig, reinterpret_cast<uint8_t*>(bte.data()), bte.size());
}
bool ProtocolFrameMessage::encrypt_and_sign(
const ProtocolMessage& msg, const SharedSecret& sessionKey, const Identity& localIdent)
{
// encode message
auto bte1 = msg.bt_encode();
// encrypt
crypto::xchacha20(reinterpret_cast<uint8_t*>(bte1.data()), bte1.size(), sessionKey, nonce);
// put encrypted buffer
std::memcpy(enc.data(), bte1.data(), bte1.size());
// zero out signature
sig.zero();
auto bte2 = bt_encode();
// sign
if (!localIdent.Sign(sig, reinterpret_cast<uint8_t*>(bte2.data()), bte2.size()))
{
log::error(logcat, "ProtocolFrameMessage failed to sign with local identity key!");
return false;
}
return true;
}
struct AsyncFrameDecrypt
{
std::shared_ptr<path::Path> path;
std::shared_ptr<ProtocolMessage> msg;
const Identity& _local_identity;
Endpoint* handler;
const ProtocolFrameMessage frame;
const Introduction src_intro;
AsyncFrameDecrypt(
const Identity& localIdent,
Endpoint* h,
std::shared_ptr<ProtocolMessage> m,
const ProtocolFrameMessage& f,
const Introduction& recvIntro)
: msg(std::move(m)), _local_identity(localIdent), handler(h), frame(f), src_intro(recvIntro)
{}
static void work(std::shared_ptr<AsyncFrameDecrypt> self)
{
SharedSecret K;
SharedSecret shared_key;
// copy
ProtocolFrameMessage frame(self->frame);
if (!crypto::pqe_decrypt(self->frame.cipher, K, pq_keypair_to_seckey(self->_local_identity.pq)))
{
log::error(logcat, "pqe_decrypt failed (cipher:{})", self->frame.cipher);
self->msg.reset();
return;
}
// decrypt
// auto buf = frame.enc.Buffer();
uint8_t* buf = frame.enc.data();
size_t sz = frame.enc.size();
crypto::xchacha20(buf, sz, K, self->frame.nonce);
auto bte = self->msg->bt_encode();
if (bte.empty())
{
log::error(logcat, "Failed to decode inner protocol message");
// DumpBuffer(*buf);
self->msg.reset();
return;
}
// verify signature of outer message after we parsed the inner message
if (!self->frame.verify(self->msg->sender))
{
log::error(
logcat,
"Intro frame has invalid signature (sig:{}, from:{})",
self->frame.sig,
self->msg->sender.address());
self->msg.reset();
return;
}
// if (self->handler->HasConvoTag(self->msg->tag))
// {
// LogError("dropping duplicate convo tag T=", self->msg->tag);
// // TODO: send convotag reset
// self->msg.reset();
// return;
// }
// PKE (A, B, N)
SharedSecret shared_secret;
if (!crypto::dh_server(
shared_secret,
self->msg->sender.encryption_pubkey(),
self->_local_identity.enckey,
self->frame.nonce))
{
log::error(logcat, "X25519 key exchange failed!");
self->msg.reset();
return;
}
std::array<uint8_t, 64> tmp;
// K
std::memcpy(tmp.begin(), K.begin(), K.size());
// S = HS( K + PKE( A, B, N))
std::memcpy(tmp.begin() + 32, shared_secret.begin(), shared_secret.size());
crypto::shorthash(shared_key, tmp.data(), tmp.size());
std::shared_ptr<ProtocolMessage> msg = std::move(self->msg);
std::shared_ptr<path::Path> path = std::move(self->path);
const HopID from = self->frame.hop_id;
msg->handler = self->handler;
// self->handler->AsyncProcessAuthMessage(
// msg,
// [path, msg, from, handler = self->handler, fromIntro = self->fromIntro,
// shared_key](
// std::string result, bool success) {
// if (success)
// {
// if (handler->WantsOutboundSession(msg->sender.Addr()))
// {
// handler->PutSenderFor(msg->tag, msg->sender, false);
// }
// else
// {
// handler->PutSenderFor(msg->tag, msg->sender, true);
// }
// handler->PutReplyIntroFor(msg->tag, msg->introReply);
// handler->PutCachedSessionKeyFor(msg->tag, shared_key);
// handler->SendAuthResult(path, from, msg->tag, result, success);
// log::info(
// logcat, "Auth accepted for tag {} from sender {}", msg->tag,
// msg->sender.Addr());
// ProtocolMessage::ProcessAsync(path, from, msg);
// }
// else
// {
// log::warning(logcat, "Auth invalid for tag {} (code: {})", msg->tag, result);
// }
// handler->Pump(time_now_ms());
// });
}
};
struct AsyncDecrypt
{
ServiceInfo si;
SharedSecret shared;
ProtocolFrameMessage frame;
};
bool ProtocolFrameMessage::async_decrypt_verify(
std::shared_ptr<path::Path> recvPath,
const Identity& localIdent,
Endpoint* handler,
std::function<void(std::shared_ptr<ProtocolMessage>)> hook) const
{
auto msg = std::make_shared<ProtocolMessage>();
msg->handler = handler;
if (convo_tag.is_zero())
{
// we need to dh
auto dh = std::make_shared<AsyncFrameDecrypt>(localIdent, handler, msg, *this, recvPath->intro);
dh->path = recvPath;
handler->router().queue_work([dh = std::move(dh)] { return AsyncFrameDecrypt::work(dh); });
return true;
}
auto v = std::make_shared<AsyncDecrypt>();
// if (!handler->GetCachedSessionKeyFor(convo_tag, v->shared))
// {
// LogError("No cached session for T=", convo_tag);
// return false;
// }
// if (v->shared.IsZero())
// {
// LogError("bad cached session key for T=", convo_tag);
// return false;
// }
// if (!handler->GetSenderFor(convo_tag, v->si))
// {
// LogError("No sender for T=", convo_tag);
// return false;
// }
// if (v->si.Addr().IsZero())
// {
// LogError("Bad sender for T=", convo_tag);
// return false;
// }
v->frame = *this;
auto callback = [loop = handler->loop(), hook](std::shared_ptr<ProtocolMessage> msg) {
if (hook)
{
loop->call([msg, hook]() { hook(msg); });
}
};
// handler->router()->queue_work(
// [v, msg = std::move(msg), recvPath = std::move(recvPath), callback, handler]() {
// auto resetTag =
// [handler, tag = v->frame.convo_tag, from = v->frame.path_id, path = recvPath]()
// {
// handler->ResetConvoTag(tag, path, from);
// };
// if (not v->frame.Verify(v->si))
// {
// LogError("Signature failure from ", v->si.Addr());
// handler->Loop()->call_soon(resetTag);
// return;
// }
// if (not v->frame.DecryptPayloadInto(v->shared, *msg))
// {
// LogError("failed to decrypt message from ", v->si.Addr());
// handler->Loop()->call_soon(resetTag);
// return;
// }
// callback(msg);
// RecvDataEvent ev;
// ev.fromPath = std::move(recvPath);
// ev.pathid = v->frame.path_id;
// auto* handler = msg->handler;
// ev.msg = std::move(msg);
// handler->QueueRecvData(std::move(ev));
// });
return true;
}
bool ProtocolFrameMessage::operator==(const ProtocolFrameMessage& other) const
{
return cipher == other.cipher && enc == other.enc && nonce == other.nonce && sig == other.sig
&& convo_tag == other.convo_tag;
}
bool ProtocolFrameMessage::verify(const ServiceInfo& svc) const
{
ProtocolFrameMessage copy(*this);
copy.sig.zero();
auto bte = copy.bt_encode();
return svc.verify(reinterpret_cast<uint8_t*>(bte.data()), bte.size(), sig);
}
bool ProtocolFrameMessage::handle_message(Router* /*r*/) const
{
return true;
}
} // namespace llarp::service

View File

@ -1,137 +0,0 @@
#pragma once
#include "identity.hpp"
#include "intro.hpp"
#include <llarp/crypto/encrypted.hpp>
#include <llarp/crypto/types.hpp>
#include <llarp/ev/loop.hpp>
#include <llarp/path/path_handler.hpp>
#include <llarp/service/tag.hpp>
#include <llarp/util/time.hpp>
#include <vector>
struct llarp_threadpool;
/** TODO:
- All of the references to service::Endpoint must be changed to EndpointBase
- Now that there are four objects handling local/remote hidden service/exit node sessions,
each of the four will need to handle ProtocolMessage objects and the ProtocolMessageFrames
that contain them
*/
namespace llarp
{
namespace path
{
/// forward declare
struct Path;
} // namespace path
namespace service
{
struct Endpoint;
inline constexpr std::size_t MAX_PROTOCOL_MESSAGE_SIZE{4096};
/// inner message
struct ProtocolMessage
{
ProtocolMessage(const SessionTag& tag);
ProtocolMessage();
~ProtocolMessage();
ProtocolType proto = ProtocolType::TrafficV4;
std::chrono::milliseconds queued = 0s;
std::vector<uint8_t> payload; // encrypted AbstractLinkMessage
Introduction intro_reply;
ServiceInfo sender;
Endpoint* handler = nullptr;
SessionTag tag;
std::chrono::milliseconds creation_time{time_now_ms()};
/// encode metainfo for lmq endpoint auth
std::vector<char> encode_auth_info() const;
std::string bt_encode() const;
bool bt_decode(std::string_view buf);
void bt_decode(oxenc::bt_dict_consumer& btdc);
void put_buffer(std::string buf);
static void process_async(std::shared_ptr<path::Path> p, HopID from, std::shared_ptr<ProtocolMessage> self);
bool operator>(const ProtocolMessage& other) const
{
return creation_time > other.creation_time;
}
};
/// outer message
struct ProtocolFrameMessage
{
PQCipherBlock cipher;
Encrypted<2048> enc;
uint64_t flag; // set to indicate in plaintext a nack, aka "dont try again"
SymmNonce nonce;
Signature sig;
HopID hop_id;
service::SessionTag convo_tag;
ProtocolFrameMessage(const ProtocolFrameMessage& other) = default;
ProtocolFrameMessage()
{
clear();
}
~ProtocolFrameMessage() = default;
bool operator==(const ProtocolFrameMessage& other) const;
bool operator!=(const ProtocolFrameMessage& other) const
{
return !(*this == other);
}
ProtocolFrameMessage& operator=(const ProtocolFrameMessage& other) = default;
bool encrypt_and_sign(
const ProtocolMessage& msg, const SharedSecret& sharedkey, const Identity& localIdent);
bool sign(const Identity& localIdent);
bool async_decrypt_verify(
std::shared_ptr<path::Path> fromPath,
const Identity& localIdent,
Endpoint* handler,
std::function<void(std::shared_ptr<ProtocolMessage>)> hook = nullptr) const;
bool decrypt_payload_to_message(const SharedSecret& sharedkey, ProtocolMessage& into) const;
/** Note: this method needs to be re-examined where it is called in the other class
methods, like ::Sign(), ::EncryptAndSign(), and ::Verify(). In all 3 of these cases,
the subsequent methods that the llarp_buffer_t is passed to must be refactored to
take either a string, a redesigned llarp_buffer, or some span backport.
*/
std::string bt_encode() const;
void clear()
{
cipher.zero();
enc.Clear();
hop_id.zero();
convo_tag.zero();
nonce.zero();
sig.zero();
flag = 0;
}
bool verify(const ServiceInfo& from) const;
bool handle_message(Router* r) const;
};
} // namespace service
} // namespace llarp

View File

@ -8,7 +8,7 @@ namespace llarp::service
{"lastSend", to_json(lastSend)},
{"lastRecv", to_json(lastRecv)},
{"replyIntro", replyIntro.ExtractStatus()},
{"remote", Addr().to_string()},
// {"remote", Addr().to_string()},
{"seqno", seqno},
{"tx", messagesSend},
{"rx", messagesRecv},
@ -16,10 +16,10 @@ namespace llarp::service
return obj;
}
Address Session::Addr() const
{
return remote.address();
}
// Address Session::Addr() const
// {
// return remote.address();
// }
bool Session::IsExpired(std::chrono::milliseconds now, std::chrono::milliseconds lifetime) const
{

View File

@ -44,7 +44,7 @@ namespace llarp::service
bool IsExpired(std::chrono::milliseconds now, std::chrono::milliseconds lifetime = SessionLifetime) const;
Address Addr() const;
// Address Addr() const;
};
} // namespace llarp::service

View File

@ -20,7 +20,7 @@ namespace llarp::vpn
_ports.erase(localport);
}
void HandleIPPacketFrom(AddressVariant_t from, UDPPacket pkt) override
void HandleIPPacketFrom(NetworkAddress from, IPPacket pkt) override
{
(void)from;
(void)pkt;
@ -46,7 +46,7 @@ namespace llarp::vpn
explicit EgresGenericLayer4Handler(EgresPacketHandlerFunc baseHandler) : _handler{std::move(baseHandler)}
{}
void HandleIPPacketFrom(AddressVariant_t from, UDPPacket pkt) override
void HandleIPPacketFrom(NetworkAddress from, IPPacket pkt) override
{
// TOFIX: this
(void)from;
@ -58,7 +58,7 @@ namespace llarp::vpn
EgresPacketRouter::EgresPacketRouter(EgresPacketHandlerFunc baseHandler) : _handler{std::move(baseHandler)}
{}
void EgresPacketRouter::HandleIPPacketFrom(AddressVariant_t from, UDPPacket pkt)
void EgresPacketRouter::HandleIPPacketFrom(NetworkAddress from, IPPacket pkt)
{
(void)from;
(void)pkt;

View File

@ -1,5 +1,6 @@
#pragma once
#include <llarp/address/address.hpp>
#include <llarp/address/ip_packet.hpp>
#include <llarp/endpoint_base.hpp>
#include <llarp/net/net_int.hpp>
@ -9,13 +10,13 @@
namespace llarp::vpn
{
using EgresPacketHandlerFunc = std::function<void(AddressVariant_t, IPPacket)>;
using EgresPacketHandlerFunc = std::function<void(NetworkAddress, IPPacket)>;
struct EgresLayer4Handler
{
virtual ~EgresLayer4Handler() = default;
virtual void HandleIPPacketFrom(AddressVariant_t from, UDPPacket pkt) = 0;
virtual void HandleIPPacketFrom(NetworkAddress from, IPPacket pkt) = 0;
virtual void AddSubHandler(uint16_t, EgresPacketHandlerFunc){};
virtual void RemoveSubHandler(uint16_t){};
@ -31,7 +32,7 @@ namespace llarp::vpn
explicit EgresPacketRouter(EgresPacketHandlerFunc baseHandler);
/// feed in an ip packet for handling
void HandleIPPacketFrom(AddressVariant_t, UDPPacket pkt);
void HandleIPPacketFrom(NetworkAddress, IPPacket pkt);
/// add a non udp packet handler using ip protocol proto
void AddIProtoHandler(uint8_t proto, EgresPacketHandlerFunc func);