mirror of
https://github.com/oxen-io/lokinet.git
synced 2024-11-15 12:13:24 +00:00
Netif and quic Tunnel reduction
- link::TunnelManager will be re-implemented in link::QUICTunnel to make and accept TCP connections - Will be simplified using Libevent and hooked into the new LocalEndpoint/RemoteHandler model - TCP{Handle,Socket} ownership model will be revised to more monadic model; this will allow the TCPSockets (sockets representing accepted connections) to function entirely independantly of the bound socket
This commit is contained in:
parent
d9cee71cf5
commit
6e5d8413f5
@ -6,7 +6,7 @@ namespace llarp
|
||||
{
|
||||
static auto logcat = log::Cat("address");
|
||||
|
||||
std::optional<NetworkAddress> NetworkAddress::from_network_addr(std::string arg)
|
||||
std::optional<NetworkAddress> NetworkAddress::from_network_addr(const std::string& arg)
|
||||
{
|
||||
std::optional<NetworkAddress> ret = std::nullopt;
|
||||
|
||||
@ -24,6 +24,11 @@ namespace llarp
|
||||
return ret;
|
||||
}
|
||||
|
||||
NetworkAddress NetworkAddress::from_pubkey(const RouterID& rid, bool is_client)
|
||||
{
|
||||
return NetworkAddress{rid, is_client};
|
||||
}
|
||||
|
||||
NetworkAddress::NetworkAddress(std::string_view arg, std::string_view tld) : _tld{tld}
|
||||
{
|
||||
if (not _pubkey.from_string(arg.substr(0, _tld.size())))
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "keys.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
#include <llarp/router_id.hpp>
|
||||
#include <llarp/service/name.hpp>
|
||||
#include <llarp/util/aligned.hpp>
|
||||
#include <llarp/util/concept.hpp>
|
||||
@ -27,30 +28,22 @@ namespace llarp
|
||||
private:
|
||||
PubKey _pubkey;
|
||||
|
||||
std::string _tld;
|
||||
bool _is_client{false};
|
||||
std::string _tld;
|
||||
|
||||
// This private constructor expects a '.snode' or '.loki' suffix
|
||||
explicit NetworkAddress(std::string_view addr, std::string_view tld);
|
||||
|
||||
public:
|
||||
template <RemotePubKeyType pubkey_t>
|
||||
explicit NetworkAddress(pubkey_t pubkey, std::string_view tld) : NetworkAddress{pubkey.to_view(), tld}
|
||||
// This private constructor expects NO '.snode' or '.loki' suffix
|
||||
explicit NetworkAddress(RouterID rid, bool is_client) : _pubkey{std::move(rid)}, _is_client{is_client}
|
||||
{}
|
||||
|
||||
public:
|
||||
NetworkAddress() = default;
|
||||
~NetworkAddress() = default;
|
||||
|
||||
explicit NetworkAddress(RelayPubKey rpk) : NetworkAddress{rpk, TLD::SNODE}
|
||||
{}
|
||||
|
||||
explicit NetworkAddress(ClientPubKey cpk) : NetworkAddress{cpk, TLD::LOKI}
|
||||
{}
|
||||
|
||||
NetworkAddress(const NetworkAddress& other) : NetworkAddress{other._pubkey, other._tld}
|
||||
{}
|
||||
|
||||
NetworkAddress(NetworkAddress&& other) : NetworkAddress{std::move(other._pubkey), std::move(other._tld)}
|
||||
{}
|
||||
NetworkAddress(const NetworkAddress& other) = default;
|
||||
NetworkAddress(NetworkAddress&& other) = default;
|
||||
|
||||
NetworkAddress& operator=(const NetworkAddress& other) = default;
|
||||
NetworkAddress& operator=(NetworkAddress&& other) = default;
|
||||
@ -66,7 +59,10 @@ namespace llarp
|
||||
|
||||
// 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);
|
||||
static std::optional<NetworkAddress> from_network_addr(const std::string& arg);
|
||||
|
||||
// Assumes that the pubkey passed is NOT terminated in either a '.loki' or '.snode' suffix
|
||||
static NetworkAddress from_pubkey(const RouterID& rid, bool is_client);
|
||||
|
||||
bool is_client() const
|
||||
{
|
||||
@ -104,11 +100,14 @@ namespace llarp
|
||||
lokinet relay. This object is NOT meant to be used in any scope referring to a hidden service or exit node
|
||||
being operated on that remote relay (not that service nodes operate exit nodes anyways) -- for that, use the
|
||||
above NetworkAddress type.
|
||||
|
||||
This object will become more differentiated from NetworkAddress once {Relay,Client}PubKey is implemented.
|
||||
That is a whole other can of worms...
|
||||
*/
|
||||
struct RelayAddress
|
||||
{
|
||||
private:
|
||||
RelayPubKey _pubkey;
|
||||
PubKey _pubkey;
|
||||
|
||||
explicit RelayAddress(std::string_view addr);
|
||||
|
||||
@ -116,7 +115,7 @@ namespace llarp
|
||||
RelayAddress() = default;
|
||||
~RelayAddress() = default;
|
||||
|
||||
explicit RelayAddress(RelayPubKey cpk) : _pubkey{std::move(cpk)}
|
||||
explicit RelayAddress(PubKey cpk) : _pubkey{std::move(cpk)}
|
||||
{}
|
||||
|
||||
RelayAddress(const RelayAddress& other) = default;
|
||||
@ -134,7 +133,7 @@ namespace llarp
|
||||
// Will throw invalid_argument with bad input
|
||||
static std::optional<RelayAddress> from_relay_addr(std::string arg);
|
||||
|
||||
const RelayPubKey& pubkey()
|
||||
const PubKey& pubkey()
|
||||
{
|
||||
return _pubkey;
|
||||
}
|
||||
|
@ -43,57 +43,4 @@ namespace llarp
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
std::string RelayPubKey::to_string() const
|
||||
{
|
||||
return oxenc::to_hex(begin(), end());
|
||||
}
|
||||
|
||||
RelayPubKey& RelayPubKey::operator=(const RelayPubKey& other)
|
||||
{
|
||||
std::memcpy(begin(), other.begin(), PUBKEYSIZE);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool RelayPubKey::operator<(const RelayPubKey& other) const
|
||||
{
|
||||
return as_array() < other.as_array();
|
||||
}
|
||||
|
||||
bool RelayPubKey::operator==(const RelayPubKey& other) const
|
||||
{
|
||||
return as_array() == other.as_array();
|
||||
}
|
||||
|
||||
bool RelayPubKey::operator!=(const RelayPubKey& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
std::string ClientPubKey::to_string() const
|
||||
{
|
||||
return oxenc::to_hex(begin(), end());
|
||||
}
|
||||
|
||||
bool ClientPubKey::operator<(const ClientPubKey& other) const
|
||||
{
|
||||
return as_array() < other.as_array();
|
||||
}
|
||||
|
||||
bool ClientPubKey::operator==(const ClientPubKey& other) const
|
||||
{
|
||||
return as_array() == other.as_array();
|
||||
}
|
||||
|
||||
bool ClientPubKey::operator!=(const ClientPubKey& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
ClientPubKey& ClientPubKey::operator=(const ClientPubKey& other)
|
||||
{
|
||||
std::memcpy(begin(), other.begin(), PUBKEYSIZE);
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace llarp
|
||||
|
@ -42,70 +42,6 @@ namespace llarp
|
||||
bool operator==(const PubKey& other) const;
|
||||
bool operator!=(const PubKey& other) const;
|
||||
};
|
||||
|
||||
struct RelayPubKey final : public PubKey
|
||||
{
|
||||
RelayPubKey() = default;
|
||||
|
||||
explicit RelayPubKey(const uint8_t* data) : PubKey{data}
|
||||
{}
|
||||
explicit RelayPubKey(const std::array<uint8_t, PUBKEYSIZE>& data) : PubKey{data}
|
||||
{}
|
||||
explicit RelayPubKey(ustring_view data) : PubKey{data.data()}
|
||||
{}
|
||||
explicit RelayPubKey(std::string_view data) : RelayPubKey{to_usv(data)}
|
||||
{}
|
||||
RelayPubKey(const RelayPubKey& other) : RelayPubKey{other.data()}
|
||||
{}
|
||||
RelayPubKey(RelayPubKey&& other) : RelayPubKey{other.data()}
|
||||
{}
|
||||
|
||||
std::string to_string() const;
|
||||
|
||||
RelayPubKey& operator=(const RelayPubKey& other);
|
||||
|
||||
bool operator<(const RelayPubKey& other) const;
|
||||
bool operator==(const RelayPubKey& other) const;
|
||||
bool operator!=(const RelayPubKey& other) const;
|
||||
};
|
||||
|
||||
struct ClientPubKey final : public PubKey
|
||||
{
|
||||
ClientPubKey() = default;
|
||||
|
||||
explicit ClientPubKey(const uint8_t* data) : PubKey{data}
|
||||
{}
|
||||
explicit ClientPubKey(const std::array<uint8_t, PUBKEYSIZE>& data) : PubKey{data}
|
||||
{}
|
||||
explicit ClientPubKey(ustring_view data) : PubKey{data.data()}
|
||||
{}
|
||||
explicit ClientPubKey(std::string_view data) : ClientPubKey{to_usv(data)}
|
||||
{}
|
||||
ClientPubKey(const ClientPubKey& other) : ClientPubKey{other.data()}
|
||||
{}
|
||||
ClientPubKey(ClientPubKey&& other) : ClientPubKey{other.data()}
|
||||
{}
|
||||
|
||||
std::string to_string() const;
|
||||
|
||||
ClientPubKey& operator=(const ClientPubKey& other);
|
||||
|
||||
bool operator<(const ClientPubKey& other) const;
|
||||
bool operator==(const ClientPubKey& other) const;
|
||||
bool operator!=(const ClientPubKey& other) const;
|
||||
};
|
||||
|
||||
template <typename addr_t>
|
||||
concept CONCEPT_COMPAT RemotePubKeyType = std::is_base_of_v<PubKey, addr_t>;
|
||||
|
||||
template <RemotePubKeyType addr_t>
|
||||
addr_t make_from_hex(const std::string& str)
|
||||
{
|
||||
addr_t p;
|
||||
oxenc::from_hex(str.begin(), str.end(), p.begin());
|
||||
return p;
|
||||
}
|
||||
|
||||
} // namespace llarp
|
||||
|
||||
namespace std
|
||||
@ -113,12 +49,4 @@ namespace std
|
||||
template <>
|
||||
struct hash<llarp::PubKey> : public hash<llarp::AlignedBuffer<PUBKEYSIZE>>
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct hash<llarp::ClientPubKey> : public hash<llarp::PubKey>
|
||||
{};
|
||||
|
||||
template <>
|
||||
struct hash<llarp::RelayPubKey> : public hash<llarp::PubKey>
|
||||
{};
|
||||
} // namespace std
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <llarp/crypto/constants.hpp>
|
||||
#include <llarp/util/logging.hpp>
|
||||
#include <llarp/util/str.hpp>
|
||||
#include <llarp/util/types.hpp>
|
||||
|
||||
#include <charconv>
|
||||
#include <optional>
|
||||
@ -13,6 +12,8 @@
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace PREFIX
|
||||
|
@ -1683,7 +1683,7 @@ namespace llarp
|
||||
config->load();
|
||||
config->logging.level = log::Level::off;
|
||||
config->api.enable_rpc_server = false;
|
||||
config->network.endpoint_type = "embedded";
|
||||
config->network.init_tun = false;
|
||||
config->network.save_profiles = false;
|
||||
config->bootstrap.files.clear();
|
||||
return config;
|
||||
|
@ -108,13 +108,12 @@ namespace llarp
|
||||
|
||||
std::optional<fs::path> keyfile;
|
||||
|
||||
std::string endpoint_type{"tun"};
|
||||
|
||||
std::optional<int> hops;
|
||||
std::optional<int> paths;
|
||||
|
||||
bool allow_exit = false;
|
||||
bool is_reachable = false;
|
||||
bool allow_exit{false};
|
||||
bool is_reachable{false};
|
||||
bool init_tun{true};
|
||||
|
||||
std::set<RouterID> snode_blacklist;
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
#include <llarp/util/time.hpp>
|
||||
#include <llarp/util/types.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <llarp/util/time.hpp>
|
||||
#include <llarp/util/types.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
|
@ -19,6 +19,8 @@
|
||||
#include <crypt.h>
|
||||
#endif
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
static auto logcat = log::Cat("crypto");
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
#include <llarp/util/aligned.hpp>
|
||||
#include <llarp/util/fs.hpp>
|
||||
#include <llarp/util/types.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
@ -3,8 +3,6 @@
|
||||
#include "kademlia.hpp"
|
||||
#include "key.hpp"
|
||||
|
||||
#include <llarp/util/types.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
@ -22,9 +20,9 @@ namespace llarp::dht
|
||||
Bucket(const Key_t& us, Random_t r) : nodes(XorMetric(us)), random(std::move(r))
|
||||
{}
|
||||
|
||||
StatusObject ExtractStatus() const
|
||||
nlohmann::json ExtractStatus() const
|
||||
{
|
||||
StatusObject obj{};
|
||||
nlohmann::json obj{};
|
||||
for (const auto& item : nodes)
|
||||
{
|
||||
obj[item.first.to_string()] = item.second.ExtractStatus();
|
||||
|
@ -25,7 +25,7 @@ namespace llarp::dht
|
||||
Key_t() : AlignedBuffer<SIZE>()
|
||||
{}
|
||||
|
||||
StatusObject ExtractStatus() const;
|
||||
nlohmann::json ExtractStatus() const;
|
||||
|
||||
std::string to_string() const
|
||||
{
|
||||
|
@ -22,7 +22,7 @@ namespace llarp::dht
|
||||
RCNode(const RouterContact& other) : rc(other), ID(other.router_id())
|
||||
{}
|
||||
|
||||
StatusObject ExtractStatus() const
|
||||
nlohmann::json ExtractStatus() const
|
||||
{
|
||||
return rc.extract_status();
|
||||
}
|
||||
@ -49,7 +49,7 @@ namespace llarp::dht
|
||||
ID = Key_t(introset.derived_signing_key.as_array());
|
||||
}
|
||||
|
||||
StatusObject ExtractStatus() const
|
||||
nlohmann::json ExtractStatus() const
|
||||
{
|
||||
return introset.ExtractStatus();
|
||||
}
|
||||
|
@ -47,9 +47,9 @@ namespace llarp::dns
|
||||
return true;
|
||||
}
|
||||
|
||||
StatusObject MessageHeader::ToJSON() const
|
||||
nlohmann::json MessageHeader::ToJSON() const
|
||||
{
|
||||
return StatusObject{};
|
||||
return nlohmann::json{};
|
||||
}
|
||||
|
||||
Message::Message(Message&& other)
|
||||
@ -129,10 +129,10 @@ namespace llarp::dns
|
||||
return true;
|
||||
}
|
||||
|
||||
StatusObject Message::ToJSON() const
|
||||
nlohmann::json Message::ToJSON() const
|
||||
{
|
||||
std::vector<StatusObject> ques;
|
||||
std::vector<StatusObject> ans;
|
||||
std::vector<nlohmann::json> ques;
|
||||
std::vector<nlohmann::json> ans;
|
||||
for (const auto& q : questions)
|
||||
{
|
||||
ques.push_back(q.ToJSON());
|
||||
@ -141,7 +141,7 @@ namespace llarp::dns
|
||||
{
|
||||
ans.push_back(a.ToJSON());
|
||||
}
|
||||
return StatusObject{{"questions", ques}, {"answers", ans}};
|
||||
return nlohmann::json{{"questions", ques}, {"answers", ans}};
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Message::to_buffer() const
|
||||
|
@ -33,7 +33,7 @@ namespace llarp
|
||||
|
||||
bool Decode(llarp_buffer_t* buf) override;
|
||||
|
||||
StatusObject ToJSON() const override;
|
||||
nlohmann::json ToJSON() const override;
|
||||
|
||||
bool operator==(const MessageHeader& other) const
|
||||
{
|
||||
@ -50,7 +50,7 @@ namespace llarp
|
||||
Message(Message&& other);
|
||||
Message(const Message& other);
|
||||
|
||||
StatusObject ToJSON() const override;
|
||||
nlohmann::json ToJSON() const override;
|
||||
|
||||
void add_nx_reply(RR_TTL_t ttl = 1);
|
||||
|
||||
|
@ -51,9 +51,9 @@ namespace llarp::dns
|
||||
return true;
|
||||
}
|
||||
|
||||
StatusObject Question::ToJSON() const
|
||||
nlohmann::json Question::ToJSON() const
|
||||
{
|
||||
return StatusObject{{"qname", qname}, {"qtype", qtype}, {"qclass", qclass}};
|
||||
return nlohmann::json{{"qname", qname}, {"qtype", qtype}, {"qclass", qclass}};
|
||||
}
|
||||
|
||||
bool Question::IsName(const std::string& other) const
|
||||
|
@ -52,6 +52,6 @@ namespace llarp::dns
|
||||
/// determine if we are using this TLD
|
||||
bool HasTLD(const std::string& tld) const;
|
||||
|
||||
StatusObject ToJSON() const override;
|
||||
nlohmann::json ToJSON() const override;
|
||||
};
|
||||
} // namespace llarp::dns
|
||||
|
@ -73,9 +73,9 @@ namespace llarp::dns
|
||||
return true;
|
||||
}
|
||||
|
||||
StatusObject ResourceRecord::ToJSON() const
|
||||
nlohmann::json ResourceRecord::ToJSON() const
|
||||
{
|
||||
return StatusObject{
|
||||
return nlohmann::json{
|
||||
{"name", rr_name},
|
||||
{"type", rr_type},
|
||||
{"class", rr_class},
|
||||
|
@ -27,7 +27,7 @@ namespace llarp::dns
|
||||
|
||||
bool Decode(llarp_buffer_t* buf) override;
|
||||
|
||||
StatusObject ToJSON() const override;
|
||||
nlohmann::json ToJSON() const override;
|
||||
|
||||
std::string to_string() const;
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <llarp/util/buffer.hpp>
|
||||
#include <llarp/util/types.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
@ -19,7 +20,7 @@ namespace llarp::dns
|
||||
virtual bool Decode(llarp_buffer_t* buf) = 0;
|
||||
|
||||
/// convert this whatever into json
|
||||
virtual StatusObject ToJSON() const = 0;
|
||||
virtual nlohmann::json ToJSON() const = 0;
|
||||
};
|
||||
|
||||
bool EncodeRData(llarp_buffer_t* buf, const std::vector<uint8_t>& rdata);
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include "srv_data.hpp"
|
||||
|
||||
#include <llarp/util/str.hpp>
|
||||
#include <llarp/util/types.hpp>
|
||||
|
||||
#include <oxenc/bt_serialize.h>
|
||||
|
||||
@ -163,9 +162,9 @@ namespace llarp::dns
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
StatusObject SRVData::ExtractStatus() const
|
||||
nlohmann::json SRVData::ExtractStatus() const
|
||||
{
|
||||
return StatusObject{
|
||||
return nlohmann::json{
|
||||
{"proto", service_proto}, {"priority", priority}, {"weight", weight}, {"port", port}, {"target", target}};
|
||||
}
|
||||
} // namespace llarp::dns
|
||||
|
@ -4,8 +4,6 @@
|
||||
#include "name.hpp"
|
||||
#include "serialize.hpp"
|
||||
|
||||
#include <llarp/util/types.hpp>
|
||||
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
|
||||
@ -89,7 +87,7 @@ namespace llarp::dns
|
||||
|
||||
bool bt_decode(std::string buf);
|
||||
|
||||
StatusObject ExtractStatus() const;
|
||||
nlohmann::json ExtractStatus() const;
|
||||
|
||||
private:
|
||||
bool bt_decode(oxenc::bt_dict_consumer& btdc);
|
||||
|
@ -50,7 +50,7 @@ namespace llarp
|
||||
: _loop{std::make_shared<oxen::quic::Loop>(std::move(loop_ptr), thread_id)}
|
||||
{}
|
||||
|
||||
bool EventLoop::add_network_interface(std::shared_ptr<vpn::NetworkInterface> netif, udp_pkt_hook handler)
|
||||
bool EventLoop::add_network_interface(std::shared_ptr<vpn::NetworkInterface> netif, ip_pkt_hook handler)
|
||||
{
|
||||
(void)netif;
|
||||
(void)handler;
|
||||
|
@ -59,7 +59,7 @@ namespace llarp
|
||||
return _loop->in_event_loop();
|
||||
}
|
||||
|
||||
bool add_network_interface(std::shared_ptr<vpn::NetworkInterface> netif, udp_pkt_hook handler);
|
||||
bool add_network_interface(std::shared_ptr<vpn::NetworkInterface> netif, ip_pkt_hook handler);
|
||||
|
||||
template <typename Callable>
|
||||
void call(Callable&& f)
|
||||
|
@ -37,19 +37,6 @@ namespace llarp
|
||||
|
||||
auto *handle = reinterpret_cast<TCPHandle *>(user_arg);
|
||||
assert(handle);
|
||||
|
||||
auto bfd = bufferevent_getfd(bev);
|
||||
|
||||
if (auto maybe_str = handle->get_socket_stream(bfd))
|
||||
{
|
||||
log::trace(logcat, "TCP handle passing received data to corresponding stream!");
|
||||
maybe_str->send(ustring_view{buf.data(), nwrite});
|
||||
}
|
||||
else
|
||||
{
|
||||
log::error(logcat, "TCP handle could not find corresponding stream to fd:{}", bfd);
|
||||
handle->close_socket(bfd);
|
||||
}
|
||||
};
|
||||
|
||||
static void tcp_event_cb(struct bufferevent *bev, short what, void *user_arg)
|
||||
@ -82,6 +69,8 @@ namespace llarp
|
||||
auto *b = evconnlistener_get_base(listener);
|
||||
auto *bevent = bufferevent_socket_new(b, fd, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE);
|
||||
|
||||
// TODO: make TCPSocket here!
|
||||
|
||||
bufferevent_setcb(bevent, tcp_read_cb, nullptr, tcp_event_cb, user_arg);
|
||||
bufferevent_enable(bevent, EV_READ | EV_WRITE);
|
||||
|
||||
@ -100,7 +89,8 @@ namespace llarp
|
||||
// DISCUSS: close everything here?
|
||||
};
|
||||
|
||||
TCPSocket::TCPSocket(struct bufferevent *_bev, const oxen::quic::Address &_src) : bev{_bev}, src{_src}
|
||||
TCPSocket::TCPSocket(struct bufferevent *_bev, evutil_socket_t _fd, const oxen::quic::Address &_src)
|
||||
: bev{_bev}, fd{_fd}, src{_src}
|
||||
{}
|
||||
|
||||
TCPSocket::~TCPSocket()
|
||||
@ -109,33 +99,17 @@ namespace llarp
|
||||
log::debug(logcat, "TCPSocket shut down!");
|
||||
}
|
||||
|
||||
TCPHandle::TCPHandle(const std::shared_ptr<EventLoop> &ev_loop, const oxen::quic::Address &bind, rcv_data_hook cb)
|
||||
: _ev{ev_loop}, _receive_cb{std::move(cb)}
|
||||
TCPHandle::TCPHandle(const std::shared_ptr<EventLoop> &ev_loop, const oxen::quic::Address &bind, tcpsock_hook cb)
|
||||
: _ev{ev_loop}, _socket_maker{std::move(cb)}
|
||||
{
|
||||
assert(_ev);
|
||||
|
||||
if (!_receive_cb)
|
||||
if (!_socket_maker)
|
||||
throw std::logic_error{"TCPSocket construction requires a non-empty receive callback"};
|
||||
|
||||
_init_internals(bind);
|
||||
}
|
||||
|
||||
std::shared_ptr<oxen::quic::Stream> TCPHandle::get_socket_stream(evutil_socket_t fd)
|
||||
{
|
||||
if (auto itr = routing.find(fd); itr != routing.end())
|
||||
{
|
||||
if (auto str = itr->second->stream.lock())
|
||||
return str;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void TCPHandle::close_socket(evutil_socket_t fd)
|
||||
{
|
||||
routing.erase(fd);
|
||||
}
|
||||
|
||||
void TCPHandle::_init_internals(const oxen::quic::Address &bind)
|
||||
{
|
||||
sockaddr_in _tcp{};
|
||||
|
@ -13,15 +13,23 @@ extern "C"
|
||||
#include <event2/listener.h>
|
||||
}
|
||||
|
||||
/** TODO:
|
||||
- set up session_map in EndpointBase
|
||||
- OutboundSession will create the path
|
||||
- separate Socket and Handle from QUIC-like "ownership" model
|
||||
- TCPHandle has a socket creation callback instead of a data callback
|
||||
- Fire socket creation cb on accepting connection
|
||||
- Socket creation cb could be given a created socket to set the callbacks on
|
||||
- QUIC stream held by TCPSocket needs to have a receive data callback that writes to the TCP connection
|
||||
*/
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
class TCPHandle;
|
||||
|
||||
struct TCPSocket
|
||||
{
|
||||
TCPSocket() = delete;
|
||||
|
||||
TCPSocket(struct bufferevent* _bev, const oxen::quic::Address& _src);
|
||||
TCPSocket(struct bufferevent* _bev, evutil_socket_t _fd, const oxen::quic::Address& _src);
|
||||
|
||||
/// Non-copyable and non-moveable
|
||||
TCPSocket(const TCPSocket& s) = delete;
|
||||
@ -32,11 +40,14 @@ namespace llarp
|
||||
~TCPSocket();
|
||||
|
||||
struct bufferevent* bev;
|
||||
evutil_socket_t fd;
|
||||
oxen::quic::Address src;
|
||||
|
||||
std::weak_ptr<oxen::quic::Stream> stream;
|
||||
};
|
||||
|
||||
using tcpsock_hook = std::function<std::shared_ptr<TCPSocket>()>;
|
||||
|
||||
class TCPHandle
|
||||
{
|
||||
public:
|
||||
@ -49,7 +60,7 @@ namespace llarp
|
||||
;
|
||||
TCPHandle() = delete;
|
||||
|
||||
explicit TCPHandle(const std::shared_ptr<EventLoop>& ev, const oxen::quic::Address& bind, rcv_data_hook cb);
|
||||
explicit TCPHandle(const std::shared_ptr<EventLoop>& ev, const oxen::quic::Address& bind, tcpsock_hook cb);
|
||||
|
||||
~TCPHandle();
|
||||
|
||||
@ -59,19 +70,13 @@ namespace llarp
|
||||
|
||||
socket_t _sock;
|
||||
oxen::quic::Address _bound;
|
||||
rcv_data_hook _receive_cb;
|
||||
tcpsock_hook _socket_maker;
|
||||
|
||||
std::unordered_map<evutil_socket_t, std::shared_ptr<TCPSocket>> routing;
|
||||
|
||||
void _init_internals(const oxen::quic::Address& bind);
|
||||
|
||||
public:
|
||||
// void map_buffer_socket(evutil_socket_t fd)
|
||||
|
||||
std::shared_ptr<oxen::quic::Stream> get_socket_stream(evutil_socket_t fd);
|
||||
|
||||
void close_socket(evutil_socket_t fd);
|
||||
|
||||
oxen::quic::Address bind()
|
||||
{
|
||||
return _bound;
|
||||
|
@ -12,7 +12,6 @@ namespace llarp
|
||||
|
||||
using udp_pkt_hook = std::function<void(UDPPacket&& pkt)>;
|
||||
using ip_pkt_hook = std::function<void(IPPacket)>;
|
||||
using rcv_data_hook = std::function<void(ustring)>;
|
||||
|
||||
using UDPSocket = oxen::quic::UDPSocket;
|
||||
|
||||
|
@ -6,12 +6,12 @@ namespace llarp::handlers
|
||||
{
|
||||
static auto logcat = llarp::log::Cat("base_handler");
|
||||
|
||||
void BaseHandler::load_key_file(std::optional<fs::path> p, Router& r)
|
||||
void BaseHandler::load_key_file(std::optional<fs::path> p)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (p.has_value())
|
||||
_identity.ensure_keys(*p, r.key_manager()->needs_backup());
|
||||
_identity.ensure_keys(*p, _router.key_manager()->needs_backup());
|
||||
else
|
||||
_identity.regenerate_keys();
|
||||
}
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
namespace llarp::handlers
|
||||
{
|
||||
inline constexpr auto LOKI_RESOLVER = "lokinet"sv;
|
||||
|
||||
/** This class holds methods common to handlers::{Tun,Null}Endpoints in regards to their packet
|
||||
routing and other API capabilities.
|
||||
@ -59,7 +58,7 @@ namespace llarp::handlers
|
||||
|
||||
virtual bool setup_networking() = 0;
|
||||
|
||||
virtual void load_key_file(std::optional<fs::path> p, Router& r);
|
||||
virtual void load_key_file(std::optional<fs::path> p);
|
||||
|
||||
virtual vpn::EgresPacketRouter* egres_packet_router()
|
||||
{
|
||||
|
@ -19,7 +19,7 @@ namespace llarp::handlers
|
||||
bool _is_snode_service{false}; // TODO:
|
||||
bool _is_v4;
|
||||
|
||||
std::string _name{"LocalEndpoint"};
|
||||
const std::string _name{"LocalEndpoint"};
|
||||
|
||||
std::string _if_name;
|
||||
oxen::quic::Address _local_addr;
|
||||
|
@ -23,10 +23,9 @@ namespace llarp
|
||||
public std::enable_shared_from_this<RemoteHandler>
|
||||
{
|
||||
private:
|
||||
std::string _name{"RemoteHandler"};
|
||||
const std::string _name{"RemoteHandler"};
|
||||
|
||||
address_map<oxen::quic::Address, NetworkAddress> _address_map;
|
||||
|
||||
address_map<IPRange, NetworkAddress> _range_map;
|
||||
|
||||
IPRange _local_range;
|
||||
|
@ -128,8 +128,24 @@ namespace llarp::handlers
|
||||
}
|
||||
};
|
||||
|
||||
TunEndpoint::TunEndpoint(Router& r) : BaseHandler{r}, _packet_router{}
|
||||
TunEndpoint::TunEndpoint(Router& r) : _router{r}, _packet_router{}
|
||||
{
|
||||
auto& keyfile = _router.config()->network.keyfile;
|
||||
|
||||
try
|
||||
{
|
||||
if (keyfile.has_value())
|
||||
_identity.ensure_keys(*keyfile, _router.key_manager()->needs_backup());
|
||||
else
|
||||
_identity.regenerate_keys();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
auto err = "API endpoint keyfile failed to load: {}"_format(e.what());
|
||||
log::error(logcat, "{}", err);
|
||||
throw std::runtime_error{err};
|
||||
}
|
||||
|
||||
_packet_router =
|
||||
std::make_shared<vpn::PacketRouter>([this](IPPacket pkt) { handle_user_packet(std::move(pkt)); });
|
||||
|
||||
@ -138,8 +154,10 @@ namespace llarp::handlers
|
||||
|
||||
void TunEndpoint::setup_dns()
|
||||
{
|
||||
log::info(logcat, "{} setting up DNS...", name());
|
||||
|
||||
auto& dns_config = _router.config()->dns;
|
||||
const auto& info = get_vpn_interface()->Info();
|
||||
const auto& info = get_vpn_interface()->interface_info();
|
||||
|
||||
if (dns_config.raw)
|
||||
{
|
||||
@ -165,14 +183,14 @@ 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 (auto vpn = router().vpn_platform())
|
||||
if (auto vpn = _router.vpn_platform())
|
||||
{
|
||||
// get the first local address we know of
|
||||
std::optional<oxen::quic::Address> localaddr;
|
||||
@ -207,7 +225,7 @@ namespace llarp::handlers
|
||||
}
|
||||
}
|
||||
|
||||
StatusObject TunEndpoint::ExtractStatus() const
|
||||
nlohmann::json TunEndpoint::ExtractStatus() const
|
||||
{
|
||||
// auto obj = service::Endpoint::ExtractStatus();
|
||||
// obj["ifaddr"] = m_OurRange.to_string();
|
||||
@ -227,10 +245,10 @@ namespace llarp::handlers
|
||||
// if (not m_DnsConfig.bind_addr.empty())
|
||||
// obj["localResolver"] = localRes[0];
|
||||
|
||||
// StatusObject ips{};
|
||||
// nlohmann::json ips{};
|
||||
// for (const auto& item : m_IPActivity)
|
||||
// {
|
||||
// StatusObject ipObj{{"lastActive", to_json(item.second)}};
|
||||
// nlohmann::json ipObj{{"lastActive", to_json(item.second)}};
|
||||
// std::string remoteStr;
|
||||
// AlignedBuffer<32> addr = m_IPToAddr.at(item.first);
|
||||
// if (m_SNodes.at(addr))
|
||||
@ -261,7 +279,7 @@ namespace llarp::handlers
|
||||
}
|
||||
}
|
||||
|
||||
bool TunEndpoint::configure()
|
||||
void TunEndpoint::configure()
|
||||
{
|
||||
auto& net_conf = _router.config()->network;
|
||||
|
||||
@ -292,7 +310,6 @@ namespace llarp::handlers
|
||||
}
|
||||
|
||||
_traffic_policy = net_conf.traffic_policy;
|
||||
|
||||
_base_ipv6_range = net_conf._base_ipv6_range;
|
||||
|
||||
if (net_conf.path_alignment_timeout)
|
||||
@ -308,7 +325,7 @@ namespace llarp::handlers
|
||||
_local_addr = *net_conf._local_addr;
|
||||
_local_ip = *net_conf._local_ip;
|
||||
|
||||
_use_v6 = not _local_range.is_ipv4();
|
||||
_is_ipv6 = not _local_range.is_ipv4();
|
||||
|
||||
_persisting_addr_file = net_conf.addr_map_persist_file;
|
||||
|
||||
@ -320,6 +337,50 @@ namespace llarp::handlers
|
||||
}
|
||||
}
|
||||
|
||||
_local_netaddr = NetworkAddress::from_pubkey(_router.pubkey(), not _router.is_service_node());
|
||||
local_ip_mapping.insert_or_assign(get_if_addr(), _local_netaddr);
|
||||
|
||||
vpn::InterfaceInfo info;
|
||||
info.addrs.emplace_back(_local_range);
|
||||
|
||||
if (_base_ipv6_range)
|
||||
{
|
||||
log::info(logcat, "{} using ipv6 range:{}", name(), *_base_ipv6_range);
|
||||
info.addrs.emplace_back(*_base_ipv6_range);
|
||||
}
|
||||
|
||||
info.ifname = _if_name;
|
||||
log::info(logcat, "{} setting up network...", name());
|
||||
|
||||
_net_if = router().vpn_platform()->CreateInterface(std::move(info), &_router);
|
||||
|
||||
_if_name = _net_if->interface_info().ifname;
|
||||
log::info(logcat, "{} got network interface:{}", name(), _if_name);
|
||||
|
||||
auto handle_packet = [netif = _net_if, pktrouter = _packet_router](IPPacket pkt) {
|
||||
// TODO: packets used to have reply hooks
|
||||
// pkt.reply = [netif](auto pkt) { netif->WritePacket(std::move(pkt)); };
|
||||
pktrouter->handle_ip_packet(std::move(pkt));
|
||||
};
|
||||
|
||||
if (not router().loop()->add_network_interface(_net_if, std::move(handle_packet)))
|
||||
{
|
||||
auto err = "{} failed to add network interface!"_format(name());
|
||||
log::error(logcat, "{}", err);
|
||||
throw std::runtime_error{std::move(err)};
|
||||
}
|
||||
|
||||
_local_ipv6 = _is_ipv6 ? _local_addr : _local_addr.mapped_ipv4_as_ipv6();
|
||||
|
||||
if constexpr (not llarp::platform::is_apple)
|
||||
{
|
||||
if (auto maybe = router().net().get_interface_ipv6_addr(_if_name))
|
||||
{
|
||||
_local_ipv6 = *maybe;
|
||||
log::info(logcat, "{} has ipv6 address:{}", name(), _local_ipv6);
|
||||
}
|
||||
}
|
||||
|
||||
// if (auto* quic = GetQUICTunnel())
|
||||
// {
|
||||
// TODO:
|
||||
@ -327,7 +388,9 @@ namespace llarp::handlers
|
||||
// return llarp::SockAddr{net::TruncateV6(GetIfAddr()), huint16_t{port}};
|
||||
// });
|
||||
// }
|
||||
return true;
|
||||
|
||||
setup_dns();
|
||||
assert(has_mapped_address(_local_netaddr));
|
||||
}
|
||||
|
||||
static bool is_random_snode(const dns::Message& msg)
|
||||
@ -733,7 +796,7 @@ namespace llarp::handlers
|
||||
|
||||
bool TunEndpoint::supports_ipv6() const
|
||||
{
|
||||
return _use_v6;
|
||||
return _is_ipv6;
|
||||
}
|
||||
|
||||
// FIXME: pass in which question it should be addressing
|
||||
@ -775,11 +838,6 @@ namespace llarp::handlers
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TunEndpoint::start()
|
||||
{
|
||||
return setup_networking();
|
||||
}
|
||||
|
||||
bool TunEndpoint::is_service_node() const
|
||||
{
|
||||
return _router.is_service_node();
|
||||
@ -790,94 +848,6 @@ namespace llarp::handlers
|
||||
return _router.is_exit_node();
|
||||
}
|
||||
|
||||
bool TunEndpoint::setup_tun()
|
||||
{
|
||||
_next_ip = _local_ip;
|
||||
// _max_ip = _local_range.HighestAddr();
|
||||
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);
|
||||
|
||||
auto& local_netaddr = _identity.pub.address();
|
||||
|
||||
local_ip_mapping.insert_or_assign(get_if_addr(), local_netaddr);
|
||||
|
||||
vpn::InterfaceInfo info;
|
||||
info.addrs.emplace_back(_local_range);
|
||||
|
||||
if (_base_ipv6_range)
|
||||
{
|
||||
log::info(logcat, "{} using ipv6 range:{}", name(), *_base_ipv6_range);
|
||||
info.addrs.emplace_back(*_base_ipv6_range);
|
||||
}
|
||||
|
||||
info.ifname = _if_name;
|
||||
|
||||
log::info(logcat, "{} setting up network...", name());
|
||||
|
||||
try
|
||||
{
|
||||
_net_if = router().vpn_platform()->CreateInterface(std::move(info), &_router);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
log::error(logcat, "{} failed to set up network interface: ", name(), ex.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
_if_name = _net_if->Info().ifname;
|
||||
log::info(logcat, "{} got network interface:{}", name(), _if_name);
|
||||
|
||||
auto handle_packet = [netif = _net_if, pktrouter = _packet_router](UDPPacket pkt) {
|
||||
// TODO: packets used to have reply hooks
|
||||
// pkt.reply = [netif](auto pkt) { netif->WritePacket(std::move(pkt)); };
|
||||
pktrouter->handle_ip_packet(std::move(pkt));
|
||||
};
|
||||
|
||||
if (not router().loop()->add_network_interface(_net_if, std::move(handle_packet)))
|
||||
{
|
||||
log::error(logcat, "{} failed to add network interface!", name());
|
||||
return false;
|
||||
}
|
||||
|
||||
_local_ipv6 = _local_range.is_ipv4()
|
||||
? oxen::quic::Address{_local_range.address().to_ipv6(), _local_range.address().port()}
|
||||
: _local_range.address();
|
||||
|
||||
if constexpr (not llarp::platform::is_apple)
|
||||
{
|
||||
if (auto maybe = router().net().get_interface_ipv6_addr(_if_name))
|
||||
{
|
||||
_local_ipv6 = *maybe;
|
||||
log::info(logcat, "{} has ipv6 address:{}", name(), _local_ipv6);
|
||||
}
|
||||
}
|
||||
|
||||
log::info(logcat, "{} setting up DNS...", name());
|
||||
setup_dns();
|
||||
// loop()->call_soon([this]() { router().route_poker()->set_dns_mode(false); });
|
||||
return has_mapped_address(local_netaddr);
|
||||
}
|
||||
|
||||
// std::unordered_map<std::string, std::string>
|
||||
// TunEndpoint::NotifyParams() const
|
||||
// {
|
||||
// auto env = Endpoint::NotifyParams();
|
||||
// env.emplace("IP_ADDR", m_OurIP.to_string());
|
||||
// env.emplace("IF_ADDR", m_OurRange.to_string());
|
||||
// env.emplace("IF_NAME", m_IfName);
|
||||
// std::string strictConnect;
|
||||
// for (const auto& addr : m_StrictConnectAddrs)
|
||||
// strictConnect += addr.to_string() + " ";
|
||||
// env.emplace("STRICT_CONNECT_ADDRS", strictConnect);
|
||||
// return env;
|
||||
// }
|
||||
|
||||
bool TunEndpoint::setup_networking()
|
||||
{
|
||||
log::info(logcat, "Set Up networking for {}", name());
|
||||
return setup_tun();
|
||||
}
|
||||
|
||||
bool TunEndpoint::stop()
|
||||
{
|
||||
// stop vpn tunnel
|
||||
|
@ -17,38 +17,22 @@
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
|
||||
/**
|
||||
DISCUSS:
|
||||
- Q: Where should {Tun,Null}Endpoint live in the heirarchy?
|
||||
|
||||
- Q: Does it make more sense for {Tun,Null}Endpoint to bypass service::Handler and directly
|
||||
inherit from PathBuilder?
|
||||
- A: Likely. The addition of handlers::RemoteHandler to the inheritance of service::Handler
|
||||
and exit::Handler strengthen this argument, as those functionalities are not necessary for
|
||||
{Tun,Null}Endpoint.
|
||||
- Q: Is EndpointBase necessary? Or is session management outside the scope of {Tun,Null}Endpoint
|
||||
- A: Likely not. But will leave it in at the moment. The previous implementation brought in
|
||||
EndpointBase via service::Endpoint, and it seems reachability in regards to introsets may
|
||||
be important.
|
||||
*/
|
||||
|
||||
namespace llarp::handlers
|
||||
{
|
||||
inline const auto TUN = "tun"s;
|
||||
inline constexpr auto TUN = "tun"sv;
|
||||
inline constexpr auto LOKI_RESOLVER = "lokinet"sv;
|
||||
|
||||
struct TunEndpoint final : public dns::Resolver_Base,
|
||||
public BaseHandler,
|
||||
public std::enable_shared_from_this<TunEndpoint>
|
||||
struct TunEndpoint : public dns::Resolver_Base, public std::enable_shared_from_this<TunEndpoint>
|
||||
{
|
||||
TunEndpoint(Router& r);
|
||||
~TunEndpoint() override;
|
||||
|
||||
vpn::NetworkInterface* get_vpn_interface() override
|
||||
vpn::NetworkInterface* get_vpn_interface()
|
||||
{
|
||||
return _net_if.get();
|
||||
}
|
||||
|
||||
std::string name() const override
|
||||
std::string_view name() const
|
||||
{
|
||||
return TUN;
|
||||
}
|
||||
@ -72,16 +56,13 @@ namespace llarp::handlers
|
||||
// Reconfigures DNS servers and restarts libunbound with the new servers.
|
||||
void reconfigure_dns(std::vector<oxen::quic::Address> servers);
|
||||
|
||||
bool configure() override;
|
||||
void configure();
|
||||
|
||||
std::string get_if_name() const override;
|
||||
std::string get_if_name() const;
|
||||
|
||||
StatusObject ExtractStatus() const;
|
||||
nlohmann::json ExtractStatus() const;
|
||||
|
||||
// std::unordered_map<std::string, std::string>
|
||||
// NotifyParams() const override;
|
||||
|
||||
bool supports_ipv6() const override;
|
||||
bool supports_ipv6() const;
|
||||
|
||||
bool should_hook_dns_message(const dns::Message& msg) const;
|
||||
|
||||
@ -89,31 +70,21 @@ namespace llarp::handlers
|
||||
|
||||
void tick_tun(std::chrono::milliseconds now);
|
||||
|
||||
bool start();
|
||||
|
||||
bool stop();
|
||||
|
||||
bool is_service_node() const;
|
||||
|
||||
bool is_exit_node() const;
|
||||
|
||||
/// set up tun interface, blocking
|
||||
bool setup_tun();
|
||||
|
||||
void setup_dns();
|
||||
|
||||
/// overrides Endpoint
|
||||
// std::shared_ptr<dns::Server> DNS() const override
|
||||
// {
|
||||
// return _dns;
|
||||
// };
|
||||
|
||||
/// overrides BaseHandler
|
||||
bool setup_networking() override;
|
||||
|
||||
/// overrides BaseHandler
|
||||
bool handle_inbound_packet(
|
||||
const service::SessionTag tag, const llarp_buffer_t& pkt, service::ProtocolType t, uint64_t seqno) override;
|
||||
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);
|
||||
@ -147,6 +118,16 @@ namespace llarp::handlers
|
||||
|
||||
bool has_mapped_address(const NetworkAddress& addr) const;
|
||||
|
||||
const Router& router() const
|
||||
{
|
||||
return _router;
|
||||
}
|
||||
|
||||
Router& router()
|
||||
{
|
||||
return _router;
|
||||
}
|
||||
|
||||
protected:
|
||||
struct WritePacket
|
||||
{
|
||||
@ -181,6 +162,8 @@ namespace llarp::handlers
|
||||
reply(*query);
|
||||
}
|
||||
|
||||
Router& _router;
|
||||
|
||||
/// dns subsystem for this endpoint
|
||||
std::shared_ptr<dns::Server> _dns;
|
||||
|
||||
@ -188,6 +171,9 @@ namespace llarp::handlers
|
||||
oxen::quic::Address _local_addr;
|
||||
ip _local_ip;
|
||||
|
||||
/// Our local Network Address holding our network pubkey
|
||||
NetworkAddress _local_netaddr;
|
||||
|
||||
/// our network interface's ipv6 address
|
||||
oxen::quic::Address _local_ipv6;
|
||||
|
||||
@ -202,7 +188,7 @@ namespace llarp::handlers
|
||||
/// list of strict connect addresses for hooks
|
||||
// std::vector<IpAddress> _strict_connect_addrs;
|
||||
/// use v6?
|
||||
bool _use_v6;
|
||||
bool _is_ipv6;
|
||||
std::string _if_name;
|
||||
|
||||
std::optional<IPRange> _base_ipv6_range = std::nullopt;
|
||||
@ -219,6 +205,8 @@ namespace llarp::handlers
|
||||
/// a file to load / store the ephemeral address map to
|
||||
std::optional<fs::path> _persisting_addr_file = std::nullopt;
|
||||
|
||||
service::Identity _identity;
|
||||
|
||||
/// for raw packet dns
|
||||
std::shared_ptr<vpn::I_Packet_IO> _raw_DNS;
|
||||
};
|
||||
|
@ -34,9 +34,9 @@ namespace llarp
|
||||
return enc;
|
||||
}
|
||||
|
||||
StatusObject Contacts::ExtractStatus() const
|
||||
nlohmann::json Contacts::ExtractStatus() const
|
||||
{
|
||||
StatusObject obj{{"services", _introset_nodes->ExtractStatus()}, {"local_key", _local_key.ToHex()}};
|
||||
nlohmann::json obj{{"services", _introset_nodes->ExtractStatus()}, {"local_key", _local_key.ToHex()}};
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ namespace llarp
|
||||
std::optional<service::EncryptedIntroSet> get_encrypted_introset(const dht::Key_t& key) const;
|
||||
|
||||
// TODO: rename every ExtractStatus function to be uniformly snake cased
|
||||
StatusObject ExtractStatus() const;
|
||||
nlohmann::json ExtractStatus() const;
|
||||
|
||||
void put_intro(service::EncryptedIntroSet enc);
|
||||
|
||||
|
@ -481,7 +481,7 @@ namespace llarp
|
||||
return true;
|
||||
}
|
||||
|
||||
log::critical(logcat, "Queueing message to ");
|
||||
log::critical(logcat, "Queueing message to {}", remote);
|
||||
|
||||
_router.loop()->call(
|
||||
[this, remote, endpoint = std::move(endpoint), body = std::move(body), f = std::move(func)]() {
|
||||
@ -632,7 +632,7 @@ namespace llarp
|
||||
}
|
||||
|
||||
// TODO: this
|
||||
StatusObject LinkManager::extract_status() const
|
||||
nlohmann::json LinkManager::extract_status() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
@ -243,7 +243,7 @@ namespace llarp
|
||||
|
||||
void check_persisting_conns(std::chrono::milliseconds now);
|
||||
|
||||
StatusObject extract_status() const;
|
||||
nlohmann::json extract_status() const;
|
||||
|
||||
void for_each_connection(std::function<void(link::Connection&)> func);
|
||||
|
||||
|
@ -1,674 +1 @@
|
||||
#include "tunnel.hpp"
|
||||
|
||||
#include <llarp/service/name.hpp>
|
||||
#include <llarp/service/tag.hpp>
|
||||
#include <llarp/util/logging.hpp>
|
||||
#include <llarp/util/logging/buffer.hpp>
|
||||
#include <llarp/util/str.hpp>
|
||||
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
|
||||
namespace llarp::quic
|
||||
{
|
||||
static auto logcat = log::Cat("tun");
|
||||
|
||||
namespace
|
||||
{
|
||||
// Takes data from the tcp connection and pushes it down the quic tunnel
|
||||
void on_outgoing_data(uvw::DataEvent& event, uvw::TCPHandle& client)
|
||||
{
|
||||
auto stream = client.data<Stream>();
|
||||
assert(stream);
|
||||
std::string_view data{event.data.get(), event.length};
|
||||
|
||||
auto peer = client.peer();
|
||||
log::trace(logcat, "{}:{} -> lokinet {}", peer.ip, peer.port, buffer_printer{data});
|
||||
|
||||
// Steal the buffer from the DataEvent's unique_ptr<char[]>:
|
||||
stream->append_buffer(reinterpret_cast<const std::byte*>(event.data.release()), event.length);
|
||||
|
||||
if (stream->used() >= tunnel::PAUSE_SIZE)
|
||||
{
|
||||
log::debug(
|
||||
logcat,
|
||||
"Quic tunnel is congested ({} bytes in flight); pausing local TCP connection reads",
|
||||
stream->used());
|
||||
client.stop();
|
||||
stream->when_available([](Stream& s) {
|
||||
auto client = s.data<uvw::TCPHandle>();
|
||||
if (s.used() < tunnel::PAUSE_SIZE)
|
||||
{
|
||||
log::debug(logcat, "Quic tunnel is no longer congested; resuming TCP connection reading!");
|
||||
client->read();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
log::debug(logcat, "Queued {} bytes", event.length);
|
||||
}
|
||||
}
|
||||
|
||||
// Received data from the quic tunnel and sends it to the TCP connection
|
||||
void on_incoming_data(Stream& stream, bstring_view bdata)
|
||||
{
|
||||
auto tcp = stream.data<uvw::TCPHandle>();
|
||||
if (!tcp)
|
||||
return; // TCP connection is gone, which would have already sent a stream close, so
|
||||
// just drop it.
|
||||
|
||||
std::string_view data{reinterpret_cast<const char*>(bdata.data()), bdata.size()};
|
||||
auto peer = tcp->peer();
|
||||
|
||||
log::trace(logcat, "{}:{} -> lokinet {}", peer.ip, peer.port, buffer_printer{data});
|
||||
|
||||
if (data.empty())
|
||||
return;
|
||||
|
||||
// Try first to write immediately from the existing buffer to avoid needing an
|
||||
// allocation and copy:
|
||||
auto written = tcp->tryWrite(const_cast<char*>(data.data()), data.size());
|
||||
if (written < (int)data.size())
|
||||
{
|
||||
data.remove_prefix(written);
|
||||
|
||||
auto wdata = std::make_unique<char[]>(data.size());
|
||||
std::copy(data.begin(), data.end(), wdata.get());
|
||||
tcp->write(std::move(wdata), data.size());
|
||||
}
|
||||
}
|
||||
|
||||
void close_tcp_pair(quic::Stream& st, std::optional<uint64_t> /*errcode*/)
|
||||
{
|
||||
if (auto tcp = st.data<uvw::TCPHandle>())
|
||||
{
|
||||
log::trace(logcat, "Closing TCP connection...");
|
||||
tcp->close();
|
||||
}
|
||||
};
|
||||
// Creates a new tcp handle that forwards incoming data/errors/closes into appropriate
|
||||
// actions on the given quic stream.
|
||||
void install_stream_forwarding(uvw::TCPHandle& tcp, Stream& stream)
|
||||
{
|
||||
tcp.data(stream.shared_from_this());
|
||||
stream.weak_data(tcp.weak_from_this());
|
||||
|
||||
tcp.clear(); // Clear any existing initial event handlers
|
||||
|
||||
tcp.on<uvw::CloseEvent>([](auto&, uvw::TCPHandle& c) {
|
||||
// This fires sometime after we call `close()` to signal that the close is done.
|
||||
if (auto stream = c.data<Stream>())
|
||||
{
|
||||
log::info(
|
||||
logcat, "Local TCP connection closed, closing associated quic stream id:{}", stream->id());
|
||||
stream->close();
|
||||
stream->data(nullptr);
|
||||
}
|
||||
c.data(nullptr);
|
||||
});
|
||||
tcp.on<uvw::EndEvent>([](auto&, uvw::TCPHandle& c) {
|
||||
// This fires on eof, most likely because the other side of the TCP connection
|
||||
// closed it.
|
||||
log::info(logcat, "EOF on connection to {}:{}", c.peer().ip, c.peer().port);
|
||||
c.close();
|
||||
});
|
||||
tcp.on<uvw::ErrorEvent>([](const uvw::ErrorEvent& e, uvw::TCPHandle& tcp) {
|
||||
log::error(
|
||||
logcat,
|
||||
"Error: [{}:{}] on connection with {}:{}; shutting down quic stream",
|
||||
e.name(),
|
||||
e.what(),
|
||||
tcp.peer().ip,
|
||||
tcp.peer().port);
|
||||
if (auto stream = tcp.data<Stream>())
|
||||
{
|
||||
stream->close(tunnel::ERROR_TCP);
|
||||
stream->data(nullptr);
|
||||
tcp.data(nullptr);
|
||||
}
|
||||
// tcp.closeReset();
|
||||
});
|
||||
tcp.on<uvw::DataEvent>(on_outgoing_data);
|
||||
stream.data_callback = on_incoming_data;
|
||||
stream.close_callback = close_tcp_pair;
|
||||
}
|
||||
// This initial data handler is responsible for pulling off the initial stream data that
|
||||
// comes back, confirming that the tunnel is opened on the other end. Currently this is a
|
||||
// null byte (CONNECT_INIT) but in the future we might encode additional data here (and, if
|
||||
// that happens, we want this older implementation to fail).
|
||||
//
|
||||
// If the initial byte checks out we replace this handler with the regular stream handler
|
||||
// (and forward the rest of the data to it if we got more than just the single byte).
|
||||
void initial_client_data_handler(uvw::TCPHandle& client, Stream& stream, bstring_view bdata)
|
||||
{
|
||||
log::trace(logcat, "Initial client handler -- data: {}", buffer_printer{bdata});
|
||||
if (bdata.empty())
|
||||
return;
|
||||
client.clear(); // Clear these initial event handlers: we either set up the proper
|
||||
// ones, or close
|
||||
|
||||
if (auto b0 = bdata[0]; b0 == tunnel::CONNECT_INIT)
|
||||
{
|
||||
// Set up callbacks, which replaces both of these initial callbacks
|
||||
client.read(); // Unfreeze (we stop() before putting into pending)
|
||||
install_stream_forwarding(client, stream);
|
||||
|
||||
if (bdata.size() > 1)
|
||||
{
|
||||
bdata.remove_prefix(1);
|
||||
stream.data_callback(stream, std::move(bdata));
|
||||
}
|
||||
|
||||
log::trace(logcat, "Starting client read...");
|
||||
}
|
||||
else
|
||||
{
|
||||
log::warning(
|
||||
logcat,
|
||||
"Remote connection returned invalid initial byte (0x{}); dropping connection",
|
||||
oxenc::to_hex(bdata.begin(), bdata.begin() + 1));
|
||||
stream.close(tunnel::ERROR_BAD_INIT);
|
||||
client.close();
|
||||
}
|
||||
stream.io_ready();
|
||||
}
|
||||
|
||||
// Initial close handler that gets replaced as soon as we receive a valid byte (in the above
|
||||
// handler). If this gets called then it means the quic remote quic end closed before we
|
||||
// established the end-to-end tunnel (for example because the remote's tunnel connection
|
||||
// failed):
|
||||
void initial_client_close_handler(
|
||||
uvw::TCPHandle& client, Stream& /*stream*/, std::optional<uint64_t> error_code)
|
||||
{
|
||||
if (error_code && *error_code == tunnel::ERROR_CONNECT)
|
||||
log::debug(logcat, "Remote TCP connection failed, closing local connection");
|
||||
else
|
||||
log::warning(
|
||||
logcat,
|
||||
"Stream connection closed {}; closing local TCP connection.",
|
||||
error_code ? "with error " + std::to_string(*error_code) : "gracefully");
|
||||
auto peer = client.peer();
|
||||
log::debug(logcat, "Closing connection to {}:{}", peer.ip, peer.port);
|
||||
client.clear();
|
||||
// TOFIX: this logic
|
||||
// if (error_code)
|
||||
// client.close();
|
||||
// else
|
||||
client.close();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TunnelManager::TunnelManager(EndpointBase& se) : service_endpoint_{se}
|
||||
{
|
||||
// Cleanup callback to clear out closed tunnel connections
|
||||
service_endpoint_.Loop()->call_every(500ms, timer_keepalive_, [this] {
|
||||
log::trace(logcat, "Checking quic tunnels for finished connections...");
|
||||
for (auto ctit = client_tunnels_.begin(); ctit != client_tunnels_.end();)
|
||||
{
|
||||
// Clear any accepted connections that have been closed:
|
||||
auto& [port, ct] = *ctit;
|
||||
for (auto it = ct.conns.begin(); it != ct.conns.end();)
|
||||
{
|
||||
// TCP connections keep a shared_ptr to their quic::Stream while open and clear
|
||||
// it when closed. (We don't want to use `.active()` here because we do
|
||||
// deliberately temporarily stop the TCP connection when the quic side gets
|
||||
// congested.
|
||||
if (not *it or not(*it)->data())
|
||||
{
|
||||
log::debug(logcat, "Cleanup up closed outgoing tunnel on quic port: {}", port);
|
||||
it = ct.conns.erase(it);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
// If there are not accepted connections left *and* we stopped listening for new
|
||||
// ones then destroy the whole thing.
|
||||
if (ct.conns.empty() and (not ct.tcp or not ct.tcp->active()))
|
||||
{
|
||||
log::debug(logcat, "All sockets closed on quic port:{},destroying tunnel data", port);
|
||||
ctit = client_tunnels_.erase(ctit);
|
||||
}
|
||||
else
|
||||
++ctit;
|
||||
}
|
||||
|
||||
log::trace(logcat, "Finished quic tunnel cleanup!");
|
||||
});
|
||||
}
|
||||
|
||||
void TunnelManager::make_server()
|
||||
{
|
||||
// auto loop = get_loop();
|
||||
|
||||
server_ = std::make_unique<Server>(service_endpoint_);
|
||||
server_->stream_open_callback = [this](Stream& stream, uint16_t port) -> bool {
|
||||
stream.close_callback = close_tcp_pair;
|
||||
|
||||
auto& conn = stream.get_connection();
|
||||
auto remote = service_endpoint_.GetEndpointWithConvoTag(conn.path.remote);
|
||||
if (!remote)
|
||||
{
|
||||
log::warning(logcat, "Received new stream open from invalid/unknown convo tag, dropping stream");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto lokinet_addr = var::visit([](auto&& remote) { return remote.to_string(); }, *remote);
|
||||
auto tunnel_to = allow_connection(lokinet_addr, port);
|
||||
if (not tunnel_to)
|
||||
return false;
|
||||
log::info(logcat, "Quic stream from {} to port:{} tunnelling to {}", lokinet_addr, port, *tunnel_to);
|
||||
|
||||
auto tcp = get_loop()->resource<uvw::TCPHandle>();
|
||||
[[maybe_unused]] auto error_handler =
|
||||
tcp->once<uvw::ErrorEvent>([&stream, to = *tunnel_to](const uvw::ErrorEvent&, uvw::TCPHandle&) {
|
||||
log::warning(logcat, "Failed to connect to {}; shutting down quic stream", to);
|
||||
stream.close(tunnel::ERROR_CONNECT);
|
||||
});
|
||||
|
||||
// As soon as we connect to the local tcp tunnel port we fire a CONNECT_INIT down the
|
||||
// stream tunnel to let the other end know the connection was successful, then set up
|
||||
// regular stream handling to handle any other to/from data.
|
||||
tcp->once<uvw::ConnectEvent>([streamw = stream.weak_from_this()](
|
||||
const uvw::ConnectEvent&, uvw::TCPHandle& tcp) {
|
||||
auto peer = tcp.peer();
|
||||
auto stream = streamw.lock();
|
||||
if (!stream)
|
||||
{
|
||||
log::warning(
|
||||
logcat,
|
||||
"Connected to TCP {}:{} but quic stream has gone away; close/resetting local TCP connection",
|
||||
peer.ip,
|
||||
peer.port);
|
||||
tcp.close();
|
||||
return;
|
||||
}
|
||||
log::debug(logcat, "Connected to {}:{} for quic stream ID:{}", peer.ip, peer.port, stream->id());
|
||||
// Set up the data stream forwarding (which also clears these initial handlers).
|
||||
install_stream_forwarding(tcp, *stream);
|
||||
assert(stream->used() == 0);
|
||||
|
||||
// Send the magic byte, and start reading from the tcp tunnel in the logic
|
||||
// thread
|
||||
stream->append_buffer(new std::byte[1]{tunnel::CONNECT_INIT}, 1);
|
||||
tcp.read();
|
||||
});
|
||||
|
||||
tcp->connect(*tunnel_to->operator const sockaddr*());
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
int TunnelManager::listen(ListenHandler handler)
|
||||
{
|
||||
if (!handler)
|
||||
throw std::logic_error{"Cannot call listen() with a null handler"};
|
||||
assert(service_endpoint_.Loop()->inEventLoop());
|
||||
if (not server_)
|
||||
make_server();
|
||||
|
||||
int id = next_handler_id_++;
|
||||
incoming_handlers_.emplace_hint(incoming_handlers_.end(), id, std::move(handler));
|
||||
return id;
|
||||
}
|
||||
|
||||
int TunnelManager::listen(SockAddr addr)
|
||||
{
|
||||
return listen([addr](std::string_view, uint16_t p) -> std::optional<SockAddr> {
|
||||
log::info(logcat, "try accepting {}", addr.getPort());
|
||||
if (p == addr.getPort())
|
||||
return addr;
|
||||
return std::nullopt;
|
||||
});
|
||||
}
|
||||
|
||||
void TunnelManager::forget(int id)
|
||||
{
|
||||
incoming_handlers_.erase(id);
|
||||
}
|
||||
|
||||
std::optional<SockAddr> TunnelManager::allow_connection(std::string_view lokinet_addr, uint16_t port)
|
||||
{
|
||||
for (auto& [id, handler] : incoming_handlers_)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (auto addr = handler(lokinet_addr, port))
|
||||
return addr;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
log::warning(
|
||||
logcat, "Incoming Quic connection from {} to port:{} denied:{}", lokinet_addr, port, e.what());
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
log::warning(logcat, "Incoming Quic connection from {} to port:{} denied by all handlers!", lokinet_addr, port);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::shared_ptr<uvw::Loop> TunnelManager::get_loop()
|
||||
{
|
||||
if (auto loop = service_endpoint_.Loop()->MaybeGetUVWLoop())
|
||||
return loop;
|
||||
throw std::logic_error{"TunnelManager requires a libuv-based event loop"};
|
||||
}
|
||||
|
||||
// Finds the first unused key in `map`, starting at `start` and wrapping back to 0 if we hit the
|
||||
// end. Requires an unsigned int type for the key. Requires nullopt if the map is completely
|
||||
// full, otherwise returns the free key.
|
||||
template <typename K, typename V, typename = std::enable_if_t<std::is_integral_v<K> && std::is_unsigned_v<K>>>
|
||||
static std::optional<K> find_unused_key(std::map<K, V>& map, K start)
|
||||
{
|
||||
if (map.size() == std::numeric_limits<K>::max())
|
||||
return std::nullopt; // The map is completely full
|
||||
[[maybe_unused]] bool from_zero = (start == K{0});
|
||||
|
||||
// Start at the first key >= start, then walk 1-by-1 (incrementing start) until we find a
|
||||
// strictly > key, which means we've found a hole we can use
|
||||
auto it = map.lower_bound(start);
|
||||
if (it == map.end())
|
||||
return start;
|
||||
|
||||
for (; it != map.end(); ++it, ++start)
|
||||
if (it->first != start)
|
||||
return start;
|
||||
if (start != 0) // `start` didn't wrap which means we found an empty slot
|
||||
return start;
|
||||
assert(!from_zero); // There *must* be a free slot somewhere in [0, max] (otherwise the map
|
||||
// would be completely full and we'd have returned nullopt).
|
||||
return find_unused_key(map, K{0});
|
||||
}
|
||||
|
||||
// Wrap common tasks and cleanup that we need to do from multiple places while establishing a
|
||||
// tunnel
|
||||
bool TunnelManager::continue_connecting(
|
||||
uint16_t pseudo_port, bool step_success, std::string_view step_name, std::string_view addr)
|
||||
{
|
||||
assert(service_endpoint_.Loop()->inEventLoop());
|
||||
auto it = client_tunnels_.find(pseudo_port);
|
||||
if (it == client_tunnels_.end())
|
||||
{
|
||||
log::debug(logcat, "Quic tunnel to {} closed before step (name:{}) finished!", addr, step_name);
|
||||
return false;
|
||||
}
|
||||
if (!step_success)
|
||||
{
|
||||
log::warning(logcat, "Quic tunnel to {} failed during step (name:{}); aborting tunnel!", addr, step_name);
|
||||
it->second.tcp->close();
|
||||
if (it->second.open_cb)
|
||||
it->second.open_cb(false);
|
||||
client_tunnels_.erase(it);
|
||||
}
|
||||
return step_success;
|
||||
}
|
||||
|
||||
std::pair<SockAddr, uint16_t> TunnelManager::open(
|
||||
std::string_view remote_address, uint16_t port, OpenCallback on_open, SockAddr bind_addr)
|
||||
{
|
||||
std::string remote_addr = lowercase_ascii_string(std::string{remote_address});
|
||||
|
||||
std::pair<SockAddr, uint16_t> result;
|
||||
auto& [saddr, pport] = result;
|
||||
|
||||
auto maybe_remote = service::ParseAddress(remote_addr);
|
||||
if (!maybe_remote)
|
||||
{
|
||||
if (not service::NameIsValid(remote_addr))
|
||||
throw std::invalid_argument{"Invalid remote lokinet name/address"};
|
||||
// Otherwise it's a valid ONS name, so we'll initiate an ONS lookup below
|
||||
}
|
||||
|
||||
// Open the TCP tunnel right away; it will just block new incoming connections until the
|
||||
// quic connection is established, but this still allows the caller to connect right away
|
||||
// and queue an initial request (rather than having to wait via a callback before
|
||||
// connecting). It also makes sure we can actually listen on the given address before we go
|
||||
// ahead with establishing the quic connection.
|
||||
auto tcp_tunnel = get_loop()->resource<uvw::TCPHandle>();
|
||||
const char* failed = nullptr;
|
||||
auto err_handler = tcp_tunnel->once<uvw::ErrorEvent>([&failed](auto& evt, auto&) { failed = evt.what(); });
|
||||
tcp_tunnel->bind(*bind_addr.operator const sockaddr*());
|
||||
tcp_tunnel->on<uvw::ListenEvent>([this](const uvw::ListenEvent&, uvw::TCPHandle& tcp_tunnel) {
|
||||
auto client = tcp_tunnel.loop().resource<uvw::TCPHandle>();
|
||||
tcp_tunnel.accept(*client);
|
||||
// Freeze the connection (after accepting) because we may need to stall it until a
|
||||
// stream becomes available; flush_pending_incoming will unfreeze it.
|
||||
client->stop();
|
||||
auto pport = tcp_tunnel.data<uint16_t>();
|
||||
if (pport)
|
||||
{
|
||||
if (auto it = client_tunnels_.find(*pport); it != client_tunnels_.end())
|
||||
{
|
||||
it->second.pending_incoming.emplace(std::move(client));
|
||||
flush_pending_incoming(it->second);
|
||||
return;
|
||||
}
|
||||
tcp_tunnel.data(nullptr);
|
||||
}
|
||||
client->close();
|
||||
});
|
||||
tcp_tunnel->listen();
|
||||
tcp_tunnel->erase(err_handler);
|
||||
|
||||
if (failed)
|
||||
{
|
||||
tcp_tunnel->close();
|
||||
throw std::runtime_error{
|
||||
fmt::format("Failed to bind/listen local TCP tunnel socket on {}: {}", bind_addr, failed)};
|
||||
}
|
||||
|
||||
auto bound = tcp_tunnel->sock();
|
||||
saddr = SockAddr{bound.ip, huint16_t{static_cast<uint16_t>(bound.port)}};
|
||||
|
||||
// Find the first unused psuedo-port value starting from next_pseudo_port_.
|
||||
if (auto p = find_unused_key(client_tunnels_, next_pseudo_port_))
|
||||
pport = *p;
|
||||
else
|
||||
throw std::runtime_error{"Unable to open an outgoing quic connection: too many existing connections"};
|
||||
(next_pseudo_port_ = pport)++;
|
||||
|
||||
log::info(logcat, "Bound TCP tunnel {} for quic client pseudo_port:{}", saddr, pport);
|
||||
|
||||
// We are emplacing into client_tunnels_ here: beyond this point we must not throw until we
|
||||
// return (or if we do, make sure we remove this row from client_tunnels_ first).
|
||||
assert(client_tunnels_.count(pport) == 0);
|
||||
auto& ct = client_tunnels_[pport];
|
||||
ct.open_cb = std::move(on_open);
|
||||
ct.tcp = std::move(tcp_tunnel);
|
||||
// We use this pport shared_ptr value on the listening tcp socket both to hand to pport into
|
||||
// the accept handler, and to let the accept handler know that `this` is still safe to use.
|
||||
ct.tcp->data(std::make_shared<uint16_t>(pport));
|
||||
|
||||
auto after_path = [this, port, pport = pport, remote_addr](auto maybe_convo) {
|
||||
if (not continue_connecting(pport, (bool)maybe_convo, "path build", remote_addr))
|
||||
return;
|
||||
SockAddr dest{maybe_convo->ToV6()};
|
||||
dest.setPort(port);
|
||||
make_client(dest, *client_tunnels_.find(pport));
|
||||
};
|
||||
|
||||
if (!maybe_remote)
|
||||
{
|
||||
// We were given an ONS address, so it's a two-step process: first we resolve the ONS
|
||||
// name, then we have to build a path to that address.
|
||||
service_endpoint_.LookupNameAsync(
|
||||
remote_addr,
|
||||
[this, after_path = std::move(after_path), pport = pport, remote_addr = std::move(remote_addr)](
|
||||
auto maybe_remote) {
|
||||
if (not continue_connecting(pport, (bool)maybe_remote, "endpoint ONS lookup", remote_addr))
|
||||
return;
|
||||
service_endpoint_.MarkAddressOutbound(*maybe_remote);
|
||||
service_endpoint_.EnsurePathTo(*maybe_remote, after_path, open_timeout);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
auto& remote = *maybe_remote;
|
||||
|
||||
// See if we have an existing convo tag we can use to start things immediately
|
||||
if (auto maybe_convo = service_endpoint_.GetBestConvoTagFor(remote))
|
||||
after_path(maybe_convo);
|
||||
else
|
||||
{
|
||||
service_endpoint_.MarkAddressOutbound(remote);
|
||||
service_endpoint_.EnsurePathTo(remote, after_path, open_timeout);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void TunnelManager::close(int id)
|
||||
{
|
||||
if (auto it = client_tunnels_.find(id); it != client_tunnels_.end())
|
||||
{
|
||||
it->second.tcp->close();
|
||||
it->second.tcp->data(nullptr);
|
||||
it->second.tcp.reset();
|
||||
}
|
||||
}
|
||||
|
||||
TunnelManager::ClientTunnel::~ClientTunnel()
|
||||
{
|
||||
if (tcp)
|
||||
{
|
||||
tcp->close();
|
||||
tcp->data(nullptr);
|
||||
tcp.reset();
|
||||
}
|
||||
for (auto& conn : conns)
|
||||
conn->close();
|
||||
conns.clear();
|
||||
|
||||
while (not pending_incoming.empty())
|
||||
{
|
||||
if (auto tcp = pending_incoming.front().lock())
|
||||
{
|
||||
tcp->clear();
|
||||
tcp->close();
|
||||
}
|
||||
pending_incoming.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void TunnelManager::make_client(const SockAddr& remote, std::pair<const uint16_t, ClientTunnel>& row)
|
||||
{
|
||||
assert(remote.getPort() > 0);
|
||||
auto& [pport, tunnel] = row;
|
||||
assert(not tunnel.client);
|
||||
tunnel.client = std::make_unique<Client>(service_endpoint_, remote, pport);
|
||||
auto conn = tunnel.client->get_connection();
|
||||
|
||||
conn->on_stream_available = [this, id = row.first](Connection&) {
|
||||
log::debug(logcat, "Quic connection (id:{}) established; streams now available", id);
|
||||
if (auto it = client_tunnels_.find(id); it != client_tunnels_.end())
|
||||
flush_pending_incoming(it->second);
|
||||
};
|
||||
}
|
||||
|
||||
void TunnelManager::flush_pending_incoming(ClientTunnel& ct)
|
||||
{
|
||||
if (!ct.client)
|
||||
return; // Happens if we're still waiting for a path to build
|
||||
if (not ct.client->get_connection())
|
||||
return;
|
||||
auto& conn = *ct.client->get_connection();
|
||||
int available = conn.get_streams_available();
|
||||
while (available > 0 and not ct.pending_incoming.empty())
|
||||
{
|
||||
auto tcp_client = ct.pending_incoming.front().lock();
|
||||
ct.pending_incoming.pop();
|
||||
if (not tcp_client)
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
auto str = conn.open_stream(
|
||||
[tcp_client](auto&&... args) {
|
||||
initial_client_data_handler(*tcp_client, std::forward<decltype(args)>(args)...);
|
||||
},
|
||||
[tcp_client](auto&&... args) {
|
||||
initial_client_close_handler(*tcp_client, std::forward<decltype(args)>(args)...);
|
||||
});
|
||||
available--;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
log::warning(logcat, "Opening quic stream failed: {}", e.what());
|
||||
tcp_client->close();
|
||||
}
|
||||
|
||||
log::trace(logcat, "Set up new stream!");
|
||||
conn.io_ready();
|
||||
}
|
||||
}
|
||||
|
||||
void TunnelManager::receive_packet(const service::ConvoTag& tag, const llarp_buffer_t& buf)
|
||||
{
|
||||
if (buf.sz <= 4)
|
||||
{
|
||||
log::warning(logcat, "Invalid quic packet: packet size ({}) too small", buf.sz);
|
||||
return;
|
||||
}
|
||||
auto type = static_cast<std::byte>(buf.base[0]);
|
||||
nuint16_t pseudo_port_n;
|
||||
std::memcpy(&pseudo_port_n.n, &buf.base[1], 2);
|
||||
uint16_t pseudo_port = ToHost(pseudo_port_n).h;
|
||||
auto ecn = static_cast<uint8_t>(buf.base[3]);
|
||||
bstring_view data{reinterpret_cast<const std::byte*>(&buf.base[4]), buf.sz - 4};
|
||||
|
||||
SockAddr remote{tag.ToV6()};
|
||||
quic::Endpoint* ep = nullptr;
|
||||
if (type == CLIENT_TO_SERVER)
|
||||
{
|
||||
log::trace(logcat, "Packet is client-to-server from client pseudo-port:{}", pseudo_port);
|
||||
// Client-to-server: the header port is the return port
|
||||
remote.setPort(pseudo_port);
|
||||
if (!server_)
|
||||
{
|
||||
log::warning(logcat, "Dropping incoming quic packet to server: no listeners");
|
||||
return;
|
||||
}
|
||||
ep = server_.get();
|
||||
}
|
||||
else if (type == SERVER_TO_CLIENT)
|
||||
{
|
||||
log::trace(logcat, "Packet is server-to-client to client pseudo-port:{}", pseudo_port);
|
||||
// Server-to-client: the header port tells us which client tunnel this is going to
|
||||
if (auto it = client_tunnels_.find(pseudo_port); it != client_tunnels_.end())
|
||||
ep = it->second.client.get();
|
||||
|
||||
if (not ep)
|
||||
{
|
||||
log::warning(logcat, "Incoming quic packet to invalid/closed client; dropping");
|
||||
return;
|
||||
}
|
||||
|
||||
// The server doesn't send back the port because we already know it 1-to-1 from our
|
||||
// outgoing connection.
|
||||
if (auto conn = static_cast<quic::Client&>(*ep).get_connection())
|
||||
{
|
||||
remote.setPort(conn->path.remote.port());
|
||||
log::trace(logcat, "Remoter port is {}", remote.getPort());
|
||||
}
|
||||
else
|
||||
{
|
||||
log::warning(logcat, "Incoming quic to a quic::Client without an active quic::Connection; dropping");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log::warning(logcat, "Invalid incoming quic packet type {}; dropping packet", type);
|
||||
return;
|
||||
}
|
||||
ep->receive_packet(remote, ecn, data);
|
||||
}
|
||||
} // namespace llarp::quic
|
||||
|
@ -1,219 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <llarp/service/tag.hpp>
|
||||
#include <llarp/util/time.hpp>
|
||||
|
||||
#include <charconv>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace llarp::link
|
||||
namespace llarp
|
||||
{
|
||||
// struct Endpoint;
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
namespace tunnel
|
||||
class QUICTunnel
|
||||
{
|
||||
// The server sends back a 0x00 to signal that the remote TCP connection was established and
|
||||
// that it is now accepting stream data; the client is not allowed to send any other data
|
||||
// down the stream until this comes back (any data sent down the stream before then is
|
||||
// discarded.)
|
||||
inline constexpr std::byte CONNECT_INIT{0x00};
|
||||
// QUIC application error codes we sent on failures:
|
||||
// Failure to establish an initial connection:
|
||||
inline constexpr uint64_t ERROR_CONNECT{0x5471907};
|
||||
// Error if we receive something other than CONNECT_INIT as the initial stream data from the
|
||||
// server
|
||||
inline constexpr uint64_t ERROR_BAD_INIT{0x5471908};
|
||||
// Close error code sent if we get an error on the TCP socket (other than an initial connect
|
||||
// failure)
|
||||
inline constexpr uint64_t ERROR_TCP{0x5471909};
|
||||
|
||||
// We pause reading from the local TCP socket if we have more than this amount of
|
||||
// outstanding unacked data in the quic tunnel, then resume once it drops below this.
|
||||
inline constexpr size_t PAUSE_SIZE = 64 * 1024;
|
||||
} // namespace tunnel
|
||||
|
||||
/// Manager class for incoming and outgoing QUIC tunnels.
|
||||
class TunnelManager
|
||||
{
|
||||
public:
|
||||
using ListenHandler = std::function<std::optional<oxen::quic::Address>(
|
||||
std::string_view lokinet_addr, // The remote's full lokinet address
|
||||
uint16_t port // The requested port the tunnel wants to reach
|
||||
)>;
|
||||
|
||||
// Timeout for the next `open()`. Note that when `open()` is given a ONS name to resolve
|
||||
// this includes the resolution time.
|
||||
std::chrono::milliseconds open_timeout = 4s;
|
||||
|
||||
TunnelManager();
|
||||
|
||||
/// Adds an incoming listener callback. When a new incoming quic connection is initiated to
|
||||
/// us by some remote we invoke these callback(s) in order of registration. Each one has
|
||||
/// three options:
|
||||
/// - return a concrete llarp::SockAddr giving the TCP address/port to which we should
|
||||
/// connect new incoming streams over the connection.
|
||||
/// - returns std::nullopt to decline handling the connection (we will try the next listen
|
||||
/// handler, in order of registration).
|
||||
/// - throws an exception (derived from std::exception) in which case we refuse the
|
||||
/// connection without trying any additional handlers.
|
||||
///
|
||||
/// If `listen()` is not called at all then new incoming connections will be immediately
|
||||
/// dropped.
|
||||
///
|
||||
/// For plain-C wrappers around this see [FIXME].
|
||||
int listen(ListenHandler handler);
|
||||
|
||||
/// Simple wrapper around `listen(...)` that adds a handler that accepts all incoming
|
||||
/// connections trying to tunnel to port `port` and maps them to `localhost:port`.
|
||||
int listen(oxen::quic::Address port);
|
||||
|
||||
/// Removes an incoming connection handler; takes the ID returned by `listen()`.
|
||||
void forget(int id);
|
||||
|
||||
/// Called when open succeeds or times out.
|
||||
using OpenCallback = std::function<void(bool success)>;
|
||||
|
||||
/// Opens a quic tunnel to some remote lokinet address. (Should only be called from the
|
||||
/// event loop thread.)
|
||||
///
|
||||
/// \param remote_addr is the lokinet address or ONS name (e.g. `azfojblahblahblah.loki` or
|
||||
/// `blocks.loki`) that the tunnel should connect to.
|
||||
/// \param port is the tunneled port on the remote that the client wants to reach. (This is
|
||||
/// *not* the quic pseudo-port, which is always 0).
|
||||
/// \param callback callback invoked when the quic connection has been established, or has
|
||||
/// timed out. \param bind_addr is the bind address and port that we should use for the
|
||||
/// localhost TCP connection. Use port 0 to let the OS choose a random high port. Defaults
|
||||
/// to `127.0.0.1:0`.
|
||||
///
|
||||
/// This call immediately opens the local TCP socket, and initiates the lokinet connection
|
||||
/// and QUIC tunnel to the remote. If the connection fails, the TCP socket will be closed.
|
||||
/// Note, however, that this TCP socket will block until the underlying quic connection is
|
||||
/// established.
|
||||
///
|
||||
/// Each connection to the local TCP socket establishes a new stream over the QUIC
|
||||
/// connection.
|
||||
///
|
||||
/// \return a pair:
|
||||
/// - SockAddr containing the just-opened localhost socket that tunnels to the remote. This
|
||||
/// is typically the same IP as `bind_addr`, with the port filled in (if bind_addr had a 0
|
||||
/// port). Note that, while you can connect to this socket immediately, it will block until
|
||||
/// the actual connection and streams are established (and will be closed if they fail).
|
||||
/// - unique integer that can be passed to close() to stop listening for new connections.
|
||||
/// This also serves as a unique internal "pseudo-port" number to route returned quic
|
||||
/// packets to the right connection.
|
||||
///
|
||||
/// TODO: add a callback to invoke when QUIC connection succeeds or fails.
|
||||
/// TODO: add a plain C wrapper around this
|
||||
std::pair<oxen::quic::Address, uint16_t> open(
|
||||
std::string_view remote_addr,
|
||||
uint16_t port,
|
||||
OpenCallback on_open = {},
|
||||
oxen::quic::Address bind_addr = {"127.0.0.1", 0});
|
||||
|
||||
/// Start closing an outgoing tunnel; takes the ID returned by `open()`. Note that an
|
||||
/// existing established tunneled connections will not be forcibly closed; this simply stops
|
||||
/// accepting new tunnel connections.
|
||||
void close(int id);
|
||||
|
||||
/// Called from tun code to deliver a quic packet.
|
||||
///
|
||||
/// \param dest - the convotag for which the packet arrived
|
||||
/// \param buf - the raw arriving packet
|
||||
///
|
||||
void receive_packet(const service::SessionTag& tag, const llarp_buffer_t& buf);
|
||||
|
||||
/// return true if we have any listeners added
|
||||
inline bool hasListeners() const
|
||||
{
|
||||
return not incoming_handlers_.empty();
|
||||
}
|
||||
|
||||
private:
|
||||
// EndpointBase& service_endpoint_;
|
||||
|
||||
struct ClientTunnel
|
||||
{
|
||||
// quic endpoint
|
||||
// std::unique_ptr<Endpoint> client;
|
||||
// Callback to invoke on quic connection established (true argument) or failed (false
|
||||
// arg)
|
||||
OpenCallback open_cb;
|
||||
// TCP listening socket
|
||||
// std::shared_ptr<uvw::TCPHandle> tcp;
|
||||
// // Accepted TCP connections
|
||||
// std::unordered_set<std::shared_ptr<uvw::TCPHandle>> conns;
|
||||
// // Queue of incoming connections that are waiting for a stream to become available
|
||||
// (either
|
||||
// // because we are still handshaking, or we reached the stream limit).
|
||||
// std::queue<std::weak_ptr<uvw::TCPHandle>> pending_incoming;
|
||||
|
||||
~ClientTunnel()
|
||||
{
|
||||
// if (tcp)
|
||||
// {
|
||||
// tcp->close();
|
||||
// tcp->data(nullptr);
|
||||
// tcp.reset();
|
||||
// }
|
||||
// for (auto& conn : conns)
|
||||
// conn->close();
|
||||
// conns.clear();
|
||||
|
||||
// while (not pending_incoming.empty())
|
||||
// {
|
||||
// if (auto tcp = pending_incoming.front().lock())
|
||||
// {
|
||||
// tcp->clear();
|
||||
// tcp->close();
|
||||
// }
|
||||
// pending_incoming.pop();
|
||||
// }
|
||||
}
|
||||
};
|
||||
|
||||
// pseudo-port -> Client instance (the "port" is used to route incoming quic packets to the
|
||||
// right quic endpoint); pseudo-ports start at 1.
|
||||
std::map<uint16_t, ClientTunnel> client_tunnels_;
|
||||
|
||||
uint16_t next_pseudo_port_ = 0;
|
||||
// bool pport_wrapped_ = false;
|
||||
|
||||
bool continue_connecting(
|
||||
uint16_t pseudo_port, bool step_success, std::string_view step_name, std::string_view addr);
|
||||
|
||||
void make_client(const oxen::quic::Address& remote, std::pair<const uint16_t, ClientTunnel>& row);
|
||||
|
||||
void flush_pending_incoming(ClientTunnel& ct);
|
||||
|
||||
// Server instance; this listens on pseudo-port 0 (if it listens). This is automatically
|
||||
// instantiated the first time `listen()` is called; if not instantiated we simply drop any
|
||||
// inbound client-to-server quic packets.
|
||||
// std::unique_ptr<Server> server_;
|
||||
|
||||
void make_server();
|
||||
|
||||
// Called when a new during connection handshaking once we have the established transport
|
||||
// parameters (which include the port) if this is an incoming connection (and this endpoint
|
||||
// is a server). This checks handlers to see whether the stream is allowed and, if so,
|
||||
// returns a SockAddr containing the IP/port the tunnel should map to. Returns nullopt if
|
||||
// the connection should be rejected.
|
||||
std::optional<oxen::quic::Address> allow_connection(std::string_view lokinet_addr, uint16_t port);
|
||||
|
||||
// Incoming stream handlers
|
||||
std::map<int, ListenHandler> incoming_handlers_;
|
||||
int next_handler_id_ = 1;
|
||||
|
||||
// std::shared_ptr<uvw::Loop>
|
||||
// get_loop();
|
||||
|
||||
// Cleanup member
|
||||
std::shared_ptr<int> timer_keepalive_ = std::make_shared<int>(0);
|
||||
//
|
||||
};
|
||||
|
||||
} // namespace llarp::link
|
||||
} // namespace llarp
|
||||
|
@ -12,6 +12,8 @@
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
using namespace std::literals;
|
||||
|
||||
namespace messages
|
||||
{
|
||||
static auto logcat = log::Cat("messages");
|
||||
|
@ -253,9 +253,9 @@ namespace llarp::net
|
||||
return true;
|
||||
}
|
||||
|
||||
StatusObject ProtocolInfo::ExtractStatus() const
|
||||
nlohmann::json ProtocolInfo::ExtractStatus() const
|
||||
{
|
||||
StatusObject status{
|
||||
nlohmann::json status{
|
||||
{"protocol", static_cast<uint32_t>(protocol)},
|
||||
};
|
||||
if (port)
|
||||
@ -263,19 +263,19 @@ namespace llarp::net
|
||||
return status;
|
||||
}
|
||||
|
||||
StatusObject TrafficPolicy::ExtractStatus() const
|
||||
nlohmann::json TrafficPolicy::ExtractStatus() const
|
||||
{
|
||||
std::vector<StatusObject> rangesStatus;
|
||||
std::vector<nlohmann::json> rangesStatus;
|
||||
std::transform(ranges.begin(), ranges.end(), std::back_inserter(rangesStatus), [](const auto& range) {
|
||||
return range.to_string();
|
||||
});
|
||||
|
||||
std::vector<StatusObject> protosStatus;
|
||||
std::vector<nlohmann::json> protosStatus;
|
||||
std::transform(protocols.begin(), protocols.end(), std::back_inserter(protosStatus), [](const auto& proto) {
|
||||
return proto.ExtractStatus();
|
||||
});
|
||||
|
||||
return StatusObject{{"ranges", rangesStatus}, {"protocols", protosStatus}};
|
||||
return nlohmann::json{{"ranges", rangesStatus}, {"protocols", protosStatus}};
|
||||
}
|
||||
|
||||
} // namespace llarp::net
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include <llarp/address/ip_packet.hpp>
|
||||
#include <llarp/address/ip_range.hpp>
|
||||
#include <llarp/util/types.hpp>
|
||||
|
||||
#include <oxenc/bt.h>
|
||||
|
||||
@ -42,7 +41,7 @@ namespace llarp::net
|
||||
|
||||
bool bt_decode(std::string_view buf);
|
||||
|
||||
StatusObject ExtractStatus() const;
|
||||
nlohmann::json ExtractStatus() const;
|
||||
|
||||
/// returns true if an ip packet looks like it matches this protocol info
|
||||
/// returns false otherwise
|
||||
@ -72,7 +71,7 @@ namespace llarp::net
|
||||
void bt_decode(oxenc::bt_dict_consumer& btdc);
|
||||
|
||||
bool bt_decode(std::string_view buf);
|
||||
StatusObject ExtractStatus() const;
|
||||
nlohmann::json ExtractStatus() const;
|
||||
|
||||
/// returns true if we allow the traffic in this ip packet
|
||||
/// returns false otherwise
|
||||
|
@ -246,9 +246,9 @@ namespace llarp::path
|
||||
return hops_str;
|
||||
}
|
||||
|
||||
StatusObject PathHopConfig::ExtractStatus() const
|
||||
nlohmann::json PathHopConfig::ExtractStatus() const
|
||||
{
|
||||
StatusObject obj{
|
||||
nlohmann::json obj{
|
||||
{"ip", rc.addr().to_string()},
|
||||
{"lifetime", to_json(lifetime)},
|
||||
{"router", rc.router_id().ToHex()},
|
||||
@ -257,11 +257,11 @@ namespace llarp::path
|
||||
return obj;
|
||||
}
|
||||
|
||||
StatusObject Path::ExtractStatus() const
|
||||
nlohmann::json Path::ExtractStatus() const
|
||||
{
|
||||
auto now = llarp::time_now_ms();
|
||||
|
||||
StatusObject obj{
|
||||
nlohmann::json obj{
|
||||
{"intro", intro.ExtractStatus()},
|
||||
{"lastRecvMsg", to_json(last_recv_msg)},
|
||||
{"lastLatencyTest", to_json(last_latency_test)},
|
||||
@ -275,8 +275,8 @@ namespace llarp::path
|
||||
// {"hasExit", SupportsAnyRoles(ePathRoleExit)}
|
||||
};
|
||||
|
||||
std::vector<StatusObject> hopsObj;
|
||||
std::transform(hops.begin(), hops.end(), std::back_inserter(hopsObj), [](const auto& hop) -> StatusObject {
|
||||
std::vector<nlohmann::json> hopsObj;
|
||||
std::transform(hops.begin(), hops.end(), std::back_inserter(hopsObj), [](const auto& hop) -> nlohmann::json {
|
||||
return hop.ExtractStatus();
|
||||
});
|
||||
obj["hops"] = hopsObj;
|
||||
|
@ -60,7 +60,7 @@ namespace llarp
|
||||
return weak_from_this();
|
||||
}
|
||||
|
||||
StatusObject ExtractStatus() const;
|
||||
nlohmann::json ExtractStatus() const;
|
||||
|
||||
void MarkActive(std::chrono::milliseconds now)
|
||||
{
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include <llarp/ev/loop.hpp>
|
||||
#include <llarp/util/compare_ptr.hpp>
|
||||
#include <llarp/util/decaying_hashset.hpp>
|
||||
#include <llarp/util/types.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
@ -32,9 +32,9 @@ namespace llarp::path
|
||||
return _edge_limiter.Contains(router);
|
||||
}
|
||||
|
||||
StatusObject BuildStats::ExtractStatus() const
|
||||
nlohmann::json BuildStats::ExtractStatus() const
|
||||
{
|
||||
return StatusObject{
|
||||
return nlohmann::json{
|
||||
{"success", success}, {"attempts", attempts}, {"timeouts", timeouts}, {"fails", build_fails}};
|
||||
}
|
||||
|
||||
@ -314,14 +314,14 @@ namespace llarp::path
|
||||
}
|
||||
}
|
||||
|
||||
StatusObject PathHandler::ExtractStatus() const
|
||||
nlohmann::json PathHandler::ExtractStatus() const
|
||||
{
|
||||
StatusObject obj{
|
||||
nlohmann::json obj{
|
||||
{"buildStats", _build_stats.ExtractStatus()},
|
||||
{"numHops", uint64_t{num_hops}},
|
||||
{"numPaths", uint64_t{num_paths_desired}}};
|
||||
std::transform(
|
||||
_paths.begin(), _paths.end(), std::back_inserter(obj["paths"]), [](const auto& item) -> StatusObject {
|
||||
_paths.begin(), _paths.end(), std::back_inserter(obj["paths"]), [](const auto& item) -> nlohmann::json {
|
||||
return item.second->ExtractStatus();
|
||||
});
|
||||
return obj;
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include <llarp/util/decaying_hashset.hpp>
|
||||
#include <llarp/util/thread/threading.hpp>
|
||||
#include <llarp/util/time.hpp>
|
||||
#include <llarp/util/types.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <set>
|
||||
@ -68,7 +67,7 @@ namespace llarp
|
||||
uint64_t path_fails = 0; // path failures post-build
|
||||
uint64_t timeouts = 0;
|
||||
|
||||
StatusObject ExtractStatus() const;
|
||||
nlohmann::json ExtractStatus() const;
|
||||
|
||||
double SuccessRatio() const;
|
||||
|
||||
@ -171,7 +170,7 @@ namespace llarp
|
||||
std::optional<std::set<service::Introduction>> get_path_intros_conditional(
|
||||
std::function<bool(const service::Introduction&)> filter) const;
|
||||
|
||||
StatusObject ExtractStatus() const;
|
||||
nlohmann::json ExtractStatus() const;
|
||||
|
||||
virtual bool should_build_more() const;
|
||||
|
||||
|
@ -33,7 +33,7 @@ namespace llarp
|
||||
// lifetime
|
||||
std::chrono::milliseconds lifetime = DEFAULT_LIFETIME;
|
||||
|
||||
StatusObject ExtractStatus() const;
|
||||
nlohmann::json ExtractStatus() const;
|
||||
|
||||
bool operator<(const PathHopConfig& other) const
|
||||
{
|
||||
|
@ -45,7 +45,7 @@ namespace llarp::path
|
||||
if (r.path_context().has_transit_hop(hop->info))
|
||||
throw std::runtime_error{PathBuildMessage::BAD_PATHID};
|
||||
|
||||
if (!crypto::dh_server(hop->shared.data(), symmkey.data(), r.pubkey(), symmnonce.data()))
|
||||
if (!crypto::dh_server(hop->shared.data(), symmkey.data(), r.pubkey().data(), symmnonce.data()))
|
||||
throw std::runtime_error{PathBuildMessage::BAD_CRYPTO};
|
||||
|
||||
// generate hash of hop key for nonce mutation
|
||||
|
@ -5,16 +5,13 @@
|
||||
#include <llarp/constants/time.hpp>
|
||||
#include <llarp/crypto/crypto.hpp>
|
||||
#include <llarp/dht/node.hpp>
|
||||
#include <llarp/handlers/common.hpp>
|
||||
#include <llarp/handlers/embedded.hpp>
|
||||
#include <llarp/handlers/tun.hpp>
|
||||
#include <llarp/link/contacts.hpp>
|
||||
#include <llarp/link/link_manager.hpp>
|
||||
#include <llarp/messages/dht.hpp>
|
||||
#include <llarp/net/net.hpp>
|
||||
#include <llarp/nodedb.hpp>
|
||||
#include <llarp/util/formattable.hpp>
|
||||
#include <llarp/util/logging.hpp>
|
||||
#include <llarp/util/types.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iterator>
|
||||
@ -56,20 +53,20 @@ namespace llarp
|
||||
_lmq->MAX_MSG_SIZE = -1;
|
||||
}
|
||||
|
||||
StatusObject Router::ExtractStatus() const
|
||||
nlohmann::json Router::ExtractStatus() const
|
||||
{
|
||||
if (not _is_running)
|
||||
StatusObject{{"running", false}};
|
||||
nlohmann::json{{"running", false}};
|
||||
|
||||
return StatusObject{
|
||||
return nlohmann::json{
|
||||
{"running", true}, {"numNodesKnown", _node_db->num_rcs()}, {"links", _link_manager->extract_status()}};
|
||||
}
|
||||
|
||||
// TODO: investigate changes needed for libquic integration
|
||||
StatusObject Router::ExtractSummaryStatus() const
|
||||
nlohmann::json Router::ExtractSummaryStatus() const
|
||||
{
|
||||
// if (!is_running)
|
||||
// return StatusObject{{"running", false}};
|
||||
// return nlohmann::json{{"running", false}};
|
||||
|
||||
// auto services = _hidden_service_context.ExtractStatus();
|
||||
|
||||
@ -140,7 +137,7 @@ namespace llarp
|
||||
// }
|
||||
// double ratio = static_cast<double>(success) / (attempts + 1);
|
||||
|
||||
StatusObject stats{
|
||||
nlohmann::json stats{
|
||||
{"running", true},
|
||||
{"version", llarp::LOKINET_VERSION_FULL},
|
||||
{"uptime", to_json(Uptime())},
|
||||
@ -234,9 +231,9 @@ namespace llarp
|
||||
try
|
||||
{
|
||||
_identity = rpc_client()->obtain_identity_key();
|
||||
const RouterID pk{pubkey()};
|
||||
_id_pubkey = seckey_to_pubkey(_identity);
|
||||
|
||||
log::warning(logcat, "Obtained lokid identity key: {}", pk);
|
||||
log::warning(logcat, "Obtained lokid identity key: {}", _id_pubkey);
|
||||
rpc_client()->start_pings();
|
||||
break;
|
||||
}
|
||||
@ -253,6 +250,7 @@ namespace llarp
|
||||
else
|
||||
{
|
||||
_identity = _key_manager->identity_key;
|
||||
_id_pubkey = seckey_to_pubkey(_identity);
|
||||
}
|
||||
|
||||
if (_identity.is_zero())
|
||||
@ -477,67 +475,14 @@ namespace llarp
|
||||
}
|
||||
}
|
||||
|
||||
void Router::init_net_if()
|
||||
void Router::init_tun()
|
||||
{
|
||||
auto& network_config = _config->network;
|
||||
|
||||
vpn::InterfaceInfo info;
|
||||
|
||||
info.ifname = *network_config._if_name;
|
||||
info.addrs.emplace_back(*network_config._local_ip_range);
|
||||
|
||||
auto if_net = vpn_platform()->CreateInterface(std::move(info), this);
|
||||
|
||||
if (not if_net)
|
||||
if (_tun = std::make_unique<handlers::TunEndpoint>(*this); _tun != nullptr)
|
||||
{
|
||||
auto err = "Could not create net interface"s;
|
||||
log::error(logcat, "{}", err);
|
||||
throw std::runtime_error{err};
|
||||
}
|
||||
if (not loop()->add_network_interface(
|
||||
if_net, [](UDPPacket pkt [[maybe_unused]]) { /* OnInetPacket(std::move(pkt)); */ }))
|
||||
{
|
||||
auto err = "Could not create tunnel for net interface"s;
|
||||
log::error(logcat, "{}", err);
|
||||
throw std::runtime_error{err};
|
||||
}
|
||||
|
||||
// _router->loop()->add_ticker([this] { Flush(); });
|
||||
#ifndef _WIN32
|
||||
// TOFIX:
|
||||
// resolver =
|
||||
// std::make_shared<dns::Server>(_router->loop(), dns_conf,
|
||||
// if_nametoindex(if_name.c_str()));
|
||||
// resolver->Start();
|
||||
#endif
|
||||
}
|
||||
|
||||
using api_constructor = std::function<std::unique_ptr<handlers::BaseHandler>(Router&)>;
|
||||
|
||||
const std::map<std::string, api_constructor> api_constructors = {
|
||||
{"tun", [](Router& r) { return std::make_unique<handlers::TunEndpoint>(r); }},
|
||||
{"android", [](Router& r) { return std::make_unique<handlers::TunEndpoint>(r); }},
|
||||
{"ios", [](Router& r) { return std::make_unique<handlers::TunEndpoint>(r); }},
|
||||
{"embedded", [](Router& r) { return std::make_unique<handlers::EmbeddedEndpoint>(r); }}};
|
||||
|
||||
void Router::init_api()
|
||||
{
|
||||
auto& net_config = _config->network;
|
||||
auto& type = net_config.endpoint_type;
|
||||
auto& key_file = net_config.keyfile;
|
||||
|
||||
if (auto itr = api_constructors.find(type); itr != api_constructors.end())
|
||||
{
|
||||
_api = itr->second(*this);
|
||||
|
||||
if (not _api)
|
||||
throw std::runtime_error{"Failed to construct API endpoint of type {}"_format(type)};
|
||||
|
||||
_api->load_key_file(key_file, *this);
|
||||
_api->configure();
|
||||
_tun->configure();
|
||||
}
|
||||
else
|
||||
throw std::runtime_error{"API endpoint of type {} does not exist"_format(type)};
|
||||
throw std::runtime_error{"Failed to construct TunEndpoint!"};
|
||||
}
|
||||
|
||||
bool Router::configure(std::shared_ptr<Config> c, std::shared_ptr<NodeDB> nodedb)
|
||||
@ -619,19 +564,15 @@ namespace llarp
|
||||
_remote_handler = std::make_shared<handlers::RemoteHandler>(*this);
|
||||
_remote_handler->configure();
|
||||
|
||||
if (conf.network.endpoint_type != "embedded")
|
||||
{
|
||||
_should_init_tun = true;
|
||||
init_net_if();
|
||||
}
|
||||
|
||||
// API config
|
||||
// all instances have an API
|
||||
// all clients have Tun or Null
|
||||
// all snodes have Tun
|
||||
//
|
||||
// TODO: change this for snodes running hidden service
|
||||
init_api();
|
||||
// Full clients have TUN
|
||||
// Embedded clients have nothing
|
||||
// All relays have TUN
|
||||
|
||||
if (_should_init_tun = conf.network.init_tun; _should_init_tun)
|
||||
{
|
||||
init_tun();
|
||||
}
|
||||
|
||||
if (not ensure_identity())
|
||||
throw std::runtime_error{"EnsureIdentity() failed"};
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <llarp/ev/loop.hpp>
|
||||
#include <llarp/handlers/endpoint.hpp>
|
||||
#include <llarp/handlers/remote.hpp>
|
||||
#include <llarp/handlers/tun.hpp>
|
||||
#include <llarp/path/path_context.hpp>
|
||||
#include <llarp/profiling.hpp>
|
||||
#include <llarp/router_contact.hpp>
|
||||
@ -21,7 +22,6 @@
|
||||
#include <llarp/util/service_manager.hpp>
|
||||
#include <llarp/util/str.hpp>
|
||||
#include <llarp/util/time.hpp>
|
||||
#include <llarp/util/types.hpp>
|
||||
#include <llarp/vpn/platform.hpp>
|
||||
|
||||
#include <oxenmq/address.h>
|
||||
@ -37,11 +37,6 @@
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace handlers
|
||||
{
|
||||
struct BaseHandler;
|
||||
}
|
||||
|
||||
namespace link
|
||||
{
|
||||
struct Connection;
|
||||
@ -125,13 +120,14 @@ namespace llarp
|
||||
std::shared_ptr<handlers::RemoteHandler> _remote_handler;
|
||||
std::shared_ptr<handlers::LocalEndpoint> _local_endpoint;
|
||||
|
||||
// TunEndpoint or NullEndpoint, depending on lokinet configuration
|
||||
std::unique_ptr<handlers::BaseHandler> _api;
|
||||
// Only created in full client and relay instances (not embedded clients)
|
||||
std::unique_ptr<handlers::TunEndpoint> _tun;
|
||||
|
||||
std::shared_ptr<EventLoop> _loop;
|
||||
std::shared_ptr<vpn::Platform> _vpn;
|
||||
path::PathContext paths;
|
||||
SecretKey _identity;
|
||||
RouterID _id_pubkey;
|
||||
SecretKey _encryption;
|
||||
std::shared_ptr<Contacts> _contacts;
|
||||
std::shared_ptr<NodeDB> _node_db;
|
||||
@ -179,9 +175,7 @@ namespace llarp
|
||||
|
||||
void init_rpc();
|
||||
|
||||
void init_net_if();
|
||||
|
||||
void init_api();
|
||||
void init_tun();
|
||||
|
||||
void init_bootstrap();
|
||||
|
||||
@ -340,9 +334,9 @@ namespace llarp
|
||||
|
||||
oxen::quic::Address listen_addr() const;
|
||||
|
||||
StatusObject ExtractStatus() const;
|
||||
nlohmann::json ExtractStatus() const;
|
||||
|
||||
StatusObject ExtractSummaryStatus() const;
|
||||
nlohmann::json ExtractSummaryStatus() const;
|
||||
|
||||
const std::set<RouterID>& get_whitelist() const;
|
||||
|
||||
@ -437,11 +431,16 @@ namespace llarp
|
||||
|
||||
bool PathToRouterAllowed(const RouterID& router) const;
|
||||
|
||||
const uint8_t* pubkey() const
|
||||
const RouterID& pubkey() const
|
||||
{
|
||||
return local_rid().data();
|
||||
return _id_pubkey;
|
||||
}
|
||||
|
||||
// const uint8_t* pubkey() const
|
||||
// {
|
||||
// return seckey_to_pubkey(_identity);
|
||||
// }
|
||||
|
||||
/// send to remote router or queue for sending
|
||||
/// returns false on overflow
|
||||
/// returns true on successful queue
|
||||
|
@ -120,9 +120,9 @@ namespace llarp
|
||||
return true;
|
||||
}
|
||||
|
||||
StatusObject RouterContact::extract_status() const
|
||||
nlohmann::json RouterContact::extract_status() const
|
||||
{
|
||||
StatusObject obj{
|
||||
nlohmann::json obj{
|
||||
{"lastUpdated", _timestamp.time_since_epoch().count()},
|
||||
{"publicRouter", is_public_addressable()},
|
||||
{"identity", _router_id.to_string()},
|
||||
@ -132,7 +132,7 @@ namespace llarp
|
||||
// {
|
||||
// obj["routerVersion"] = routerVersion->to_string();
|
||||
// }
|
||||
// std::vector<StatusObject> srv;
|
||||
// std::vector<nlohmann::json> srv;
|
||||
// for (const auto& record : srvRecords)
|
||||
// {
|
||||
// srv.emplace_back(record.ExtractStatus());
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include <llarp/dns/srv_data.hpp>
|
||||
#include <llarp/util/aligned.hpp>
|
||||
#include <llarp/util/time.hpp>
|
||||
#include <llarp/util/types.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <oxen/quic.hpp>
|
||||
@ -113,7 +112,7 @@ namespace llarp
|
||||
/// should we serialize the exit info?
|
||||
static const bool serializeExit = true;
|
||||
|
||||
StatusObject extract_status() const;
|
||||
nlohmann::json extract_status() const;
|
||||
|
||||
nlohmann::json to_json() const
|
||||
{
|
||||
|
@ -19,9 +19,9 @@ namespace llarp
|
||||
return oxenc::to_base32z(begin(), begin() + 5);
|
||||
}
|
||||
|
||||
StatusObject RouterID::ExtractStatus() const
|
||||
nlohmann::json RouterID::ExtractStatus() const
|
||||
{
|
||||
StatusObject obj{{"snode", to_string()}, {"hex", ToHex()}};
|
||||
nlohmann::json obj{{"snode", to_string()}, {"hex", ToHex()}};
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include <llarp/crypto/types.hpp>
|
||||
#include <llarp/util/formattable.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
struct RouterID : public PubKey
|
||||
@ -27,7 +29,7 @@ namespace llarp
|
||||
RouterID(std::string_view data) : RouterID(to_usv(data))
|
||||
{}
|
||||
|
||||
StatusObject ExtractStatus() const;
|
||||
nlohmann::json ExtractStatus() const;
|
||||
|
||||
std::string to_string() const;
|
||||
|
||||
|
@ -131,7 +131,7 @@ namespace llarp::rpc
|
||||
|
||||
void RPCServer::invoke(Version& version)
|
||||
{
|
||||
StatusObject result{{"version", llarp::LOKINET_VERSION_FULL}, {"uptime", to_json(m_Router.Uptime())}};
|
||||
nlohmann::json result{{"version", llarp::LOKINET_VERSION_FULL}, {"uptime", to_json(m_Router.Uptime())}};
|
||||
|
||||
SetJSONResponse(result, version.response);
|
||||
}
|
||||
@ -196,7 +196,7 @@ namespace llarp::rpc
|
||||
// auto [addr, id] = quic->open(
|
||||
// req.remoteHost, req.port, [](auto&&) {}, laddr);
|
||||
|
||||
StatusObject status;
|
||||
nlohmann::json status;
|
||||
// status["addr"] = addr.to_string();
|
||||
// status["id"] = id;
|
||||
|
||||
@ -258,7 +258,7 @@ namespace llarp::rpc
|
||||
return;
|
||||
}
|
||||
|
||||
StatusObject result;
|
||||
nlohmann::json result;
|
||||
result["id"] = id;
|
||||
std::string localAddress;
|
||||
var::visit([&](auto&& addr) { localAddress = addr.to_string(); }, endpoint->local_address());
|
||||
@ -310,7 +310,7 @@ namespace llarp::rpc
|
||||
// if (session and session->IsReady())
|
||||
// {
|
||||
// const auto ip = net::TruncateV6(endpoint->GetIPForIdent(PubKey{routerID}));
|
||||
// StatusObject status{{"ip", ip.to_string()}};
|
||||
// nlohmann::json status{{"ip", ip.to_string()}};
|
||||
// SetJSONResponse(status, lookupsnode.response);
|
||||
// return;
|
||||
// }
|
||||
|
@ -1,7 +1,5 @@
|
||||
#include "info.hpp"
|
||||
|
||||
#include "address.hpp"
|
||||
|
||||
#include <llarp/crypto/crypto.hpp>
|
||||
|
||||
namespace llarp::service
|
||||
|
@ -6,9 +6,9 @@ namespace llarp::service
|
||||
{
|
||||
static auto logcat = log::Cat("introduction");
|
||||
|
||||
StatusObject Introduction::ExtractStatus() const
|
||||
nlohmann::json Introduction::ExtractStatus() const
|
||||
{
|
||||
StatusObject obj{
|
||||
nlohmann::json obj{
|
||||
{"router", pivot_router.ToHex()},
|
||||
{"path", hop_id.ToHex()},
|
||||
{"expiresAt", to_json(expiry)},
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include <llarp/crypto/types.hpp>
|
||||
#include <llarp/path/path_types.hpp>
|
||||
#include <llarp/util/types.hpp>
|
||||
|
||||
#include <oxenc/bt.h>
|
||||
|
||||
@ -22,7 +21,7 @@ namespace llarp::service
|
||||
Introduction() = default;
|
||||
Introduction(std::string buf);
|
||||
|
||||
StatusObject ExtractStatus() const;
|
||||
nlohmann::json ExtractStatus() const;
|
||||
|
||||
bool is_expired(std::chrono::milliseconds now) const
|
||||
{
|
||||
|
@ -18,7 +18,7 @@ namespace llarp::service
|
||||
introset_payload{reinterpret_cast<uint8_t*>(enc_payload.data()), enc_payload.size()},
|
||||
nonce{reinterpret_cast<uint8_t*>(nonce.data())}
|
||||
{
|
||||
derived_signing_key = make_from_hex<PubKey>(signing_key);
|
||||
derived_signing_key.from_hex(signing_key);
|
||||
sig.from_string(std::move(s));
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ namespace llarp::service
|
||||
}
|
||||
}
|
||||
|
||||
StatusObject EncryptedIntroSet::ExtractStatus() const
|
||||
nlohmann::json EncryptedIntroSet::ExtractStatus() const
|
||||
{
|
||||
const auto sz = introset_payload.size();
|
||||
return {{"location", derived_signing_key.to_string()}, {"signedAt", to_json(signed_at)}, {"size", sz}};
|
||||
@ -180,33 +180,33 @@ namespace llarp::service
|
||||
reinterpret_cast<uint8_t*>(sig.data()));
|
||||
}
|
||||
|
||||
StatusObject IntroSet::ExtractStatus() const
|
||||
nlohmann::json IntroSet::ExtractStatus() const
|
||||
{
|
||||
StatusObject obj{{"published", to_json(time_signed)}};
|
||||
nlohmann::json obj{{"published", to_json(time_signed)}};
|
||||
// TODO: this
|
||||
// std::vector<StatusObject> introsObjs;
|
||||
// std::vector<nlohmann::json> introsObjs;
|
||||
// std::transform(
|
||||
// intros.begin(),
|
||||
// intros.end(),
|
||||
// std::back_inserter(introsObjs),
|
||||
// [](const auto& intro) -> StatusObject { return intro.ExtractStatus(); });
|
||||
// [](const auto& intro) -> nlohmann::json { return intro.ExtractStatus(); });
|
||||
// obj["intros"] = introsObjs;
|
||||
// if (!topic.IsZero())
|
||||
// obj["topic"] = topic.to_string();
|
||||
|
||||
// std::vector<StatusObject> protocols;
|
||||
// std::vector<nlohmann::json> protocols;
|
||||
// std::transform(
|
||||
// supported_protocols.begin(),
|
||||
// supported_protocols.end(),
|
||||
// std::back_inserter(protocols),
|
||||
// [](const auto& proto) -> StatusObject { return service::to_string(proto); });
|
||||
// [](const auto& proto) -> nlohmann::json { return service::to_string(proto); });
|
||||
// obj["protos"] = protocols;
|
||||
// std::vector<StatusObject> ranges;
|
||||
// std::vector<nlohmann::json> ranges;
|
||||
// std::transform(
|
||||
// owned_ranges.begin(),
|
||||
// owned_ranges.end(),
|
||||
// std::back_inserter(ranges),
|
||||
// [](const auto& range) -> StatusObject { return range.to_string(); });
|
||||
// [](const auto& range) -> nlohmann::json { return range.to_string(); });
|
||||
|
||||
// obj["advertisedRanges"] = ranges;
|
||||
// if (exit_policy)
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include <llarp/dns/srv_data.hpp>
|
||||
#include <llarp/net/traffic_policy.hpp>
|
||||
#include <llarp/util/time.hpp>
|
||||
#include <llarp/util/types.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
@ -75,7 +74,7 @@ namespace llarp::service
|
||||
|
||||
bool verify(std::chrono::milliseconds now) const;
|
||||
|
||||
StatusObject ExtractStatus() const;
|
||||
nlohmann::json ExtractStatus() const;
|
||||
};
|
||||
|
||||
inline bool operator<(const IntroSet& lhs, const IntroSet& rhs)
|
||||
@ -139,7 +138,7 @@ namespace llarp::service
|
||||
|
||||
std::string to_string() const;
|
||||
|
||||
StatusObject ExtractStatus() const;
|
||||
nlohmann::json ExtractStatus() const;
|
||||
|
||||
std::optional<IntroSet> decrypt(const PubKey& root) const;
|
||||
};
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
namespace llarp::service
|
||||
{
|
||||
StatusObject Session::ExtractStatus() const
|
||||
nlohmann::json Session::ExtractStatus() const
|
||||
{
|
||||
StatusObject obj{
|
||||
nlohmann::json obj{
|
||||
{"lastSend", to_json(lastSend)},
|
||||
{"lastRecv", to_json(lastRecv)},
|
||||
{"replyIntro", replyIntro.ExtractStatus()},
|
||||
|
@ -5,7 +5,6 @@
|
||||
|
||||
#include <llarp/crypto/types.hpp>
|
||||
#include <llarp/path/path.hpp>
|
||||
#include <llarp/util/types.hpp>
|
||||
|
||||
namespace llarp::service
|
||||
{
|
||||
@ -34,7 +33,7 @@ namespace llarp::service
|
||||
std::chrono::milliseconds lastSend{};
|
||||
std::chrono::milliseconds lastRecv{};
|
||||
|
||||
StatusObject ExtractStatus() const;
|
||||
nlohmann::json ExtractStatus() const;
|
||||
|
||||
/// called to indicate we recieved on this session
|
||||
void RX();
|
||||
|
@ -62,7 +62,7 @@ namespace llarp::session
|
||||
p->rebuild();
|
||||
}
|
||||
|
||||
StatusObject OutboundSession::ExtractStatus() const
|
||||
nlohmann::json OutboundSession::ExtractStatus() const
|
||||
{
|
||||
auto obj = path::PathHandler::ExtractStatus();
|
||||
obj["lastExitUse"] = to_json(_last_use);
|
||||
|
@ -92,7 +92,7 @@ namespace llarp
|
||||
|
||||
void build_more(size_t n = 0) override;
|
||||
|
||||
StatusObject ExtractStatus() const;
|
||||
nlohmann::json ExtractStatus() const;
|
||||
|
||||
void reset_path_state() override;
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include "common.hpp"
|
||||
#include "mem.h"
|
||||
#include "types.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
@ -2,16 +2,16 @@
|
||||
|
||||
#include "concept.hpp"
|
||||
|
||||
#include <fmt/format.h>
|
||||
// #include <fmt/format.h>
|
||||
#include <oxen/log/format.hpp>
|
||||
#include <oxen/quic/format.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
// Formattable types can specialize this to true and will get automatic fmt formattering support via
|
||||
// their .to_string() method.
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
using namespace oxen::log::literals;
|
||||
|
||||
// Types can opt-in to being fmt-formattable by ensuring they have a ::to_string() method defined
|
||||
template <typename T>
|
||||
concept CONCEPT_COMPAT ToStringFormattable = oxen::quic::ToStringFormattable<T>;
|
||||
|
@ -1,20 +1,18 @@
|
||||
#include "time.hpp"
|
||||
|
||||
#include "types.hpp"
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
using namespace std::literals;
|
||||
|
||||
namespace
|
||||
{
|
||||
using Clock_t = std::chrono::system_clock;
|
||||
|
||||
template <typename Res, typename Clock>
|
||||
static std::chrono::milliseconds time_since_epoch(std::chrono::time_point<Clock> point)
|
||||
{
|
||||
return std::chrono::duration_cast<Res>(point.time_since_epoch());
|
||||
}
|
||||
|
||||
static const auto started_at_system = Clock_t::now();
|
||||
static const auto started_at_system = std::chrono::system_clock::now();
|
||||
|
||||
static const auto started_at_steady = std::chrono::steady_clock::now();
|
||||
} // namespace
|
||||
@ -52,7 +50,7 @@ namespace llarp
|
||||
#ifdef TESTNET_SPEED
|
||||
t /= uint64_t{TESTNET_SPEED};
|
||||
#endif
|
||||
return t + time_since_epoch<std::chrono::milliseconds, Clock_t>(started_at_system);
|
||||
return t + time_since_epoch<std::chrono::milliseconds, std::chrono::system_clock>(started_at_system);
|
||||
}
|
||||
|
||||
nlohmann::json to_json(const std::chrono::milliseconds& t)
|
||||
@ -69,46 +67,24 @@ namespace llarp
|
||||
(std::chrono::duration_cast<std::chrono::milliseconds>(dur) % 1s).count());
|
||||
}
|
||||
|
||||
std::string short_time_from_now(const TimePoint_t& t, const std::chrono::milliseconds& now_threshold)
|
||||
std::string short_time_from_now(
|
||||
const std::chrono::system_clock::time_point& t, const std::chrono::milliseconds& now_threshold)
|
||||
{
|
||||
auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(llarp::TimePoint_t::clock::now() - t);
|
||||
auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::time_point::clock::now() - t);
|
||||
|
||||
bool future = delta < 0s;
|
||||
if (future)
|
||||
delta = -delta;
|
||||
|
||||
auto [hours, mins, secs, ms] = extract_h_m_s_ms(delta);
|
||||
|
||||
using namespace fmt::literals;
|
||||
return fmt::format(
|
||||
delta < now_threshold ? "now"
|
||||
: delta < 10s ? "{in}{secs:d}.{ms:03d}s{ago}"
|
||||
: delta < 1h ? "{in}{mins:d}m{secs:02d}s{ago}"
|
||||
: "{in}{hours:d}h{mins:02d}m{ago}",
|
||||
"in"_a = future ? "in " : "",
|
||||
"ago"_a = future ? "" : " ago",
|
||||
"hours"_a = hours,
|
||||
"mins"_a = mins,
|
||||
"secs"_a = secs,
|
||||
"ms"_a = ms);
|
||||
auto in = future ? "in "sv : ""sv;
|
||||
auto ago = future ? ""sv : " ago"sv;
|
||||
return delta < now_threshold ? "now"s
|
||||
: delta < 10s ? "{}{}.{:03d}s{}"_format(in, secs, ms, ago)
|
||||
: delta < 1h ? "{}{}m{:02d}s{}"_format(in, mins, secs, ago)
|
||||
: "{}{}h{:02d}m{}"_format(in, hours, mins, ago);
|
||||
}
|
||||
|
||||
std::string to_string(std::chrono::milliseconds delta)
|
||||
{
|
||||
bool neg = delta < 0s;
|
||||
if (neg)
|
||||
delta = -delta;
|
||||
|
||||
auto [hours, mins, secs, ms] = extract_h_m_s_ms(delta);
|
||||
|
||||
using namespace fmt::literals;
|
||||
return fmt::format(
|
||||
delta < 1min ? "{neg}{secs:d}.{ms:03d}s"
|
||||
: delta < 1h ? "{neg}{mins:d}m{secs:02d}.{ms:03d}s"
|
||||
: "{neg}{hours:d}h{mins:02d}m{secs:02d}.{ms:03d}s",
|
||||
"neg"_a = neg ? "-" : "",
|
||||
"hours"_a = hours,
|
||||
"mins"_a = mins,
|
||||
"secs"_a = secs,
|
||||
"ms"_a = ms);
|
||||
}
|
||||
} // namespace llarp
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.hpp"
|
||||
#include "buffer.hpp"
|
||||
#include "formattable.hpp"
|
||||
|
||||
#include <fmt/chrono.h>
|
||||
#include <fmt/format.h>
|
||||
@ -33,11 +34,8 @@ namespace llarp
|
||||
// Returns a string such as "27m13s ago" or "in 1h12m" or "now". You get precision of minutes
|
||||
// (for >=1h), seconds (>=10s), or milliseconds. The `now_threshold` argument controls how
|
||||
// close to current time (default 1s) the time has to be to get the "now" argument.
|
||||
std::string short_time_from_now(const TimePoint_t& t, const std::chrono::milliseconds& now_threshold = 1s);
|
||||
|
||||
// Makes a duration human readable. This always has full millisecond precision, but formats up
|
||||
// to hours. E.g. "-4h04m12.123s" or "1234h00m09.876s.
|
||||
std::string to_string(std::chrono::milliseconds t);
|
||||
std::string short_time_from_now(
|
||||
const std::chrono::system_clock::time_point& t, const std::chrono::milliseconds& now_threshold = 1s);
|
||||
|
||||
inline timeval loop_time_to_timeval(loop_time t)
|
||||
{
|
||||
|
@ -1,22 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <oxen/log/format.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
using namespace std::literals;
|
||||
using namespace oxen::log::literals;
|
||||
|
||||
/// convert to milliseconds
|
||||
uint64_t to_milliseconds(std::chrono::milliseconds duration);
|
||||
|
||||
using DateClock_t = std::chrono::system_clock;
|
||||
using TimePoint_t = DateClock_t::time_point;
|
||||
|
||||
using StatusObject = nlohmann::json;
|
||||
} // namespace llarp
|
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <llarp/address/ip_packet.hpp>
|
||||
#include <llarp/util/types.hpp>
|
||||
|
||||
#include <functional>
|
||||
|
||||
|
@ -314,7 +314,7 @@ namespace llarp::vpn
|
||||
|
||||
void default_route_via_interface(NetworkInterface& vpn, int cmd, int flags)
|
||||
{
|
||||
const auto& info = vpn.Info();
|
||||
const auto& info = vpn.interface_info();
|
||||
|
||||
const auto maybe = Net().get_interface_addr(info.ifname);
|
||||
if (not maybe)
|
||||
@ -340,7 +340,7 @@ namespace llarp::vpn
|
||||
|
||||
void route_via_interface(int cmd, int flags, NetworkInterface& vpn, IPRange range)
|
||||
{
|
||||
const auto& info = vpn.Info();
|
||||
const auto& info = vpn.interface_info();
|
||||
if (range.is_ipv4())
|
||||
{
|
||||
const auto maybe = Net().get_interface_addr(info.ifname);
|
||||
@ -431,7 +431,7 @@ namespace llarp::vpn
|
||||
|
||||
std::vector<oxen::quic::Address> get_non_interface_gateways(NetworkInterface& vpn) override
|
||||
{
|
||||
const auto& ifname = vpn.Info().ifname;
|
||||
const auto& ifname = vpn.interface_info().ifname;
|
||||
std::vector<oxen::quic::Address> gateways{};
|
||||
|
||||
std::ifstream inf{"/proc/net/route"};
|
||||
|
@ -1,5 +1,4 @@
|
||||
#pragma once
|
||||
#include <llarp/util/types.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
@ -50,7 +50,7 @@ namespace llarp::vpn
|
||||
PacketRouter::PacketRouter(ip_pkt_hook baseHandler) : _handler{std::move(baseHandler)}
|
||||
{}
|
||||
|
||||
void PacketRouter::handle_ip_packet(UDPPacket pkt)
|
||||
void PacketRouter::handle_ip_packet(IPPacket pkt)
|
||||
{
|
||||
(void)pkt;
|
||||
// const auto proto = pkt.Header()->protocol;
|
||||
|
@ -9,8 +9,6 @@ namespace llarp::vpn
|
||||
{
|
||||
struct Layer4Handler;
|
||||
|
||||
// DISCUSS: do we need this fucking protocol mapping shit??
|
||||
|
||||
class PacketRouter
|
||||
{
|
||||
ip_pkt_hook _handler;
|
||||
@ -21,7 +19,7 @@ namespace llarp::vpn
|
||||
explicit PacketRouter(ip_pkt_hook baseHandler);
|
||||
|
||||
/// feed in an ip packet for handling
|
||||
void handle_ip_packet(UDPPacket pkt);
|
||||
void handle_ip_packet(IPPacket pkt);
|
||||
|
||||
/// add a non udp packet handler using ip protocol proto
|
||||
void add_ip_proto_handler(uint8_t proto, ip_pkt_hook func);
|
||||
|
@ -57,7 +57,7 @@ namespace llarp::vpn
|
||||
NetworkInterface(const NetworkInterface&) = delete;
|
||||
NetworkInterface(NetworkInterface&&) = delete;
|
||||
|
||||
const InterfaceInfo& Info() const
|
||||
const InterfaceInfo& interface_info() const
|
||||
{
|
||||
return _info;
|
||||
}
|
||||
@ -116,7 +116,7 @@ namespace llarp::vpn
|
||||
virtual ~Platform() = default;
|
||||
|
||||
/// create and start a network interface
|
||||
inline std::shared_ptr<NetworkInterface> CreateInterface(InterfaceInfo info, Router* router)
|
||||
std::shared_ptr<NetworkInterface> CreateInterface(InterfaceInfo info, Router* router)
|
||||
{
|
||||
if (auto netif = ObtainInterface(std::move(info), router))
|
||||
{
|
||||
|
@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
#include <llarp/util/service_manager.hpp>
|
||||
#include <llarp/util/types.hpp>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user