re-separated address classes

- there is one key difference between the address classes: ClientAddress can be constructed with an ONS name, and can therefore exist in one of 2 dual states (pubkey vs ONS)
pull/2212/head
dr7ana 6 months ago
parent b037c04285
commit 0301bc8164

@ -3,4 +3,79 @@
#include "utils.hpp"
namespace llarp
{} // namespace llarp
{
static auto logcat = log::Cat("address");
std::optional<ClientAddress> ClientAddress::from_client_addr(std::string arg)
{
std::optional<ClientAddress> ret = std::nullopt;
if (not arg.ends_with(".loki"))
log::warning(logcat, "Invalid ClientAddress constructor input lacking '.loki' (input:{})", arg);
else
ret = ClientAddress{arg, service::is_valid_ons(arg)};
return ret;
}
ClientAddress::ClientAddress(std::string_view arg, bool is_ons) : RemoteAddress{TLD::CLIENT}, _is_ons{is_ons}
{
// This private constructor is only called after checking for a '.loki' suffix; only Santa checks twice
arg.remove_suffix(5);
// If this was constructed using an ONS name, we don't fill in the pubkey
if (not _is_ons)
_pubkey->from_string(arg);
else
_name = arg;
}
bool ClientAddress::operator<(const ClientAddress& other) const
{
return std::tie(_pubkey, _name, _is_ons) < std::tie(other._pubkey, other._name, other._is_ons);
}
bool ClientAddress::operator==(const ClientAddress& other) const
{
return std::tie(_pubkey, _name, _is_ons) == std::tie(other._pubkey, other._name, other._is_ons);
}
bool ClientAddress::operator!=(const ClientAddress& other) const
{
return !(*this == other);
}
std::optional<RelayAddress> RelayAddress::from_relay_addr(std::string arg)
{
std::optional<RelayAddress> ret = std::nullopt;
if (not arg.ends_with(".snode"))
log::warning(logcat, "Invalid RelayAddress constructor input lacking '.loki' (input:{})", arg);
else
ret = RelayAddress{arg};
return ret;
}
RelayAddress::RelayAddress(std::string_view arg) : RemoteAddress{TLD::RELAY}
{
// This private constructor is only called after checking for a '.loki' suffix; only Santa checks twice
arg.remove_suffix(6);
_pubkey.from_string(arg);
}
bool RelayAddress::operator<(const RelayAddress& other) const
{
return _pubkey < other._pubkey;
}
bool RelayAddress::operator==(const RelayAddress& other) const
{
return _pubkey == other._pubkey;
}
bool RelayAddress::operator!=(const RelayAddress& other) const
{
return !(*this == other);
}
} // namespace llarp

@ -13,117 +13,187 @@
namespace llarp
{
template <typename pubkey_t = PubKey, std::enable_if_t<std::is_base_of_v<PubKey, pubkey_t>, int> = 0>
struct RemoteAddress
{
pubkey_t _pubkey;
std::optional<std::string> _name = std::nullopt;
protected:
std::string _tld;
bool is_ons{false};
explicit RemoteAddress(std::string_view tld) : _tld{std::move(tld)}
{}
public:
RemoteAddress() = default;
virtual ~RemoteAddress() = default;
explicit RemoteAddress(std::string addr, bool _is_ons = false) : _name{std::move(addr)}, is_ons{_is_ons}
std::string to_string() const
{
if (not is_ons)
_pubkey.from_string(*_name);
if constexpr (std::is_same_v<pubkey_t, ClientPubKey>)
_tld = std::string{TLD::CLIENT};
else if constexpr (std::is_same_v<pubkey_t, RelayPubKey>)
_tld = std::string{TLD::RELAY};
else
throw std::invalid_argument{"Something seriously weird just happened."};
return remote_name();
}
explicit RemoteAddress(PubKey pk, std::string_view tld, std::optional<std::string> n = std::nullopt)
: _pubkey{pk.data()}, _name{std::move(n)}, _tld{tld}
{}
RemoteAddress(const RemoteAddress& other) : RemoteAddress{other._pubkey, other._tld, other._name}
{}
RemoteAddress(RemoteAddress&& other)
: RemoteAddress{std::move(other._pubkey), std::move(other._tld), std::move(other._name)}
{}
virtual std::string name() const = 0;
RemoteAddress& operator=(const RemoteAddress& other) = default;
RemoteAddress& operator=(RemoteAddress&& other)
std::string tld() const
{
_pubkey = std::move(other._pubkey);
_name = std::move(other._name);
_tld = std::move(other._tld);
return *this;
return _tld;
}
bool operator<(const RemoteAddress& other) const
{
return std::tie(_pubkey, _name, _tld) < std::tie(other._pubkey, other._name, other._tld);
}
bool operator==(const RemoteAddress& other) const
{
return _pubkey == other._pubkey and _name == other._name && _tld == other._tld;
}
bool operator!=(const RemoteAddress& other) const
std::string remote_name() const
{
return not(*this == other);
return name() + tld();
}
};
~RemoteAddress() = default;
struct ClientAddress final : public RemoteAddress
{
private:
std::optional<ClientPubKey> _pubkey{std::nullopt};
std::optional<std::string> _name{std::nullopt};
bool _is_ons{false};
std::string to_string() const
{
return remote_name();
}
explicit ClientAddress(std::string_view addr, bool is_ons);
public:
ClientAddress() = default;
~ClientAddress() override = default;
explicit ClientAddress(ClientPubKey cpk, std::optional<std::string> n = std::nullopt)
: RemoteAddress{TLD::CLIENT}, _pubkey{std::move(cpk)}, _name{std::move(n)}
{}
ClientAddress(const ClientAddress& other)
: RemoteAddress{TLD::RELAY}, _pubkey{other._pubkey}, _name{other._name}
{}
ClientAddress(ClientAddress&& other)
: RemoteAddress{TLD::RELAY}, _pubkey{std::move(other._pubkey)}, _name{std::move(other._name)}
{}
ClientAddress& operator=(const ClientAddress& other) = default;
ClientAddress& operator=(ClientAddress&& other) = default;
std::string name() const
bool operator<(const ClientAddress& other) const;
bool operator==(const ClientAddress& other) const;
bool operator!=(const ClientAddress& other) const;
static std::optional<ClientAddress> from_client_addr(std::string arg);
std::optional<ClientPubKey> pubkey()
{
return _name.value_or(_pubkey.to_string());
return _pubkey;
}
std::string tld() const
bool is_ons() const
{
return _tld;
return _is_ons;
}
std::string remote_name() const
std::string name() const override
{
return name() + tld();
return _name.value_or(_pubkey->to_string());
}
};
template <typename pubkey_t = PubKey, std::enable_if_t<std::is_base_of_v<PubKey, pubkey_t>, int> = 0>
std::optional<RemoteAddress<pubkey_t>> from_pubkey_addr(const std::string& arg)
struct RelayAddress final : public RemoteAddress
{
if constexpr (std::is_same_v<pubkey_t, ClientPubKey> || std::is_same_v<pubkey_t, PubKey>)
private:
RelayPubKey _pubkey;
explicit RelayAddress(std::string_view addr);
public:
RelayAddress() = default;
~RelayAddress() override = default;
explicit RelayAddress(RelayPubKey cpk) : RemoteAddress{TLD::CLIENT}, _pubkey{std::move(cpk)}
{}
RelayAddress(const RelayAddress& other) : RemoteAddress{TLD::RELAY}, _pubkey{other._pubkey}
{}
RelayAddress(RelayAddress&& other) : RemoteAddress{TLD::RELAY}, _pubkey{std::move(other._pubkey)}
{}
RelayAddress& operator=(const RelayAddress& other) = default;
RelayAddress& operator=(RelayAddress&& other) = default;
bool operator<(const RelayAddress& other) const;
bool operator==(const RelayAddress& other) const;
bool operator!=(const RelayAddress& other) const;
static std::optional<RelayAddress> from_relay_addr(std::string arg);
const RelayPubKey& pubkey()
{
if (service::is_valid_ons(arg))
{
return std::make_optional(RemoteAddress<ClientPubKey>(arg, true));
}
if (auto maybe_addr = parse_addr_string(arg, TLD::CLIENT))
{
return std::make_optional(RemoteAddress<ClientPubKey>(*maybe_addr));
}
return _pubkey;
}
if (auto maybe_addr = parse_addr_string(arg, TLD::RELAY))
std::string name() const override
{
return std::make_optional(RemoteAddress<RelayPubKey>(*maybe_addr));
return _pubkey.to_string();
}
};
return std::nullopt;
}
template <typename pk_t>
inline constexpr bool IsToStringFormattable<RemoteAddress<pk_t>> = true;
// template <typename pubkey_t = PubKey, std::enable_if_t<std::is_base_of_v<PubKey, pubkey_t>, int> = 0>
// std::optional<RemoteAddress<pubkey_t>> from_pubkey_addr(const std::string& arg)
// {
// if constexpr (std::is_same_v<pubkey_t, ClientPubKey> || std::is_same_v<pubkey_t, PubKey>)
// {
// if (service::is_valid_ons(arg))
// {
// return std::make_optional(RemoteAddress<ClientPubKey>(arg, true));
// }
// if (auto maybe_addr = parse_addr_string(arg, TLD::CLIENT))
// {
// return std::make_optional(RemoteAddress<ClientPubKey>(*maybe_addr));
// }
// }
// if (auto maybe_addr = parse_addr_string(arg, TLD::RELAY))
// {
// return std::make_optional(RemoteAddress<RelayPubKey>(*maybe_addr));
// }
// return std::nullopt;
// }
// template <typename pubkey_t, std::enable_if_t<std::is_base_of_v<PubKey, pubkey_t>, int> = 0>
// std::optional<RemoteAddress<pubkey_t>> from_pubkey_addr(const std::string& arg)
// // auto from_pubkey_addr(const std::string& arg)
// {
// if (arg.ends_with(".loki"))
// {
// return RemoteAddress<ClientPubKey>(arg, service::is_valid_ons(arg));
// }
// if (arg.ends_with(".snode"))
// {
// return RemoteAddress<RelayPubKey>(arg);
// }
// return std::nullopt;
// }
template <>
inline constexpr bool IsToStringFormattable<RemoteAddress> = true;
template <typename T>
inline constexpr bool IsToStringFormattable<T, std::enable_if_t<std::is_base_of_v<RemoteAddress, T>>> = true;
} // namespace llarp
namespace std
{
template <typename pk_t>
struct hash<llarp::RemoteAddress<pk_t>>
template <>
struct hash<llarp::RemoteAddress>
{
virtual size_t operator()(const llarp::RemoteAddress<pk_t>& r) const
virtual size_t operator()(const llarp::RemoteAddress& r) const
{
return std::hash<std::string>{}(r.to_string());
}
};
template <>
struct hash<llarp::RelayAddress> : public hash<llarp::RemoteAddress>
{};
template <>
struct hash<llarp::ClientAddress> : public hash<llarp::RemoteAddress>
{};
} // namespace std

@ -22,9 +22,8 @@ namespace llarp
public:
IPRange() = default;
explicit IPRange(std::string a) : IPRange{a, 0}
{}
explicit IPRange(std::string a, uint8_t m)
explicit IPRange(std::string a, uint8_t m = 0)
: _addr{std::move(a), 0}, _mask{m}, _is_ipv4{_addr.is_ipv4()}, _ip{init_ip()}
{}
explicit IPRange(oxen::quic::Address a, uint8_t m)

@ -18,6 +18,11 @@ namespace llarp
using ipv6_net = oxen::quic::ipv6_net;
using ip_net = std::variant<ipv4_net, ipv6_net>;
template <>
inline constexpr bool IsToStringFormattable<ip> = true;
template <>
inline constexpr bool IsToStringFormattable<ip_net> = true;
inline constexpr uint32_t ipv6_flowlabel_mask = 0b0000'0000'0000'1111'1111'1111'1111'1111;
inline constexpr size_t ICMP_HEADER_SIZE{8};

@ -471,7 +471,6 @@ namespace llarp
return;
std::optional<IPRange> range;
RemoteAddress remote;
const auto pos = arg.find(":");
@ -485,8 +484,8 @@ namespace llarp
if (pos != std::string::npos)
arg = arg.substr(0, pos);
if (auto maybe_raddr = from_pubkey_addr<ClientPubKey>(arg); maybe_raddr)
_range_map.emplace(std::move(*maybe_raddr), std::move(*range));
if (auto maybe_raddr = ClientAddress::from_client_addr(arg); maybe_raddr)
_client_ranges.emplace(std::move(*maybe_raddr), std::move(*range));
else
throw std::invalid_argument{"[network]:exit-node bad address: {}"_format(arg)};
});
@ -575,10 +574,14 @@ namespace llarp
"lokinet will attempt to find an unused private range.",
},
[this](std::string arg) {
if (not _local_ip_range.from_string(arg))
if (auto maybe_range = IPRange::from_string(arg); maybe_range)
{
throw std::invalid_argument{fmt::format("[network]:ifaddr invalid value: '{}'", arg)};
_local_ip_range = *maybe_range;
_local_addr = _local_ip_range->address();
_local_ip = _local_ip_range->get_ip();
}
else
throw std::invalid_argument{fmt::format("[network]:ifaddr invalid value: '{}'", arg)};
});
conf.define_option<std::string>(
@ -633,10 +636,10 @@ namespace llarp
auto addr_arg = arg.substr(0, pos);
auto ip_arg = arg.substr(pos + 1);
if (auto maybe_raddr = from_pubkey_addr<ClientPubKey>(std::move(addr_arg)); maybe_raddr)
if (auto maybe_raddr = ClientAddress::from_client_addr(std::move(addr_arg)); maybe_raddr)
{
oxen::quic::Address addr{std::move(ip_arg), 0};
_addr_map.emplace(std::move(*maybe_raddr), std::move(addr));
_client_addrs.emplace(std::move(*maybe_raddr), std::move(addr));
}
else
throw std::invalid_argument{"[endpoint]:mapaddr invalid entry: {}"_format(arg)};
@ -747,7 +750,7 @@ namespace llarp
}
else
{
auto err = "Config could not load persisting address map file from path:{} --"_format(file);
auto err = "Config could not load persisting address map file from path:{}"_format(file);
log::info(logcat, "{} {}", err, load_file ? "NOT FOUND" : "STALE");
@ -768,17 +771,47 @@ namespace llarp
for (const auto& [key, value] : parsed)
{
oxen::quic::Address addr;
try
{
addr = oxen::quic::Address{key, 0};
oxen::quic::Address addr{key, 0};
bool in_range{false}, is_local{false};
if (addr.is_ipv4())
{
auto addr_v4 = addr.to_ipv4();
in_range = _local_ip_range->contains(addr_v4);
is_local = addr_v4 == std::get<ipv4>(*_local_ip);
}
else
{
auto addr_v6 = addr.to_ipv6();
in_range = _local_ip_range->contains(addr.to_ipv6());
is_local = addr_v6 == std::get<ipv6>(*_local_ip);
}
if (is_local)
continue;
if (not in_range)
{
log::warning(
logcat,
"Out of range IP in addr map data: IP:{}, local range{}",
addr.host(),
_local_ip_range);
continue;
}
if (const auto* str = std::get_if<std::string>(&value))
{
if (auto maybe_raddr = from_pubkey_addr(*str); maybe_raddr)
if (auto maybe_raddr = ClientAddress::from_client_addr(*str); maybe_raddr)
{
_persisting_clients.emplace(std::move(*maybe_raddr), std::move(addr));
continue;
}
if (auto maybe_raddr = RelayAddress::from_relay_addr(*str); maybe_raddr)
{
_persisting_addrs.emplace(std::move(*maybe_raddr), std::move(addr));
_persisting_relays.emplace(std::move(*maybe_raddr), std::move(addr));
continue;
}

@ -141,20 +141,25 @@ namespace llarp
/* TESTNET: Under modification */
std::optional<fs::path> addr_map_persist_file;
std::unordered_map<RemoteAddress<PubKey>, oxen::quic::Address> _persisting_addrs;
std::unordered_map<ClientAddress, oxen::quic::Address> _persisting_clients;
std::unordered_map<RelayAddress, oxen::quic::Address> _persisting_relays;
// only member that refers to an actual interface
std::string _if_name;
IPRange _local_ip_range;
std::optional<IPRange> _local_ip_range;
std::optional<oxen::quic::Address> _local_addr;
std::optional<ip> _local_ip;
std::optional<IPRange> _base_ipv6_range = std::nullopt;
// Remote client exit addresses mapped to fixed local IP addresses
std::unordered_map<RemoteAddress<ClientPubKey>, oxen::quic::Address> _addr_map;
std::unordered_map<ClientAddress, oxen::quic::Address> _client_addrs;
// Remote client exit addresses mapped to local IP ranges. Addresses can be populated via client
// PubKey or their ONS name
std::unordered_map<RemoteAddress<ClientPubKey>, IPRange> _range_map;
std::unordered_map<ClientAddress, IPRange> _client_ranges;
std::set<IPRange> _owned_ranges;

@ -158,7 +158,7 @@ namespace llarp::handlers
log::info(logcat, "{} set ifname to {}", name(), _if_name);
for (const auto& addr : _net_config._addr_map)
for (const auto& addr : _net_config._client_addrs)
{
(void)addr;
// TODO: here is where we should map remote services and exits, but first we need

@ -312,7 +312,7 @@ namespace llarp::handlers
else
_path_alignment_timeout = service::DEFAULT_PATH_ALIGN_TIMEOUT;
for (const auto& item : conf._addr_map)
for (const auto& item : conf._client_addrs)
{
(void)item;
// if (not map_address(item.second, item.first, false))
@ -354,11 +354,12 @@ namespace llarp::handlers
else
_local_ip = _local_addr.to_ipv4();
// TODO: move all this parsing to the config
// DISCUSS: what format do we expect these to be bt-encoded in? If strings, then must make
// string ctors for ipv4/ipv6 types to load directly into and pass to IPRange::contains(...)
_persisting_addr_file = conf.addr_map_persist_file;
if (conf.addr_map_persist_file and not conf._persisting_clients.empty())
{
}
if (_persisting_addr_file)
{
const auto& file = *_persisting_addr_file;
@ -427,7 +428,7 @@ namespace llarp::handlers
continue;
if (not _local_range.contains(ip))
{
log::warning(logcat, "{} out of range IP in addr map data", name(), ip);
// log::warning(logcat, "{} out of range IP in addr map data", name(), ip);
continue;
}

@ -18,11 +18,11 @@ namespace llarp::service
inline bool is_valid_ons(std::string_view ons_name)
{
// make sure it ends with .loki because no fucking shit right?
if (not ends_with(ons_name, ".loki"))
if (not ons_name.ends_with(".loki"))
return false;
// strip off .loki suffix
ons_name = ons_name.substr(0, ons_name.find_last_of('.'));
ons_name.remove_suffix(5);
// ensure chars are sane
for (const auto ch : ons_name)

Loading…
Cancel
Save