TUN ip packet re-writing; deps bump

- Packets coming in and out of full clients need their IP src/dest addresses re-written
- Lokinet's TUN device sucks up all packets aimed at the if range, correctly addressing them to the proper outbound
- On reception, lokinet's TUN device addresses correctly for the mapped application receiving the packet
- Brought a lil somethin' somethin' from libquic for CI
- Bump oxenmq to cpp20 branch
- Revert cpr to 1.9 stable for subproject curl dep bug
This commit is contained in:
dr7ana 2024-06-02 11:52:43 -07:00
parent 4979f9aab8
commit f755d2601f
32 changed files with 397 additions and 465 deletions

View File

@ -384,7 +384,7 @@ local docs_pipeline(name, image, extra_cmds=[], allow_fail=false) = {
'echo "Building on ${DRONE_STAGE_MACHINE}"',
apt_get_quiet + ' update',
apt_get_quiet + ' install -y eatmydata',
'eatmydata ' + apt_get_quiet + ' install --no-install-recommends -y git clang-format-17 jsonnet',
'eatmydata ' + apt_get_quiet + ' install --no-install-recommends -y git clang-format-15 jsonnet',
'./contrib/ci/drone-format-verify.sh',
],
}],

View File

@ -188,14 +188,22 @@ if(NOT TARGET sodium)
endif()
set(warning_flags -Wall -Wextra -Wno-unknown-pragmas -Wno-unused-function -Werror=vla)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
list(APPEND warning_flags -Wno-unknown-warning-option)
endif()
if(WARNINGS_AS_ERRORS)
list(APPEND warning_flags -Werror -Wno-error=array-bounds)
endif()
list(APPEND warning_flags -Wno-deprecated-declarations)
add_library(lokinet-base-internal_warnings INTERFACE)
# If we blindly add these directly as compile_options then they get passed to swiftc on Apple and
# break, so we use a generate expression to set them only for C++/C/ObjC
add_compile_options("$<$<OR:$<COMPILE_LANGUAGE:CXX>,$<COMPILE_LANGUAGE:C>,$<COMPILE_LANGUAGE:OBJC>>:${warning_flags}>")
target_compile_options(lokinet-base-internal_warnings INTERFACE "$<$<OR:$<COMPILE_LANGUAGE:CXX>,$<COMPILE_LANGUAGE:C>,$<COMPILE_LANGUAGE:OBJC>>:${warning_flags}>")
if(XSAN)
string(APPEND CMAKE_CXX_FLAGS_DEBUG " -fsanitize=${XSAN} -fno-omit-frame-pointer -fno-sanitize-recover")
@ -268,6 +276,11 @@ add_library(lokinet-base INTERFACE)
target_include_directories(lokinet-base INTERFACE . include)
target_link_libraries(lokinet-base INTERFACE quic nlohmann_json::nlohmann_json)
add_library(lokinet-base-internal INTERFACE)
target_include_directories(lokinet-base-internal INTERFACE include/lokinet)
target_link_libraries(lokinet-base-internal INTERFACE lokinet-base-internal_warnings)
if(WITH_SYSTEMD AND (NOT ANDROID))
if(NOT SD_FOUND)
message(FATAL_ERROR "libsystemd not found")
@ -276,7 +289,6 @@ if(WITH_SYSTEMD AND (NOT ANDROID))
target_compile_definitions(lokinet-base INTERFACE WITH_SYSTEMD)
endif()
if(USE_JEMALLOC AND NOT STATIC_LINK)
pkg_check_modules(JEMALLOC jemalloc IMPORTED_TARGET)
if(JEMALLOC_FOUND)

View File

@ -1,5 +1,5 @@
CLANG_FORMAT_DESIRED_VERSION=17
CLANG_FORMAT_DESIRED_VERSION=16
CLANG_FORMAT=$(command -v clang-format-$CLANG_FORMAT_DESIRED_VERSION 2>/dev/null)
if [ $? -ne 0 ]; then

View File

@ -81,10 +81,6 @@ if(WITH_PEERSTATS)
target_link_libraries(sqlite_orm INTERFACE sqlite3)
endif()
add_library(uvw INTERFACE)
target_include_directories(uvw INTERFACE uvw/src)
target_link_libraries(uvw INTERFACE libuv)
add_subdirectory(oxen-libquic)
# cpr configuration. Ideally we'd just do this via add_subdirectory, but cpr's cmake requires

2
external/cpr vendored

@ -1 +1 @@
Subproject commit 3b15fa82ea74739b574d705fea44959b58142eb8
Subproject commit 23598e8a867934280db1f3bd3fe8cfa268a8d378

2
external/oxen-mq vendored

@ -1 +1 @@
Subproject commit a27961d787c9065f2bf6da9d60d01dca2e125739
Subproject commit 9d5776bc5f85e68b03f927374710d359929e72ba

View File

@ -1,8 +1,8 @@
#pragma once
#include "lokinet/lokinet_addr.h"
#include "lokinet/lokinet_context.h"
#include "lokinet/lokinet_misc.h"
#include "lokinet/lokinet_srv.h"
#include "lokinet/lokinet_stream.h"
#include "lokinet/lokinet_udp.h"
#include "lokinet/addr.h"
#include "lokinet/context.h"
#include "lokinet/misc.h"
#include "lokinet/srv.h"
#include "lokinet/stream.h"
#include "lokinet/udp.h"

View File

@ -6,7 +6,7 @@ include(Version)
# lokinet_add_library(lokinet-foo foo/source1.cpp foo/source2.cpp)
function(lokinet_add_library libname)
add_library(${libname} STATIC ${ARGN})
target_link_libraries(${libname} PUBLIC lokinet-base)
target_link_libraries(${libname} PUBLIC lokinet-base PRIVATE lokinet-base-internal)
enable_lto(${libname})
endfunction()
@ -266,19 +266,20 @@ target_link_libraries(lokinet-core
lokinet-wire
)
target_link_libraries(lokinet-base INTERFACE oxenc::oxenc oxen::logging)
# target_link_libraries(lokinet-base INTERFACE oxenc::oxenc oxen::logging)
target_link_libraries(lokinet-base INTERFACE oxenc::oxenc oxen::logging oxenmq::oxenmq Threads::Threads libunbound)
target_link_libraries(lokinet-rpc PUBLIC oxenmq::oxenmq)
target_link_libraries(lokinet-core PUBLIC oxenmq::oxenmq)
target_link_libraries(lokinet-config PUBLIC oxenmq::oxenmq)
target_link_libraries(lokinet-nodedb PUBLIC oxenmq::oxenmq)
target_link_libraries(lokinet-path PUBLIC oxenmq::oxenmq)
target_link_libraries(lokinet-time-place PUBLIC uvw)
target_link_libraries(lokinet-platform PUBLIC oxenmq::oxenmq Threads::Threads uvw)
target_link_libraries(lokinet-cryptography PUBLIC sodium)
target_link_libraries(lokinet-dns PUBLIC libunbound)
target_link_libraries(lokinet-utils PUBLIC nlohmann_json::nlohmann_json)
target_link_libraries(lokinet-wire PUBLIC oxenmq::oxenmq quic)
# target_link_libraries(lokinet-rpc PUBLIC oxenmq::oxenmq)
# target_link_libraries(lokinet-core PUBLIC oxenmq::oxenmq)
# target_link_libraries(lokinet-config PUBLIC oxenmq::oxenmq)
# target_link_libraries(lokinet-nodedb PUBLIC oxenmq::oxenmq)
# target_link_libraries(lokinet-path PUBLIC oxenmq::oxenmq)
# target_link_libraries(lokinet-platform PUBLIC oxenmq::oxenmq Threads::Threads)
# target_link_libraries(lokinet-cryptography PUBLIC sodium)
# target_link_libraries(lokinet-dns PUBLIC libunbound)
# target_link_libraries(lokinet-utils PUBLIC nlohmann_json::nlohmann_json)
# target_link_libraries(lokinet-wire PUBLIC oxenmq::oxenmq quic)
if(WITH_EMBEDDED_LOKINET)
include(GNUInstallDirs)

View File

@ -44,7 +44,7 @@ namespace llarp
_init_internals();
}
IPPacket IPPacket::from_udp(UDPPacket pkt)
IPPacket IPPacket::from_netpkt(NetworkPacket pkt)
{
auto data = pkt.data();
return IPPacket{reinterpret_cast<const unsigned char*>(data.data()), data.size()};
@ -217,6 +217,7 @@ namespace llarp
{
case 6: // TCP
chksumoff = 16;
[[fallthrough]];
case 33: // DCCP
chksum = tcp_checksum_ipv6(&hdr->srcaddr, &hdr->dstaddr, hdr->payload_len, 0);
@ -296,9 +297,9 @@ namespace llarp
return std::nullopt;
}
UDPPacket IPPacket::make_udp()
NetworkPacket IPPacket::make_netpkt()
{
return UDPPacket{oxen::quic::Path{_src_addr, _dst_addr}, bview()};
return NetworkPacket{oxen::quic::Path{_src_addr, _dst_addr}, bview()};
}
bool IPPacket::load(ustring_view data)
@ -345,7 +346,7 @@ namespace llarp
return true;
}
std::vector<uint8_t> IPPacket::steal() &&
std::vector<uint8_t> IPPacket::steal_buffer() &&
{
std::vector<uint8_t> b;
b.resize(size());
@ -353,7 +354,14 @@ namespace llarp
return b;
}
std::vector<uint8_t> IPPacket::give()
std::string IPPacket::steal_payload() &&
{
auto ret = to_string();
_buf.clear();
return ret;
}
std::vector<uint8_t> IPPacket::give_buffer()
{
std::vector<uint8_t> b;
b.resize(size());

View File

@ -12,6 +12,24 @@ namespace llarp
inline constexpr size_t MAX_PACKET_SIZE{1500};
inline constexpr size_t MIN_PACKET_SIZE{20};
struct IPPacket;
// Typedef for packets being transmitted between lokinet instances
using NetworkPacket = oxen::quic::Packet;
using net_pkt_hook = std::function<void(NetworkPacket&& pkt)>;
using ip_pkt_hook = std::function<void(IPPacket)>;
/** IPPacket
This class encapsulates the functionalities and attributes required for data transmission between the local
lokinet instance and the surrounding IP landscape. As data enters lokinet from the device/internet/etc, it is
transmitted across the network as a NetworkPacket via QUIC. As it exits lokinet to the device/internet/etc, it
is constructed into an IPPacket.
This allows for necessary functionalities at the junction that data is entering and exiting the local lokinet
instance. For example
*/
struct IPPacket
{
private:
@ -36,10 +54,10 @@ namespace llarp
explicit IPPacket(std::vector<uint8_t> data);
explicit IPPacket(const uint8_t* buf, size_t len);
static IPPacket from_udp(UDPPacket pkt);
static IPPacket from_netpkt(NetworkPacket pkt);
static std::optional<IPPacket> from_buffer(const uint8_t* buf, size_t len);
UDPPacket make_udp();
NetworkPacket make_netpkt();
bool is_ipv4() const { return _is_v4; }
@ -55,9 +73,9 @@ namespace llarp
ipv6 source_ipv6() { return _src_addr.to_ipv6(); }
ipv4 dest_ipv4() { return _dst_addr.to_ipv4(); }
ipv4 dest_ipv4() const { return _dst_addr.to_ipv4(); }
ipv6 dest_ipv6() { return _dst_addr.to_ipv6(); }
ipv6 dest_ipv6() const { return _dst_addr.to_ipv6(); }
ip_header* header() { return _header; }
@ -69,6 +87,13 @@ namespace llarp
std::optional<std::pair<const char*, size_t>> l4_data() const;
void clear_addresses()
{
if (_is_v4)
return update_ipv4_address(ipv4{}, ipv4{});
return update_ipv6_address(ipv6{}, ipv6{});
}
void update_ipv4_address(ipv4 src, ipv4 dst);
void update_ipv6_address(ipv6 src, ipv6 dst, std::optional<uint32_t> flowlabel = std::nullopt);
@ -79,6 +104,8 @@ namespace llarp
const uint8_t* data() const { return _buf.data(); }
const uint8_t* protocol() const { return _is_v4 ? &header()->protocol : &v6_header()->protocol; }
size_t size() const { return _buf.size(); }
bool empty() const { return _buf.empty(); }
@ -95,10 +122,12 @@ namespace llarp
bool take(std::vector<uint8_t> data);
// steals posession of the underlying data, and can only be used in an r-value context
std::vector<uint8_t> steal() &&;
std::vector<uint8_t> steal_buffer() &&;
std::string steal_payload() &&;
// gives a copy of the underlying data
std::vector<uint8_t> give();
std::vector<uint8_t> give_buffer();
std::string_view view() const { return {reinterpret_cast<const char*>(data()), size()}; }

View File

@ -171,7 +171,7 @@ namespace llarp
if (range_exhausted())
return ret;
if (auto b = is_ipv4() ? _increment_ipv4() : _increment_ipv6())
if (is_ipv4() ? _increment_ipv4() : _increment_ipv6())
ret = _current_ip;
return ret;

View File

@ -30,6 +30,24 @@ namespace llarp
inline constexpr size_t ICMP_HEADER_SIZE{8};
// Compares the given ip variant against a quic address
// Returns:
// - true : ip == address
// - false : ip != address
// Error:
// - throws : ip and address are mismatched ipv4 vs ipv6
inline bool ip_equals_address(const ip_v& ip, const oxen::quic::Address& addr, bool compare_v4)
{
if (compare_v4 and std::holds_alternative<ipv4>(ip))
return std::get<ipv4>(ip) == addr.to_ipv4();
if (not compare_v4 and std::holds_alternative<ipv6>(ip))
return std::get<ipv6>(ip) == addr.to_ipv6();
throw std::invalid_argument{
"Failed to compare ip variant in desired {} scheme!"_format(compare_v4 ? "ipv4" : "ipv6")};
}
struct ip_header_le
{
uint8_t header_len : 4;

View File

@ -119,10 +119,10 @@ namespace llarp
bool KeyManager::copy_backup_keyfile(const fs::path& filepath)
{
auto findFreeBackupFilename = [](const fs::path& filepath) {
auto findFreeBackupFilename = [](const fs::path& filepath) mutable {
for (int i = 0; i < 9; i++)
{
std::string ext("." + std::to_string(i) + ".bak");
auto ext = ".{}.bak"_format(i);
fs::path newPath = filepath;
newPath += ext;

View File

@ -36,14 +36,13 @@ namespace llarp::dns
public:
explicit UDPReader(Server& dns, const std::shared_ptr<EventLoop>& loop, oxen::quic::Address bind) : _dns{dns}
{
_udp = std::make_unique<UDPHandle>(loop, bind, [&](UDPPacket pkt) {
_udp = std::make_unique<UDPHandle>(loop, bind, [&](NetworkPacket pkt) {
auto& src = pkt.path.local;
if (src == _local_addr)
return;
(void)_dns;
if (not _dns.maybe_handle_packet(shared_from_this(), _local_addr, src, IPPacket::from_udp(pkt)))
if (not _dns.maybe_handle_packet(shared_from_this(), _local_addr, src, IPPacket::from_netpkt(pkt)))
{
log::warning(logcat, "did not handle dns packet from {} to {}", src, _local_addr);
}
@ -66,7 +65,7 @@ namespace llarp::dns
void send_to(const oxen::quic::Address& to, const oxen::quic::Address&, IPPacket data) const override
{
_udp->send(to, data.give());
_udp->send(to, data.give_buffer());
}
void send_to(
@ -157,7 +156,7 @@ namespace llarp::dns
hdr.Encode(&buf);
// send reply
query->send_reply(std::move(pkt).give());
query->send_reply(std::move(pkt).give_buffer());
}
void add_upstream_resolver(const oxen::quic::Address& dns)

View File

@ -72,10 +72,10 @@ namespace llarp::dns
class PacketSource_Wrapper : public PacketSource_Base
{
std::weak_ptr<PacketSource_Base> _wrapped;
udp_pkt_hook _write_pkt;
ip_pkt_hook _write_pkt;
public:
explicit PacketSource_Wrapper(std::weak_ptr<PacketSource_Base> wrapped, udp_pkt_hook write_packet)
explicit PacketSource_Wrapper(std::weak_ptr<PacketSource_Base> wrapped, ip_pkt_hook write_packet)
: _wrapped{std::move(wrapped)}, _write_pkt{std::move(write_packet)}
{}
@ -93,7 +93,7 @@ namespace llarp::dns
(void)to;
(void)from;
(void)data;
_write_pkt(data.make_udp());
_write_pkt(data);
}
void send_to(

View File

@ -1,7 +1,6 @@
#pragma once
#include "types.hpp"
#include <llarp/address/ip_packet.hpp>
#include <llarp/net/interface_info.hpp>
#include <llarp/util/buffer.hpp>
#include <llarp/util/logging.hpp>
@ -17,6 +16,11 @@ namespace llarp
class NetworkInterface;
} // namespace vpn
using event_ptr = oxen::quic::event_ptr;
// shared_ptr containing the actual libev loop
using loop_ptr = std::shared_ptr<::event_base>;
struct EventHandler
{
event_ptr ev;

View File

@ -61,6 +61,7 @@ namespace llarp
auto *conn = reinterpret_cast<TCPConnection *>(user_arg);
assert(conn);
(void)conn;
// conn->stream->close();
}
@ -92,6 +93,7 @@ namespace llarp
auto *handle = reinterpret_cast<TCPHandle *>(user_arg);
assert(handle);
(void)handle;
// DISCUSS: close everything here?
};

View File

@ -6,23 +6,5 @@
namespace llarp
{
struct IPPacket;
using UDPPacket = oxen::quic::Packet;
using udp_pkt_hook = std::function<void(UDPPacket&& pkt)>;
using ip_pkt_hook = std::function<void(IPPacket)>;
using UDPSocket = oxen::quic::UDPSocket;
using io_result = oxen::quic::io_result;
using event_ptr = oxen::quic::event_ptr;
// shared_ptr containing the actual libev loop
using loop_ptr = std::shared_ptr<::event_base>;
// Libevent callbacks
using event_hook = std::function<void()>;
//
} // namespace llarp

View File

@ -11,7 +11,7 @@ namespace llarp
1;
#endif
UDPHandle::UDPHandle(const std::shared_ptr<EventLoop>& ev, const oxen::quic::Address& bind, udp_pkt_hook cb)
UDPHandle::UDPHandle(const std::shared_ptr<EventLoop>& ev, const oxen::quic::Address& bind, net_pkt_hook cb)
: _loop{ev}
{
socket = std::make_unique<UDPSocket>(ev->loop().get(), bind, std::move(cb));

View File

@ -5,15 +5,21 @@
#include <llarp/util/buffer.hpp>
#include <llarp/util/logging.hpp>
#include <oxen/quic.hpp>
namespace llarp
{
class EventLoop;
using UDPSocket = oxen::quic::UDPSocket;
using io_result = oxen::quic::io_result;
class UDPHandle
{
public:
UDPHandle() = delete;
explicit UDPHandle(const std::shared_ptr<EventLoop>& ev, const oxen::quic::Address& bind, udp_pkt_hook cb);
explicit UDPHandle(const std::shared_ptr<EventLoop>& ev, const oxen::quic::Address& bind, net_pkt_hook cb);
~UDPHandle();
private:
@ -37,8 +43,6 @@ namespace llarp
io_result send(const oxen::quic::Address& dest, std::vector<uint8_t> data);
oxen::quic::Address bind() { return _local; }
// void close();
};
} // namespace llarp

View File

@ -43,13 +43,12 @@ namespace llarp::handlers
/// (windows/macos/ios/android ... aka everything that is not linux... funny that)
class DnsInterceptor : public dns::PacketSource_Base
{
// TODO: refactor this with deprecating IP_packet_deprecated
udp_pkt_hook _hook;
ip_pkt_hook _hook;
oxen::quic::Address _our_ip; // maybe should be an IP type...?
llarp::DnsConfig _config;
public:
explicit DnsInterceptor(udp_pkt_hook reply, oxen::quic::Address our_ip, llarp::DnsConfig conf)
explicit DnsInterceptor(ip_pkt_hook reply, oxen::quic::Address our_ip, llarp::DnsConfig conf)
: _hook{std::move(reply)}, _our_ip{std::move(our_ip)}, _config{std::move(conf)}
{}
@ -104,17 +103,21 @@ namespace llarp::handlers
~TunDNS() override = default;
explicit TunDNS(TunEndpoint* ep, const llarp::DnsConfig& conf)
: dns::Server{ep->router().loop(), conf, 0}, _tun{ep}, _query_bind{conf._query_bind}
// TOFIX:
// _our_ip{ep->get_if_addr(), _query_bind ? _query_bind->port() : 0}
{}
: dns::Server{ep->router().loop(), conf, 0},
_tun{ep},
_query_bind{conf._query_bind},
_our_ip{ep->get_if_addr()}
{
if (_query_bind)
_our_ip.set_port(_query_bind->port());
}
std::shared_ptr<dns::PacketSource_Base> make_packet_source_on(
const oxen::quic::Address&, const llarp::DnsConfig& conf) override
{
(void)_tun;
auto ptr = std::make_shared<DnsInterceptor>(
[](UDPPacket pkt) {
[](IPPacket pkt) {
(void)pkt;
// ep->handle_write_ip_packet(pkt.ConstBuffer(), pkt.srcv6(), pkt.dstv6(), 0);
},
@ -144,7 +147,7 @@ namespace llarp::handlers
}
_packet_router =
std::make_shared<vpn::PacketRouter>([this](IPPacket pkt) { handle_user_packet(std::move(pkt)); });
std::make_shared<vpn::PacketRouter>([this](IPPacket pkt) { handle_outbound_packet(std::move(pkt)); });
}
void TunEndpoint::setup_dns()
@ -159,16 +162,16 @@ namespace llarp::handlers
auto dns = std::make_shared<TunDNS>(this, dns_config);
_dns = dns;
_packet_router->add_udp_handler(uint16_t{53}, [this, dns](UDPPacket pkt) {
_packet_router->add_udp_handler(uint16_t{53}, [this, dns](NetworkPacket pkt) {
auto dns_pkt_src = dns->pkt_source;
auto& pkt_path = pkt.path;
if (dns->maybe_handle_packet(
std::move(dns_pkt_src), pkt_path.remote, pkt_path.local, IPPacket::from_udp(pkt)))
std::move(dns_pkt_src), pkt_path.remote, pkt_path.local, IPPacket::from_netpkt(pkt)))
return;
handle_user_packet(IPPacket::from_udp(pkt));
handle_outbound_packet(IPPacket::from_netpkt(pkt));
});
}
else
@ -207,6 +210,8 @@ namespace llarp::handlers
// });
// m_RawDNS = dns_io;
}
(void)vpn;
}
if (_raw_DNS)
@ -830,11 +835,7 @@ namespace llarp::handlers
std::string TunEndpoint::get_if_name() const
{
#ifdef _WIN32
return net::TruncateV6(GetIfAddr()).to_string();
#else
return _if_name;
#endif
}
bool TunEndpoint::is_service_node() const
@ -883,17 +884,6 @@ namespace llarp::handlers
return true;
}
void TunEndpoint::handle_outbound_packet(bstring data)
{
(void)data;
}
bool TunEndpoint::handle_inbound_packet(IPPacket pkt)
{
(void)pkt;
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;
@ -975,326 +965,177 @@ namespace llarp::handlers
}
}
// std::optional<service::Address> TunEndpoint::get_exit_address_for_ip(
// huint128_t ip, std::function<service::Address(std::unordered_set<service::Address>)> exitSelectionStrat)
// {
// // is it already mapped? return the mapping
// if (auto itr = _exit_to_ip.find(ip); itr != _exit_to_ip.end())
// return itr->second;
// const auto& net = router().net();
// const bool is_bogon = net.IsBogonIP(ip);
// build up our candidates to choose
// std::unordered_set<service::Address> candidates;
// for (const auto& entry : _exit_map.FindAllEntries(ip))
// {
// // in the event the exit's range is a bogon range, make sure the ip is located in that
// range
// // to allow it
// if ((is_bogon and net.IsBogonRange(entry.first) and entry.first.Contains(ip))
// or entry.first.Contains(ip))
// candidates.emplace(entry.second);
// }
// // no candidates? bail.
// if (candidates.empty())
// return std::nullopt;
// if (not exitSelectionStrat)
// {
// // default strat to random choice
// exitSelectionStrat = [](auto candidates) {
// auto itr = candidates.begin();
// std::advance(itr, llarp::randint() % candidates.size());
// return *itr;
// };
// }
// // map the exit and return the endpoint we mapped it to
// return _exit_to_ip.emplace(ip, exitSelectionStrat(candidates)).first->second;
// }
void TunEndpoint::handle_user_packet(IPPacket pkt)
void TunEndpoint::handle_outbound_packet(IPPacket pkt)
{
(void)pkt;
// huint128_t dst, src;
// if (pkt.IsV4())
// {
// dst = pkt.dst4to6();
// src = pkt.src4to6();
// }
// else
// {
// dst = pkt.dstv6();
// src = pkt.srcv6();
// }
ip_v src, dest;
// if constexpr (llarp::platform::is_apple)
// {
// if (dst == _local_ip)
// {
// handle_write_ip_packet(pkt.ConstBuffer(), src, dst, 0);
// return;
// }
// }
auto pkt_is_ipv4 = pkt.is_ipv4();
// // if (_state->is_exit_enabled)
// // {
// // dst = net::ExpandV4(net::TruncateV6(dst));
// // }
if (pkt_is_ipv4)
{
src = pkt.source_ipv4();
dest = pkt.dest_ipv4();
}
else
{
src = pkt.source_ipv6();
dest = pkt.dest_ipv6();
}
// auto itr = _ip_to_addr.find(dst);
if constexpr (llarp::platform::is_apple)
{
if (ip_equals_address(dest, _local_addr, pkt_is_ipv4))
{
rewrite_and_send_packet(std::move(pkt), src, dest);
return;
}
}
// if (itr == _ip_to_addr.end())
// {
// service::Address addr{};
// we pass `dest` because that is our local private IP on the outgoing IPPacket
if (auto maybe_remote = _local_ip_mapping.get_remote_from_local(dest))
{
auto& remote = *maybe_remote;
pkt.clear_addresses();
// if (auto maybe = get_exit_address_for_ip(dst))
// addr = *maybe;
// else
// {
// // send icmp unreachable as we dont have any exits for this ip
// if (const auto icmp = pkt.MakeICMPUnreachable())
// handle_write_ip_packet(icmp->ConstBuffer(), dst, src, 0);
// return;
// }
// std::function<void(void)> extra_cb;
// // if (not HasFlowToService(addr))
// // {
// // extra_cb = [poker = router().route_poker()]() { poker->put_up(); };
// // }
// // pkt.ZeroSourceAddress();
// // MarkAddressOutbound(addr);
// // EnsurePathToService(
// // addr,
// // [pkt, extra_cb, this](service::Address addr, service::OutboundContext* ctx)
// // mutable {
// // if (ctx)
// // {
// // if (extra_cb)
// // extra_cb();
// // ctx->send_packet_to_remote(pkt.to_string());
// // router().TriggerPump();
// // return;
// // }
// // log::warning(logcat, "cannot ensure path to exit {}; so we drop some packets", addr);
// // },
// // PathAlignmentTimeout());
// return;
// }
// std::variant<service::Address, RouterID> to;
// service::ProtocolType type{};
// // if (m_SNodes.at(itr->second))
// // {
// // to = RouterID{itr->second.as_array()};
// // type = service::ProtocolType::TrafficV4;
// // }
// // else
// // {
// // to = service::Address{itr->second.as_array()};
// // type = _state->is_exit_enabled and src != m_OurIP ? service::ProtocolType::Exit
// // : pkt.ServiceProtocol();
// // }
// // prepare packet for insertion into network
// // this includes clearing IP addresses, recalculating checksums, etc
// // this does not happen for exits because the point is they don't rewrite addresses
// // TODO: can we fix this shit
// // - clear addresses if it is our local TUN address, invariant of protocoltype
// if (type != service::ProtocolType::Exit)
// {
// if (pkt.IsV4())
// pkt.UpdateIPv4Address({0}, {0});
// else
// pkt.UpdateIPv6Address({0}, {0});
// }
// // try sending it on an existing convotag
// // this succeds for inbound convos, probably.
// // if (auto maybe = GetBestConvoTagFor(to))
// // {
// // if (send_to(*maybe, pkt.to_string()))
// // {
// // MarkIPActive(dst);
// // router().TriggerPump();
// // return;
// // }
// // }
// // // try establishing a path to this guy
// // // will fail if it's an inbound convo
// // EnsurePathTo(
// // to,
// // [pkt, dst, to, this](auto maybe) mutable {
// // if (not maybe)
// // {
// // var::visit(
// // [this](auto&& addr) {
// // Log Warn(name(), " failed to ensure path to ", addr, " no convo tag found");
// // },
// // to);
// // }
// // if (send_to(*maybe, pkt.to_string()))
// // {
// // MarkIPActive(dst);
// // router().TriggerPump();
// // }
// // else
// // {
// // var::visit(
// // [this](auto&& addr) {
// // Log Warn(name(), " failed to send to ", addr, ", SendToOrQueue failed");
// // },
// // to);
// // }
// // },
// // PathAlignmentTimeout());
if (auto session = _router.session_endpoint()->get_session(remote))
{
log::info(logcat, "Dispatching outbound packet for session (remote: {})", remote);
session->send_path_data_message(std::move(pkt).steal_payload());
return;
}
throw std::runtime_error{"Could not find session (remote: {}) for outbound packet!"_format(remote)};
}
throw std::runtime_error{"Could not find remote mapped to local ip: {}"_format(dest)};
}
bool TunEndpoint::is_allowing_traffic(const IPPacket& pkt) const
bool TunEndpoint::obtain_src_for_remote(const NetworkAddress& remote, ip_v& src, bool use_ipv4)
{
// if (auto exitPolicy = get_traffic_policy())
// return exitPolicy->allow_ip_traffic(pkt);
(void)pkt;
// we are receiving traffic from a session to a local exit node
if (auto maybe_src = _local_ip_mapping.get_local_from_remote(remote))
{
if (std::holds_alternative<ipv4>(*maybe_src))
{
if (use_ipv4)
src = *maybe_src;
else
{
auto quicaddr = oxen::quic::Address{std::get<ipv4>(*maybe_src)};
src = quicaddr.to_ipv6();
}
}
else
{
if (use_ipv4)
{
auto quicaddr = oxen::quic::Address{std::get<ipv6>(*maybe_src)};
src = quicaddr.to_ipv4();
}
else
src = *maybe_src;
}
}
else
{
log::critical(logcat, "Unable to find local IP for inbound packet from remote: {}", remote);
return false;
}
return true;
}
// bool TunEndpoint::handle_inbound_packet(
// const service::SessionTag tag, const llarp_buffer_t& buf, service::ProtocolType t, uint64_t seqno)
// {
// log::trace(logcat, "Inbound packet on session:{}", tag);
// // if (t == service::ProtocolType::QUIC)
// // {
// // auto* quic = GetQUICTunnel();
// // if (!quic)
// // {
// // Log Warn("incoming quic packet but this endpoint is not quic capable; dropping");
// // return false;
// // }
// // if (buf.sz < 4)
// // {
// // Log Warn("invalid incoming quic packet, dropping");
// // return false;
// // }
// // log::info(logcat, "tag active T={}", tag);
// // // TODO:
// // // quic->receive_packet(tag, buf);
// // return true;
// // }
// if (t != service::ProtocolType::TrafficV4 && t != service::ProtocolType::TrafficV6
// && t != service::ProtocolType::Exit)
// return false;
// // std::variant<service::Address, RouterID> addr;
// // if (auto maybe = GetEndpointWithConvoTag(tag))
// // {
// // addr = *maybe;
// // }
// // else
// // return false;
// huint128_t src, dst;
// IPPacket pkt;
// if (not pkt.load(buf.base))
// return false;
// // if (_state->is_exit_enabled)
// // {
// // // exit side from exit
// // // check packet against exit policy and if as needed
// // if (not ShouldAllowTraffic(pkt))
// // return false;
// // src = ObtainIPForAddr(addr);
// // if (t == service::ProtocolType::Exit)
// // {
// // if (pkt.IsV4())
// // dst = pkt.dst4to6();
// // else if (pkt.IsV6())
// // {
// // dst = pkt.dstv6();
// // src = net::ExpandV4Lan(net::TruncateV6(src));
// // }
// // }
// // else
// // {
// // // non exit traffic on exit
// // dst = m_OurIP;
// // }
// // }
// // else if (t == service::ProtocolType::Exit)
// // {
// // // client side exit traffic from exit
// // if (pkt.IsV4())
// // {
// // dst = m_OurIP;
// // src = pkt.src4to6();
// // }
// // else if (pkt.IsV6())
// // {
// // dst = m_OurIPv6;
// // src = pkt.srcv6();
// // }
// // // find what exit we think this should be for
// // service::Address fromAddr{};
// // if (const auto* ptr = std::get_if<service::Address>(&addr))
// // {
// // fromAddr = *ptr;
// // }
// // else // don't allow snode
// // return false;
// // // make sure the mapping matches
// // if (auto itr = m_ExitIPToExitAddress.find(src); itr != m_ExitIPToExitAddress.end())
// // {
// // if (itr->second != fromAddr)
// // return false;
// // }
// // else
// // return false;
// // }
// // else
// // {
// // // snapp traffic
// // src = ObtainIPForAddr(addr);
// // dst = m_OurIP;
// // }
// handle_write_ip_packet(buf, src, dst, seqno);
// return true;
// }
bool TunEndpoint::handle_write_ip_packet(const llarp_buffer_t& b, huint128_t src, huint128_t dst, uint64_t seqno)
void TunEndpoint::send_packet_to_net_if(IPPacket&& pkt)
{
ManagedBuffer buf(b);
IPPacket pkt;
_router.loop()->call([this, pkt = std::move(pkt)]() { _net_if->WritePacket(std::move(pkt)); });
}
// load
if (!pkt.load(buf.underlying.base))
void TunEndpoint::rewrite_and_send_packet(IPPacket&& pkt, ip_v src, ip_v dest)
{
if (pkt.is_ipv4())
pkt.update_ipv4_address(std::get<ipv4>(src), std::get<ipv4>(dest));
else
pkt.update_ipv6_address(std::get<ipv6>(src), std::get<ipv6>(dest));
send_packet_to_net_if(std::move(pkt));
}
bool TunEndpoint::handle_inbound_packet(
IPPacket pkt, NetworkAddress remote, bool is_exit_session, bool is_outbound_session)
{
ip_v src, dest;
auto pkt_is_ipv4 = pkt.is_ipv4();
if (is_exit_session and is_outbound_session)
{
return false;
// we are receiving traffic from a session to a remote exit node
if (pkt_is_ipv4)
{
src = pkt.source_ipv4();
dest = _local_addr.to_ipv4();
}
else
{
src = pkt.source_ipv6();
dest = _local_ipv6.to_ipv6();
}
assert(remote.is_client());
auto maybe_remote = _local_ip_mapping.get_remote_from_local(src);
if (not maybe_remote)
{
log::critical(
logcat, "Could not find mapping of local IP (ip:{}) for session to remote: {}", src, remote);
return false;
}
if (*maybe_remote != remote)
{
log::critical(
logcat,
"Internal mapping of local IP (ip:{}, remote:{}) did not match inbound packet from remote: {}",
src,
*maybe_remote,
remote);
return false;
}
}
// if (pkt.IsV4())
// {
// pkt.UpdateIPv4Address(xhtonl(net::TruncateV6(src)), xhtonl(net::TruncateV6(dst)));
// }
// else if (pkt.IsV6())
// {
// pkt.UpdateIPv6Address(src, dst);
// }
(void)src;
(void)dst;
(void)seqno;
else
{
if (is_exit_session and not is_outbound_session)
{
// we are receiving traffic from a session to a local exit node
if (not is_allowing_traffic(pkt))
return false;
// TODO: send this along but without a fucking huint182_t
// m_NetworkToUserPktQueue.push(std::move(write));
if (pkt_is_ipv4)
dest = pkt.dest_ipv4();
else
dest = pkt.dest_ipv6();
}
else
{
// we are receiving hidden service traffic
if (pkt_is_ipv4)
dest = _local_addr.to_ipv4();
else
dest = _local_ipv6.to_ipv6();
}
if (not obtain_src_for_remote(remote, src, pkt_is_ipv4))
return false;
}
rewrite_and_send_packet(std::move(pkt), src, dest);
return true;
}
bool TunEndpoint::is_allowing_traffic(const IPPacket& pkt) const
{
if (auto exitPolicy = get_traffic_policy())
return exitPolicy->allow_ip_traffic(pkt);
// wake up so we ensure that all packets are written to user
// router().TriggerPump();
return true;
}

View File

@ -70,30 +70,22 @@ namespace llarp::handlers
// };
// INPROGRESS: new API
// Handles a packet going out of the network through the TUN device
void handle_outbound_packet(bstring data);
// Handle a packet coming into the network through the TUN device
bool handle_inbound_packet(IPPacket pkt);
// Handles an outbound packet going out INTO the network
void handle_outbound_packet(IPPacket pkt);
void rewrite_and_send_packet(IPPacket&& pkt, ip_v src, ip_v dest);
// Handle an inbound packet coming in FROM the network
bool handle_inbound_packet(IPPacket pkt, NetworkAddress remote, bool is_exit_session, bool is_outbound_session);
// 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);
/// handle inbound traffic
bool handle_write_ip_packet(const llarp_buffer_t& buf, huint128_t src, huint128_t dst, uint64_t seqno);
/// we got a packet from the user
void handle_user_packet(llarp::IPPacket pkt);
/// get the local interface's address
oxen::quic::Address get_if_addr() const;
/// we have an interface addr
bool has_if_addr() const { return true; }
std::optional<net::TrafficPolicy> get_traffic_policy() const { return _traffic_policy; }
@ -130,6 +122,10 @@ namespace llarp::handlers
private:
std::optional<ip_v> get_next_local_ip();
bool obtain_src_for_remote(const NetworkAddress& remote, ip_v& src, bool use_ipv4);
void send_packet_to_net_if(IPPacket&& pkt);
template <typename Addr_t, typename Endpoint_t>
void send_dns_reply(
Addr_t addr,

View File

@ -14,6 +14,7 @@
#include <llarp/util/priority_queue.hpp>
#include <oxen/quic.hpp>
#include <oxen/quic/format.hpp>
#include <atomic>
#include <set>

View File

@ -62,24 +62,12 @@ namespace llarp::net
port = std::nullopt;
}
// DISCUSS: wtf is this
bool ProtocolInfo::matches_packet_proto(const IPPacket&) const
bool ProtocolInfo::matches_packet_proto(const IPPacket& pkt) const
{
// if (pkt.Header()->protocol != static_cast<std::underlying_type_t<IPProtocol>>(protocol))
// return false;
if (not port)
return true;
// if (const auto maybe = pkt.DstPort())
// {
// return *port == *maybe;
// }
// we can't tell what the port is but the protocol matches and that's good enough
return true;
return pkt.header()->protocol == static_cast<std::underlying_type_t<IPProtocol>>(protocol);
}
bool TrafficPolicy::allow_ip_traffic(IPPacket& pkt) const
bool TrafficPolicy::allow_ip_traffic(const IPPacket& pkt)
{
if (protocols.empty() and ranges.empty())
return true;

View File

@ -75,6 +75,6 @@ namespace llarp::net
/// returns true if we allow the traffic in this ip packet
/// returns false otherwise
bool allow_ip_traffic(IPPacket& pkt) const;
bool allow_ip_traffic(const IPPacket& pkt);
};
} // namespace llarp::net

View File

@ -20,13 +20,15 @@ namespace llarp::session
NetworkAddress remote,
service::SessionTag _t,
bool use_tun,
bool is_exit,
bool is_outbound)
: _r{r},
_parent{parent},
_tag{std::move(_t)},
_remote{std::move(remote)},
_use_tun{use_tun},
_is_outbound{is_outbound}
_is_outbound{is_outbound},
_is_exit_session{is_exit}
{
set_new_current_path(std::move(_p));
}
@ -57,11 +59,13 @@ namespace llarp::session
_current_hop_id = _current_path->intro.pivot_hop_id;
if (_use_tun)
_current_path->link_session(
[this](bstring data) { _r.tun_endpoint()->handle_outbound_packet(std::move(data)); });
_current_path->link_session([this](bstring data) {
_r.tun_endpoint()->handle_inbound_packet(
IPPacket{std::move(data)}, _remote, _is_exit_session, _is_outbound);
});
else
_current_path->link_session([this](bstring data) {
_ep->manually_receive_packet(UDPPacket{oxen::quic::Path{}, std::move(data)});
_ep->manually_receive_packet(NetworkPacket{oxen::quic::Path{}, std::move(data)});
});
assert(_current_path->is_linked());
@ -153,18 +157,25 @@ namespace llarp::session
service::SessionTag _t,
bool is_exit)
: PathHandler{parent._router, path::DEFAULT_PATHS_HELD},
BaseSession{_router, std::move(path), parent, std::move(remote), std::move(_t), _router.using_tun_if(), true},
BaseSession{
_router,
std::move(path),
parent,
std::move(remote),
std::move(_t),
_router.using_tun_if(),
is_exit,
true},
_last_use{_router.now()},
_is_exit_service{is_exit},
_is_snode_service{not _remote.is_client()}
_is_snode_session{not _remote.is_client()}
{
// These can both be false but CANNOT both be true
if (_is_exit_service and _is_snode_service)
if (_is_exit_session and _is_snode_session)
throw std::runtime_error{"Cannot create OutboundSession for a remote exit and remote service!"};
add_path(_current_path);
if (_is_snode_service)
if (_is_snode_session)
_session_key = _router.identity();
else
crypto::identity_keygen(_session_key);
@ -312,8 +323,15 @@ namespace llarp::session
handlers::SessionEndpoint& parent,
service::SessionTag _t,
bool use_tun)
: BaseSession{parent._router, std::move(_path), parent, std::move(remote), std::move(_t), use_tun, false},
_is_exit_node{_parent.is_exit_node()}
: BaseSession{
parent._router,
std::move(_path),
parent,
std::move(remote),
std::move(_t),
use_tun,
parent.is_exit_node(),
false}
{
if (not _current_path->is_client_path() and _remote.is_client())
throw std::runtime_error{

View File

@ -51,6 +51,8 @@ namespace llarp
bool _use_tun;
bool _is_outbound;
const bool _is_exit_session{false};
std::shared_ptr<path::Path> _current_path;
HopID _current_hop_id;
@ -76,6 +78,7 @@ namespace llarp
NetworkAddress remote,
service::SessionTag _t,
bool use_tun,
bool is_exit,
bool is_outbound);
bool is_outbound() const { return _is_outbound; }
@ -102,6 +105,8 @@ namespace llarp
service::SessionTag tag() { return _tag; }
const service::SessionTag& tag() const { return _tag; }
bool is_exit_session() const { return _is_exit_session; }
};
struct OutboundSession final : public llarp::path::PathHandler,
@ -123,8 +128,7 @@ namespace llarp
std::chrono::milliseconds _last_use;
const bool _is_exit_service{false};
const bool _is_snode_service{false};
const bool _is_snode_session{false};
public:
std::shared_ptr<path::PathHandler> get_self() override { return shared_from_this(); }
@ -186,9 +190,6 @@ namespace llarp
~InboundSession() = default;
void set_new_tag(const service::SessionTag& tag);
private:
const bool _is_exit_node{false}; // TODO: remember why I added this here...
};
template <typename session_t>

View File

@ -10,6 +10,7 @@
#include <cstring>
#include <iterator>
#include <memory>
#include <string>
#include <string_view>
#include <type_traits>
#include <utility>
@ -22,19 +23,47 @@ namespace llarp
using bstring = std::basic_string<std::byte>;
using bstring_view = std::basic_string_view<std::byte>;
namespace detail
{
template <size_t N>
struct bsv_literal
{
consteval bsv_literal(const char (&s)[N])
{
for (size_t i = 0; i < N; i++)
str[i] = static_cast<std::byte>(s[i]);
}
std::byte str[N]; // we keep the null on the end, in case you pass .data() to a C func
using size = std::integral_constant<size_t, N - 1>;
};
template <size_t N>
struct usv_literal
{
consteval usv_literal(const char (&s)[N])
{
for (size_t i = 0; i < N; i++)
str[i] = static_cast<unsigned char>(s[i]);
}
unsigned char str[N]; // we keep the null on the end, in case you pass .data() to a C func
using size = std::integral_constant<size_t, N - 1>;
};
} // namespace detail
inline ustring operator""_us(const char* str, size_t len) noexcept
{
return {reinterpret_cast<const unsigned char*>(str), len};
}
inline ustring_view operator""_usv(const char* str, size_t len) noexcept
template <detail::usv_literal UStr>
constexpr ustring_view operator""_usv() noexcept
{
return {reinterpret_cast<const unsigned char*>(str), len};
return {UStr.str, decltype(UStr)::size::value};
}
inline bstring_view operator""_bsv(const char* str, size_t len) noexcept
template <detail::bsv_literal BStr>
constexpr bstring_view operator""_bsv()
{
return {reinterpret_cast<const std::byte*>(str), len};
return {BStr.str, decltype(BStr)::size::value};
}
inline bstring operator""_bs(const char* str, size_t len) noexcept

View File

@ -39,7 +39,8 @@ namespace llarp
inline timeval loop_time_to_timeval(loop_time t)
{
return timeval{.tv_sec = t / 1s, .tv_usec = (t % 1s) / 1us};
return timeval{
.tv_sec = static_cast<long>(t.count() / 1000), .tv_usec = static_cast<long>((t.count() % 1000) * 1000)};
}
std::chrono::nanoseconds get_timestamp();

View File

@ -69,7 +69,9 @@ namespace llarp::vpn
ifr.ifr_addr.sa_family = AF_INET;
auto in4 = range.address().in4();
std::memcpy(
&((sockaddr_in*)&ifr.ifr_addr)->sin_addr.s_addr, &in4.sin_addr.s_addr, sizeof(sockaddr));
&((sockaddr_in*)&ifr.ifr_addr)->sin_addr.s_addr,
&in4.sin_addr.s_addr,
range.address().socklen());
control.ioctl(SIOCSIFADDR, &ifr);

View File

@ -5,16 +5,16 @@ namespace llarp::vpn
struct UDPPacketHandler : public Layer4Handler
{
ip_pkt_hook _base_handler;
std::unordered_map<uint16_t, udp_pkt_hook> _port_mapped_handlers;
std::unordered_map<uint16_t, net_pkt_hook> _port_mapped_handlers;
explicit UDPPacketHandler(ip_pkt_hook baseHandler) : _base_handler{std::move(baseHandler)} {}
void add_sub_handler(uint16_t localport, udp_pkt_hook handler) override
void add_sub_handler(uint16_t localport, net_pkt_hook handler) override
{
_port_mapped_handlers.emplace(localport, std::move(handler));
}
void handle_ip_packet(UDPPacket pkt) override
void handle_ip_packet(NetworkPacket pkt) override
{
auto dstport = pkt.path.remote.port();
@ -38,7 +38,7 @@ namespace llarp::vpn
explicit GenericLayer4Handler(ip_pkt_hook baseHandler) : _base_handler{std::move(baseHandler)} {}
void handle_ip_packet(UDPPacket) override
void handle_ip_packet(NetworkPacket) override
{
// TOFIX:
// _base_handler(IPPacket::from_udp(std::move(pkt)));
@ -57,7 +57,7 @@ namespace llarp::vpn
// _handler(std::move(pkt));
}
void PacketRouter::add_udp_handler(uint16_t localport, udp_pkt_hook func)
void PacketRouter::add_udp_handler(uint16_t localport, net_pkt_hook func)
{
constexpr uint8_t udp_proto = 0x11;

View File

@ -25,7 +25,7 @@ namespace llarp::vpn
void add_ip_proto_handler(uint8_t proto, ip_pkt_hook func);
/// helper that adds a udp packet handler for UDP destined for localport
void add_udp_handler(uint16_t port, udp_pkt_hook func);
void add_udp_handler(uint16_t port, net_pkt_hook func);
/// remove a udp handler that is already set up by bound port
void remove_udp_handler(uint16_t port);
@ -35,9 +35,9 @@ namespace llarp::vpn
{
virtual ~Layer4Handler() = default;
virtual void handle_ip_packet(UDPPacket pkt) = 0;
virtual void handle_ip_packet(NetworkPacket pkt) = 0;
virtual void add_sub_handler(uint16_t, udp_pkt_hook){};
virtual void add_sub_handler(uint16_t, net_pkt_hook){};
};
} // namespace llarp::vpn