#ifndef BITCOIN_NETBASE_H
#define BITCOIN_NETBASE_H
#include <compat/compat.h>
#include <netaddress.h>
#include <serialize.h>
#include <util/sock.h>
#include <util/threadinterrupt.h>
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include <type_traits>
#include <unordered_set>
#include <vector>
extern int nConnectTimeout;
extern bool fNameLookup;
static const int DEFAULT_CONNECT_TIMEOUT = 5000;
static const int DEFAULT_NAME_LOOKUP = true;
const std::string ADDR_PREFIX_UNIX = "unix:";
enum class ConnectionDirection {
None = 0,
In = (1U << 0),
Out = (1U << 1),
Both = (In | Out),
};
static inline ConnectionDirection& operator|=(ConnectionDirection& a, ConnectionDirection b) {
using underlying = std::underlying_type_t<ConnectionDirection>;
a = ConnectionDirection(underlying(a) | underlying(b));
return a;
}
static inline bool operator&(ConnectionDirection a, ConnectionDirection b) {
using underlying = std::underlying_type_t<ConnectionDirection>;
return (underlying(a) & underlying(b));
}
bool IsUnixSocketPath(const std::string& name);
class Proxy
{
public:
Proxy() : m_is_unix_socket(false), m_tor_stream_isolation(false) {}
explicit Proxy(const CService& _proxy, bool tor_stream_isolation = false) : proxy(_proxy), m_is_unix_socket(false), m_tor_stream_isolation(tor_stream_isolation) {}
explicit Proxy(std::string path, bool tor_stream_isolation = false)
: m_unix_socket_path(std::move(path)), m_is_unix_socket(true), m_tor_stream_isolation(tor_stream_isolation) {}
CService proxy;
std::string m_unix_socket_path;
bool m_is_unix_socket;
bool m_tor_stream_isolation;
bool IsValid() const
{
if (m_is_unix_socket) return IsUnixSocketPath(m_unix_socket_path);
return proxy.IsValid();
}
sa_family_t GetFamily() const
{
if (m_is_unix_socket) return AF_UNIX;
return proxy.GetSAFamily();
}
std::string ToString() const
{
if (m_is_unix_socket) return m_unix_socket_path;
return proxy.ToStringAddrPort();
}
std::unique_ptr<Sock> Connect() const;
};
struct ProxyCredentials
{
std::string username;
std::string password;
};
class ReachableNets {
public:
void Add(Network net) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
{
AssertLockNotHeld(m_mutex);
LOCK(m_mutex);
m_reachable.insert(net);
}
void Remove(Network net) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
{
AssertLockNotHeld(m_mutex);
LOCK(m_mutex);
m_reachable.erase(net);
}
void RemoveAll() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
{
AssertLockNotHeld(m_mutex);
LOCK(m_mutex);
m_reachable.clear();
}
void Reset() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
{
AssertLockNotHeld(m_mutex);
LOCK(m_mutex);
m_reachable = DefaultNets();
}
[[nodiscard]] bool Contains(Network net) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
{
AssertLockNotHeld(m_mutex);
LOCK(m_mutex);
return m_reachable.contains(net);
}
[[nodiscard]] bool Contains(const CNetAddr& addr) const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
{
AssertLockNotHeld(m_mutex);
return Contains(addr.GetNetwork());
}
[[nodiscard]] std::unordered_set<Network> All() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
{
AssertLockNotHeld(m_mutex);
LOCK(m_mutex);
return m_reachable;
}
private:
static std::unordered_set<Network> DefaultNets()
{
return {
NET_UNROUTABLE,
NET_IPV4,
NET_IPV6,
NET_ONION,
NET_I2P,
NET_CJDNS,
NET_INTERNAL
};
};
mutable Mutex m_mutex;
std::unordered_set<Network> m_reachable GUARDED_BY(m_mutex){DefaultNets()};
};
extern ReachableNets g_reachable_nets;
std::vector<CNetAddr> WrappedGetAddrInfo(const std::string& name, bool allow_lookup);
enum Network ParseNetwork(const std::string& net);
std::string GetNetworkName(enum Network net);
std::vector<std::string> GetNetworkNames(bool append_unroutable = false);
bool SetProxy(enum Network net, const Proxy &addrProxy);
bool GetProxy(enum Network net, Proxy &proxyInfoOut);
bool IsProxy(const CNetAddr &addr);
bool SetNameProxy(const Proxy &addrProxy);
bool HaveNameProxy();
bool GetNameProxy(Proxy &nameProxyOut);
using DNSLookupFn = std::function<std::vector<CNetAddr>(const std::string&, bool)>;
extern DNSLookupFn g_dns_lookup;
std::vector<CNetAddr> LookupHost(const std::string& name, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function = g_dns_lookup);
std::optional<CNetAddr> LookupHost(const std::string& name, bool fAllowLookup, DNSLookupFn dns_lookup_function = g_dns_lookup);
std::vector<CService> Lookup(const std::string& name, uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function = g_dns_lookup);
std::optional<CService> Lookup(const std::string& name, uint16_t portDefault, bool fAllowLookup, DNSLookupFn dns_lookup_function = g_dns_lookup);
CService LookupNumeric(const std::string& name, uint16_t portDefault = 0, DNSLookupFn dns_lookup_function = g_dns_lookup);
CSubNet LookupSubNet(const std::string& subnet_str);
std::unique_ptr<Sock> CreateSockOS(int domain, int type, int protocol);
extern std::function<std::unique_ptr<Sock>(int, int, int)> CreateSock;
std::unique_ptr<Sock> ConnectDirectly(const CService& dest, bool manual_connection);
std::unique_ptr<Sock> ConnectThroughProxy(const Proxy& proxy,
const std::string& dest,
uint16_t port,
bool& proxy_connection_failed);
extern CThreadInterrupt g_socks5_interrupt;
bool Socks5(const std::string& strDest, uint16_t port, const ProxyCredentials* auth, const Sock& socket);
bool IsBadPort(uint16_t port);
CService MaybeFlipIPv6toCJDNS(const CService& service);
CService GetBindAddress(const Sock& sock);
#endif