Upgrades to epee::net_utils::network_address

- internal nullptr checks
  - prevent modifications to network_address (shallow copy issues)
  - automagically works with any type containing interface functions
  - removed fnv1a hashing
  - ipv4_network_address now flattened with no base class
This commit is contained in:
Lee Clagett 2017-08-25 11:14:46 -04:00
parent a2041c9874
commit 8b00687735
11 changed files with 446 additions and 92 deletions

View file

@ -137,14 +137,14 @@ PRAGMA_WARNING_DISABLE_VS(4355)
CHECK_AND_NO_ASSERT_MES(!ec, false, "Failed to get local endpoint: " << ec.message() << ':' << ec.value()); CHECK_AND_NO_ASSERT_MES(!ec, false, "Failed to get local endpoint: " << ec.message() << ':' << ec.value());
context = boost::value_initialized<t_connection_context>(); context = boost::value_initialized<t_connection_context>();
long ip_ = boost::asio::detail::socket_ops::host_to_network_long(remote_ep.address().to_v4().to_ulong()); const unsigned long ip_{boost::asio::detail::socket_ops::host_to_network_long(remote_ep.address().to_v4().to_ulong())};
// create a random uuid // create a random uuid
boost::uuids::uuid random_uuid; boost::uuids::uuid random_uuid;
// that stuff turns out to be included, even though it's from src... Taking advantage // that stuff turns out to be included, even though it's from src... Taking advantage
random_uuid = crypto::rand<boost::uuids::uuid>(); random_uuid = crypto::rand<boost::uuids::uuid>();
context.set_details(random_uuid, new epee::net_utils::ipv4_network_address(ip_, remote_ep.port()), is_income); context.set_details(random_uuid, epee::net_utils::ipv4_network_address(ip_, remote_ep.port()), is_income);
_dbg3("[sock " << socket_.native_handle() << "] new connection from " << print_connection_context_short(context) << _dbg3("[sock " << socket_.native_handle() << "] new connection from " << print_connection_context_short(context) <<
" to " << local_ep.address().to_string() << ':' << local_ep.port() << " to " << local_ep.address().to_string() << ':' << local_ep.port() <<
", total sockets objects " << m_ref_sock_count); ", total sockets objects " << m_ref_sock_count);

View file

@ -29,11 +29,12 @@
#ifndef _NET_UTILS_BASE_H_ #ifndef _NET_UTILS_BASE_H_
#define _NET_UTILS_BASE_H_ #define _NET_UTILS_BASE_H_
#include <typeinfo>
#include <boost/asio/io_service.hpp> #include <boost/asio/io_service.hpp>
#include <boost/uuid/uuid.hpp> #include <boost/uuid/uuid.hpp>
#include <memory>
#include <typeinfo>
#include <type_traits>
#include "serialization/keyvalue_serialization.h" #include "serialization/keyvalue_serialization.h"
#include "net/local_ip.h"
#include "string_tools.h" #include "string_tools.h"
#include "misc_log_ex.h" #include "misc_log_ex.h"
@ -49,78 +50,119 @@ namespace epee
{ {
namespace net_utils namespace net_utils
{ {
struct network_address_base class ipv4_network_address
{ {
public:
bool operator==(const network_address_base &other) const { return m_full_id == other.m_full_id; }
bool operator!=(const network_address_base &other) const { return !operator==(other); }
bool operator<(const network_address_base &other) const { return m_full_id < other.m_full_id; }
bool is_same_host(const network_address_base &other) const { return m_host_id == other.m_host_id; }
virtual std::string str() const = 0;
virtual std::string host_str() const = 0;
virtual bool is_loopback() const = 0;
virtual bool is_local() const = 0;
virtual uint8_t get_type_id() const = 0;
protected:
// A very simple non cryptographic hash function by Fowler, Noll, Vo
uint64_t fnv1a(const uint8_t *data, size_t len) const {
uint64_t h = 0xcbf29ce484222325;
while (len--)
h = (h ^ *data++) * 0x100000001b3;
return h;
}
uint64_t m_host_id;
uint64_t m_full_id;
protected:
virtual ~network_address_base() {}
};
struct ipv4_network_address: public network_address_base
{
void init_ids()
{
m_host_id = fnv1a((const uint8_t*)&m_ip, sizeof(m_ip));
m_full_id = fnv1a((const uint8_t*)&m_ip, sizeof(m_ip) + sizeof(m_port));
}
public:
ipv4_network_address(uint32_t ip, uint16_t port): network_address_base(), m_ip(ip), m_port(port) { init_ids(); }
uint32_t ip() const { return m_ip; }
uint16_t port() const { return m_port; }
virtual std::string str() const { return epee::string_tools::get_ip_string_from_int32(m_ip) + ":" + std::to_string(m_port); }
virtual std::string host_str() const { return epee::string_tools::get_ip_string_from_int32(m_ip); }
virtual bool is_loopback() const { return epee::net_utils::is_ip_loopback(m_ip); }
virtual bool is_local() const { return epee::net_utils::is_ip_local(m_ip); }
virtual uint8_t get_type_id() const { return ID; }
public: // serialization
static const uint8_t ID = 1;
#pragma pack(push)
#pragma pack(1)
uint32_t m_ip; uint32_t m_ip;
uint16_t m_port; uint16_t m_port;
#pragma pack(pop)
public:
constexpr ipv4_network_address(uint32_t ip, uint16_t port) noexcept
: m_ip(ip), m_port(port) {}
bool equal(const ipv4_network_address& other) const noexcept;
bool less(const ipv4_network_address& other) const noexcept;
constexpr bool is_same_host(const ipv4_network_address& other) const noexcept
{ return ip() == other.ip(); }
constexpr uint32_t ip() const noexcept { return m_ip; }
constexpr uint16_t port() const noexcept { return m_port; }
std::string str() const;
std::string host_str() const;
bool is_loopback() const;
bool is_local() const;
static constexpr uint8_t get_type_id() noexcept { return ID; }
static const uint8_t ID = 1;
BEGIN_KV_SERIALIZE_MAP() BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(m_ip) KV_SERIALIZE(m_ip)
KV_SERIALIZE(m_port) KV_SERIALIZE(m_port)
if (!is_store)
const_cast<ipv4_network_address&>(this_ref).init_ids();
END_KV_SERIALIZE_MAP() END_KV_SERIALIZE_MAP()
}; };
class network_address: public boost::shared_ptr<network_address_base>
inline bool operator==(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept
{ return lhs.equal(rhs); }
inline bool operator!=(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept
{ return !lhs.equal(rhs); }
inline bool operator<(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept
{ return lhs.less(rhs); }
inline bool operator<=(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept
{ return !rhs.less(lhs); }
inline bool operator>(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept
{ return rhs.less(lhs); }
inline bool operator>=(const ipv4_network_address& lhs, const ipv4_network_address& rhs) noexcept
{ return !lhs.less(rhs); }
class network_address
{ {
struct interface
{
virtual ~interface() {};
virtual bool equal(const interface&) const = 0;
virtual bool less(const interface&) const = 0;
virtual bool is_same_host(const interface&) const = 0;
virtual std::string str() const = 0;
virtual std::string host_str() const = 0;
virtual bool is_loopback() const = 0;
virtual bool is_local() const = 0;
virtual uint8_t get_type_id() const = 0;
};
template<typename T>
struct implementation final : interface
{
T value;
implementation(const T& src) : value(src) {}
~implementation() = default;
// Type-checks for cast are done in cpp
static const T& cast(const interface& src) noexcept
{ return static_cast<const implementation<T>&>(src).value; }
virtual bool equal(const interface& other) const override
{ return value.equal(cast(other)); }
virtual bool less(const interface& other) const override
{ return value.less(cast(other)); }
virtual bool is_same_host(const interface& other) const override
{ return value.is_same_host(cast(other)); }
virtual std::string str() const override { return value.str(); }
virtual std::string host_str() const override { return value.host_str(); }
virtual bool is_loopback() const override { return value.is_loopback(); }
virtual bool is_local() const override { return value.is_local(); }
virtual uint8_t get_type_id() const override { return value.get_type_id(); }
};
std::shared_ptr<interface> self;
template<typename Type>
Type& as_mutable() const
{
// types `implmentation<Type>` and `implementation<const Type>` are unique
using Type_ = typename std::remove_const<Type>::type;
network_address::interface* const self_ = self.get(); // avoid clang warning in typeid
if (!self_ || typeid(implementation<Type_>) != typeid(*self_))
throw std::bad_cast{};
return static_cast<implementation<Type_>*>(self_)->value;
}
public: public:
network_address() {} network_address() : self(nullptr) {}
network_address(ipv4_network_address *address): boost::shared_ptr<network_address_base>(address) {} template<typename T>
bool operator==(const network_address &other) const { return (*this)->operator==(*other); } network_address(const T& src)
bool operator!=(const network_address &other) const { return (*this)->operator!=(*other); } : self(std::make_shared<implementation<T>>(src)) {}
bool operator<(const network_address &other) const { return (*this)->operator<(*other); } bool equal(const network_address &other) const;
bool is_same_host(const network_address &other) const { return (*this)->is_same_host(*other); } bool less(const network_address &other) const;
std::string str() const { return (*this) ? (*this)->str() : "<none>"; } bool is_same_host(const network_address &other) const;
std::string host_str() const { return (*this) ? (*this)->host_str() : "<none>"; } std::string str() const { return self ? self->str() : "<none>"; }
bool is_loopback() const { return (*this)->is_loopback(); } std::string host_str() const { return self ? self->host_str() : "<none>"; }
bool is_local() const { return (*this)->is_local(); } bool is_loopback() const { return self ? self->is_loopback() : false; }
uint8_t get_type_id() const { return (*this)->get_type_id(); } bool is_local() const { return self ? self->is_local() : false; }
template<typename Type> Type &as() { if (get_type_id() != Type::ID) throw std::runtime_error("Bad type"); return *(Type*)get(); } uint8_t get_type_id() const { return self ? self->get_type_id() : 0; }
template<typename Type> const Type &as() const { if (get_type_id() != Type::ID) throw std::runtime_error("Bad type"); return *(const Type*)get(); } template<typename Type> const Type &as() const { return as_mutable<const Type>(); }
BEGIN_KV_SERIALIZE_MAP() BEGIN_KV_SERIALIZE_MAP()
uint8_t type = is_store ? this_ref.get_type_id() : 0; uint8_t type = is_store ? this_ref.get_type_id() : 0;
@ -129,13 +171,27 @@ namespace net_utils
{ {
case ipv4_network_address::ID: case ipv4_network_address::ID:
if (!is_store) if (!is_store)
const_cast<network_address&>(this_ref).reset(new ipv4_network_address(0, 0)); const_cast<network_address&>(this_ref) = ipv4_network_address{0, 0};
KV_SERIALIZE(template as<ipv4_network_address>()); KV_SERIALIZE(template as_mutable<ipv4_network_address>());
break; break;
default: MERROR("Unsupported network address type: " << type); return false; default: MERROR("Unsupported network address type: " << type); return false;
} }
END_KV_SERIALIZE_MAP() END_KV_SERIALIZE_MAP()
}; };
inline bool operator==(const network_address& lhs, const network_address& rhs)
{ return lhs.equal(rhs); }
inline bool operator!=(const network_address& lhs, const network_address& rhs)
{ return !lhs.equal(rhs); }
inline bool operator<(const network_address& lhs, const network_address& rhs)
{ return lhs.less(rhs); }
inline bool operator<=(const network_address& lhs, const network_address& rhs)
{ return !rhs.less(lhs); }
inline bool operator>(const network_address& lhs, const network_address& rhs)
{ return rhs.less(lhs); }
inline bool operator>=(const network_address& lhs, const network_address& rhs)
{ return !lhs.less(rhs); }
inline bool create_network_address(network_address &address, const std::string &string, uint16_t default_port = 0) inline bool create_network_address(network_address &address, const std::string &string, uint16_t default_port = 0)
{ {
uint32_t ip; uint32_t ip;
@ -144,7 +200,7 @@ namespace net_utils
{ {
if (default_port && !port) if (default_port && !port)
port = default_port; port = default_port;
address.reset(new ipv4_network_address(ip, port)); address = ipv4_network_address{ip, port};
return true; return true;
} }
return false; return false;
@ -182,7 +238,7 @@ namespace net_utils
{} {}
connection_context_base(): m_connection_id(), connection_context_base(): m_connection_id(),
m_remote_address(new ipv4_network_address(0,0)), m_remote_address(ipv4_network_address{0,0}),
m_is_income(false), m_is_income(false),
m_started(time(NULL)), m_started(time(NULL)),
m_last_recv(0), m_last_recv(0),
@ -235,7 +291,7 @@ namespace net_utils
std::string print_connection_context(const connection_context_base& ctx) std::string print_connection_context(const connection_context_base& ctx)
{ {
std::stringstream ss; std::stringstream ss;
ss << ctx.m_remote_address->str() << " " << epee::string_tools::get_str_from_guid_a(ctx.m_connection_id) << (ctx.m_is_income ? " INC":" OUT"); ss << ctx.m_remote_address.str() << " " << epee::string_tools::get_str_from_guid_a(ctx.m_connection_id) << (ctx.m_is_income ? " INC":" OUT");
return ss.str(); return ss.str();
} }
@ -243,7 +299,7 @@ namespace net_utils
std::string print_connection_context_short(const connection_context_base& ctx) std::string print_connection_context_short(const connection_context_base& ctx)
{ {
std::stringstream ss; std::stringstream ss;
ss << ctx.m_remote_address->str() << (ctx.m_is_income ? " INC":" OUT"); ss << ctx.m_remote_address.str() << (ctx.m_is_income ? " INC":" OUT");
return ss.str(); return ss.str();
} }

View file

@ -27,9 +27,9 @@
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (USE_READLINE AND GNU_READLINE_FOUND) if (USE_READLINE AND GNU_READLINE_FOUND)
add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp string_tools.cpp readline_buffer.cpp) add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp net_utils_base.cpp string_tools.cpp readline_buffer.cpp)
else() else()
add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp string_tools.cpp) add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp net_utils_base.cpp string_tools.cpp)
endif() endif()
# Build and install libepee if we're building for GUI # Build and install libepee if we're building for GUI

View file

@ -0,0 +1,60 @@
#include "net/net_utils_base.h"
#include <cstring>
#include <typeindex>
#include "net/local_ip.h"
namespace epee { namespace net_utils
{
const uint8_t ipv4_network_address::ID;
bool ipv4_network_address::equal(const ipv4_network_address& other) const noexcept
{ return is_same_host(other) && port() == other.port(); }
bool ipv4_network_address::less(const ipv4_network_address& other) const noexcept
{ return is_same_host(other) ? port() < other.port() : ip() < other.ip(); }
std::string ipv4_network_address::str() const
{ return string_tools::get_ip_string_from_int32(ip()) + ":" + std::to_string(port()); }
std::string ipv4_network_address::host_str() const { return string_tools::get_ip_string_from_int32(ip()); }
bool ipv4_network_address::is_loopback() const { return net_utils::is_ip_loopback(ip()); }
bool ipv4_network_address::is_local() const { return net_utils::is_ip_local(ip()); }
bool network_address::equal(const network_address& other) const
{
// clang typeid workaround
network_address::interface const* const self_ = self.get();
network_address::interface const* const other_self = other.self.get();
if (self_ == other_self) return true;
if (!self_ || !other_self) return false;
if (typeid(*self_) != typeid(*other_self)) return false;
return self_->equal(*other_self);
}
bool network_address::less(const network_address& other) const
{
// clang typeid workaround
network_address::interface const* const self_ = self.get();
network_address::interface const* const other_self = other.self.get();
if (self_ == other_self) return false;
if (!self_ || !other_self) return self == nullptr;
if (typeid(*self_) != typeid(*other_self))
return self_->get_type_id() < other_self->get_type_id();
return self_->less(*other_self);
}
bool network_address::is_same_host(const network_address& other) const
{
// clang typeid workaround
network_address::interface const* const self_ = self.get();
network_address::interface const* const other_self = other.self.get();
if (self_ == other_self) return true;
if (!self_ || !other_self) return false;
if (typeid(*self_) != typeid(*other_self)) return false;
return self_->is_same_host(*other_self);
}
}}

View file

@ -390,7 +390,7 @@ namespace nodetool
ip::tcp::endpoint endpoint = *i; ip::tcp::endpoint endpoint = *i;
if (endpoint.address().is_v4()) if (endpoint.address().is_v4())
{ {
epee::net_utils::network_address na(new epee::net_utils::ipv4_network_address(boost::asio::detail::socket_ops::host_to_network_long(endpoint.address().to_v4().to_ulong()), endpoint.port())); epee::net_utils::network_address na{epee::net_utils::ipv4_network_address{boost::asio::detail::socket_ops::host_to_network_long(endpoint.address().to_v4().to_ulong()), endpoint.port()}};
seed_nodes.push_back(na); seed_nodes.push_back(na);
MINFO("Added seed node: " << na.str()); MINFO("Added seed node: " << na.str());
} }
@ -1521,7 +1521,7 @@ namespace nodetool
return false; return false;
std::string ip = epee::string_tools::get_ip_string_from_int32(actual_ip); std::string ip = epee::string_tools::get_ip_string_from_int32(actual_ip);
std::string port = epee::string_tools::num_to_string_fast(node_data.my_port); std::string port = epee::string_tools::num_to_string_fast(node_data.my_port);
epee::net_utils::network_address address(new epee::net_utils::ipv4_network_address(actual_ip, node_data.my_port)); epee::net_utils::network_address address{epee::net_utils::ipv4_network_address(actual_ip, node_data.my_port)};
peerid_type pr = node_data.peer_id; peerid_type pr = node_data.peer_id;
bool r = m_net_server.connect_async(ip, port, m_config.m_net_config.ping_connection_timeout, [cb, /*context,*/ address, pr, this]( bool r = m_net_server.connect_async(ip, port, m_config.m_net_config.ping_connection_timeout, [cb, /*context,*/ address, pr, this](
const typename net_server::t_connection_context& ping_context, const typename net_server::t_connection_context& ping_context,
@ -1678,7 +1678,7 @@ namespace nodetool
//called only(!) if success pinged, update local peerlist //called only(!) if success pinged, update local peerlist
peerlist_entry pe; peerlist_entry pe;
const epee::net_utils::network_address na = context.m_remote_address; const epee::net_utils::network_address na = context.m_remote_address;
pe.adr.reset(new epee::net_utils::ipv4_network_address(na.as<epee::net_utils::ipv4_network_address>().ip(), port_l)); pe.adr = epee::net_utils::ipv4_network_address(na.as<epee::net_utils::ipv4_network_address>().ip(), port_l);
time_t last_seen; time_t last_seen;
time(&last_seen); time(&last_seen);
pe.last_seen = static_cast<int64_t>(last_seen); pe.last_seen = static_cast<int64_t>(last_seen);

View file

@ -31,11 +31,19 @@
#pragma once #pragma once
#include "net/net_utils_base.h" #include "net/net_utils_base.h"
#include "p2p/p2p_protocol_defs.h"
namespace boost namespace boost
{ {
namespace serialization namespace serialization
{ {
template <class T, class Archive>
inline void do_serialize(Archive &a, epee::net_utils::network_address& na, T local)
{
if (typename Archive::is_saving()) local = na.as<T>();
a & local;
if (!typename Archive::is_saving()) na = local;
}
template <class Archive, class ver_type> template <class Archive, class ver_type>
inline void serialize(Archive &a, epee::net_utils::network_address& na, const ver_type ver) inline void serialize(Archive &a, epee::net_utils::network_address& na, const ver_type ver)
{ {
@ -46,10 +54,8 @@ namespace boost
switch (type) switch (type)
{ {
case epee::net_utils::ipv4_network_address::ID: case epee::net_utils::ipv4_network_address::ID:
if (!typename Archive::is_saving()) do_serialize(a, na, epee::net_utils::ipv4_network_address{0, 0});
na.reset(new epee::net_utils::ipv4_network_address(0, 0)); break;
a & na.as<epee::net_utils::ipv4_network_address>();
break;
default: default:
throw std::runtime_error("Unsupported network address type"); throw std::runtime_error("Unsupported network address type");
} }
@ -57,13 +63,14 @@ namespace boost
template <class Archive, class ver_type> template <class Archive, class ver_type>
inline void serialize(Archive &a, epee::net_utils::ipv4_network_address& na, const ver_type ver) inline void serialize(Archive &a, epee::net_utils::ipv4_network_address& na, const ver_type ver)
{ {
a & na.m_ip; uint32_t ip{na.ip()};
a & na.m_port; uint16_t port{na.port()};
a & ip;
a & port;
if (!typename Archive::is_saving()) if (!typename Archive::is_saving())
na.init_ids(); na = epee::net_utils::ipv4_network_address{ip, port};
} }
template <class Archive, class ver_type> template <class Archive, class ver_type>
inline void serialize(Archive &a, nodetool::peerlist_entry& pl, const ver_type ver) inline void serialize(Archive &a, nodetool::peerlist_entry& pl, const ver_type ver)
{ {

View file

@ -120,7 +120,7 @@ namespace nodetool
ss << std::setfill ('0') << std::setw (8) << std::hex << std::noshowbase; ss << std::setfill ('0') << std::setw (8) << std::hex << std::noshowbase;
for(const peerlist_entry& pe: pl) for(const peerlist_entry& pe: pl)
{ {
ss << pe.id << "\t" << pe.adr->str() << " \tlast_seen: " << epee::misc_utils::get_time_interval_string(now_time - pe.last_seen) << std::endl; ss << pe.id << "\t" << pe.adr.str() << " \tlast_seen: " << epee::misc_utils::get_time_interval_string(now_time - pe.last_seen) << std::endl;
} }
return ss.str(); return ss.str();
} }
@ -216,7 +216,7 @@ namespace nodetool
std::list<peerlist_entry_base<network_address_old>> local_peerlist; std::list<peerlist_entry_base<network_address_old>> local_peerlist;
epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(local_peerlist, stg, hparent_section, "local_peerlist"); epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(local_peerlist, stg, hparent_section, "local_peerlist");
for (const auto &p: local_peerlist) for (const auto &p: local_peerlist)
((response&)this_ref).local_peerlist_new.push_back(peerlist_entry({new epee::net_utils::ipv4_network_address(p.adr.ip, p.adr.port), p.id, p.last_seen})); ((response&)this_ref).local_peerlist_new.push_back(peerlist_entry({epee::net_utils::ipv4_network_address(p.adr.ip, p.adr.port), p.id, p.last_seen}));
} }
} }
END_KV_SERIALIZE_MAP() END_KV_SERIALIZE_MAP()
@ -275,7 +275,7 @@ namespace nodetool
std::list<peerlist_entry_base<network_address_old>> local_peerlist; std::list<peerlist_entry_base<network_address_old>> local_peerlist;
epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(local_peerlist, stg, hparent_section, "local_peerlist"); epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(local_peerlist, stg, hparent_section, "local_peerlist");
for (const auto &p: local_peerlist) for (const auto &p: local_peerlist)
((response&)this_ref).local_peerlist_new.push_back(peerlist_entry({new epee::net_utils::ipv4_network_address(p.adr.ip, p.adr.port), p.id, p.last_seen})); ((response&)this_ref).local_peerlist_new.push_back(peerlist_entry({epee::net_utils::ipv4_network_address(p.adr.ip, p.adr.port), p.id, p.last_seen}));
} }
} }
END_KV_SERIALIZE_MAP() END_KV_SERIALIZE_MAP()

View file

@ -1395,7 +1395,7 @@ namespace cryptonote
} }
else else
{ {
na.reset(new epee::net_utils::ipv4_network_address(i->ip, 0)); na = epee::net_utils::ipv4_network_address{i->ip, 0};
} }
if (i->ban) if (i->ban)
m_p2p.block_host(na, i->seconds); m_p2p.block_host(na, i->seconds);

View file

@ -33,7 +33,7 @@
#include "p2p/net_node.h" #include "p2p/net_node.h"
#include "cryptonote_protocol/cryptonote_protocol_handler.h" #include "cryptonote_protocol/cryptonote_protocol_handler.h"
#define MAKE_IPV4_ADDRESS(a,b,c,d) new epee::net_utils::ipv4_network_address(MAKE_IP(a,b,c,d),0) #define MAKE_IPV4_ADDRESS(a,b,c,d) epee::net_utils::ipv4_network_address{MAKE_IP(a,b,c,d),0}
namespace cryptonote { namespace cryptonote {
class blockchain_storage; class blockchain_storage;

View file

@ -27,6 +27,7 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <array> #include <array>
#include <boost/endian/conversion.hpp>
#include <boost/range/algorithm/equal.hpp> #include <boost/range/algorithm/equal.hpp>
#include <boost/range/algorithm_ext/iota.hpp> #include <boost/range/algorithm_ext/iota.hpp>
#include <cstdint> #include <cstdint>
@ -42,7 +43,11 @@
# include <arpa/inet.h> # include <arpa/inet.h>
#endif #endif
#include "boost/archive/portable_binary_iarchive.hpp"
#include "boost/archive/portable_binary_oarchive.hpp"
#include "hex.h" #include "hex.h"
#include "net/net_utils_base.h"
#include "p2p/net_peerlist_boost_serialization.h"
#include "span.h" #include "span.h"
#include "string_tools.h" #include "string_tools.h"
@ -100,6 +105,40 @@ namespace
boost::range::iota(out, 0); boost::range::iota(out, 0);
return out; return out;
} }
#define CHECK_EQUAL(lhs, rhs) \
EXPECT_TRUE( lhs == rhs ); \
EXPECT_TRUE( rhs == lhs ); \
EXPECT_FALSE( lhs != rhs ); \
EXPECT_FALSE( rhs != lhs ); \
EXPECT_FALSE( lhs < rhs ); \
EXPECT_FALSE( rhs < lhs ); \
EXPECT_TRUE( lhs <= rhs ); \
EXPECT_TRUE( rhs <= lhs ); \
EXPECT_FALSE( lhs > rhs ); \
EXPECT_FALSE( rhs > lhs ); \
EXPECT_TRUE( lhs >= rhs ); \
EXPECT_TRUE( rhs >= lhs )
#define CHECK_LESS(lhs, rhs) \
EXPECT_FALSE( lhs == rhs ); \
EXPECT_FALSE( rhs == lhs ); \
EXPECT_TRUE( lhs != rhs ); \
EXPECT_TRUE( rhs != lhs ); \
EXPECT_TRUE( lhs < rhs ); \
EXPECT_FALSE( rhs < lhs ); \
EXPECT_TRUE( lhs <= rhs ); \
EXPECT_FALSE( rhs <= lhs ); \
EXPECT_FALSE( lhs > rhs ); \
EXPECT_TRUE( rhs > lhs ); \
EXPECT_FALSE( lhs >= rhs ); \
EXPECT_TRUE( rhs >= lhs )
#ifdef BOOST_LITTLE_ENDIAN
#define CHECK_LESS_ENDIAN(lhs, rhs) CHECK_LESS( rhs , lhs )
#else
#define CHECK_LESS_ENDIAN(lhs, rhs) CHECK_LESS( lhs , rhs )
#endif
} }
TEST(Span, Traits) TEST(Span, Traits)
@ -419,3 +458,195 @@ TEST(StringTools, GetIpInt32)
EXPECT_EQ(htonl(0xff0aff00), ip); EXPECT_EQ(htonl(0xff0aff00), ip);
} }
TEST(NetUtils, IPv4NetworkAddress)
{
const auto ip1 = boost::endian::native_to_big(0x330012FFu);
const auto ip_loopback = boost::endian::native_to_big(0x7F000001u);
const auto ip_local = boost::endian::native_to_big(0x0A000000u);
epee::net_utils::ipv4_network_address address1{ip1, 65535};
CHECK_EQUAL(address1, address1);
EXPECT_STREQ("51.0.18.255:65535", address1.str().c_str());
EXPECT_STREQ("51.0.18.255", address1.host_str().c_str());
EXPECT_FALSE(address1.is_loopback());
EXPECT_FALSE(address1.is_local());
EXPECT_EQ(epee::net_utils::ipv4_network_address::ID, address1.get_type_id());
EXPECT_EQ(ip1, address1.ip());
EXPECT_EQ(65535, address1.port());
EXPECT_TRUE(epee::net_utils::ipv4_network_address{std::move(address1)} == address1);
EXPECT_TRUE(epee::net_utils::ipv4_network_address{address1} == address1);
const epee::net_utils::ipv4_network_address loopback{ip_loopback, 0};
CHECK_EQUAL(loopback, loopback);
CHECK_LESS_ENDIAN(address1, loopback);
EXPECT_STREQ("127.0.0.1:0", loopback.str().c_str());
EXPECT_STREQ("127.0.0.1", loopback.host_str().c_str());
EXPECT_TRUE(loopback.is_loopback());
EXPECT_FALSE(loopback.is_local());
EXPECT_EQ(epee::net_utils::ipv4_network_address::ID, address1.get_type_id());
EXPECT_EQ(ip_loopback, loopback.ip());
EXPECT_EQ(0, loopback.port());
const epee::net_utils::ipv4_network_address local{ip_local, 8080};
CHECK_EQUAL(local, local);
CHECK_LESS(local, address1);
CHECK_LESS(local, loopback);
EXPECT_FALSE(local.is_loopback());
EXPECT_TRUE(local.is_local());
epee::net_utils::ipv4_network_address address2{ip1, 55};
CHECK_EQUAL(address2, address2);
CHECK_LESS_ENDIAN(address2, loopback);
CHECK_LESS(local, address2);
EXPECT_STREQ("51.0.18.255:55", address2.str().c_str());
EXPECT_STREQ("51.0.18.255", address2.host_str().c_str());
address2 = std::move(address1);
CHECK_EQUAL(address2, address1);
address2 = local;
CHECK_EQUAL(address2, local);
CHECK_LESS(address2, address1);
{
std::stringstream stream;
{
boost::archive::portable_binary_oarchive ostream{stream};
ostream << address1;
}
{
boost::archive::portable_binary_iarchive istream{stream};
istream >> address2;
}
}
CHECK_EQUAL(address1, address2);
EXPECT_EQ(ip1, address2.ip());
EXPECT_EQ(65535, address2.port());
}
TEST(NetUtils, NetworkAddress)
{
const auto ip1 = boost::endian::native_to_big(0x330012FFu);
const auto ip_loopback = boost::endian::native_to_big(0x7F000001u);
const auto ip_local = boost::endian::native_to_big(0x0A000000u);
struct custom_address {
constexpr static bool equal(const custom_address&) noexcept { return false; }
constexpr static bool less(const custom_address&) noexcept { return false; }
constexpr static bool is_same_host(const custom_address&) noexcept { return false; }
constexpr static bool is_loopback() noexcept { return false; }
constexpr static bool is_local() noexcept { return false; }
static std::string str() { return {}; }
static std::string host_str() { return {}; }
constexpr static uint8_t get_type_id() noexcept { return uint8_t(-1); }
};
const epee::net_utils::network_address empty;
CHECK_EQUAL(empty, empty);
EXPECT_TRUE(empty.is_same_host(empty));
EXPECT_STREQ("<none>", empty.str().c_str());
EXPECT_STREQ("<none>", empty.host_str().c_str());
EXPECT_FALSE(empty.is_loopback());
EXPECT_FALSE(empty.is_local());
EXPECT_EQ(0, empty.get_type_id());
EXPECT_THROW(empty.as<custom_address>(), std::bad_cast);
epee::net_utils::network_address address1{
epee::net_utils::ipv4_network_address{ip1, 65535}
};
CHECK_EQUAL(address1, address1);
CHECK_EQUAL(epee::net_utils::network_address{address1}, address1);
CHECK_LESS(empty, address1);
EXPECT_TRUE(address1.is_same_host(address1));
EXPECT_FALSE(empty.is_same_host(address1));
EXPECT_FALSE(address1.is_same_host(empty));
EXPECT_STREQ("51.0.18.255:65535", address1.str().c_str());
EXPECT_STREQ("51.0.18.255", address1.host_str().c_str());
EXPECT_FALSE(address1.is_loopback());
EXPECT_FALSE(address1.is_local());
EXPECT_EQ(epee::net_utils::ipv4_network_address::ID, address1.get_type_id());
EXPECT_NO_THROW(address1.as<epee::net_utils::ipv4_network_address>());
EXPECT_THROW(address1.as<custom_address>(), std::bad_cast);
const epee::net_utils::network_address loopback{
epee::net_utils::ipv4_network_address{ip_loopback, 0}
};
CHECK_EQUAL(loopback, loopback);
CHECK_LESS(empty, loopback);
CHECK_LESS_ENDIAN(address1, loopback);
EXPECT_TRUE(loopback.is_same_host(loopback));
EXPECT_FALSE(loopback.is_same_host(address1));
EXPECT_FALSE(address1.is_same_host(loopback));
EXPECT_STREQ("127.0.0.1:0", loopback.str().c_str());
EXPECT_STREQ("127.0.0.1", loopback.host_str().c_str());
EXPECT_TRUE(loopback.is_loopback());
EXPECT_FALSE(loopback.is_local());
EXPECT_EQ(epee::net_utils::ipv4_network_address::ID, address1.get_type_id());
const epee::net_utils::network_address local{
epee::net_utils::ipv4_network_address{ip_local, 8080}
};
CHECK_EQUAL(local, local);
CHECK_LESS(local, loopback);
CHECK_LESS(local, address1);
EXPECT_FALSE(local.is_loopback());
EXPECT_TRUE(local.is_local());
epee::net_utils::network_address address2{
epee::net_utils::ipv4_network_address{ip1, 55}
};
CHECK_EQUAL(address2, address2);
CHECK_LESS(address2, address1);
CHECK_LESS(local, address2);
CHECK_LESS_ENDIAN(address2, loopback);
EXPECT_TRUE(address1.is_same_host(address2));
EXPECT_TRUE(address2.is_same_host(address1));
EXPECT_STREQ("51.0.18.255:55", address2.str().c_str());
EXPECT_STREQ("51.0.18.255", address2.host_str().c_str());
address2 = std::move(address1);
CHECK_EQUAL(address1, address1);
CHECK_EQUAL(empty, address1);
CHECK_LESS(address1, address2);
EXPECT_FALSE(address1.is_same_host(address2));
EXPECT_FALSE(address2.is_same_host(address1));
EXPECT_STREQ("51.0.18.255:65535", address2.str().c_str());
EXPECT_STREQ("51.0.18.255", address2.host_str().c_str());
EXPECT_FALSE(address1.is_loopback());
EXPECT_FALSE(address1.is_local());
EXPECT_THROW(address1.as<epee::net_utils::ipv4_network_address>(), std::bad_cast);
EXPECT_NO_THROW(address2.as<epee::net_utils::ipv4_network_address>());
address2 = local;
CHECK_EQUAL(address2, local);
CHECK_LESS(address1, address2);
EXPECT_TRUE(address2.is_same_host(local));
EXPECT_TRUE(local.is_same_host(address2));
EXPECT_FALSE(address2.is_same_host(address1));
EXPECT_FALSE(address1.is_same_host(address2));
{
std::stringstream stream;
{
boost::archive::portable_binary_oarchive ostream{stream};
ostream << address2;
}
{
boost::archive::portable_binary_iarchive istream{stream};
istream >> address1;
}
}
CHECK_EQUAL(address1, address2);
EXPECT_TRUE(address1.is_same_host(address2));
EXPECT_TRUE(address2.is_same_host(address1));
EXPECT_NO_THROW(address1.as<epee::net_utils::ipv4_network_address>());
address1 = custom_address{};
CHECK_EQUAL(address1, address1);
CHECK_LESS(address2, address1);
EXPECT_FALSE(address1.is_same_host(loopback));
EXPECT_FALSE(loopback.is_same_host(address1));
EXPECT_THROW(address1.as<epee::net_utils::ipv4_network_address>(), std::bad_cast);
EXPECT_NO_THROW(address1.as<custom_address>());
}

View file

@ -38,7 +38,7 @@ TEST(peer_list, peer_list_general)
{ {
nodetool::peerlist_manager plm; nodetool::peerlist_manager plm;
plm.init(false); plm.init(false);
#define MAKE_IPV4_ADDRESS(a,b,c,d,e) new epee::net_utils::ipv4_network_address(MAKE_IP(a,b,c,d),e) #define MAKE_IPV4_ADDRESS(a,b,c,d,e) epee::net_utils::ipv4_network_address{MAKE_IP(a,b,c,d),e}
#define ADD_GRAY_NODE(addr_, id_, last_seen_) { nodetool::peerlist_entry ple; ple.last_seen=last_seen_;ple.adr = addr_; ple.id = id_;plm.append_with_peer_gray(ple);} #define ADD_GRAY_NODE(addr_, id_, last_seen_) { nodetool::peerlist_entry ple; ple.last_seen=last_seen_;ple.adr = addr_; ple.id = id_;plm.append_with_peer_gray(ple);}
#define ADD_WHITE_NODE(addr_, id_, last_seen_) { nodetool::peerlist_entry ple;ple.last_seen=last_seen_; ple.adr = addr_; ple.id = id_;plm.append_with_peer_white(ple);} #define ADD_WHITE_NODE(addr_, id_, last_seen_) { nodetool::peerlist_entry ple;ple.last_seen=last_seen_; ple.adr = addr_; ple.id = id_;plm.append_with_peer_white(ple);}