mirror of
https://github.com/oxen-io/lokinet
synced 2023-12-14 06:53:00 +01:00
just the headers for the internals refactor.
llarp/layers/platform/*.hpp was the "front end" of the previous kitchen sink. this component bridges the userland platforms, be the full VPN mode, embedded mode or any other kind of future mode of operation we may support. this component is meant to slowly consilidate the location of platform specific quarks, like ones for proactor vs reactor event loops. the vpn platform code will exist independantly from this layer but this will be where any kind of idempotent queue flushing when we get something from or destinted the "platform" (e.g. the vpn interface, or some kind of internal for embedded lokinet). llarp/layers/flow/*.hpp was the "back end" of the previous kitchen sink. we provide all headers for the logic of .loki and .snode traffic codepaths for snodes and clients. these headers support .loki and .snode in a unified api, any additional kinds of remote endpoint types like a .exit whatever else would be easy to add with this. defines hooks for any authentication between us and remote flows, regardless of if we are initiator or recipient. defines ons name to flow address lookup interface, as well as ons name caching interface. both of which adds a slot to define future configurable knobs how strict of a consensus we want for a ons lookup and result caching lifetime and lookup result invalidation (e.g. allows us to purge things when we add consensus state hints into lokinet clients). llarp/layers/route/*.hpp the routing layer which used to blur into the "back end" old kitchen sink (now called the flow layer). currently mostly baren and exists as a placeholder stub until later. llarp/layers/onion/*.hpp stub for onion layer, basically for llarp/path/* as a mechanism for removing llarp::path::PathSet type forever. this has yet to happen. llarp/context.hpp this was include/llarp.hpp, but now it is here and no longer a public header. we really dont have a nice way to expose a C++ api just a C api. going forward a public C++ api does not seem to be a worthwhile efffort for abi stability reasons and how crap our current headers are. will remove include/llarp.hpp later as so much includes it. (maybe C++ modules will help later... maybe...)
This commit is contained in:
parent
7d2ad5621b
commit
10eddfb177
115
llarp/context.hpp
Normal file
115
llarp/context.hpp
Normal file
|
@ -0,0 +1,115 @@
|
|||
#ifndef LLARP_HPP
|
||||
#define LLARP_HPP
|
||||
|
||||
#include <future>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
namespace vpn
|
||||
{
|
||||
class Platform;
|
||||
}
|
||||
|
||||
class EventLoop;
|
||||
struct Config;
|
||||
struct RouterContact;
|
||||
struct Config;
|
||||
struct Crypto;
|
||||
struct CryptoManager;
|
||||
struct AbstractRouter;
|
||||
class NodeDB;
|
||||
|
||||
namespace thread
|
||||
{
|
||||
class ThreadPool;
|
||||
}
|
||||
|
||||
struct RuntimeOptions
|
||||
{
|
||||
bool showBanner = true;
|
||||
bool debug = false;
|
||||
bool isSNode = false;
|
||||
};
|
||||
|
||||
struct Context
|
||||
{
|
||||
std::shared_ptr<Crypto> crypto = nullptr;
|
||||
std::shared_ptr<CryptoManager> cryptoManager = nullptr;
|
||||
std::shared_ptr<AbstractRouter> router = nullptr;
|
||||
std::shared_ptr<EventLoop> loop = nullptr;
|
||||
std::shared_ptr<NodeDB> nodedb = nullptr;
|
||||
|
||||
Context();
|
||||
virtual ~Context() = default;
|
||||
|
||||
void
|
||||
Setup(const RuntimeOptions& opts);
|
||||
|
||||
int
|
||||
Run(const RuntimeOptions& opts);
|
||||
|
||||
void
|
||||
HandleSignal(int sig);
|
||||
|
||||
/// Configure given the specified config.
|
||||
void
|
||||
Configure(std::shared_ptr<Config> conf);
|
||||
|
||||
/// handle SIGHUP
|
||||
void
|
||||
Reload();
|
||||
|
||||
bool
|
||||
IsUp() const;
|
||||
|
||||
bool
|
||||
LooksAlive() const;
|
||||
|
||||
bool
|
||||
IsStopping() const;
|
||||
|
||||
/// close async
|
||||
void
|
||||
CloseAsync();
|
||||
|
||||
/// wait until closed and done
|
||||
void
|
||||
Wait();
|
||||
|
||||
/// call a function in logic thread
|
||||
/// return true if queued for calling
|
||||
/// return false if not queued for calling
|
||||
bool
|
||||
CallSafe(std::function<void(void)> f);
|
||||
|
||||
/// Creates a router. Can be overridden to allow a different class of router
|
||||
/// to be created instead. Defaults to llarp::Router.
|
||||
virtual std::shared_ptr<AbstractRouter>
|
||||
makeRouter(const std::shared_ptr<EventLoop>& loop);
|
||||
|
||||
/// create the nodedb given our current configs
|
||||
virtual std::shared_ptr<NodeDB>
|
||||
makeNodeDB();
|
||||
|
||||
/// create the vpn platform for use in creating network interfaces
|
||||
virtual std::shared_ptr<llarp::vpn::Platform>
|
||||
makeVPNPlatform();
|
||||
|
||||
int androidFD = -1;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Config> config = nullptr;
|
||||
|
||||
private:
|
||||
void
|
||||
SigINT();
|
||||
std::unique_ptr<std::promise<void>> closeWaiter;
|
||||
};
|
||||
} // namespace llarp
|
||||
|
||||
#endif
|
67
llarp/layers/flow/flow_addr.hpp
Normal file
67
llarp/layers/flow/flow_addr.hpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
#pragma once
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <llarp/util/aligned.hpp>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <llarp/endpoint_base.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace llarp::layers::flow
|
||||
{
|
||||
|
||||
/// a long form .snode or .loki address
|
||||
class FlowAddr : public AlignedBuffer<32>
|
||||
{
|
||||
public:
|
||||
enum class Kind : uint8_t
|
||||
{
|
||||
snapp,
|
||||
snode,
|
||||
};
|
||||
|
||||
FlowAddr() = default;
|
||||
|
||||
/// construct from string
|
||||
explicit FlowAddr(std::string str);
|
||||
|
||||
explicit FlowAddr(EndpointBase::AddressVariant_t arg);
|
||||
|
||||
std::string
|
||||
ToString() const;
|
||||
|
||||
bool
|
||||
operator==(const FlowAddr& other) const;
|
||||
|
||||
Kind
|
||||
kind() const;
|
||||
|
||||
private:
|
||||
static Kind
|
||||
get_kind(std::string_view str);
|
||||
|
||||
Kind _kind;
|
||||
};
|
||||
|
||||
} // namespace llarp::layers::flow
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
template <>
|
||||
inline constexpr bool IsToStringFormattable<llarp::layers::flow::FlowAddr> = true;
|
||||
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct hash<llarp::layers::flow::FlowAddr>
|
||||
{
|
||||
size_t
|
||||
operator()(const llarp::layers::flow::FlowAddr& addr) const
|
||||
{
|
||||
return std::hash<llarp::AlignedBuffer<32>>{}(addr)
|
||||
^ (std::hash<uint8_t>{}(static_cast<uint8_t>(addr.kind())) << 3);
|
||||
}
|
||||
};
|
||||
} // namespace std
|
37
llarp/layers/flow/flow_auth.hpp
Normal file
37
llarp/layers/flow/flow_auth.hpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <optional>
|
||||
|
||||
#include <llarp/util/formattable.hpp>
|
||||
#include <string_view>
|
||||
|
||||
namespace llarp::layers::flow
|
||||
{
|
||||
|
||||
/// which phase in authentication a flow is in while establishing.
|
||||
enum class FlowAuthPhase
|
||||
{
|
||||
/// we have not sent the auth to the remote yet.
|
||||
auth_req_not_sent,
|
||||
/// we sent our auth to the remote.
|
||||
auth_req_sent,
|
||||
/// the remote explicitly rejected our auth.
|
||||
auth_nack,
|
||||
/// the remote asked for auth.
|
||||
auth_more,
|
||||
/// the remote accepted our auth.
|
||||
auth_ok,
|
||||
};
|
||||
std::string_view
|
||||
ToString(FlowAuthPhase phase);
|
||||
|
||||
} // namespace llarp::layers::flow
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
|
||||
template <>
|
||||
inline constexpr bool IsToStringFormattable<layers::flow::FlowAuthPhase> = true;
|
||||
} // namespace llarp
|
12
llarp/layers/flow/flow_constants.hpp
Normal file
12
llarp/layers/flow/flow_constants.hpp
Normal file
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
namespace llarp::layers::flow
|
||||
{
|
||||
/// the mtu of plaintext data we transport via the flow layer.
|
||||
static inline constexpr uint16_t default_flow_mtu = 1500;
|
||||
/// maximum mtu we can carry of the flow layer
|
||||
// TODO: verify
|
||||
static inline constexpr uint16_t max_flow_mtu = 4096;
|
||||
|
||||
} // namespace llarp::layers::flow
|
28
llarp/layers/flow/flow_data_kind.hpp
Normal file
28
llarp/layers/flow/flow_data_kind.hpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
#include <llarp/util/formattable.hpp>
|
||||
|
||||
namespace llarp::layers::flow
|
||||
{
|
||||
enum class FlowDataKind
|
||||
{
|
||||
unknown,
|
||||
/// unicast ip traffic that does NOT exit lokinet.
|
||||
direct_ip_unicast,
|
||||
/// unicast ip traffic that does exit lokinet.
|
||||
exit_ip_unicast,
|
||||
/// auth data.
|
||||
auth,
|
||||
/// unicast stream data.
|
||||
stream_unicast,
|
||||
};
|
||||
|
||||
std::string_view
|
||||
ToString(FlowDataKind kind);
|
||||
} // namespace llarp::layers::flow
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
|
||||
template <>
|
||||
inline constexpr bool IsToStringFormattable<llarp::layers::flow::FlowDataKind> = true;
|
||||
}
|
44
llarp/layers/flow/flow_establish.hpp
Normal file
44
llarp/layers/flow/flow_establish.hpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <optional>
|
||||
|
||||
#include "flow_info.hpp"
|
||||
#include "flow_auth.hpp"
|
||||
|
||||
namespace llarp::layers::flow
|
||||
{
|
||||
|
||||
/// handles informing an observer at each step of obtaining a flow on the flow layer.
|
||||
class FlowEstablish
|
||||
{
|
||||
std::function<void(std::optional<FlowInfo>, std::string)> _completion_handler;
|
||||
std::function<void(FlowAuthPhase, std::string)> _phase_handler;
|
||||
std::optional<FlowInfo> _result;
|
||||
|
||||
public:
|
||||
FlowEstablish(
|
||||
std::function<void(std::optional<FlowInfo>, std::string)> completion_handler,
|
||||
std::function<void(FlowAuthPhase, std::string)> phase_handler);
|
||||
|
||||
/// an optional static auth code
|
||||
std::string authcode;
|
||||
|
||||
/// how long we wait for establishment timeout
|
||||
std::chrono::milliseconds timeout{5s};
|
||||
|
||||
/// enter phase of flow establishment.
|
||||
void
|
||||
enter_phase(FlowAuthPhase phase, std::string info);
|
||||
|
||||
/// explicitly fail establishment with an error message.
|
||||
void
|
||||
fail(std::string msg);
|
||||
|
||||
/// explicitly inform that we are done with the establishment and we are ready to send.
|
||||
/// calls _completion_handler.
|
||||
void
|
||||
ready(FlowInfo flow_info);
|
||||
};
|
||||
} // namespace llarp::layers::flow
|
100
llarp/layers/flow/flow_identity.hpp
Normal file
100
llarp/layers/flow/flow_identity.hpp
Normal file
|
@ -0,0 +1,100 @@
|
|||
#pragma once
|
||||
|
||||
#include <oxenc/bt_producer.h>
|
||||
#include <oxenc/bt_serialize.h>
|
||||
#include <llarp/crypto/types.hpp>
|
||||
#include <llarp/dht/key.hpp>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
#include "flow_addr.hpp"
|
||||
#include "flow_establish.hpp"
|
||||
#include "flow_info.hpp"
|
||||
#include "flow_state.hpp"
|
||||
#include "flow_tag.hpp"
|
||||
#include "flow_traffic.hpp"
|
||||
|
||||
namespace llarp::layers::flow
|
||||
{
|
||||
|
||||
class FlowLayer;
|
||||
|
||||
/// private keys used at the flow layer that are persistable.
|
||||
/// this includes any kinds of ephemeral private keys.
|
||||
/// ephemeral keys do not need to be persisted.
|
||||
/// shared secrets not included.
|
||||
struct FlowIdentityPrivateKeys
|
||||
{
|
||||
PQKeyPair sntrup;
|
||||
SecretKey identity;
|
||||
SecretKey encryption;
|
||||
PrivateKey derivedKey;
|
||||
|
||||
/// generate a new private key bundle for the flow layer.
|
||||
static FlowIdentityPrivateKeys
|
||||
keygen();
|
||||
|
||||
/// get the public .loki or .snode address
|
||||
const FlowAddr&
|
||||
public_addr() const;
|
||||
|
||||
/// get the blinded dht keyspace location
|
||||
const dht::Key_t&
|
||||
keyspace_location() const;
|
||||
|
||||
private:
|
||||
mutable FlowAddr _root_pubkey;
|
||||
mutable dht::Key_t _derived_pubkey;
|
||||
};
|
||||
|
||||
/// the local end of a one to one flow to a remote given a flow isolation metric (flow_tag)
|
||||
/// flows do not change their source/destination address or their flow tag/convo tag.
|
||||
/// note: historically path handovers were allowed, but going forward this is discontinued.
|
||||
class FlowIdentity
|
||||
{
|
||||
FlowLayer& _parent;
|
||||
const FlowIdentityPrivateKeys& _local_privkeys;
|
||||
|
||||
/// internal state holder.
|
||||
/// effectively a pimpl to abstract away .loki vs .snode codepaths.
|
||||
std::unique_ptr<FlowState_Base> _state;
|
||||
|
||||
public:
|
||||
/// holds the local/remote flow layer address and any flow isolation metric
|
||||
const FlowInfo flow_info;
|
||||
|
||||
FlowIdentity(const FlowIdentity&) = delete;
|
||||
FlowIdentity(FlowIdentity&&) = delete;
|
||||
|
||||
FlowIdentity(
|
||||
FlowLayer& parent,
|
||||
FlowAddr remote_addr,
|
||||
FlowTag flow_tag,
|
||||
const FlowIdentityPrivateKeys& local_keys);
|
||||
|
||||
/// ensure we have a flow to the remote endpoint.
|
||||
/// pass in a handshaker to do any additional steps after establishment.
|
||||
void
|
||||
async_ensure_flow(FlowEstablish handshaker);
|
||||
|
||||
/// send flow traffic to the remote.
|
||||
void
|
||||
send_to_remote(std::vector<byte_t> dataum, FlowDataKind kind);
|
||||
|
||||
bool
|
||||
operator==(const FlowIdentity& other) const;
|
||||
};
|
||||
} // namespace llarp::layers::flow
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct hash<llarp::layers::flow::FlowIdentity>
|
||||
{
|
||||
size_t
|
||||
operator()(const llarp::layers::flow::FlowIdentity& ident) const
|
||||
{
|
||||
return std::hash<llarp::layers::flow::FlowInfo>{}(ident.flow_info);
|
||||
}
|
||||
};
|
||||
} // namespace std
|
59
llarp/layers/flow/flow_info.hpp
Normal file
59
llarp/layers/flow/flow_info.hpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
#pragma once
|
||||
|
||||
#include "flow_addr.hpp"
|
||||
#include "flow_tag.hpp"
|
||||
#include "flow_constants.hpp"
|
||||
|
||||
namespace llarp::layers::flow
|
||||
{
|
||||
|
||||
/// in lokinet our onion routed flows are comprised of a source and destination flow layer
|
||||
/// address, a flow tag (an identifier to mark a distinct flow), and a pivot that each is using in
|
||||
/// common which acts as our analog to an ipv6 flow label, see rfc6437.
|
||||
struct FlowInfo
|
||||
{
|
||||
/// source and destination addresses we associate with this flow.
|
||||
FlowAddr src, dst;
|
||||
|
||||
/// flow address of the pivot we use to get from src to dst.
|
||||
/// for .loki traffic this is a .snode address, which we aligh our paths to.
|
||||
/// for .snode traffic this is a .snode address, which we align our paths to.
|
||||
/// for .exit traffic this is a .loki address, which we will fetch the exit descriptor it is
|
||||
/// associated with.
|
||||
FlowAddr pivot;
|
||||
|
||||
/// cleartext identifier used on outer framing of the traffic. lets us tell what is from who.
|
||||
FlowTag tag;
|
||||
|
||||
/// mtu between src and dst.
|
||||
uint16_t mtu{default_flow_mtu};
|
||||
|
||||
std::string
|
||||
ToString() const;
|
||||
|
||||
bool
|
||||
operator==(const FlowInfo& other) const;
|
||||
};
|
||||
} // namespace llarp::layers::flow
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
template <>
|
||||
inline constexpr bool IsToStringFormattable<llarp::layers::flow::FlowInfo> = true;
|
||||
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct hash<llarp::layers::flow::FlowInfo>
|
||||
{
|
||||
size_t
|
||||
operator()(const llarp::layers::flow::FlowInfo& info) const
|
||||
{
|
||||
return std::hash<llarp::layers::flow::FlowAddr>{}(info.src)
|
||||
^ (std::hash<llarp::layers::flow::FlowAddr>{}(info.dst) << 3)
|
||||
^ (std::hash<llarp::layers::flow::FlowTag>{}(info.tag) << 5);
|
||||
}
|
||||
};
|
||||
} // namespace std
|
113
llarp/layers/flow/flow_layer.hpp
Normal file
113
llarp/layers/flow/flow_layer.hpp
Normal file
|
@ -0,0 +1,113 @@
|
|||
#pragma once
|
||||
|
||||
#include "flow_addr.hpp"
|
||||
#include "flow_identity.hpp"
|
||||
#include "flow_info.hpp"
|
||||
#include "flow_tag.hpp"
|
||||
#include "flow_stats.hpp"
|
||||
#include "flow_traffic.hpp"
|
||||
#include "name_cache.hpp"
|
||||
#include "name_resolver.hpp"
|
||||
|
||||
#include <llarp/config/config.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
struct AbstractRouter;
|
||||
}
|
||||
|
||||
namespace llarp::service
|
||||
{
|
||||
struct Endpoint;
|
||||
}
|
||||
|
||||
namespace llarp::layers::flow
|
||||
{
|
||||
|
||||
/// flow layer's context that holds all the things in the flow layer
|
||||
class FlowLayer
|
||||
{
|
||||
const NetworkConfig _conf;
|
||||
std::vector<std::shared_ptr<FlowIdentity>> _local_flows;
|
||||
|
||||
FlowIdentityPrivateKeys _privkeys;
|
||||
|
||||
NameCache _name_cache;
|
||||
|
||||
std::shared_ptr<service::Endpoint> _deprecated_endpoint;
|
||||
|
||||
/// flow layer traffic we got from the void.
|
||||
std::vector<FlowTraffic> _recv;
|
||||
|
||||
/// wake this up to send things out the lower layers.
|
||||
std::shared_ptr<EventLoopWakeup> _wakeup_send;
|
||||
/// wakes up the upper layers to tell it we recieved flow layer traffic.
|
||||
std::shared_ptr<EventLoopWakeup> _wakeup_recv;
|
||||
|
||||
/// ensure privkeys are generated and persisted if requested by configuration.
|
||||
/// throws on any kind of failure. TODO: document what is thrown when.
|
||||
void
|
||||
maybe_store_or_load_privkeys();
|
||||
|
||||
/// generate a flow tag we dont current have tracked.
|
||||
FlowTag
|
||||
unique_flow_tag() const;
|
||||
|
||||
/// return true if we have a flow tag tracked.
|
||||
bool
|
||||
has_flow_tag(const FlowTag&) const;
|
||||
|
||||
public:
|
||||
FlowLayer(AbstractRouter&, NetworkConfig);
|
||||
FlowLayer(const FlowLayer&) = delete;
|
||||
FlowLayer(FlowLayer&&) = delete;
|
||||
|
||||
/// get flow layer's informational stats at this moment in time.
|
||||
FlowStats
|
||||
current_stats() const;
|
||||
|
||||
/// return true if we have this flow.
|
||||
bool
|
||||
has_flow(const flow::FlowInfo& flow_info) const;
|
||||
|
||||
/// remove a flow we have tracked. does nothing if we do not have it tracked.
|
||||
void
|
||||
remove_flow(const flow::FlowInfo& flow_info);
|
||||
|
||||
/// get our flow address of our local given a flow tag.
|
||||
/// if we give a nullopt flow tag we get our "default" inbound flow address we publish to the
|
||||
/// network.
|
||||
const FlowAddr&
|
||||
local_addr(const std::optional<FlowTag>& maybe_tag = std::nullopt) const;
|
||||
|
||||
/// get our DEPRECATED endpointbase for our local "us"
|
||||
std::shared_ptr<service::Endpoint>
|
||||
local_deprecated_loki_endpoint() const;
|
||||
|
||||
/// autovivify a flow to a remote.
|
||||
std::shared_ptr<FlowIdentity>
|
||||
flow_to(const FlowAddr& to);
|
||||
|
||||
/// pop off all flow layer traffic that we have processed.
|
||||
std::vector<FlowTraffic>
|
||||
poll_flow_traffic();
|
||||
|
||||
/// synthetically inject flow layer traffic into the flow layer
|
||||
void
|
||||
offer_flow_traffic(FlowTraffic&& traff);
|
||||
|
||||
void
|
||||
start();
|
||||
|
||||
void
|
||||
stop();
|
||||
|
||||
NameResolver name_resolver;
|
||||
|
||||
AbstractRouter& router;
|
||||
/// wake this up when you send stuff on the flow layer.
|
||||
const std::shared_ptr<EventLoopWakeup>& wakeup_send{_wakeup_send};
|
||||
};
|
||||
} // namespace llarp::layers::flow
|
40
llarp/layers/flow/flow_state.hpp
Normal file
40
llarp/layers/flow/flow_state.hpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "flow_auth.hpp"
|
||||
|
||||
namespace llarp::layers::flow
|
||||
{
|
||||
|
||||
struct FlowState_Pimpl;
|
||||
|
||||
/// internal state of a flow on the flow layer.
|
||||
class FlowState_Base
|
||||
{
|
||||
std::shared_ptr<FlowState_Pimpl> _pimpl;
|
||||
|
||||
public:
|
||||
FlowState_Base(const FlowState_Base&) = delete;
|
||||
FlowState_Base(FlowState_Base&&) = delete;
|
||||
|
||||
/// returns true if we have paths that are aligned to the right place on the network to send to
|
||||
/// the remote.
|
||||
bool
|
||||
paths_aligned() const;
|
||||
|
||||
/// returns true if we are to do authentication with the remote.
|
||||
bool
|
||||
requires_authentication() const;
|
||||
|
||||
/// get the phase we are in with auth.
|
||||
|
||||
FlowAuthPhase
|
||||
auth_phase() const;
|
||||
|
||||
/// returns true if we have an established session for sending traffic over to the remote.
|
||||
/// any authentication has completed and accepted.
|
||||
bool
|
||||
established() const;
|
||||
};
|
||||
|
||||
} // namespace llarp::layers::flow
|
50
llarp/layers/flow/flow_stats.hpp
Normal file
50
llarp/layers/flow/flow_stats.hpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <unordered_set>
|
||||
#include "flow_addr.hpp"
|
||||
#include "flow_info.hpp"
|
||||
|
||||
namespace llarp::layers::flow
|
||||
{
|
||||
|
||||
enum class FlowInfoState
|
||||
{
|
||||
good,
|
||||
active,
|
||||
idle,
|
||||
stalled
|
||||
};
|
||||
|
||||
/// informational data about a flow we have
|
||||
struct FlowInfoStats
|
||||
{
|
||||
FlowInfoState state;
|
||||
/// put extra info here
|
||||
};
|
||||
|
||||
struct FlowStats
|
||||
{
|
||||
std::unordered_map<FlowInfo, FlowInfoStats> all_flows;
|
||||
|
||||
/// default inbound flow address. (our .snode / .loki address)
|
||||
FlowAddr local_addr;
|
||||
|
||||
/// get all local addresses with the first element being local_addr.
|
||||
std::vector<FlowAddr>
|
||||
local_addrs() const;
|
||||
|
||||
/// get all flow infos that are considered "good".
|
||||
std::unordered_set<FlowInfo>
|
||||
good_flows() const;
|
||||
|
||||
/// return true if we have a flow to the remote that is "good".
|
||||
bool
|
||||
has_good_flow_to(const FlowAddr& remote) const;
|
||||
|
||||
/// all flow addrs with auth codes.
|
||||
std::unordered_map<FlowAddr, std::string>
|
||||
auth_map() const;
|
||||
};
|
||||
|
||||
} // namespace llarp::layers::flow
|
41
llarp/layers/flow/flow_tag.hpp
Normal file
41
llarp/layers/flow/flow_tag.hpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include <llarp/util/aligned.hpp>
|
||||
#include <llarp/util/formattable.hpp>
|
||||
|
||||
namespace llarp::layers::flow
|
||||
{
|
||||
/// a flow layer tag that indicates a distinct convo between us and other entity on the flow
|
||||
/// layer. was called a convotag in the past.
|
||||
struct FlowTag : public AlignedBuffer<16>
|
||||
{
|
||||
using AlignedBuffer<16>::AlignedBuffer;
|
||||
|
||||
std::string
|
||||
ToString() const;
|
||||
|
||||
/// make a random flow tag
|
||||
static FlowTag
|
||||
random();
|
||||
};
|
||||
} // namespace llarp::layers::flow
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
template <>
|
||||
inline constexpr bool IsToStringFormattable<llarp::layers::flow::FlowTag> = true;
|
||||
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct hash<llarp::layers::flow::FlowTag>
|
||||
{
|
||||
size_t
|
||||
operator()(const llarp::layers::flow::FlowTag& tag) const
|
||||
{
|
||||
return std::hash<llarp::AlignedBuffer<16>>{}(tag);
|
||||
}
|
||||
};
|
||||
} // namespace std
|
16
llarp/layers/flow/flow_traffic.hpp
Normal file
16
llarp/layers/flow/flow_traffic.hpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include "flow_data_kind.hpp"
|
||||
#include "flow_info.hpp"
|
||||
|
||||
namespace llarp::layers::flow
|
||||
{
|
||||
|
||||
struct FlowTraffic
|
||||
{
|
||||
FlowInfo flow_info;
|
||||
std::vector<byte_t> datum;
|
||||
FlowDataKind kind;
|
||||
};
|
||||
|
||||
} // namespace llarp::layers::flow
|
28
llarp/layers/flow/name_cache.hpp
Normal file
28
llarp/layers/flow/name_cache.hpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include "flow_addr.hpp"
|
||||
#include <llarp/util/decaying_hashtable.hpp>
|
||||
|
||||
namespace llarp::layers::flow
|
||||
{
|
||||
/// cache for in network names (ONS records) with static TTL.
|
||||
/// has no negative lookup cache.
|
||||
class NameCache
|
||||
{
|
||||
/// a cache of all the names we have looked up.
|
||||
/// note: unlike other uses in the code, the decaying hashtabe this wraps uses monotonic uptime
|
||||
/// instead of unix timestamps.
|
||||
util::DecayingHashTable<std::string, FlowAddr> _names;
|
||||
|
||||
public:
|
||||
NameCache(std::chrono::seconds ttl = 5min);
|
||||
|
||||
/// apply any cache expiry then get an entry from the cache if it exists.
|
||||
std::optional<FlowAddr>
|
||||
get(std::string name);
|
||||
|
||||
/// apply any cache expiry and then put a name into the cache.
|
||||
void
|
||||
put(std::string name, FlowAddr addr);
|
||||
};
|
||||
} // namespace llarp::layers::flow
|
37
llarp/layers/flow/name_resolver.hpp
Normal file
37
llarp/layers/flow/name_resolver.hpp
Normal file
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
|
||||
#include "flow_addr.hpp"
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <oxenc/variant.h>
|
||||
|
||||
#include <llarp/util/types.hpp>
|
||||
#include <llarp/dns/question.hpp>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
namespace llarp::layers::flow
|
||||
{
|
||||
|
||||
class NameCache;
|
||||
class FlowLayer;
|
||||
|
||||
class NameResolver
|
||||
{
|
||||
NameCache& _name_cache;
|
||||
FlowLayer& _parent;
|
||||
|
||||
public:
|
||||
NameResolver(const NameResolver&) = delete;
|
||||
NameResolver(NameResolver&&) = delete;
|
||||
NameResolver(NameCache& name_cache, FlowLayer& parent);
|
||||
|
||||
/// resolve name using in network resolution
|
||||
void
|
||||
resolve_flow_addr_async(std::string name, std::function<void(std::optional<FlowAddr>)> handler);
|
||||
};
|
||||
|
||||
} // namespace llarp::layers::flow
|
43
llarp/layers/layers.hpp
Normal file
43
llarp/layers/layers.hpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
|
||||
#include <llarp/layers/platform/platform_layer.hpp>
|
||||
#include <llarp/layers/flow/flow_layer.hpp>
|
||||
#include <llarp/layers/route/route_layer.hpp>
|
||||
#include <llarp/layers/onion/onion_layer.hpp>
|
||||
#include <memory>
|
||||
namespace llarp
|
||||
{
|
||||
// forward declare
|
||||
struct AbstractRouter;
|
||||
struct Config;
|
||||
} // namespace llarp
|
||||
|
||||
namespace llarp::layers
|
||||
{
|
||||
/// a holder type that abstracts out how lokinet works at each layer.
|
||||
/// this is owned by AbstractRouter, and in time all the members on this will be moved to
|
||||
/// AbstractRouter.
|
||||
struct Layers
|
||||
{
|
||||
std::unique_ptr<platform::PlatformLayer> platform;
|
||||
std::unique_ptr<flow::FlowLayer> flow;
|
||||
std::unique_ptr<route::RouteLayer> route;
|
||||
std::unique_ptr<onion::OnionLayer> onion;
|
||||
// TODO: add more layers as they are wired up
|
||||
|
||||
/// move all owned members to a const version.
|
||||
std::unique_ptr<const Layers>
|
||||
freeze();
|
||||
|
||||
void
|
||||
start_all() const;
|
||||
|
||||
void
|
||||
stop_all() const;
|
||||
};
|
||||
|
||||
/// this lets us hide which implementation we are using durring the refactor
|
||||
std::unique_ptr<Layers>
|
||||
make_layers(AbstractRouter& router, const Config& conf);
|
||||
|
||||
} // namespace llarp::layers
|
60
llarp/layers/onion/onion_layer.hpp
Normal file
60
llarp/layers/onion/onion_layer.hpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <llarp/path/path_types.hpp>
|
||||
#include "onion_stats.hpp"
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
struct AbstractRouter;
|
||||
class EventLoopWakeup;
|
||||
} // namespace llarp
|
||||
|
||||
namespace llarp::path
|
||||
{
|
||||
struct IHopHandler;
|
||||
}
|
||||
|
||||
namespace llarp::layers::onion
|
||||
{
|
||||
class OnionLayer
|
||||
{
|
||||
/// all paths that exist in our lokinet.
|
||||
std::unordered_set<std::shared_ptr<path::IHopHandler>> _all;
|
||||
/// map from pathid to owned path.
|
||||
std::unordered_map<PathID_t, std::weak_ptr<path::IHopHandler>> _id_to_owned;
|
||||
/// map from pathid to transit path.
|
||||
std::unordered_map<PathID_t, std::weak_ptr<path::IHopHandler>> _id_to_transit;
|
||||
|
||||
AbstractRouter& _router;
|
||||
|
||||
std::shared_ptr<EventLoopWakeup> _work;
|
||||
|
||||
/// submit all work items for onion layer cryptography
|
||||
void
|
||||
submit_work() const;
|
||||
|
||||
/// remove expired entires.
|
||||
void
|
||||
remove_expired();
|
||||
|
||||
public:
|
||||
explicit OnionLayer(AbstractRouter&);
|
||||
|
||||
/// idempotently tell the onion layer that we have work to submit.
|
||||
void
|
||||
trigger_work() const;
|
||||
|
||||
void
|
||||
start();
|
||||
|
||||
void
|
||||
stop();
|
||||
|
||||
OnionStats
|
||||
current_stats() const;
|
||||
};
|
||||
|
||||
} // namespace llarp::layers::onion
|
27
llarp/layers/onion/onion_path_info.hpp
Normal file
27
llarp/layers/onion/onion_path_info.hpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace llarp::layers::onion
|
||||
{
|
||||
/// all informational data about a singular onion path we created.
|
||||
struct OnionPathInfo
|
||||
{
|
||||
bool
|
||||
ready_to_use() const;
|
||||
};
|
||||
} // namespace llarp::layers::onion
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct hash<llarp::layers::onion::OnionPathInfo>
|
||||
{
|
||||
size_t
|
||||
operator()(const llarp::layers::onion::OnionPathInfo&) const
|
||||
{
|
||||
// TODO: implement me
|
||||
return size_t{};
|
||||
}
|
||||
};
|
||||
} // namespace std
|
26
llarp/layers/onion/onion_stats.hpp
Normal file
26
llarp/layers/onion/onion_stats.hpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <unordered_set>
|
||||
#include "onion_path_info.hpp"
|
||||
|
||||
namespace llarp::layers::onion
|
||||
{
|
||||
struct OnionStats
|
||||
{
|
||||
std::unordered_set<OnionPathInfo> path;
|
||||
|
||||
double path_success_ratio;
|
||||
|
||||
/// set to true if we are routing transit traffic as a service node.
|
||||
bool allowing_transit;
|
||||
|
||||
/// return true if we have enough paths built to operate as a client.
|
||||
bool
|
||||
ready() const;
|
||||
|
||||
/// return a set of all paths that are built.
|
||||
std::unordered_set<OnionPathInfo>
|
||||
built_paths() const;
|
||||
};
|
||||
|
||||
} // namespace llarp::layers::onion
|
217
llarp/layers/platform/addr_mapper.hpp
Normal file
217
llarp/layers/platform/addr_mapper.hpp
Normal file
|
@ -0,0 +1,217 @@
|
|||
#pragma once
|
||||
|
||||
#include "llarp/layers/flow/flow_addr.hpp"
|
||||
#include "platform_addr.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <llarp/layers/flow/flow_info.hpp>
|
||||
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace llarp::layers::flow
|
||||
{
|
||||
class FlowLayer;
|
||||
}
|
||||
|
||||
namespace llarp::layers::platform
|
||||
{
|
||||
|
||||
class AddrMapper;
|
||||
|
||||
struct AddressMapping
|
||||
{
|
||||
std::optional<flow::FlowInfo> flow_info;
|
||||
PlatformAddr src, dst;
|
||||
/// ip ranges for "exit"
|
||||
std::vector<IPRange> owned_ranges;
|
||||
|
||||
/// return true if we own this exact range range.
|
||||
bool
|
||||
owns_range(const IPRange& range) const;
|
||||
|
||||
std::string
|
||||
ToString() const;
|
||||
};
|
||||
|
||||
/// container that holds an addressmapping and extra metadata we need in the addrmapper.
|
||||
class AddressMappingEntry
|
||||
{
|
||||
/// the time this entry was last used.
|
||||
std::chrono::steady_clock::time_point _last_used_at;
|
||||
/// the entry itself.
|
||||
AddressMapping _entry;
|
||||
|
||||
public:
|
||||
/// return true if we match this src and dst address.
|
||||
bool
|
||||
has_addr(const PlatformAddr& src, const PlatformAddr& dst) const;
|
||||
|
||||
/// return true if this entry is for this flow info.
|
||||
bool
|
||||
has_flow_info(const flow::FlowInfo& flow_info) const;
|
||||
|
||||
/// return how long since we last used this entry.
|
||||
inline auto
|
||||
idle_for() const
|
||||
{
|
||||
return decltype(_last_used_at)::clock::now() - _last_used_at;
|
||||
}
|
||||
|
||||
constexpr const auto&
|
||||
last_used_at() const
|
||||
{
|
||||
return _last_used_at;
|
||||
}
|
||||
|
||||
/// update last used and access the entry.
|
||||
AddressMapping&
|
||||
access();
|
||||
|
||||
/// view address mapping without updating last use.
|
||||
const AddressMapping&
|
||||
view() const;
|
||||
};
|
||||
|
||||
/// in charge of mapping flow addresses and platform addresses to each other
|
||||
class AddrMapper
|
||||
{
|
||||
// remote flow mappings
|
||||
std::vector<AddressMappingEntry> _addrs;
|
||||
|
||||
const IPRange _our_range;
|
||||
|
||||
/// remove the lease recently used mapping.
|
||||
void
|
||||
remove_lru();
|
||||
|
||||
/// return a free address we can map to.
|
||||
/// throws if full.
|
||||
PlatformAddr
|
||||
next_addr();
|
||||
|
||||
friend class ReservedAddressMapping;
|
||||
|
||||
public:
|
||||
explicit AddrMapper(const IPRange& range);
|
||||
|
||||
const IPRange range;
|
||||
|
||||
/// unconditionally put an entry in.
|
||||
/// stomps existing entry.
|
||||
/// if full, removes the least frequenty used mapping.
|
||||
void
|
||||
put(AddressMapping&&);
|
||||
|
||||
/// prune all mappings we have no flows for
|
||||
void
|
||||
prune(flow::FlowLayer&);
|
||||
|
||||
/// get a platform for a flow if it exists. updates last used time.
|
||||
std::optional<AddressMapping>
|
||||
get_addr_for_flow(const flow::FlowInfo& flow);
|
||||
|
||||
/// return true if we have an address for this flow info, will not update last used time.
|
||||
bool
|
||||
has_addr_for_flow(const flow::FlowInfo& flow) const;
|
||||
|
||||
/// find a mapping that best matches src/dst address.
|
||||
/// updates last use time.
|
||||
std::optional<AddressMapping>
|
||||
mapping_for(const PlatformAddr& src, const PlatformAddr& dst);
|
||||
|
||||
/// return all address mappings to this remote. does not update last used time.
|
||||
std::vector<AddressMapping>
|
||||
mappings_to(const flow::FlowAddr& remote) const;
|
||||
|
||||
/// return true if we have mapped as many ip addresses as we are able to.
|
||||
bool
|
||||
is_full() const;
|
||||
|
||||
/// get a new address mapping with a filled out destination address and an optionally provided
|
||||
/// source address. if the source address is nullopt we will use the base address of the range
|
||||
/// as the source. throws if full.
|
||||
AddressMapping&
|
||||
allocate_mapping(std::optional<PlatformAddr> src = std::nullopt);
|
||||
|
||||
/// read only iterate over all entries.
|
||||
/// visit returns false to break iteration.
|
||||
template <typename Viewer_t>
|
||||
void
|
||||
view_all_entries(Viewer_t&& visit) const
|
||||
{
|
||||
for (const auto& ent : _addrs)
|
||||
{
|
||||
if (not visit(ent.view()))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/// return an iterator for first entry matching predicate.
|
||||
/// this is a helper so we will not update last used.
|
||||
template <typename Predicate_t>
|
||||
[[nodiscard]] auto
|
||||
find_if(Predicate_t&& pred)
|
||||
{
|
||||
return std::find_if(
|
||||
_addrs.begin(), _addrs.end(), [pred](const auto& ent) { return pred(ent.view()); });
|
||||
}
|
||||
|
||||
/// return an iterator for first entry matching predicate.
|
||||
/// this is a helper so we will not update last used.
|
||||
template <typename Predicate_t>
|
||||
[[nodiscard]] auto
|
||||
find_if(Predicate_t&& pred) const
|
||||
{
|
||||
return std::find_if(
|
||||
_addrs.begin(), _addrs.end(), [pred](const auto& ent) { return pred(ent.view()); });
|
||||
}
|
||||
|
||||
/// remove via predicate on entry.
|
||||
template <typename Predicate_t>
|
||||
void
|
||||
remove_if_entry(Predicate_t&& pred)
|
||||
{
|
||||
auto itr = _addrs.begin();
|
||||
while (itr != _addrs.end())
|
||||
{
|
||||
if (pred(*itr))
|
||||
itr = _addrs.erase(itr);
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
/// remove via predicate on mapping.
|
||||
template <typename Predicate_t>
|
||||
void
|
||||
remove_if_mapping(Predicate_t&& pred)
|
||||
{
|
||||
remove_if_entry([pred](auto& ent) { return pred(ent.view()); });
|
||||
}
|
||||
|
||||
/// return all exits we have.
|
||||
/// last use time not updated.
|
||||
std::vector<AddressMapping>
|
||||
all_exits() const;
|
||||
|
||||
/// make an ip range map for all our exits.
|
||||
net::IPRangeMap<flow::FlowAddr>
|
||||
exit_map() const;
|
||||
};
|
||||
|
||||
} // namespace llarp::layers::platform
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
nlohmann::json
|
||||
to_json(const llarp::layers::platform::AddressMapping&);
|
||||
|
||||
template <>
|
||||
inline constexpr bool IsToStringFormattable<layers::platform::AddressMapping> = true;
|
||||
} // namespace llarp
|
95
llarp/layers/platform/dns_bridge.hpp
Normal file
95
llarp/layers/platform/dns_bridge.hpp
Normal file
|
@ -0,0 +1,95 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <llarp/dns/server.hpp>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <llarp/layers/flow/flow_addr.hpp>
|
||||
#include "llarp/dns/question.hpp"
|
||||
#include "llarp/dns/rr.hpp"
|
||||
#include "llarp/layers/flow/flow_layer.hpp"
|
||||
#include "llarp/util/decaying_hashtable.hpp"
|
||||
#include "llarp/util/str.hpp"
|
||||
|
||||
namespace llarp::layers::flow
|
||||
{
|
||||
class FlowLayer;
|
||||
}
|
||||
|
||||
namespace llarp::layers::platform
|
||||
{
|
||||
|
||||
class PlatformLayer;
|
||||
class AddrMapper;
|
||||
|
||||
/// synthesizes authoritative RR for a .loki or .snode address.
|
||||
class DNSZone
|
||||
{
|
||||
/// the flow address of the dns zone this is responsible for.
|
||||
flow::FlowAddr _flow_addr;
|
||||
|
||||
/// any known cached ons names for this zone.
|
||||
std::vector<std::string> _ons_names;
|
||||
std::vector<dns::SRVData> _srv;
|
||||
AddrMapper& _addr_mapper;
|
||||
|
||||
/// synth srv records rdata.
|
||||
std::vector<dns::RData>
|
||||
srv_records() const;
|
||||
|
||||
/// synth cname records rdata.
|
||||
std::vector<dns::RData>
|
||||
cname_records() const;
|
||||
|
||||
/// get ttl for a rr type.
|
||||
uint32_t
|
||||
ttl(dns::RRType rr_type) const;
|
||||
|
||||
std::string
|
||||
zone_name() const;
|
||||
|
||||
public:
|
||||
DNSZone(AddrMapper&, flow::FlowAddr addr);
|
||||
|
||||
/// add a new srv recrod to this dns zone.
|
||||
void
|
||||
add_srv_record(dns::SRVTuple record);
|
||||
|
||||
/// synthesize any resource records for a rr type.
|
||||
std::vector<dns::ResourceRecord>
|
||||
synth_rr_for(dns::RRType r_type) const;
|
||||
};
|
||||
|
||||
/// handles dns queries, for .loki / .snode
|
||||
class DNSQueryHandler : public dns::Resolver_Base
|
||||
{
|
||||
PlatformLayer& _plat;
|
||||
|
||||
std::unordered_map<flow::FlowAddr, std::unique_ptr<DNSZone>> _zones;
|
||||
|
||||
/// async resolve dns zone given a dns question.
|
||||
void
|
||||
async_obtain_dns_zone(
|
||||
const dns::Question& qestion, std::function<void(std::optional<DNSZone>)> result_handler);
|
||||
|
||||
public:
|
||||
explicit DNSQueryHandler(PlatformLayer& parent);
|
||||
~DNSQueryHandler() override = default;
|
||||
|
||||
int
|
||||
Rank() const override;
|
||||
|
||||
std::string_view
|
||||
ResolverName() const override;
|
||||
|
||||
bool
|
||||
MaybeHookDNS(
|
||||
std::shared_ptr<dns::PacketSource_Base> source,
|
||||
const dns::Message& query,
|
||||
const SockAddr& to,
|
||||
const SockAddr& from) override;
|
||||
};
|
||||
} // namespace llarp::layers::platform
|
25
llarp/layers/platform/ethertype.hpp
Normal file
25
llarp/layers/platform/ethertype.hpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include "llarp/util/formattable.hpp"
|
||||
namespace llarp::layers::platform
|
||||
{
|
||||
/// the kind of traffic we are tunneling
|
||||
enum class EtherType_t
|
||||
{
|
||||
/// ipv4/ipv6 unicast traffic
|
||||
ip_unicast,
|
||||
/// plainquic stream
|
||||
plainquic,
|
||||
/// flow layer auth protocol
|
||||
proto_auth
|
||||
};
|
||||
|
||||
std::string
|
||||
ToString(EtherType_t kind);
|
||||
} // namespace llarp::layers::platform
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
template <>
|
||||
inline constexpr bool IsToStringFormattable<layers::platform::EtherType_t> = true;
|
||||
}
|
28
llarp/layers/platform/name_cache.hpp
Normal file
28
llarp/layers/platform/name_cache.hpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include <llarp/layers/flow/flow_addr.hpp>
|
||||
#include <llarp/util/decaying_hashtable.hpp>
|
||||
|
||||
namespace llarp::layers::platform
|
||||
{
|
||||
/// cache for in network names (ONS records) with static TTL.
|
||||
/// has no negative lookup cache.
|
||||
class NameCache
|
||||
{
|
||||
/// a cache of all the names we have looked up.
|
||||
/// note: unlike other uses in the code, the decaying hashtabe this wraps uses monotonic uptime
|
||||
/// instead of unix timestamps.
|
||||
util::DecayingHashTable<std::string, flow::FlowAddr> _names;
|
||||
|
||||
public:
|
||||
NameCache(std::chrono::seconds ttl = 5min);
|
||||
|
||||
/// apply any cache expiry then get an entry from the cache if it exists.
|
||||
std::optional<flow::FlowAddr>
|
||||
get(std::string name);
|
||||
|
||||
/// apply any cache expiry and then put a name into the cache.
|
||||
void
|
||||
put(std::string name, flow::FlowAddr addr);
|
||||
};
|
||||
} // namespace llarp::layers::platform
|
39
llarp/layers/platform/name_resolver.hpp
Normal file
39
llarp/layers/platform/name_resolver.hpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
#pragma once
|
||||
|
||||
#include <llarp/layers/flow/flow_layer.hpp>
|
||||
|
||||
#include "platform_addr.hpp"
|
||||
#include "name_cache.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <oxenc/variant.h>
|
||||
|
||||
#include <llarp/util/types.hpp>
|
||||
#include <llarp/dns/question.hpp>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
namespace llarp::layers::platform
|
||||
{
|
||||
class PlatformLayer;
|
||||
class NameCache;
|
||||
|
||||
class NameResolver
|
||||
{
|
||||
NameCache& _name_cache;
|
||||
flow::FlowLayer& _flow_layer;
|
||||
|
||||
public:
|
||||
NameResolver(NameCache& name_cache, flow::FlowLayer& flow_layer);
|
||||
|
||||
/// resolve name using in network resolution
|
||||
void
|
||||
resolve_flow_addr_async(
|
||||
std::string name, std::function<void(std::optional<flow::FlowAddr>)> handler);
|
||||
};
|
||||
|
||||
} // namespace llarp::layers::platform
|
43
llarp/layers/platform/os_traffic.hpp
Normal file
43
llarp/layers/platform/os_traffic.hpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
#include <llarp/util/formattable.hpp>
|
||||
#include "ethertype.hpp"
|
||||
#include "llarp/net/ip_packet.hpp"
|
||||
#include "platform_addr.hpp"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace llarp::layers::platform
|
||||
{
|
||||
/// platfrom datum that is used to read and write to the os
|
||||
struct OSTraffic
|
||||
{
|
||||
/// the kind of traffic it is
|
||||
EtherType_t kind;
|
||||
/// platform level source and destination addresses of this traffic
|
||||
PlatformAddr src, dst;
|
||||
/// the datum itself
|
||||
std::vector<uint8_t> data;
|
||||
|
||||
OSTraffic() = default;
|
||||
|
||||
/// construct from a valid ip packet.
|
||||
explicit OSTraffic(net::IPPacket);
|
||||
|
||||
OSTraffic(EtherType_t kind, PlatformAddr src, PlatformAddr dst, std::vector<uint8_t> data);
|
||||
|
||||
std::string
|
||||
ToString() const;
|
||||
|
||||
private:
|
||||
/// make sure all the checksums are correct.
|
||||
void
|
||||
recompute_checksums();
|
||||
};
|
||||
|
||||
} // namespace llarp::layers::platform
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
template <>
|
||||
inline constexpr bool IsToStringFormattable<layers::platform::OSTraffic> = true;
|
||||
}
|
83
llarp/layers/platform/platform_addr.hpp
Normal file
83
llarp/layers/platform/platform_addr.hpp
Normal file
|
@ -0,0 +1,83 @@
|
|||
#pragma once
|
||||
|
||||
#include <llarp/net/net_int.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <numeric>
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <functional>
|
||||
|
||||
namespace llarp::layers::platform
|
||||
{
|
||||
|
||||
/// a (ipv6 address, flowlabel) tuple that we use for platform layer side addressing
|
||||
struct PlatformAddr
|
||||
{
|
||||
/// ip network address
|
||||
net::ipv6addr_t ip{};
|
||||
|
||||
/// flowlabel, ingored if ip is a v4 mapped address
|
||||
/// this is used as a metric to do flow layer isolation where we can use different identities
|
||||
/// and / or paths on each. defaults to zero.
|
||||
net::flowlabel_t flowlabel{};
|
||||
|
||||
PlatformAddr() = default;
|
||||
PlatformAddr(const PlatformAddr&) = default;
|
||||
PlatformAddr(PlatformAddr&&) = default;
|
||||
|
||||
PlatformAddr&
|
||||
operator=(const PlatformAddr&) = default;
|
||||
PlatformAddr&
|
||||
operator=(PlatformAddr&&) = default;
|
||||
|
||||
explicit PlatformAddr(net::ipaddr_t addr);
|
||||
explicit PlatformAddr(const std::string& str);
|
||||
explicit PlatformAddr(huint128_t addr);
|
||||
|
||||
/// string representation
|
||||
std::string
|
||||
ToString() const;
|
||||
|
||||
/// convert to variant. compacts to ipv4 if it is a mapped address.
|
||||
net::ipaddr_t
|
||||
as_ipaddr() const;
|
||||
|
||||
/// returns ipv4 address if it's a mapped address. otherwise returns nullopt.
|
||||
std::optional<net::ipv4addr_t>
|
||||
as_ipv4addr() const;
|
||||
|
||||
bool
|
||||
operator==(const PlatformAddr& other) const;
|
||||
bool
|
||||
operator!=(const PlatformAddr& other) const;
|
||||
|
||||
bool
|
||||
operator<(const PlatformAddr& other) const;
|
||||
};
|
||||
|
||||
} // namespace llarp::layers::platform
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
template <>
|
||||
inline constexpr bool IsToStringFormattable<layers::platform::PlatformAddr> = true;
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct hash<llarp::layers::platform::PlatformAddr>
|
||||
{
|
||||
size_t
|
||||
operator()(const llarp::layers::platform::PlatformAddr& addr) const
|
||||
{
|
||||
const std::array<uint64_t, 4> data{addr.ip.n.upper, addr.ip.n.lower, addr.flowlabel.n};
|
||||
int n{};
|
||||
return std::accumulate(
|
||||
data.begin(), data.end(), uint64_t{}, [&n](uint64_t lhs, uint64_t rhs) {
|
||||
return lhs ^ (rhs << (n += (n ? 2 : 1)));
|
||||
});
|
||||
}
|
||||
};
|
||||
} // namespace std
|
216
llarp/layers/platform/platform_layer.hpp
Normal file
216
llarp/layers/platform/platform_layer.hpp
Normal file
|
@ -0,0 +1,216 @@
|
|||
#pragma once
|
||||
|
||||
#include "addr_mapper.hpp"
|
||||
#include "platform_addr.hpp"
|
||||
#include "platform_stats.hpp"
|
||||
#include "os_traffic.hpp"
|
||||
|
||||
#include <llarp/config/config.hpp>
|
||||
#include <llarp/net/ip_packet.hpp>
|
||||
#include <llarp/net/ip_range.hpp>
|
||||
|
||||
#include <llarp/util/formattable.hpp>
|
||||
#include <llarp/util/types.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
class EventLoop;
|
||||
}
|
||||
|
||||
namespace llarp::dns
|
||||
{
|
||||
class Server;
|
||||
}
|
||||
|
||||
namespace llarp::quic
|
||||
{
|
||||
// TODO: forward declared no idea if this is an existing type or not.
|
||||
class TunnelManager;
|
||||
} // namespace llarp::quic
|
||||
|
||||
namespace llarp::vpn
|
||||
{
|
||||
class NetworkInterface;
|
||||
class IRouteManager;
|
||||
} // namespace llarp::vpn
|
||||
|
||||
namespace llarp::layers::flow
|
||||
{
|
||||
class FlowLayer;
|
||||
class FlowAddr;
|
||||
struct FlowInfo;
|
||||
struct FlowTraffic;
|
||||
|
||||
} // namespace llarp::layers::flow
|
||||
|
||||
namespace llarp::layers::platform
|
||||
{
|
||||
class DNSZone;
|
||||
class DNSQueryHandler;
|
||||
|
||||
// handles reading and writing os traffic, like ip packets or whatever embedded lokinet wants to
|
||||
// do.
|
||||
class OSTraffic_IO_Base
|
||||
{
|
||||
PlatformAddr _our_addr;
|
||||
std::vector<OSTraffic> _recv_queue;
|
||||
std::atomic<bool> _running;
|
||||
|
||||
protected:
|
||||
std::weak_ptr<EventLoop> _loop;
|
||||
std::shared_ptr<vpn::NetworkInterface> _netif;
|
||||
std::shared_ptr<quic::TunnelManager> _quic;
|
||||
|
||||
virtual void got_ip_packet(net::IPPacket);
|
||||
|
||||
public:
|
||||
explicit OSTraffic_IO_Base(const EventLoop_ptr&);
|
||||
|
||||
virtual ~OSTraffic_IO_Base() = default;
|
||||
|
||||
/// get the platform address of the underlying device managed.
|
||||
constexpr const PlatformAddr&
|
||||
our_platform_addr() const
|
||||
{
|
||||
return _our_addr;
|
||||
}
|
||||
|
||||
/// attach to a vpn interface. sets up io handlers.
|
||||
/// idempotently wakes up wakeup_recv when we get packets read.
|
||||
void
|
||||
attach(
|
||||
std::shared_ptr<vpn::NetworkInterface> netif, std::shared_ptr<EventLoopWakeup> wakeup_recv);
|
||||
|
||||
/// attach to a quic handler. idempotently wakes up wakeup_recv when we get any kind of data
|
||||
/// from quic_tun.
|
||||
void
|
||||
attach(
|
||||
std::shared_ptr<quic::TunnelManager> quic_tun,
|
||||
std::shared_ptr<EventLoopWakeup> wakeup_recv);
|
||||
|
||||
/// read from the os.
|
||||
/// this MUST NOT have any internal userland buffering from previous calls to
|
||||
/// read_platform_traffic().
|
||||
virtual std::vector<OSTraffic>
|
||||
read_platform_traffic();
|
||||
|
||||
/// write traffic to the os.
|
||||
virtual void
|
||||
write_platform_traffic(std::vector<OSTraffic>&& traff);
|
||||
|
||||
/// stop all future io and detach from event loop.
|
||||
void
|
||||
detach();
|
||||
};
|
||||
|
||||
struct platform_io_wakeup_handler;
|
||||
|
||||
/// responsible for bridging the os and the flow layer.
|
||||
class PlatformLayer
|
||||
{
|
||||
protected:
|
||||
friend struct platform_io_wakeup_handler;
|
||||
|
||||
AbstractRouter& _router;
|
||||
flow::FlowLayer& _flow_layer;
|
||||
|
||||
/// called to wake up the loop to read os traffic
|
||||
std::shared_ptr<EventLoopWakeup> _os_recv;
|
||||
|
||||
NetworkConfig _netconf;
|
||||
|
||||
/// handler of dns queries.
|
||||
std::shared_ptr<DNSQueryHandler> _dns_query_handler;
|
||||
|
||||
std::weak_ptr<vpn::NetworkInterface> _netif;
|
||||
|
||||
std::unique_ptr<OSTraffic_IO_Base> _io;
|
||||
|
||||
std::shared_ptr<DNSZone> _local_dns_zone;
|
||||
/// called once per event loop tick after platform layer event loop polled for and consumed io.
|
||||
void
|
||||
on_io();
|
||||
|
||||
/// make platform specific io with quarks.
|
||||
virtual std::unique_ptr<OSTraffic_IO_Base>
|
||||
make_io() const;
|
||||
|
||||
public:
|
||||
/// holds address mapping state.
|
||||
AddrMapper addr_mapper;
|
||||
/// underlying io.
|
||||
const std::unique_ptr<OSTraffic_IO_Base>& io{_io};
|
||||
|
||||
/// wake this up when the event loop reads ip packets.
|
||||
const std::shared_ptr<EventLoopWakeup>& wakeup{_os_recv};
|
||||
|
||||
PlatformLayer(const PlatformLayer&) = delete;
|
||||
PlatformLayer(PlatformLayer&&) = delete;
|
||||
|
||||
PlatformLayer(
|
||||
AbstractRouter& router, flow::FlowLayer& flow_layer, const NetworkConfig& netconf);
|
||||
|
||||
void
|
||||
start();
|
||||
|
||||
void
|
||||
stop();
|
||||
|
||||
std::shared_ptr<vpn::NetworkInterface>
|
||||
vpn_interface() const;
|
||||
|
||||
vpn::IRouteManager*
|
||||
route_manager() const;
|
||||
|
||||
/// return the dns zone for our local self.
|
||||
DNSZone&
|
||||
local_dns_zone();
|
||||
|
||||
/// called each time we get a bunch of os traffic.
|
||||
void
|
||||
os_traffic(std::vector<OSTraffic>&& pkts);
|
||||
|
||||
/// give the platform layer flow layer traffic to write to the os.
|
||||
void
|
||||
flow_traffic(std::vector<flow::FlowTraffic>&& traff);
|
||||
|
||||
/// async resolve dns zone given a flow level name.
|
||||
void
|
||||
async_obtain_dns_zone(
|
||||
std::string name, std::function<void(std::optional<DNSZone>)> result_handler);
|
||||
|
||||
void
|
||||
map_remote(
|
||||
std::string name,
|
||||
std::string auth,
|
||||
std::vector<IPRange> ranges,
|
||||
std::optional<PlatformAddr> src = std::nullopt,
|
||||
std::function<void(std::optional<flow::FlowInfo>, std::string)> result_handler = nullptr);
|
||||
|
||||
/// calls map_remote() for exits
|
||||
void
|
||||
map_exit(
|
||||
std::string name,
|
||||
std::string auth,
|
||||
std::vector<IPRange> ranges,
|
||||
std::function<void(bool, std::string)> result_handler);
|
||||
|
||||
/// unmap an exit from a range
|
||||
void
|
||||
unmap_exit(flow::FlowAddr remote, std::optional<IPRange> range = std::nullopt);
|
||||
|
||||
/// unmap every exit that is mapped to this range.
|
||||
void
|
||||
unmap_all_exits_on_range(IPRange range);
|
||||
|
||||
PlatformStats
|
||||
current_stats() const;
|
||||
};
|
||||
} // namespace llarp::layers::platform
|
12
llarp/layers/platform/platform_stats.hpp
Normal file
12
llarp/layers/platform/platform_stats.hpp
Normal file
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include <llarp/layers/flow/flow_addr.hpp>
|
||||
#include <llarp/net/ip_range_map.hpp>
|
||||
|
||||
namespace llarp::layers::platform
|
||||
{
|
||||
struct PlatformStats
|
||||
{};
|
||||
} // namespace llarp::layers::platform
|
22
llarp/layers/route/destination.hpp
Normal file
22
llarp/layers/route/destination.hpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include <llarp/crypto/types.hpp>
|
||||
#include <optional>
|
||||
#include <llarp/layers/flow/flow_info.hpp>
|
||||
#include <llarp/path/transit_hop.hpp>
|
||||
|
||||
namespace llarp::layers::route
|
||||
{
|
||||
/// a routable destination when we are an endpoint router transiting routing layer traffic.
|
||||
class Destination
|
||||
{
|
||||
public:
|
||||
PubKey src;
|
||||
PubKey dst;
|
||||
/// the info of the transit hop that we are located.
|
||||
path::TransitHopInfo onion_info;
|
||||
|
||||
/// flow layer convo this routing destination is fascilitating. if applicable.
|
||||
std::optional<flow::FlowInfo> flow_info;
|
||||
};
|
||||
} // namespace llarp::layers::route
|
58
llarp/layers/route/route_layer.hpp
Normal file
58
llarp/layers/route/route_layer.hpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
#pragma once
|
||||
|
||||
#include <llarp/path/transit_hop.hpp>
|
||||
#include <llarp/crypto/types.hpp>
|
||||
#include <memory>
|
||||
#include "destination.hpp"
|
||||
|
||||
namespace llarp
|
||||
{
|
||||
struct AbstractRouter;
|
||||
}
|
||||
|
||||
namespace llarp::layers::route
|
||||
{
|
||||
|
||||
class RouteLayer
|
||||
{
|
||||
std::vector<std::unique_ptr<Destination>> _destinations;
|
||||
|
||||
public:
|
||||
explicit RouteLayer(AbstractRouter&);
|
||||
|
||||
/// create a routing destination belonging to pubkey+endpoint transithop going to a snode.
|
||||
Destination*
|
||||
create_destination(const path::TransitHopInfo& info, PubKey src, RouterID dst);
|
||||
|
||||
/// remove a routing destination for an existing endpoint transit hop.
|
||||
/// returns true if we removed something.
|
||||
bool
|
||||
remove_destination_on(const path::TransitHopInfo& info);
|
||||
|
||||
/// remove all routing destination from a source to a destination.
|
||||
/// returns the number of entries we removed.
|
||||
size_t
|
||||
remove_destinations_to(const PubKey& src, const RouterID& dst);
|
||||
|
||||
/// remove all routing destination from a source.
|
||||
/// returns the number of entries we removed.
|
||||
size_t
|
||||
remove_destinations_from(const PubKey& dst);
|
||||
|
||||
/// get a routing destination given a local path rxID.
|
||||
Destination*
|
||||
destination_to(const PathID_t& rxid);
|
||||
|
||||
/// get a routing destination given its local path txid.
|
||||
Destination*
|
||||
destination_from(const PathID_t& txid);
|
||||
|
||||
/// get all routing destinations given the source pubkey going to a snode dst.
|
||||
std::vector<Destination*>
|
||||
all_destinations_from(const PubKey& src);
|
||||
|
||||
/// maybe fetch a routing destination that was previously created for an endpoint transit hop.
|
||||
Destination*
|
||||
destination_on(const path::TransitHopInfo& info) const;
|
||||
};
|
||||
} // namespace llarp::layers::route
|
Loading…
Reference in a new issue