TUN/Session IP routing negotiation

- TUN endpoint assigns a local IP to route traffic for inbound/outbound sessions
- Config mappings pre-loaded and superside ip iteration
This commit is contained in:
dr7ana 2024-05-29 13:38:17 -07:00
parent ce16778412
commit 4979f9aab8
35 changed files with 384 additions and 197 deletions

View File

@ -6,9 +6,9 @@ if(APPLE)
else()
add_executable(lokinet lokinet.cpp)
endif()
add_executable(lokinet-vpn lokinet-vpn.cpp)
enable_lto(lokinet lokinet-vpn)
list(APPEND exetargets lokinet-vpn)
# add_executable(lokinet-vpn lokinet-vpn.cpp)
# enable_lto(lokinet lokinet-vpn)
# list(APPEND exetargets lokinet-vpn)
if(WITH_BOOTSTRAP)
add_executable(lokinet-bootstrap lokinet-bootstrap.cpp)
@ -81,7 +81,7 @@ foreach(exe ${exetargets})
endforeach()
target_link_libraries(lokinet PRIVATE CLI11)
target_link_libraries(lokinet-vpn PRIVATE CLI11)
# target_link_libraries(lokinet-vpn PRIVATE CLI11)
if(WITH_SETCAP)
install(CODE "execute_process(COMMAND ${SETCAP} cap_net_admin,cap_net_bind_service=+eip ${CMAKE_INSTALL_PREFIX}/bin/lokinet)")

View File

@ -1,6 +1,5 @@
#include <llarp/constants/files.hpp>
#include <llarp/constants/version.hpp>
#include <llarp/util/fs.hpp>
#include <cpr/cpr.h>
@ -93,8 +92,8 @@ int main(int argc, char* argv[])
try
{
std::cout << "writing bootstrap file to: " << outputfile << std::endl;
fs::ofstream ofs{outputfile, std::ios::binary};
ofs.exceptions(fs::ofstream::failbit);
std::ofstream ofs{outputfile, std::ios::binary};
ofs.exceptions(std::ofstream::failbit);
ofs << data;
return 0;
}

View File

@ -26,15 +26,12 @@ if(SUBMODULE_CHECK)
message(STATUS "Checking submodules")
check_submodule(CLI11)
check_submodule(cpr)
check_submodule(ghc-filesystem)
check_submodule(nlohmann)
check_submodule(oxen-encoding)
check_submodule(oxen-libquic)
check_submodule(oxen-mq)
check_submodule(pybind11)
check_submodule(span-lite)
check_submodule(sqlite_orm)
check_submodule(uvw)
endif()
endif()
@ -90,8 +87,6 @@ target_link_libraries(uvw INTERFACE libuv)
add_subdirectory(oxen-libquic)
add_subdirectory(span-lite)
# cpr configuration. Ideally we'd just do this via add_subdirectory, but cpr's cmake requires
# 3.15+, and we target lower than that (and this is fairly simple to build).
if(WITH_BOOTSTRAP)

@ -1 +1 @@
Subproject commit a4dc44eaabcf4dc59478ec8c36247e5c4b97e781
Subproject commit c3d9ff5ca8353735caab09fdede4a0519a691a9d

View File

@ -206,7 +206,7 @@ lokinet_add_library(lokinet-config
# All path objects; link directly to lokinet-core
lokinet_add_library(lokinet-path
path/path.cpp
# path/path_context.cpp
path/path_context.cpp
path/path_handler.cpp
path/transit_hop.cpp
)

View File

@ -54,9 +54,9 @@ namespace llarp
return false;
if (is_ipv4())
return _contains(std::get<ipv4>(other.get_ip()));
return _contains(std::get<ipv4>(other.base_ip()));
return _contains(std::get<ipv6>(other.get_ip()));
return _contains(std::get<ipv6>(other.base_ip()));
}
bool IPRange::_contains(const ipv4& other) const

View File

@ -24,29 +24,27 @@ namespace llarp
void _init_ip();
oxen::quic::Address init_max();
// internal functions that do no type checking for ipv4 vs ipv6
bool _contains(const ipv4& other) const;
bool _contains(const ipv6& other) const;
// getters to DRY out varianta access
// getters to DRY out variant access
ipv4_range& _ipv4_range() { return std::get<ipv4_range>(_ip_range); }
const ipv4_range& _ipv4_range() const { return std::get<ipv4_range>(_ip_range); }
ipv6_range& _ipv6_range() { return std::get<ipv6_range>(_ip_range); }
const ipv6_range& _ipv6_range() const { return std::get<ipv6_range>(_ip_range); }
public:
IPRange() : IPRange{"", 0} {}
IPRange() : IPRange{oxen::quic::Address{}, 0} {}
explicit IPRange(std::string a, uint8_t m = 0) : IPRange{oxen::quic::Address{std::move(a), 0}, m} {}
explicit IPRange(oxen::quic::Address a, uint8_t m) : _addr{a}, _mask{m}, _is_ipv4{_addr.is_ipv4()}
explicit IPRange(oxen::quic::Address a, uint8_t m) : _addr{std::move(a)}, _mask{m}, _is_ipv4{_addr.is_ipv4()}
{
_init_ip();
}
IPRange(ipv4_range ipv4)
IPRange(const ipv4_range& ipv4)
: _addr{ipv4.base},
_mask{ipv4.mask},
_is_ipv4{true},
@ -55,10 +53,10 @@ namespace llarp
_max_ip{ipv4.max_ip()}
{}
IPRange(ipv6_range ipv6)
IPRange(const ipv6_range& ipv6)
: _addr{ipv6.base},
_mask{ipv6.mask},
_is_ipv4{true},
_is_ipv4{false},
_base_ip{ipv6.base},
_ip_range{ipv6},
_max_ip{ipv6.max_ip()}
@ -79,7 +77,7 @@ namespace llarp
ip_range_v get_ip_range() const { return _ip_range; }
ip_v get_ip() const { return _base_ip; }
ip_v base_ip() const { return _base_ip; }
ip_v max_ip() const { return _max_ip; }
@ -108,6 +106,10 @@ namespace llarp
}
};
/** IPRangeIterator
- When lokinet is assigning IP's within a range, this object functions as a robust managing context for the
distribution and tracking of IP's within that range
*/
struct IPRangeIterator
{
private:
@ -155,8 +157,10 @@ namespace llarp
}
public:
IPRangeIterator() = default;
IPRangeIterator(const IPRange& range)
: _ip_range{range}, _is_ipv4{range.is_ipv4()}, _current_ip{range.get_ip()}, _max_ip{range.max_ip()}
: _ip_range{range}, _is_ipv4{range.is_ipv4()}, _current_ip{range.base_ip()}, _max_ip{range.max_ip()}
{}
// Returns the next ip address in the iterating range; returns std::nullopt if range is exhausted
@ -177,7 +181,7 @@ namespace llarp
void reset()
{
_current_ip = _ip_range.get_ip();
_current_ip = _ip_range.base_ip();
_max_ip = _ip_range.max_ip();
}
@ -190,24 +194,27 @@ namespace llarp
};
template <typename local_t>
concept LocalAddrType = std::is_same_v<oxen::quic::Address, local_t> || std::is_same_v<IPRange, local_t>;
concept LocalAddrType = std::is_same_v<oxen::quic::Address, local_t> || std::is_same_v<IPRange, local_t>
|| std::is_same_v<ip_v, local_t>;
} // namespace llarp
namespace std
{
inline constexpr size_t golden_ratio_inverse = sizeof(size_t) >= 8 ? 0x9e37'79b9'7f4a'7c15 : 0x9e37'79b9;
template <>
struct hash<llarp::IPRange>
{
size_t operator()(const llarp::IPRange& r) const
{
auto& addr = r.address();
auto& m = r.mask();
size_t h;
if (r.is_ipv4())
return hash<llarp::ipv4>{}(addr.to_ipv4().to_base(m));
return hash<llarp::ipv6>{}(addr.to_ipv6().to_base(m));
h = hash<llarp::ipv4>{}(std::get<llarp::ipv4>(r.base_ip()));
else
h = hash<llarp::ipv6>{}(std::get<llarp::ipv6>(r.base_ip()));
h ^= hash<uint8_t>{}(r.mask()) + inverse_golden_ratio + (h << 6) + (h >> 2);
return h;
}
};

View File

@ -9,8 +9,14 @@
namespace llarp
{
/** TODO:
- if libquic Address is never used for this templated class, then either:
- this map can potentially be made (mostly) constexpr
- a new map just for IP addresses can be made fully constexpr
*/
/** This class will accept any types satisfying the concepts LocalAddrType and RemoteAddrType
LocalAddrType: oxen::quic::Address or IPRange
LocalAddrType: oxen::quic::Address, IPRange, or ip_v (ipv{4,6} variant)
NetworkAddrType: must be inherited from NetworkAddress
*/
template <LocalAddrType local_addr_t, NetworkAddrType net_addr_t>
@ -92,6 +98,13 @@ namespace llarp
return ret;
}
bool has_local(const local_addr_t& local) const
{
Lock_t l{addr_mutex};
return _local_to_remote.contains(local);
}
bool has_remote(const net_addr_t& remote) const
{
Lock_t l{addr_mutex};

View File

@ -127,7 +127,7 @@ namespace std
size_t operator()(const llarp::ipv6& obj) const
{
auto h = hash<decltype(obj.hi)>{}(obj.hi);
h ^= hash<decltype(obj.lo)>{}(obj.lo);
h ^= hash<decltype(obj.lo)>{}(obj.lo) + inverse_golden_ratio + (h << 6) + (h >> 2);
return h;
}
};
@ -140,8 +140,7 @@ namespace std
if (auto maybe_v4 = std::get_if<llarp::ipv4>(&obj))
return hash<llarp::ipv4>{}(*maybe_v4);
auto maybe_v6 = std::get_if<llarp::ipv6>(&obj);
return hash<llarp::ipv6>{}(*maybe_v6);
return hash<llarp::ipv6>{}(std::get<llarp::ipv6>(obj));
}
};
} // namespace std

View File

@ -26,7 +26,7 @@ namespace llarp
inline constexpr auto SNODE = ".snode"sv;
inline constexpr auto LOKI = ".loki"sv;
std::set<std::string_view> allowed = {SNODE, LOKI};
static std::set<std::string_view> allowed = {SNODE, LOKI};
} // namespace TLD
uint16_t checksum_ipv4(const void *header, uint8_t header_len);

View File

@ -9,7 +9,7 @@ namespace llarp::auth
{
for (const auto& f : _files)
{
fs::ifstream i{f};
std::ifstream i{f};
std::string line{};
while (std::getline(i, line))
{

View File

@ -584,7 +584,7 @@ namespace llarp
{
_local_ip_range = *maybe_range;
_local_addr = _local_ip_range->address();
_local_ip = _local_ip_range->get_ip();
_local_base_ip = _local_ip_range->base_ip();
}
else
throw std::invalid_argument{fmt::format("[network]:ifaddr invalid value: '{}'", arg)};
@ -645,8 +645,14 @@ namespace llarp
if (auto maybe_raddr = NetworkAddress::from_network_addr(std::move(addr_arg)); maybe_raddr)
{
oxen::quic::Address addr{std::move(ip_arg), 0};
_reserved_local_addrs.emplace(std::move(*maybe_raddr), std::move(addr));
ip_v ipv;
// ipv6
if (ip_arg.find(':') != std::string_view::npos)
ipv = ipv6{std::move(ip_arg)};
else
ipv = ipv4{std::move(ip_arg)};
_reserved_local_ips.emplace(std::move(*maybe_raddr), std::move(ipv));
}
else
throw std::invalid_argument{"[endpoint]:mapaddr invalid entry: {}"_format(arg)};
@ -777,25 +783,18 @@ namespace llarp
try
{
oxen::quic::Address addr{key, 0};
bool in_range{false}, is_local{false};
ip_v _ip;
if (addr.is_ipv4())
{
auto addr_v4 = addr.to_ipv4();
in_range = _local_ip_range->contains(addr_v4);
is_local = addr_v4 == std::get<ipv4>(*_local_ip);
}
_ip = addr.to_ipv4();
else
{
auto addr_v6 = addr.to_ipv6();
in_range = _local_ip_range->contains(addr_v6);
is_local = addr_v6 == std::get<ipv6>(*_local_ip);
}
_ip = addr.to_ipv6();
if (is_local)
if (_ip == _local_base_ip)
continue;
if (not in_range)
if (not _local_ip_range->contains(_ip))
{
log::warning(
logcat,
@ -821,7 +820,7 @@ namespace llarp
if (auto maybe_netaddr = NetworkAddress::from_network_addr(*arg))
{
_reserved_local_addrs.emplace(std::move(*maybe_netaddr), std::move(addr));
_reserved_local_ips.emplace(std::move(*maybe_netaddr), std::move(_ip));
}
else
log::warning(logcat, "{}: {}", addrmap_errorstr, *arg);

View File

@ -150,15 +150,15 @@ namespace llarp
// If _local_ip_range is set, the following two optionals are also set
std::optional<IPRange> _local_ip_range;
std::optional<oxen::quic::Address> _local_addr;
std::optional<ip_v> _local_ip;
std::optional<ip_v> _local_base_ip;
std::optional<IPRange> _base_ipv6_range = std::nullopt;
// Remote exit or hidden service addresses mapped to fixed local IP addresses
// TODO:
// - (DONE) 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;
// - load directly into TunEndpoint mapping
// - when a session is created, check mapping when assigning IP's
std::unordered_map<NetworkAddress, ip_v> _reserved_local_ips;
// Remote client exit addresses mapped to local IP ranges
std::unordered_map<NetworkAddress, IPRange> _exit_ranges;

View File

@ -5,6 +5,7 @@
#include <fmt/core.h>
#include <cassert>
#include <filesystem>
#include <functional>
#include <initializer_list>
#include <iostream>
@ -17,6 +18,8 @@
#include <unordered_map>
#include <vector>
namespace fs = std::filesystem;
namespace llarp
{
namespace config

View File

@ -37,6 +37,8 @@ namespace llarp
return true;
}
oxenc::bt_deserialize(tmp, *data());
// return true;
return bt_decode(tmp);
}

View File

@ -9,7 +9,6 @@
#include <oxen/log.hpp>
#include <unbound.h>
#include <uvw.hpp>
#include <memory>
#include <optional>
@ -76,7 +75,7 @@ namespace llarp::dns
_udp->send(to, std::move(data));
}
void stop() override { _udp->close(); }
void stop() override { _udp->loop()->stop(); }
};
namespace libunbound
@ -118,7 +117,7 @@ namespace llarp::dns
std::thread runner;
std::atomic<bool> running;
#else
std::shared_ptr<uvw::PollHandle> _poller;
// std::shared_ptr<uvw::PollHandle> _poller;
#endif
std::optional<oxen::quic::Address> _local_addr;
@ -375,8 +374,8 @@ namespace llarp::dns
runner.join();
}
#else
if (_poller)
_poller->close();
// if (_poller)
// _poller->close();
#endif
if (m_ctx)
{
@ -557,7 +556,7 @@ namespace llarp::dns
std::shared_ptr<PacketSource_Base> Server::make_packet_source_on(
const oxen::quic::Address& addr, const llarp::DnsConfig&)
{
return std::make_shared<UDPReader>(*this, _loop->loop(), addr);
return std::make_shared<UDPReader>(*this, _loop, addr);
}
std::shared_ptr<Resolver_Base> Server::make_default_resolver()

View File

@ -35,12 +35,12 @@ namespace llarp
std::shared_ptr<EventLoop> EventLoop::make()
{
return std::make_shared<EventLoop>();
return std::shared_ptr<EventLoop>{new EventLoop{}};
}
std::shared_ptr<EventLoop> EventLoop::make(loop_ptr loop_ptr, std::thread::id loop_thread_id)
{
return std::make_shared<EventLoop>(std::move(loop_ptr), loop_thread_id);
return std::shared_ptr<EventLoop>{new EventLoop{std::move(loop_ptr), loop_thread_id}};
}
EventLoop::EventLoop() : _loop{std::make_shared<oxen::quic::Loop>()} {}
@ -49,6 +49,13 @@ namespace llarp
: _loop{std::make_shared<oxen::quic::Loop>(std::move(loop_ptr), thread_id)}
{}
EventLoop::~EventLoop()
{
log::info(logcat, "Shutting down lokinet loop {}", _close_immediately ? "ASAP" : "gracefully");
_loop->shutdown(_close_immediately);
}
bool EventLoop::add_network_interface(std::shared_ptr<vpn::NetworkInterface> netif, ip_pkt_hook handler)
{
(void)netif;

View File

@ -33,14 +33,16 @@ namespace llarp
class EventLoop
{
EventLoop();
EventLoop(loop_ptr loop_ptr, std::thread::id loop_thread_id);
std::atomic<bool> _close_immediately{false};
public:
static std::shared_ptr<EventLoop> make();
static std::shared_ptr<EventLoop> make(loop_ptr loop_ptr, std::thread::id loop_thread_id);
EventLoop();
EventLoop(loop_ptr loop_ptr, std::thread::id loop_thread_id);
~EventLoop(); // TODO:
~EventLoop();
std::shared_ptr<oxen::quic::Loop> _loop;
@ -48,7 +50,8 @@ namespace llarp
std::shared_ptr<EventHandler> make_handler();
public:
void set_close_immediate(bool b) { _close_immediately.store(b); }
const loop_ptr& loop() const { return _loop->loop(); }
bool in_event_loop() const { return _loop->in_event_loop(); }
@ -111,7 +114,7 @@ namespace llarp
template <typename T, typename Callable>
std::shared_ptr<T> shared_ptr(T* obj, Callable&& deleter)
{
return _loop->shared_ptr<T, Callable>(std::forward<T>(obj), std::forward<Callable>(deleter));
return _loop->shared_ptr<T, Callable>(obj, std::forward<Callable>(deleter));
}
template <typename Callable>

View File

@ -18,11 +18,18 @@ namespace llarp
_local = socket->address();
}
UDPHandle::~UDPHandle()
{
socket.reset();
}
io_result UDPHandle::_send_impl(
const oxen::quic::Path& path, std::byte* buf, size_t* bufsize, uint8_t ecn, size_t& n_pkts)
const oxen::quic::Path& path, std::byte* buf, size_t size, uint8_t ecn, size_t& n_pkts)
{
log::trace(logcat, "{} called", __PRETTY_FUNCTION__);
auto* bufsize = &size;
if (!socket)
{
log::warning(logcat, "Cannot send packets on closed socket ({})", path);
@ -83,8 +90,8 @@ namespace llarp
}
size_t n_pkts = 1;
size_t bufsize = buf.size();
auto res = _send_impl(path, buf.data(), &bufsize, ecn, n_pkts);
// size_t bufsize = buf.size();
auto res = _send_impl(path, buf.data(), buf.size(), ecn, n_pkts);
if (res.blocked())
{
@ -95,4 +102,17 @@ namespace llarp
else if (callback)
callback({});
}
io_result UDPHandle::send(const oxen::quic::Address& dest, bstring data)
{
size_t n_pkts = 1;
return _send_impl(oxen::quic::Path{_local, dest}, data.data(), data.size(), 0, n_pkts);
}
io_result UDPHandle::send(const oxen::quic::Address& dest, std::vector<uint8_t> data)
{
size_t n_pkts = 1;
return _send_impl(
oxen::quic::Path{_local, dest}, reinterpret_cast<std::byte*>(data.data()), data.size(), 0, n_pkts);
}
} // namespace llarp

View File

@ -21,8 +21,7 @@ namespace llarp
std::unique_ptr<UDPSocket> socket;
oxen::quic::Address _local;
io_result _send_impl(
const oxen::quic::Path& path, std::byte* buf, size_t* bufsize, uint8_t ecn, size_t& n_pkts);
io_result _send_impl(const oxen::quic::Path& path, std::byte* buf, size_t bufsize, uint8_t ecn, size_t& n_pkts);
void _send_or_queue(
const oxen::quic::Path& path,
@ -31,13 +30,15 @@ namespace llarp
std::function<void(io_result)> callback = nullptr);
public:
const std::shared_ptr<EventLoop>& loop() const { return _loop; }
io_result send(const oxen::quic::Address& dest, bstring data);
io_result send(const oxen::quic::Address& dest, std::vector<uint8_t> data);
oxen::quic::Address bind() { return _local; }
void close();
// void close();
};
} // namespace llarp

View File

@ -20,6 +20,11 @@ namespace llarp::handlers
return _router.loop();
}
void SessionEndpoint::Tick(std::chrono::milliseconds now)
{
(void)now;
}
void SessionEndpoint::configure()
{
auto net_config = _router.config()->network;
@ -56,13 +61,13 @@ namespace llarp::handlers
_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;
_local_base_ip = *net_config._local_base_ip;
_is_v4 = _local_range.is_ipv4();
for (auto& [addr, range] : net_config._exit_ranges)
{
map_remote_to_local_range(addr, range);
_range_map.insert_or_assign(range, addr);
}
if (not net_config.exit_auths.empty())
@ -122,7 +127,7 @@ namespace llarp::handlers
"Successfully resolved ONS lookup for {} mapped to IPRange:{}",
*maybe_addr,
ip_range);
map_remote_to_local_range(std::move(*maybe_addr), std::move(ip_range));
_range_map.insert_or_assign(std::move(ip_range), std::move(*maybe_addr));
}
// we don't need to print a fail message, as it is logged prior to invoking with std::nullopt
});
@ -339,6 +344,7 @@ namespace llarp::handlers
bool SessionEndpoint::prefigure_session(
NetworkAddress initiator, service::SessionTag tag, std::shared_ptr<path::Path> path, bool use_tun)
{
bool ret = true;
assert(path->is_client_path());
auto inbound =
@ -346,12 +352,35 @@ namespace llarp::handlers
auto [session, _] = _sessions.insert_or_assign(std::move(initiator), std::move(inbound));
log::info(
logcat, "SessionEndpoint successfully created and mapped InboundSession object! Starting TCP tunnel...");
auto msg = "SessionEndpoint successfully created and mapped InboundSession object!";
session->tcp_backend_connect();
// TESTNET:
// instruct the lokinet TUN device to create a mapping from a local IP to this session
if (session->using_tun())
{
log::info(logcat, "{} Instructing lokinet TUN device to create mapped route...", msg);
return true;
if (auto maybe_ip = _router.tun_endpoint()->map_session_to_local_ip(session->remote()))
{
log::info(
logcat,
"TUN device successfully routing session (remote: {}) via local ip: {}",
session->remote(),
std::holds_alternative<ipv4>(*maybe_ip) ? std::get<ipv4>(*maybe_ip).to_string()
: std::get<ipv6>(*maybe_ip).to_string());
}
else
{
// TODO: if this fails, we should close the session
}
}
else
{
log::info(logcat, "{} Connecting to TCP backend to route session traffic...", msg);
session->tcp_backend_connect();
}
return ret;
}
bool SessionEndpoint::publish_introset(const service::EncryptedIntroSet& introset)
@ -404,12 +433,29 @@ namespace llarp::handlers
auto [session, _] = _sessions.insert_or_assign(std::move(remote), std::move(outbound));
log::info(
logcat,
"SessionEndpoint successfully created and mapped OutboundSession object! Starting TCP "
"tunnel...");
auto msg = "SessionEndpoint successfully created and mapped InboundSession object!";
session->tcp_backend_listen(std::move(hook));
// TESTNET:
if (session->using_tun())
{
log::info(logcat, "{} Instructing lokinet TUN device to create mapped route...", msg);
if (auto maybe_ip = _router.tun_endpoint()->map_session_to_local_ip(session->remote()))
{
log::info(
logcat, "TUN device successfully routing session to remote: {}", session->remote());
hook(*maybe_ip);
}
else
{
// TODO: if this fails, we should close the session
}
}
else
{
log::info(logcat, "{} Starting TCP listener to route session traffic to backend...", msg);
session->tcp_backend_listen(std::move(hook));
}
}
});
}

View File

@ -27,9 +27,8 @@ namespace llarp
address_map<oxen::quic::Address, NetworkAddress> _address_map;
// Remote client exit addresses mapped to local IP ranges
// Remote client exit-node addresses mapped to local IP ranges
// - Directly pre-loaded from config
//
address_map<IPRange, NetworkAddress> _range_map;
service::Identity _identity;
@ -50,7 +49,7 @@ namespace llarp
IPRange _local_range;
oxen::quic::Address _local_addr;
ip_v _local_ip;
ip_v _local_base_ip;
ip_v _next_ip;
std::string _if_name;
@ -128,7 +127,6 @@ namespace llarp
// resolves any config mappings that parsed ONS addresses to their pubkey network address
void resolve_ons_mappings();
// TODO: add callback to return local TCPHandle bind address for requesting app
bool initiate_remote_service_session(const NetworkAddress& remote, on_session_init_hook cb)
{
return initiate_session(remote, std::move(cb), false);
@ -141,6 +139,7 @@ namespace llarp
void Tick(std::chrono::milliseconds now) override;
// TESTNET: the following functions may not be needed -- revisit this
/* Address Mapping - Public Mutators */
void map_remote_to_local_addr(NetworkAddress remote, oxen::quic::Address local);

View File

@ -323,22 +323,22 @@ namespace llarp::handlers
_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;
_local_base_ip = *net_conf._local_base_ip;
_is_ipv6 = not _local_range.is_ipv4();
_persisting_addr_file = net_conf.addr_map_persist_file;
if (not net_conf._reserved_local_addrs.empty())
if (not net_conf._reserved_local_ips.empty())
{
for (auto& [remote, local] : net_conf._reserved_local_addrs)
for (auto& [remote, local] : net_conf._reserved_local_ips)
{
local_ip_mapping.insert_or_assign(local, remote);
_local_ip_mapping.insert_or_assign(local, remote);
}
}
_local_netaddr = NetworkAddress::from_pubkey(_router.pubkey(), not _router.is_service_node());
local_ip_mapping.insert_or_assign(get_if_addr(), _local_netaddr);
_local_ip_mapping.insert_or_assign(_local_base_ip, std::move(_local_netaddr));
vpn::InterfaceInfo info;
info.addrs.emplace_back(_local_range);
@ -390,7 +390,6 @@ namespace llarp::handlers
// }
setup_dns();
assert(has_mapped_address(_local_netaddr));
}
static bool is_random_snode(const dns::Message& msg)
@ -895,6 +894,87 @@ namespace llarp::handlers
return true;
}
std::optional<ip_v> TunEndpoint::get_next_local_ip()
{
// if our IP range is exhausted, we loop back around to see if any have been unmapped from terminated sessions;
// we only want to reset the iterator and loop back through once though
bool has_reset = false;
do
{
// this will be std::nullopt if IP range is exhausted OR the IP incrementing overflowed (basically equal)
if (auto maybe_next_ip = _local_range_iterator.next_ip(); maybe_next_ip)
{
if (not _local_ip_mapping.has_local(*maybe_next_ip))
return maybe_next_ip;
// local IP is already assigned; try again
continue;
}
if (not has_reset)
{
log::debug(logcat, "Resetting IP range iterator for range: {}...", _local_range);
_local_range_iterator.reset();
has_reset = true;
}
else
break;
} while (true);
return std::nullopt;
}
std::optional<ip_v> TunEndpoint::map_session_to_local_ip(const NetworkAddress& remote)
{
std::optional<ip_v> ret = std::nullopt;
// first: check if we have a config value for this remote
if (auto maybe_ip = _local_ip_mapping.get_local_from_remote(remote); maybe_ip)
{
ret = maybe_ip;
log::info(
logcat,
"Local IP for session to remote ({}) pre-loaded from config: {}",
remote,
std::holds_alternative<ipv4>(*maybe_ip) ? std::get<ipv4>(*maybe_ip).to_string()
: std::get<ipv6>(*maybe_ip).to_string());
}
else
{
// We need to check that we both have a valid IP in our local range and that it is not already pre-assigned
// to a remote from the config
if (auto maybe_next_ip = get_next_local_ip(); maybe_next_ip)
{
ret = maybe_next_ip;
_local_ip_mapping.insert_or_assign(*maybe_next_ip, remote);
log::info(
logcat,
"Local IP for session to remote ({}) assigned: {}",
remote,
std::holds_alternative<ipv4>(*maybe_next_ip) ? std::get<ipv4>(*maybe_next_ip).to_string()
: std::get<ipv6>(*maybe_next_ip).to_string());
}
else
log::critical(logcat, "TUN device failed to assign local private IP for session to remote: {}", remote);
}
return ret;
}
void TunEndpoint::unmap_session_to_local_ip(const NetworkAddress& remote)
{
if (_local_ip_mapping.has_remote(remote))
{
_local_ip_mapping.unmap(remote);
log::info(logcat, "TUN device unmapped session to remote: {}", remote);
}
else
{
log::critical(logcat, "TUN device could not unmap session (remote: {})", remote);
}
}
// std::optional<service::Address> TunEndpoint::get_exit_address_for_ip(
// huint128_t ip, std::function<service::Address(std::unordered_set<service::Address>)> exitSelectionStrat)
// {
@ -1218,9 +1298,14 @@ namespace llarp::handlers
return true;
}
bool TunEndpoint::has_mapped_address(const NetworkAddress& addr) const
bool TunEndpoint::has_mapping_to_remote(const NetworkAddress& addr) const
{
return local_ip_mapping.has_remote(addr);
return _local_ip_mapping.has_remote(addr);
}
std::optional<ip_v> TunEndpoint::get_mapped_ip(const NetworkAddress& addr)
{
return _local_ip_mapping.get_local_from_remote(addr);
}
oxen::quic::Address TunEndpoint::get_if_addr() const

View File

@ -75,6 +75,13 @@ namespace llarp::handlers
// Handle a packet coming into the network through the TUN device
bool handle_inbound_packet(IPPacket pkt);
// TODO: think of a better name
// Upon session creation, SessionHandler will instruct TunEndpoint to requisition a private IP through which to
// route session traffic
std::optional<ip_v> map_session_to_local_ip(const NetworkAddress& remote);
void unmap_session_to_local_ip(const NetworkAddress& remote);
// TONUKE: this old bullshit
// bool handle_inbound_packet(
// const service::SessionTag tag, const llarp_buffer_t& pkt, service::ProtocolType t, uint64_t seqno);
@ -98,7 +105,9 @@ namespace llarp::handlers
/// returns true otherwise
bool is_allowing_traffic(const IPPacket& pkt) const;
bool has_mapped_address(const NetworkAddress& addr) const;
bool has_mapping_to_remote(const NetworkAddress& addr) const;
std::optional<ip_v> get_mapped_ip(const NetworkAddress& addr);
const Router& router() const { return _router; }
@ -116,9 +125,11 @@ namespace llarp::handlers
// Stores assigned IP's for each session in/out of this lokinet instance
// - Reserved local addresses is directly pre-loaded from config
// - Persisting address map is directly pre-loaded from config
address_map<oxen::quic::Address, NetworkAddress> local_ip_mapping;
address_map<ip_v, NetworkAddress> _local_ip_mapping;
private:
std::optional<ip_v> get_next_local_ip();
template <typename Addr_t, typename Endpoint_t>
void send_dns_reply(
Addr_t addr,
@ -143,12 +154,12 @@ namespace llarp::handlers
/// dns subsystem for this endpoint
std::shared_ptr<dns::Server> _dns;
// std::shared_ptr<auth::AuthPolicy> _auth_policy;
/// our local ip range (config-mapped as `if-addr`), address, and ip
IPRange _local_range;
oxen::quic::Address _local_addr;
ip_v _local_ip;
ip_v _local_base_ip;
IPRangeIterator _local_range_iterator;
/// Our local Network Address holding our network pubkey
NetworkAddress _local_netaddr;
@ -156,12 +167,6 @@ namespace llarp::handlers
/// our network interface's ipv6 address
oxen::quic::Address _local_ipv6;
/// next ip address to allocate
ip_v _next_ip;
/// highest ip address to allocate
ip_v _max_ip; // last IP address in the range (add to IPRange class)
/// list of strict connect addresses for hooks
// std::vector<IpAddress> _strict_connect_addrs;
/// use v6?

View File

@ -41,7 +41,7 @@ namespace llarp
public:
const std::unique_ptr<oxen::quic::Network>& net() { return _q; }
const std::shared_ptr<oxen::quic::GNUTLSCreds>& creds() { return _tls_creds; }
std::shared_ptr<oxen::quic::GNUTLSCreds> creds() { return _tls_creds; }
uint16_t listen();

View File

@ -98,12 +98,12 @@ namespace llarp::net
{
if (is_ipv4)
{
if (range._contains(v4))
if (range.contains(v4))
return true;
}
else
{
if (range._contains(v6))
if (range.contains(v6))
return true;
}
}

View File

@ -31,10 +31,6 @@ namespace llarp::path
std::shared_ptr<Path> get_path(const HopID& hop_id);
// std::shared_ptr<Path> get_path_by_pivot(const HopID& path_id);
// std::shared_ptr<Path> get_path_by_upstream(const HopID& pivot);
std::shared_ptr<TransitHop> get_path_for_transfer(const HopID& topath);
std::shared_ptr<TransitHop> get_transit_hop(const HopID&);

View File

@ -373,7 +373,7 @@ namespace llarp
std::string _if_name;
IPRange _local_range;
oxen::quic::Address _local_addr;
ip_v _local_ip;
ip_v _local_base_ip;
auto& conf = _config->network;
@ -406,31 +406,28 @@ namespace llarp
_local_range = *maybe;
_local_addr = _local_range.address();
_local_ip = *_local_range.get_ip();
_local_base_ip = _local_range.base_ip();
}
else
{
_local_range = *conf._local_ip_range;
_local_addr = *conf._local_addr;
_local_ip = *conf._local_ip;
_local_base_ip = *conf._local_base_ip;
}
// set values back in config
conf._local_ip_range = _local_range;
conf._local_addr = _local_addr;
conf._local_ip = _local_ip;
conf._local_base_ip = _local_base_ip;
conf._if_name = _if_name;
// process remote client map; addresses muyst be within _local_ip_range
auto& client_addrs = conf._reserved_local_addrs;
// process remote client map; addresses must be within _local_ip_range
auto& client_ips = conf._reserved_local_ips;
for (auto itr = client_addrs.begin(); itr != client_addrs.end();)
for (auto itr = client_ips.begin(); itr != client_ips.end();)
{
auto is_v4 = itr->second.is_ipv4();
if ((is_v4 and conf._local_ip_range->_contains(itr->second.to_ipv4()))
|| (conf._local_ip_range->_contains(itr->second.to_ipv6())))
itr = client_addrs.erase(itr);
if (conf._local_ip_range->contains(itr->second))
itr = client_ips.erase(itr);
else
++itr;
}

View File

@ -3,6 +3,8 @@
#include <oxenc/base64.h>
#include <oxenc/hex.h>
using namespace std::literals;
namespace llarp::rpc
{

View File

@ -156,22 +156,23 @@ namespace llarp::rpc
return;
}
auto endpoint =
(req.endpoint.empty()) ? GetEndpointByName(m_Router, "default") : GetEndpointByName(m_Router, req.endpoint);
// auto endpoint =
// (req.endpoint.empty()) ? GetEndpointByName(m_Router, "default") : GetEndpointByName(m_Router,
// req.endpoint);
if (not endpoint)
{
SetJSONError("No such local endpoint found.", quicconnect.response);
return;
}
// if (not endpoint)
// {
// SetJSONError("No such local endpoint found.", quicconnect.response);
// return;
// }
auto quic = endpoint->GetQUICTunnel();
// auto quic = endpoint->GetQUICTunnel();
if (not quic)
{
SetJSONError("No quic interface available on endpoint " + req.endpoint, quicconnect.response);
return;
}
// if (not quic)
// {
// SetJSONError("No quic interface available on endpoint " + req.endpoint, quicconnect.response);
// return;
// }
if (req.closeID)
{
@ -211,22 +212,23 @@ namespace llarp::rpc
return;
}
auto endpoint =
(req.endpoint.empty()) ? GetEndpointByName(m_Router, "default") : GetEndpointByName(m_Router, req.endpoint);
// auto endpoint =
// (req.endpoint.empty()) ? GetEndpointByName(m_Router, "default") : GetEndpointByName(m_Router,
// req.endpoint);
if (not endpoint)
{
SetJSONError("No such local endpoint found", quiclistener.response);
return;
}
// if (not endpoint)
// {
// SetJSONError("No such local endpoint found", quiclistener.response);
// return;
// }
auto quic = endpoint->GetQUICTunnel();
// auto quic = endpoint->GetQUICTunnel();
if (not quic)
{
SetJSONError("No quic interface available on endpoint " + req.endpoint, quiclistener.response);
return;
}
// if (not quic)
// {
// SetJSONError("No quic interface available on endpoint " + req.endpoint, quiclistener.response);
// return;
// }
if (req.closeID)
{
@ -254,13 +256,13 @@ namespace llarp::rpc
nlohmann::json result;
result["id"] = id;
std::string localAddress;
var::visit([&](auto&& addr) { localAddress = addr.to_string(); }, endpoint->local_address());
// var::visit([&](auto&& addr) { localAddress = addr.to_string(); }, endpoint->local_address());
result["addr"] = localAddress + ":" + std::to_string(req.port);
if (not req.srvProto.empty())
{
dns::SRVData srvData{req.srvProto, 1, 1, req.port, ""};
endpoint->put_srv_record(std::move(srvData));
// endpoint->put_srv_record(std::move(srvData));
}
SetJSONResponse(result, quiclistener.response);
@ -450,28 +452,29 @@ namespace llarp::rpc
dns::Message msg{dns::Question{qname, qtype}};
auto endpoint = (dnsquery.request.endpoint.empty()) ? GetEndpointByName(m_Router, "default")
: GetEndpointByName(m_Router, dnsquery.request.endpoint);
// auto endpoint = (dnsquery.request.endpoint.empty()) ? GetEndpointByName(m_Router, "default")
// : GetEndpointByName(m_Router, dnsquery.request.endpoint);
if (endpoint == nullptr)
{
SetJSONError("No such endpoint found for dns query", dnsquery.response);
return;
}
// if (endpoint == nullptr)
// {
// SetJSONError("No such endpoint found for dns query", dnsquery.response);
// return;
// }
if (auto dns = endpoint->DNS())
{
auto packet_src = std::make_shared<DummyPacketSource>([&](auto result) {
if (result)
SetJSONResponse(result->ToJSON(), dnsquery.response);
else
SetJSONError("No response from DNS", dnsquery.response);
});
if (not dns->maybe_handle_packet(packet_src, packet_src->dumb, packet_src->dumb, IPPacket{msg.to_buffer()}))
SetJSONError("DNS query not accepted by endpoint", dnsquery.response);
}
else
SetJSONError("Endpoint does not have dns", dnsquery.response);
// if (auto dns = endpoint->DNS())
// {
// auto packet_src = std::make_shared<DummyPacketSource>([&](auto result) {
// if (result)
// SetJSONResponse(result->ToJSON(), dnsquery.response);
// else
// SetJSONError("No response from DNS", dnsquery.response);
// });
// if (not dns->maybe_handle_packet(packet_src, packet_src->dumb, packet_src->dumb,
// IPPacket{msg.to_buffer()}))
// SetJSONError("DNS query not accepted by endpoint", dnsquery.response);
// }
// else
// SetJSONError("Endpoint does not have dns", dnsquery.response);
return;
}

View File

@ -98,6 +98,7 @@ namespace llarp::session
// - make a TCP connection over the bufferevent to lokinet-primary-ip:port
auto tcp_conn = h->connect(s.shared_from_this());
_tcp_conns.insert(std::move(tcp_conn));
return 0;
});
_handles.emplace(_handle->port(), std::move(_handle));
@ -139,7 +140,7 @@ namespace llarp::session
_ci = _ep->connect(
KeyedAddress{TUNNEL_PUBKEY},
_r.quic_tunnel()->creds(),
[addr = *bind, hook = std::move(cb)](oxen::quic::connection_interface&) { hook(std::move(addr)); },
[addr = *bind, hook = std::move(cb)](oxen::quic::connection_interface&) { hook(addr.to_ipv4()); },
[](oxen::quic::connection_interface&, uint64_t) {
//
});

View File

@ -14,7 +14,7 @@
namespace llarp
{
using on_session_init_hook = std::function<void(oxen::quic::Address)>;
using on_session_init_hook = std::function<void(ip_v)>;
namespace link
{
@ -78,7 +78,11 @@ namespace llarp
bool use_tun,
bool is_outbound);
constexpr bool is_outbound() const { return _is_outbound; }
bool is_outbound() const { return _is_outbound; }
const NetworkAddress& remote() const { return _remote; }
NetworkAddress remote() { return _remote; }
bool send_path_control_message(
std::string method, std::string body, std::function<void(std::string)> func = nullptr);
@ -92,6 +96,12 @@ namespace llarp
void tcp_backend_connect();
void tcp_backend_listen(on_session_init_hook cb, uint16_t port = 0);
bool using_tun() const { return _use_tun; }
service::SessionTag tag() { return _tag; }
const service::SessionTag& tag() const { return _tag; }
};
struct OutboundSession final : public llarp::path::PathHandler,
@ -162,10 +172,6 @@ namespace llarp
}
bool is_expired(std::chrono::milliseconds now) const;
service::SessionTag tag() { return _tag; }
const service::SessionTag& tag() const { return _tag; }
};
struct InboundSession final : public BaseSession

View File

@ -155,7 +155,7 @@ namespace llarp
bool bt_decode(std::string buf)
{
oxenc::bt_deserialize<decltype(*this)>(buf, *this);
oxenc::bt_deserialize(buf, *data());
return true;
}

View File

@ -20,7 +20,7 @@ namespace llarp::util
{
static auto logcat = log::Cat("util.file");
static std::streampos file_reader_impl(const fs::path& filename, fs::ifstream& in)
static std::streampos file_reader_impl(const fs::path& filename, std::ifstream& in)
{
in.exceptions(std::ifstream::failbit | std::ifstream::badbit);
in.open(filename, std::ios::binary | std::ios::in);
@ -32,7 +32,7 @@ namespace llarp::util
std::string file_to_string(const fs::path& filename)
{
fs::ifstream in;
std::ifstream in;
std::string contents;
auto size = file_reader_impl(filename, in);
contents.resize(size);
@ -42,7 +42,7 @@ namespace llarp::util
size_t file_to_buffer(const fs::path& filename, char* buffer, size_t buffer_size)
{
fs::ifstream in;
std::ifstream in;
auto size = file_reader_impl(filename, in);
if (static_cast<size_t>(size) > buffer_size)
throw std::length_error{"file is too large for buffer"};
@ -52,7 +52,7 @@ namespace llarp::util
void buffer_to_file(const fs::path& filename, std::string_view contents)
{
fs::ofstream out;
std::ofstream out;
out.exceptions(std::ifstream::failbit | std::ifstream::badbit);
out.open(filename, std::ios::binary | std::ios::out | std::ios::trunc);
out.write(contents.data(), static_cast<std::streamsize>(contents.size()));

View File

@ -315,8 +315,8 @@ namespace llarp::vpn
throw std::runtime_error{"we dont have our own network interface?"};
const _inet_addr gateway{*maybe};
const _inet_addr lower{ToNet(ipaddr_ipv4_bits(0, 0, 0, 0)), 1};
const _inet_addr upper{ToNet(ipaddr_ipv4_bits(128, 0, 0, 0)), 1};
const _inet_addr lower{ipv4(0, 0, 0, 0)};
const _inet_addr upper{ipv4(128, 0, 0, 0)};
make_route(cmd, flags, lower, gateway, GatewayMode::eLowerDefault, info.index);
make_route(cmd, flags, upper, gateway, GatewayMode::eUpperDefault, info.index);