#ifndef SRC_NODE_SOCKADDR_H_ #define SRC_NODE_SOCKADDR_H_ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #include "env.h" #include "memory_tracker.h" #include "base_object.h" #include "node.h" #include "node_worker.h" #include "uv.h" #include "v8.h" #include #include #include #include namespace node { class Environment; class SocketAddress : public MemoryRetainer { public: enum class CompareResult { NOT_COMPARABLE = -2, LESS_THAN, SAME, GREATER_THAN }; struct Hash { size_t operator()(const SocketAddress& addr) const; }; inline bool operator==(const SocketAddress& other) const; inline bool operator!=(const SocketAddress& other) const; inline bool operator<(const SocketAddress& other) const; inline bool operator>(const SocketAddress& other) const; inline bool operator<=(const SocketAddress& other) const; inline bool operator>=(const SocketAddress& other) const; inline static bool is_numeric_host(const char* hostname); inline static bool is_numeric_host(const char* hostname, int family); // Returns true if converting {family, host, port} to *addr succeeded. static bool ToSockAddr( int32_t family, const char* host, uint32_t port, sockaddr_storage* addr); // Returns true if converting {family, host, port} to *addr succeeded. static bool New( int32_t family, const char* host, uint32_t port, SocketAddress* addr); static bool New( const char* host, uint32_t port, SocketAddress* addr); // Returns the port for an IPv4 or IPv6 address. inline static int GetPort(const sockaddr* addr); inline static int GetPort(const sockaddr_storage* addr); // Returns the numeric host as a string for an IPv4 or IPv6 address. inline static std::string GetAddress(const sockaddr* addr); inline static std::string GetAddress(const sockaddr_storage* addr); // Returns the struct length for an IPv4, IPv6 or UNIX domain. inline static size_t GetLength(const sockaddr* addr); inline static size_t GetLength(const sockaddr_storage* addr); SocketAddress() = default; inline explicit SocketAddress(const sockaddr* addr); inline SocketAddress(const SocketAddress& addr); inline SocketAddress& operator=(const sockaddr* other); inline SocketAddress& operator=(const SocketAddress& other); inline const sockaddr& operator*() const; inline const sockaddr* operator->() const; inline const sockaddr* data() const; inline const uint8_t* raw() const; inline sockaddr* storage(); inline size_t length() const; inline int family() const; inline std::string address() const; inline int port() const; // Returns true if the given other SocketAddress is a match // for this one. The addresses are a match if: // 1. They are the same family and match identically // 2. They are different family but match semantically ( // for instance, an IPv4 address in IPv6 notation) bool is_match(const SocketAddress& other) const; // Compares this SocketAddress to the given other SocketAddress. CompareResult compare(const SocketAddress& other) const; // Returns true if this SocketAddress is within the subnet // identified by the given network address and CIDR prefix. bool is_in_network(const SocketAddress& network, int prefix) const; // If the SocketAddress is an IPv6 address, returns the // current value of the IPv6 flow label, if set. Otherwise // returns 0. inline uint32_t flow_label() const; // If the SocketAddress is an IPv6 address, sets the // current value of the IPv6 flow label. If not an // IPv6 address, set_flow_label is a non-op. It // is important to note that the flow label, // while represented as an uint32_t, the flow // label is strictly limited to 20 bits, and // this will assert if any value larger than // 20-bits is specified. inline void set_flow_label(uint32_t label = 0); inline void Update(uint8_t* data, size_t len); inline void Update(const sockaddr* data, size_t len); static SocketAddress FromSockName(const uv_udp_t& handle); static SocketAddress FromSockName(const uv_tcp_t& handle); static SocketAddress FromPeerName(const uv_udp_t& handle); static SocketAddress FromPeerName(const uv_tcp_t& handle); inline v8::MaybeLocal ToJS( Environment* env, v8::Local obj = v8::Local()) const; inline std::string ToString() const; SET_NO_MEMORY_INFO() SET_MEMORY_INFO_NAME(SocketAddress) SET_SELF_SIZE(SocketAddress) template using Map = std::unordered_map; private: sockaddr_storage address_; }; class SocketAddressBase : public BaseObject { public: static bool HasInstance(Environment* env, v8::Local value); static v8::Local GetConstructorTemplate( Environment* env); static void Initialize(Environment* env, v8::Local target); static BaseObjectPtr Create( Environment* env, std::shared_ptr address); static void New(const v8::FunctionCallbackInfo& args); static void Detail(const v8::FunctionCallbackInfo& args); static void LegacyDetail(const v8::FunctionCallbackInfo& args); static void GetFlowLabel(const v8::FunctionCallbackInfo& args); SocketAddressBase( Environment* env, v8::Local wrap, std::shared_ptr address); inline const std::shared_ptr& address() const { return address_; } void MemoryInfo(MemoryTracker* tracker) const override; SET_MEMORY_INFO_NAME(SocketAddressBase) SET_SELF_SIZE(SocketAddressBase) TransferMode GetTransferMode() const override { return TransferMode::kCloneable; } std::unique_ptr CloneForMessaging() const override; class TransferData : public worker::TransferData { public: inline explicit TransferData(const SocketAddressBase* wrap) : address_(wrap->address_) {} inline explicit TransferData(std::shared_ptr address) : address_(std::move(address)) {} BaseObjectPtr Deserialize( Environment* env, v8::Local context, std::unique_ptr self) override; void MemoryInfo(MemoryTracker* tracker) const override; SET_MEMORY_INFO_NAME(SocketAddressBase::TransferData) SET_SELF_SIZE(TransferData) private: std::shared_ptr address_; }; private: std::shared_ptr address_; }; template class SocketAddressLRU : public MemoryRetainer { public: using Type = typename T::Type; inline explicit SocketAddressLRU(size_t max_size); // If the item already exists, returns a reference to // the existing item, adjusting items position in the // LRU. If the item does not exist, emplaces the item // and returns the new item. Type* Upsert(const SocketAddress& address); // Returns a reference to the item if it exists, or // nullptr. The position in the LRU is not modified. Type* Peek(const SocketAddress& address) const; size_t size() const { return map_.size(); } size_t max_size() const { return max_size_; } void MemoryInfo(MemoryTracker* tracker) const override; SET_MEMORY_INFO_NAME(SocketAddressLRU) SET_SELF_SIZE(SocketAddressLRU) private: using Pair = std::pair; using Iterator = typename std::list::iterator; void CheckExpired(); std::list list_; SocketAddress::Map map_; size_t max_size_; }; // A BlockList is used to evaluate whether a given // SocketAddress should be accepted for inbound or // outbound network activity. class SocketAddressBlockList : public MemoryRetainer { public: explicit SocketAddressBlockList( std::shared_ptr parent = {}); ~SocketAddressBlockList() = default; void AddSocketAddress(const std::shared_ptr& address); void RemoveSocketAddress(const std::shared_ptr& address); void AddSocketAddressRange( const std::shared_ptr& start, const std::shared_ptr& end); void AddSocketAddressMask( const std::shared_ptr& address, int prefix); bool Apply(const std::shared_ptr& address); size_t size() const { return rules_.size(); } v8::MaybeLocal ListRules(Environment* env); struct Rule : public MemoryRetainer { virtual bool Apply(const std::shared_ptr& address) = 0; inline v8::MaybeLocal ToV8String(Environment* env); virtual std::string ToString() = 0; }; struct SocketAddressRule final : Rule { std::shared_ptr address; explicit SocketAddressRule(const std::shared_ptr& address); bool Apply(const std::shared_ptr& address) override; std::string ToString() override; void MemoryInfo(node::MemoryTracker* tracker) const override; SET_MEMORY_INFO_NAME(SocketAddressRule) SET_SELF_SIZE(SocketAddressRule) }; struct SocketAddressRangeRule final : Rule { std::shared_ptr start; std::shared_ptr end; SocketAddressRangeRule( const std::shared_ptr& start, const std::shared_ptr& end); bool Apply(const std::shared_ptr& address) override; std::string ToString() override; void MemoryInfo(node::MemoryTracker* tracker) const override; SET_MEMORY_INFO_NAME(SocketAddressRangeRule) SET_SELF_SIZE(SocketAddressRangeRule) }; struct SocketAddressMaskRule final : Rule { std::shared_ptr network; int prefix; SocketAddressMaskRule( const std::shared_ptr& address, int prefix); bool Apply(const std::shared_ptr& address) override; std::string ToString() override; void MemoryInfo(node::MemoryTracker* tracker) const override; SET_MEMORY_INFO_NAME(SocketAddressMaskRule) SET_SELF_SIZE(SocketAddressMaskRule) }; void MemoryInfo(node::MemoryTracker* tracker) const override; SET_MEMORY_INFO_NAME(SocketAddressBlockList) SET_SELF_SIZE(SocketAddressBlockList) private: bool ListRules( Environment* env, std::vector>* vec); std::shared_ptr parent_; std::list> rules_; SocketAddress::Map>::iterator> address_rules_; Mutex mutex_; }; class SocketAddressBlockListWrap : public BaseObject { public: static bool HasInstance(Environment* env, v8::Local value); static v8::Local GetConstructorTemplate( Environment* env); static void Initialize(v8::Local target, v8::Local unused, v8::Local context, void* priv); static BaseObjectPtr New(Environment* env); static BaseObjectPtr New( Environment* env, std::shared_ptr blocklist); static void New(const v8::FunctionCallbackInfo& args); static void AddAddress(const v8::FunctionCallbackInfo& args); static void AddRange(const v8::FunctionCallbackInfo& args); static void AddSubnet(const v8::FunctionCallbackInfo& args); static void Check(const v8::FunctionCallbackInfo& args); static void GetRules(const v8::FunctionCallbackInfo& args); SocketAddressBlockListWrap( Environment* env, v8::Local wrap, std::shared_ptr blocklist = std::make_shared()); void MemoryInfo(node::MemoryTracker* tracker) const override; SET_MEMORY_INFO_NAME(SocketAddressBlockListWrap) SET_SELF_SIZE(SocketAddressBlockListWrap) TransferMode GetTransferMode() const override { return TransferMode::kCloneable; } std::unique_ptr CloneForMessaging() const override; class TransferData : public worker::TransferData { public: inline explicit TransferData(const SocketAddressBlockListWrap* wrap) : blocklist_(wrap->blocklist_) {} inline explicit TransferData( std::shared_ptr blocklist) : blocklist_(std::move(blocklist)) {} BaseObjectPtr Deserialize( Environment* env, v8::Local context, std::unique_ptr self) override; void MemoryInfo(MemoryTracker* tracker) const override; SET_MEMORY_INFO_NAME(SocketAddressBlockListWrap::TransferData) SET_SELF_SIZE(TransferData) private: std::shared_ptr blocklist_; }; private: std::shared_ptr blocklist_; }; } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #endif // SRC_NODE_SOCKADDR_H_