This is an automated email from the ASF dual-hosted git repository. bneradt pushed a commit to branch dev-1-0-14 in repository https://gitbox.apache.org/repos/asf/trafficserver-libswoc.git
commit 20425cece7e81c6c76acc0590e5783544ebcc1fc Author: Alan M. Carroll <[email protected]> AuthorDate: Mon Mar 2 17:12:35 2020 -0600 Added network extraction support for IPRange. --- swoc++/include/swoc/swoc_ip.h | 830 +++++++++++++++++++++++++++--------------- swoc++/src/bw_ip_format.cc | 6 +- swoc++/src/swoc_ip.cc | 76 +++- unit_tests/test_ip.cc | 20 +- 4 files changed, 623 insertions(+), 309 deletions(-) diff --git a/swoc++/include/swoc/swoc_ip.h b/swoc++/include/swoc/swoc_ip.h index 788c727..7fe13b3 100644 --- a/swoc++/include/swoc/swoc_ip.h +++ b/swoc++/include/swoc/swoc_ip.h @@ -16,15 +16,25 @@ namespace swoc { class IP4Addr; + class IP6Addr; + class IPAddr; + class IPMask; + class IP4Range; + class IP6Range; + class IPRange; + class IP4Net; + class IP6Net; +class IPNet; + using ::std::string_view; /** A union to hold @c sockaddr compliant IP address structures. @@ -47,10 +57,10 @@ union IPEndpoint { IPEndpoint(); /// Construct from the @a text representation of an address. - IPEndpoint(string_view const&text); + IPEndpoint(string_view const& text); // Construct from @a IPAddr - IPEndpoint(IPAddr const&addr); + IPEndpoint(IPAddr const& addr); /** Break a string in to IP address relevant tokens. * @@ -73,16 +83,16 @@ union IPEndpoint { @return @c true on success, @c false otherwise. */ - bool parse(string_view const&str); + bool parse(string_view const& str); /// Invalidate a @c sockaddr. static void invalidate(sockaddr *addr); /// Invalidate this endpoint. - self_type&invalidate(); + self_type& invalidate(); /// Copy constructor. - self_type&operator=(self_type const&that); + self_type& operator=(self_type const& that); /** Copy (assign) the contents of @a src to @a dst. * @@ -98,13 +108,13 @@ union IPEndpoint { /** Assign from a socket address. The entire address (all parts) are copied if the @a ip is valid. */ - self_type&assign(sockaddr const *addr); + self_type& assign(sockaddr const *addr); /// Assign from an @a addr and @a port. - self_type&assign(IPAddr const&addr, in_port_t port = 0); + self_type& assign(IPAddr const& addr, in_port_t port = 0); /// Copy to @a sa. - const self_type&fill(sockaddr *addr) const; + const self_type& fill(sockaddr *addr) const; /// Test for valid IP address. bool is_valid() const; @@ -127,15 +137,15 @@ union IPEndpoint { /// Set to be the ANY address for family @a family. /// @a family must be @c AF_INET or @c AF_INET6. /// @return This object. - self_type&set_to_any(int family); + self_type& set_to_any(int family); /// Set to be loopback address for family @a family. /// @a family must be @c AF_INET or @c AF_INET6. /// @return This object. - self_type&set_to_loopback(int family); + self_type& set_to_loopback(int family); /// Port in network order. - in_port_t&port(); + in_port_t& port(); /// Port in network order. in_port_t port() const; @@ -144,7 +154,7 @@ union IPEndpoint { in_port_t host_order_port() const; /// Port in network order from @a sockaddr. - static in_port_t&port(sockaddr *sa); + static in_port_t& port(sockaddr *sa); /// Port in network order from @a sockaddr. static in_port_t port(sockaddr const *sa); @@ -187,22 +197,22 @@ public: /// Construct from text representation. /// If the @a text is invalid the result is an invalid instance. - IP4Addr(string_view const&text); + IP4Addr(string_view const& text); /// Construct from generic address @a addr. - explicit IP4Addr(IPAddr const&addr); + explicit IP4Addr(IPAddr const& addr); /// Assign from IPv4 raw address. - self_type&operator=(in_addr_t ip); + self_type& operator=(in_addr_t ip); /// Set to the address in @a addr. - self_type&operator=(sockaddr_in const *sa); + self_type& operator=(sockaddr_in const *sa); /// Increment address. - self_type&operator++(); + self_type& operator++(); /// Decrement address. - self_type&operator--(); + self_type& operator--(); /** Byte access. * @@ -214,10 +224,10 @@ public: } /// Apply @a mask to address, leaving the network portion. - self_type&operator&=(IPMask const&mask); + self_type& operator&=(IPMask const& mask); /// Apply @a mask to address, creating the broadcast address. - self_type&operator|=(IPMask const&mask); + self_type& operator|=(IPMask const& mask); /// Write this adddress and @a port to the sockaddr @a sa. sockaddr_in *fill(sockaddr_in *sa, in_port_t port = 0) const; @@ -234,10 +244,10 @@ public: @return @c true on success, @c false otherwise. */ - bool load(string_view const&text); + bool load(string_view const& text); /// Standard ternary compare. - int cmp(self_type const&that) const; + int cmp(self_type const& that) const; /// Get the IP address family. /// @return @c AF_INET @@ -254,14 +264,14 @@ public: * @param n Number of bits to shift left. * @return @a this. */ - self_type&operator<<=(unsigned n); + self_type& operator<<=(unsigned n); /** Right shift. * * @param n Number of bits to shift right. * @return @a this. */ - self_type&operator>>=(unsigned n); + self_type& operator>>=(unsigned n); /** Bitwise AND. * @@ -270,7 +280,7 @@ public: * * The bits in @a this are set to the bitwise AND of the corresponding bits in @a this and @a that. */ - self_type&operator&=(self_type const&that); + self_type& operator&=(self_type const& that); /** Bitwise OR. * @@ -279,7 +289,7 @@ public: * * The bits in @a this are set to the bitwise OR of the corresponding bits in @a this and @a that. */ - self_type&operator|=(self_type const&that); + self_type& operator|=(self_type const& that); /** Convert between network and host order. * @@ -356,10 +366,10 @@ public: static const self_type MAX; IP6Addr() = default; ///< Default constructor - 0 address. - IP6Addr(self_type const&that) = default; + IP6Addr(self_type const& that) = default; /// Construct using IPv6 @a addr. - explicit IP6Addr(in6_addr const&addr); + explicit IP6Addr(in6_addr const& addr); /// Construct from @c sockaddr_in. explicit IP6Addr(sockaddr_in6 const *addr) { @@ -368,24 +378,24 @@ public: /// Construct from text representation. /// If the @a text is invalid the result is an invalid instance. - IP6Addr(string_view const&text); + IP6Addr(string_view const& text); /// Construct from generic @a addr. - IP6Addr(IPAddr const&addr); + IP6Addr(IPAddr const& addr); /** Left shift. * * @param n Number of bits to shift left. * @return @a this. */ - self_type&operator<<=(unsigned n); + self_type& operator<<=(unsigned n); /** Right shift. * * @param n Number of bits to shift right. * @return @a this. */ - self_type&operator>>=(unsigned n); + self_type& operator>>=(unsigned n); /** Bitwise AND. * @@ -394,7 +404,7 @@ public: * * The bits in @a this are set to the bitwise AND of the corresponding bits in @a this and @a that. */ - self_type&operator&=(self_type const&that); + self_type& operator&=(self_type const& that); /** Bitwise OR. * @@ -403,25 +413,25 @@ public: * * The bits in @a this are set to the bitwise OR of the corresponding bits in @a this and @a that. */ - self_type&operator|=(self_type const&that); + self_type& operator|=(self_type const& that); /// Increment address. - self_type&operator++(); + self_type& operator++(); /// Decrement address. - self_type&operator--(); + self_type& operator--(); /// Assign from IPv6 raw address. - self_type&operator=(in6_addr const&ip); + self_type& operator=(in6_addr const& ip); /// Set to the address in @a addr. - self_type&operator=(sockaddr_in6 const *addr); + self_type& operator=(sockaddr_in6 const *addr); /// Write to @c sockaddr using network order and @a port. sockaddr *copy_to(sockaddr *sa, in_port_t port = 0) const; /// Copy address to @a addr in network order. - in6_addr©_to(in6_addr&addr) const; + in6_addr& copy_to(in6_addr& addr) const; /// Return the address in network order. in6_addr network_order() const; @@ -433,10 +443,10 @@ public: @return @c true on success, @c false otherwise. */ - bool load(string_view const&str); + bool load(string_view const& str); /// Generic compare. - int cmp(self_type const&that) const; + int cmp(self_type const& that) const; /// Get the address family. /// @return The address family. @@ -448,18 +458,18 @@ public: /// Test for loopback bool is_multicast() const { return IN6_IS_ADDR_MULTICAST(_addr._raw.data()); } - self_type&clear() { + self_type& clear() { _addr._store[0] = _addr._store[1] = 0; return *this; } - self_type&operator&=(IPMask const&mask); + self_type& operator&=(IPMask const& mask); - self_type&operator|=(IPMask const&mask); + self_type& operator|=(IPMask const& mask); - static void reorder(in6_addr&dst, raw_type const&src); + static void reorder(in6_addr& dst, raw_type const& src); - static void reorder(raw_type&dst, in6_addr const&src); + static void reorder(raw_type& dst, in6_addr const& src); protected: friend bool operator==(self_type const&, self_type const&); @@ -493,9 +503,9 @@ protected: */ IP6Addr(word_store_type::value_type msw, word_store_type::value_type lsw) : _addr{msw, lsw} {} - friend IP6Addr operator&(IP6Addr const&addr, IPMask const&mask); + friend IP6Addr operator&(IP6Addr const& addr, IPMask const& mask); - friend IP6Addr operator|(IP6Addr const&addr, IPMask const&mask); + friend IP6Addr operator|(IP6Addr const& addr, IPMask const& mask); }; /** Storage for an IP address. @@ -506,74 +516,75 @@ class IPAddr { using self_type = IPAddr; ///< Self reference type. public: IPAddr() = default; ///< Default constructor - invalid result. - IPAddr(self_type const&that) = default; ///< Copy constructor. + IPAddr(self_type const& that) = default; ///< Copy constructor. /// Construct using IPv4 @a addr. explicit IPAddr(in_addr_t addr); /// Construct using an IPv4 @a addr - IPAddr(IP4Addr const&addr) : _family(AF_INET), _addr{addr} {} + IPAddr(IP4Addr const& addr) : _family(AF_INET), _addr{addr} {} /// Construct using IPv6 @a addr. - explicit IPAddr(in6_addr const&addr); + explicit IPAddr(in6_addr const& addr); /// construct using an IPv6 @a addr - IPAddr(IP6Addr const&addr) : _family(AF_INET6), _addr{addr} {} + IPAddr(IP6Addr const& addr) : _family(AF_INET6), _addr{addr} {} /// Construct from @c sockaddr. explicit IPAddr(sockaddr const *addr); /// Construct from @c IPEndpoint. - explicit IPAddr(IPEndpoint const&addr); + explicit IPAddr(IPEndpoint const& addr); /// Construct from text representation. /// If the @a text is invalid the result is an invalid instance. - explicit IPAddr(string_view const&text); + explicit IPAddr(string_view const& text); /// Set to the address in @a addr. - self_type&assign(sockaddr const *addr); + self_type& assign(sockaddr const *addr); /// Set to the address in @a addr. - self_type&assign(sockaddr_in const *addr); + self_type& assign(sockaddr_in const *addr); /// Set to the address in @a addr. - self_type&assign(sockaddr_in6 const *addr); + self_type& assign(sockaddr_in6 const *addr); /// Set to the address in @a addr. - self_type&assign(in_addr_t addr); + self_type& assign(in_addr_t addr); /// Set to address in @a addr. - self_type&assign(in6_addr const&addr); + self_type& assign(in6_addr const& addr); /// Assign from end point. - self_type&operator=(IPEndpoint const&ip); + self_type& operator=(IPEndpoint const& ip); /// Assign from IPv4 raw address. - self_type&operator=(in_addr_t ip); + self_type& operator=(in_addr_t ip); /// Assign from IPv6 raw address. - self_type&operator=(in6_addr const&ip); + self_type& operator=(in6_addr const& ip); /// Assign from @c sockaddr - self_type&operator=(sockaddr const *addr); + self_type& operator=(sockaddr const *addr); + + self_type& operator&=(IPMask const& mask); - self_type&operator&=(IPMask const&mask); + self_type& operator|=(IPMask const& mask); - self_type&operator|=(IPMask const&mask); - /** Parse a string and load the result in @a this. +/** Parse a string and load the result in @a this. * * @param text Text to parse. * @return @c true on success, @c false otherwise. */ - bool load(string_view const&text); + bool load(string_view const& text); /// Generic compare. - int cmp(self_type const&that) const; + int cmp(self_type const& that) const; /// Test for same address family. /// @c return @c true if @a that is the same address family as @a this. - bool isCompatibleWith(self_type const&that); + bool isCompatibleWith(self_type const& that); /// Get the address family. /// @return The address family. @@ -585,9 +596,9 @@ public: /// Test for IPv6. bool is_ip6() const; - in_addr_t network_ip4() const; + IP4Addr const& ip4() const; - in6_addr network_ip6() const; + IP6Addr const& ip6() const; explicit operator IP4Addr const&() const { return _addr._ip4; } @@ -601,7 +612,7 @@ public: bool is_valid() const; /// Make invalid. - self_type&invalidate(); + self_type& invalidate(); /// Test for multicast bool is_multicast() const; @@ -629,11 +640,11 @@ protected: raw_addr_type(in_addr_t addr) : _ip4(addr) {} - raw_addr_type(in6_addr const&addr) : _ip6(addr) {} + raw_addr_type(in6_addr const& addr) : _ip6(addr) {} - raw_addr_type(IP4Addr const&addr) : _ip4(addr) {} + raw_addr_type(IP4Addr const& addr) : _ip4(addr) {} - raw_addr_type(IP6Addr const&addr) : _ip6(addr) {} + raw_addr_type(IP6Addr const& addr) : _ip6(addr) {} } _addr; sa_family_t _family{AF_UNSPEC}; ///< Protocol family. @@ -664,28 +675,28 @@ public: * @param text A number in string format. * @return @a true if a valid CIDR value, @c false if not. */ - bool load(string_view const&text); + bool load(string_view const& text); /** Copmute a mask for the network at @a addr. * @param addr Lower bound of network. * @return The width of the largest network starting at @a addr. */ - static self_type mask_for(IPAddr const&addr); + static self_type mask_for(IPAddr const& addr); /** Copmute a mask for the network at @a addr. * @param addr Lower bound of network. * @return A mask with the width of the largest network starting at @a addr. */ - static self_type mask_for(IP4Addr const&addr); + static self_type mask_for(IP4Addr const& addr); /** Copmute a mask for the network at @a addr. * @param addr Lower bound of network. * @return A mask with the width of the largest network starting at @a addr. */ - static self_type mask_for(IP6Addr const&addr); + static self_type mask_for(IP6Addr const& addr); /// Force @a this to an invalid state. - self_type&clear() { + self_type& clear() { _cidr = INVALID; return *this; } @@ -693,12 +704,12 @@ public: /// The width of the mask. raw_type width() const; - self_type&operator<<=(raw_type n) { + self_type& operator<<=(raw_type n) { _cidr -= n; return *this; } - self_type&operator>>=(raw_type n) { + self_type& operator>>=(raw_type n) { _cidr += n; return *this; } @@ -729,7 +740,6 @@ protected: static raw_type mask_for_quad(IP6Addr::quad_type q); }; - /** An inclusive range of IPv4 addresses. */ class IP4Range : public DiscreteRange<IP4Addr> { @@ -738,17 +748,15 @@ class IP4Range : public DiscreteRange<IP4Addr> { using metric_type = IP4Addr; public: - using super_type::super_type; ///< Import super class constructors. - /// Default constructor, invalid range. IP4Range() = default; /// Construct from an network expressed as @a addr and @a mask. - IP4Range(IP4Addr const&addr, IPMask const&mask); + IP4Range(IP4Addr const& addr, IPMask const& mask); /// Construct from super type. /// @internal Why do I have to do this, even though the super type constructors are inherited? - IP4Range(super_type const&r) : super_type(r) {} + IP4Range(super_type const& r) : super_type(r) {} /** Construct range from @a text. * @@ -758,7 +766,9 @@ public: * This results in a zero address if @a text is not a valid string. If this should be checked, * use @c load. */ - IP4Range(string_view const&text); + IP4Range(string_view const& text); + + using super_type::super_type; ///< Import super class constructors. /** Set @a this range. * @@ -766,7 +776,9 @@ public: * @param mask CIDR mask to compute maximum adddress from @a addr. * @return @a this */ - self_type&assign(IP4Addr const&addr, IPMask const&mask); + self_type& assign(IP4Addr const& addr, IPMask const& mask); + + using super_type::assign; ///< Import assign methods. /** Assign to this range from text. * @@ -809,10 +821,10 @@ public: using range_type = IP4Range; ///< Import base range type. /// Construct from @a range. - explicit NetSource(range_type const&range); + explicit NetSource(range_type const& range); /// Copy constructor. - NetSource(self_type const&that) = default; + NetSource(self_type const& that) = default; /// This class acts as a container and an iterator. using iterator = self_type; @@ -830,23 +842,23 @@ public: /// Iterator support. /// @areturn The current network address. - IP4Addr const&addr() const; + IP4Addr const& addr() const; /// Iterator support. /// @return The current network mask. IPMask mask() const; /// Move to next network. - self_type&operator++(); + self_type& operator++(); /// Move to next network. self_type operator++(int); /// Equality. - bool operator==(self_type const&that); + bool operator==(self_type const& that) const; /// Inequality. - bool operator!=(self_type const&that); + bool operator!=(self_type const& that) const; protected: IP4Range _range; ///< Remaining range. @@ -866,11 +878,9 @@ class IP6Range : public DiscreteRange<IP6Addr> { using super_type = DiscreteRange<IP6Addr>; public: - using super_type::super_type; ///< Import super class constructors. - /// Construct from super type. /// @internal Why do I have to do this, even though the super type constructors are inherited? - IP6Range(super_type const&r) : super_type(r) {} + IP6Range(super_type const& r) : super_type(r) {} /** Construct range from @a text. * @@ -880,7 +890,9 @@ public: * This results in a zero address if @a text is not a valid string. If this should be checked, * use @c load. */ - IP6Range(string_view const&text); + IP6Range(string_view const& text); + + using super_type::super_type; ///< Import super class constructors. /** Set @a this range. * @@ -888,7 +900,9 @@ public: * @param mask CIDR mask to compute maximum adddress from @a addr. * @return @a this */ - self_type&assign(IP6Addr const&addr, IPMask const&mask); + self_type& assign(IP6Addr const& addr, IPMask const& mask); + + using super_type::assign; ///< Import assign methods. /** Assign to this range from text. * @@ -911,7 +925,7 @@ public: * the unique minimal set of networks that cover @a this range. * * @code - * void (IP4Range const& range) { + * void (IP6Range const& range) { * for ( auto const& net : range ) { * net.addr(); // network address. * net.mask(); // network mask; @@ -931,10 +945,10 @@ public: using range_type = IP6Range; ///< Import base range type. /// Construct from @a range. - explicit NetSource(range_type const&range); + explicit NetSource(range_type const& range); /// Copy constructor. - NetSource(self_type const&that) = default; + NetSource(self_type const& that) = default; /// This class acts as a container and an iterator. using iterator = self_type; @@ -952,23 +966,23 @@ public: /// Iterator support. /// @areturn The current network address. - IP6Addr const&addr() const; + IP6Addr const& addr() const { return _range.min(); } /// Iterator support. /// @return The current network mask. - IPMask mask() const; + IPMask mask() const { return _mask; } /// Move to next network. - self_type&operator++(); + self_type& operator++(); /// Move to next network. self_type operator++(int); /// Equality. - bool operator==(self_type const&that); + bool operator==(self_type const& that) const; /// Inequality. - bool operator!=(self_type const&that); + bool operator!=(self_type const& that) const; protected: IP6Range _range; ///< Remaining range. @@ -978,7 +992,7 @@ protected: void search_narrower(); - bool is_valid(IPMask const&mask); + bool is_valid(IPMask const& mask); }; class IPRange { @@ -987,11 +1001,13 @@ public: /// Default constructor - construct invalid range. IPRange() = default; + IPRange(IPAddr const& min, IPAddr const& max); + /// Construct from an IPv4 @a range. - IPRange(IP4Range const&range); + IPRange(IP4Range const& range); /// Construct from an IPv6 @a range. - IPRange(IP6Range const&range); + IPRange(IP6Range const& range); /** Construct from a string format. * @@ -999,7 +1015,13 @@ public: * * The string can be a single address, two addresses separated by a dash '-' or a CIDR network. */ - IPRange(string_view const&text); + IPRange(string_view const& text); + + /// @return @c true if this is an IPv4 range, @c false if not. + bool is_ip4() const { return AF_INET == _family; } + + /// @return @c true if this is an IPv6 range, @c false if not. + bool is_ip6() const { return AF_INET6 == _family; } /** Check if @a this range is the IP address @a family. * @@ -1016,7 +1038,7 @@ public: * A successful parse means @a this was loaded with the specified range. If not the range is * marked as invalid. */ - bool load(std::string_view const&text); + bool load(std::string_view const& text); /// @return The minimum address in the range. IPAddr min() const; @@ -1026,13 +1048,28 @@ public: bool empty() const; - operator IP4Range&() { return _range._ip4; } + IP4Range const& ip4() const { return _range._ip4; } + IP6Range const& ip6() const { return _range._ip6; } - operator IP6Range&() { return _range._ip6; } - - operator IP4Range const&() const { return _range._ip4; } + class NetSource; - operator IP6Range const&() const { return _range._ip6; } + /** Generate a list of networks covering @a this range. + * + * @return A network generator. + * + * The returned object can be used as an iterator, or as a container to iterating over + * the unique minimal set of networks that cover @a this range. + * + * @code + * void (IPRange const& range) { + * for ( auto const& net : range ) { + * net.addr(); // network address. + * net.mask(); // network mask; + * } + * } + * @endcode + */ + NetSource networks() const; protected: /** Range container. @@ -1053,12 +1090,69 @@ protected: sa_family_t _family{AF_UNSPEC}; }; +/** Network generator class. + * This generates networks from a range and acts as both a forward iterator and a container. + */ +class IPRange::NetSource { + using self_type = NetSource; ///< Self reference type. +public: + using range_type = IPRange; ///< Import base range type. + + /// Construct from @a range. + explicit NetSource(range_type const& range); + + /// Copy constructor. + NetSource(self_type const& that) = default; + + /// This class acts as a container and an iterator. + using iterator = self_type; + /// All iteration is constant so no distinction between iterators. + using const_iterator = iterator; + + iterator begin() const; ///< First network. + iterator end() const; ///< Past last network. + + /// @return The current network. + IPNet operator*() const; + + /// Access @a this as if it were an @c IP6Net. + self_type *operator->(); + + /// Iterator support. + /// @areturn The current network address. + IPAddr addr() const; + + /// Iterator support. + /// @return The current network mask. + IPMask mask() const; + + /// Move to next network. + self_type& operator++(); + + /// Move to next network. + self_type operator++(int); + + /// Equality. + bool operator==(self_type const& that) const; + + /// Inequality. + bool operator!=(self_type const& that) const; + +protected: + union { + std::monostate _nil; + IP4Range::NetSource _ip4; + IP6Range::NetSource _ip6; + }; + sa_family_t _family = AF_UNSPEC; +}; + /// An IPv4 network. class IP4Net { using self_type = IP4Net; ///< Self reference type. public: IP4Net() = default; ///< Construct invalid network. - IP4Net(self_type const&that) = default; ///< Copy constructor. + IP4Net(self_type const& that) = default; ///< Copy constructor. /** Construct from @a addr and @a mask. * @@ -1092,7 +1186,7 @@ public: IP4Addr upper_bound() const; /// @return The mask for the network. - IPMask const&mask() const; + IPMask const& mask() const; /// @return A range that exactly covers the network. IP4Range as_range() const; @@ -1103,19 +1197,19 @@ public: * @param mask Network mask. * @return @a this. */ - self_type&assign(IP4Addr const&addr, IPMask const&mask); + self_type& assign(IP4Addr const& addr, IPMask const& mask); /// Reset network to invalid state. - self_type&clear() { + self_type& clear() { _mask.clear(); return *this; } /// Equality. - bool operator==(self_type const&that) const; + bool operator==(self_type const& that) const; /// Inequality - bool operator!=(self_type const&that) const; + bool operator!=(self_type const& that) const; protected: IP4Addr _addr; ///< Network address (also lower_bound). @@ -1126,7 +1220,7 @@ class IP6Net { using self_type = IP6Net; ///< Self reference type. public: IP6Net() = default; ///< Construct invalid network. - IP6Net(self_type const&that) = default; ///< Copy constructor. + IP6Net(self_type const& that) = default; ///< Copy constructor. /** Construct from @a addr and @a mask. * @@ -1156,7 +1250,7 @@ public: IP6Addr upper_bound() const; /// @return The mask for the network. - IPMask const&mask() const; + IPMask const& mask() const; /// @return A range that exactly covers the network. IP6Range as_range() const; @@ -1167,19 +1261,19 @@ public: * @param mask Network mask. * @return @a this. */ - self_type&assign(IP6Addr const&addr, IPMask const&mask); + self_type& assign(IP6Addr const& addr, IPMask const& mask); /// Reset network to invalid state. - self_type&clear() { + self_type& clear() { _mask.clear(); return *this; } /// Equality. - bool operator==(self_type const&that) const; + bool operator==(self_type const& that) const; /// Inequality - bool operator!=(self_type const&that) const; + bool operator!=(self_type const& that) const; protected: IP6Addr _addr; ///< Network address (also lower_bound). @@ -1192,39 +1286,77 @@ protected: class IPNet { using self_type = IPNet; ///< Self reference type. public: - static constexpr char SEPARATOR = '/'; // the character used between the address and mask + IPNet() = default; ///< Construct invalid network. + IPNet(self_type const& that) = default; ///< Copy constructor. - IPNet() = default; - - IPNet(const IPAddr&addr, const IPMask&mask); - - operator IPAddr const&() const; + /** Construct from @a addr and @a mask. + * + * @param addr An address in the network. + * @param mask The mask for the network. + * + * The network is based on the mask, and the resulting network address is chosen such that the + * network will contain @a addr. For a given @a addr and @a mask there is only one network + * that satisifies these criteria. + */ + IPNet(IPAddr const& addr, IPMask const& mask); - operator IPMask const&() const; + IPNet(TextView text); - IPAddr const&addr() const; + /** Parse network as @a text. + * + * @param text String describing the network in CIDR format. + * @return @c true if a valid string, @c false if not. + */ + bool load(swoc::TextView text); - IPMask const&mask() const; + /// @return @c true if the network is valid, @c false if not. + bool is_valid() const; + /// @return THh smallest address in the network. IPAddr lower_bound() const; + /// @return The largest address in the network. IPAddr upper_bound() const; + IPMask::raw_type width() const; + + /// @return The mask for the network. + IPMask const& mask() const; + + /// @return A range that exactly covers the network. IPRange as_range() const; - bool contains(IPAddr const&addr) const; + bool is_ip4() const { return _addr.is_ip4(); } + bool is_ip6() const { return _addr.is_ip6(); } + + sa_family_t family() const { return _addr.family(); } + + IP4Net ip4() const { return IP4Net{_addr.ip4(), _mask}; } + IP6Net ip6() const { return IP6Net{_addr.ip6(), _mask};} + + /** Assign an @a addr and @a mask to @a this. + * + * @param addr Network addres. + * @param mask Network mask. + * @return @a this. + */ + self_type& assign(IPAddr const& addr, IPMask const& mask); - // computes this is strict subset of other - bool is_subnet_of(self_type const&that); + /// Reset network to invalid state. + self_type& clear() { + _mask.clear(); + return *this; + } - // Check if there are any addresses in both @a this and @a that. - bool intersects(self_type const&that); + /// Equality. + bool operator==(self_type const& that) const; - self_type&assign(IPAddr const&addr, IPMask const&mask); + /// Inequality + bool operator!=(self_type const& that) const; protected: - IPAddr _addr; - IPMask _mask; + IPAddr _addr; ///< Address and family. + IPMask _mask; ///< Network mask. }; // -------------------------------------------------------------------------- @@ -1260,7 +1392,7 @@ public: * * All addresses in @a r are set to have the @a payload. */ - self_type&mark(IPRange const&range, PAYLOAD const&payload); + self_type& mark(IPRange const& range, PAYLOAD const& payload); /** Fill the @a range with @a payload. * @@ -1270,7 +1402,7 @@ public: * * Addresses in @a range are set to have @a payload if the address does not already have a payload. */ - self_type&fill(IPRange const&range, PAYLOAD const&payload); + self_type& fill(IPRange const& range, PAYLOAD const& payload); /** Blend @a color in to the @a range. * @@ -1292,16 +1424,16 @@ public: * that @a p will be updated in place. */ template<typename F, typename U = PAYLOAD> - self_type&blend(IPRange const&range, U const&color, F&&blender); + self_type& blend(IPRange const& range, U const& color, F&& blender); template<typename F, typename U = PAYLOAD> - self_type&blend(IP4Range const&range, U const&color, F&&blender) { + self_type& blend(IP4Range const& range, U const& color, F&& blender) { _ip4.blend(range, color, blender); return *this; } template<typename F, typename U = PAYLOAD> - self_type&blend(IP6Range const&range, U const&color, F&&blender) { + self_type& blend(IP6Range const& range, U const& color, F&& blender) { _ip6.blend(range, color, blender); return *this; } @@ -1311,7 +1443,7 @@ public: * @param addr Address to find. * @return The payload if any, @c nullptr if the address is not in the space. */ - PAYLOAD *find(IP4Addr const&addr) { + PAYLOAD *find(IP4Addr const& addr) { return _ip4.find(addr); } @@ -1320,7 +1452,7 @@ public: * @param addr Address to find. * @return The payload if any, @c nullptr if the address is not in the space. */ - PAYLOAD *find(IP6Addr const&addr) { + PAYLOAD *find(IP6Addr const& addr) { return _ip6.find(addr); } @@ -1329,7 +1461,7 @@ public: * @param addr Address to find. * @return The payload if any, @c nullptr if the address is not in the space. */ - PAYLOAD *find(IPAddr const&addr) { + PAYLOAD *find(IPAddr const& addr) { if (addr.is_ip4()) { return _ip4.find(IP4Addr{addr}); } else if (addr.is_ip6()) { @@ -1368,12 +1500,12 @@ public: /// Pre-increment. /// Move to the next element in the list. /// @return The iterator. - self_type&operator++(); + self_type& operator++(); /// Pre-decrement. /// Move to the previous element in the list. /// @return The iterator. - self_type&operator--(); + self_type& operator--(); /// Post-increment. /// Move to the next element in the list. @@ -1387,17 +1519,17 @@ public: /// Dereference. /// @return A reference to the referent. - value_type const&operator*() const; + value_type const& operator*() const; /// Dereference. /// @return A pointer to the referent. value_type const *operator->() const; /// Equality - bool operator==(self_type const&that) const; + bool operator==(self_type const& that) const; /// Inequality - bool operator!=(self_type const&that) const; + bool operator!=(self_type const& that) const; protected: // These are stored non-const to make implementing @c iterator easier. This class provides the @@ -1421,8 +1553,8 @@ public: * * In practice, both iterators should be either the beginning or ending iterator for the subspace. */ - const_iterator(typename IP4Space::iterator const&iter4 - , typename IP6Space::iterator const&iter6); + const_iterator(typename IP4Space::iterator const& iter4 + , typename IP6Space::iterator const& iter6); }; /** Iterator. @@ -1450,12 +1582,12 @@ public: /// Pre-increment. /// Move to the next element in the list. /// @return The iterator. - self_type&operator++(); + self_type& operator++(); /// Pre-decrement. /// Move to the previous element in the list. /// @return The iterator. - self_type&operator--(); + self_type& operator--(); /// Post-increment. /// Move to the next element in the list. @@ -1477,7 +1609,7 @@ public: /// Dereference. /// @return A reference to the referent. - value_type const&operator*() const; + value_type const& operator*() const; /// Dereference. /// @return A pointer to the referent. @@ -1503,8 +1635,8 @@ protected: }; template<typename PAYLOAD> -IPSpace<PAYLOAD>::const_iterator::const_iterator(typename IP4Space::iterator const&iter4 - , typename IP6Space::iterator const&iter6) +IPSpace<PAYLOAD>::const_iterator::const_iterator(typename IP4Space::iterator const& iter4 + , typename IP6Space::iterator const& iter6) : _iter_4(iter4), _iter_6(iter6) { if (_iter_4.has_next()) { new(&_value) value_type{_iter_4->range(), _iter_4->payload()}; @@ -1581,13 +1713,13 @@ auto IPSpace<PAYLOAD>::const_iterator::operator->() const -> value_type const * template<typename PAYLOAD> bool -IPSpace<PAYLOAD>::const_iterator::operator==(self_type const&that) const { +IPSpace<PAYLOAD>::const_iterator::operator==(self_type const& that) const { return _iter_4 == that._iter_4 && _iter_6 == that._iter_6; } template<typename PAYLOAD> bool -IPSpace<PAYLOAD>::const_iterator::operator!=(self_type const&that) const { +IPSpace<PAYLOAD>::const_iterator::operator!=(self_type const& that) const { return _iter_4 != that._iter_4 || _iter_6 != that._iter_6; } @@ -1620,17 +1752,17 @@ inline constexpr IPAddr::raw_addr_type::raw_addr_type() : _ip4(INADDR_ANY) {} inline IPAddr::IPAddr(in_addr_t addr) : _family(AF_INET), _addr(addr) {} -inline IPAddr::IPAddr(in6_addr const&addr) : _family(AF_INET6), _addr(addr) {} +inline IPAddr::IPAddr(in6_addr const& addr) : _family(AF_INET6), _addr(addr) {} inline IPAddr::IPAddr(sockaddr const *addr) { this->assign(addr); } -inline IPAddr::IPAddr(IPEndpoint const&addr) { +inline IPAddr::IPAddr(IPEndpoint const& addr) { this->assign(&addr.sa); } -inline IPAddr::IPAddr(string_view const&text) { +inline IPAddr::IPAddr(string_view const& text) { this->load(text); } @@ -1642,14 +1774,14 @@ IPAddr::operator=(in_addr_t addr) { } inline IPAddr& -IPAddr::operator=(in6_addr const&addr) { +IPAddr::operator=(in6_addr const& addr) { _family = AF_INET6; _addr._ip6 = addr; return *this; } inline IPAddr& -IPAddr::operator=(IPEndpoint const&addr) { +IPAddr::operator=(IPEndpoint const& addr) { return this->assign(&addr.sa); } @@ -1674,7 +1806,7 @@ IPAddr::is_ip6() const { } inline bool -IPAddr::isCompatibleWith(self_type const&that) { +IPAddr::isCompatibleWith(self_type const& that) { return this->is_valid() && _family == that._family; } @@ -1685,7 +1817,7 @@ IPAddr::is_loopback() const { } inline bool -operator==(IPAddr const&lhs, IPAddr const&rhs) { +operator==(IPAddr const& lhs, IPAddr const& rhs) { if (lhs._family != rhs._family) { return false; } @@ -1699,7 +1831,7 @@ operator==(IPAddr const&lhs, IPAddr const&rhs) { } inline bool -operator!=(IPAddr const&lhs, IPAddr const&rhs) { +operator!=(IPAddr const& lhs, IPAddr const& rhs) { return !(lhs == rhs); } @@ -1711,7 +1843,7 @@ IPAddr::assign(in_addr_t addr) { } inline IPAddr& -IPAddr::assign(in6_addr const&addr) { +IPAddr::assign(in6_addr const& addr) { _family = AF_INET6; _addr._ip6 = addr; return *this; @@ -1751,72 +1883,66 @@ IPAddr::invalidate() { } // Associated operators. -bool operator==(IPAddr const&lhs, sockaddr const *rhs); +bool operator==(IPAddr const& lhs, sockaddr const *rhs); inline bool -operator==(sockaddr const *lhs, IPAddr const&rhs) { +operator==(sockaddr const *lhs, IPAddr const& rhs) { return rhs == lhs; } inline bool -operator!=(IPAddr const&lhs, sockaddr const *rhs) { +operator!=(IPAddr const& lhs, sockaddr const *rhs) { return !(lhs == rhs); } inline bool -operator!=(sockaddr const *lhs, IPAddr const&rhs) { +operator!=(sockaddr const *lhs, IPAddr const& rhs) { return !(rhs == lhs); } inline bool -operator==(IPAddr const&lhs, IPEndpoint const&rhs) { +operator==(IPAddr const& lhs, IPEndpoint const& rhs) { return lhs == &rhs.sa; } inline bool -operator==(IPEndpoint const&lhs, IPAddr const&rhs) { +operator==(IPEndpoint const& lhs, IPAddr const& rhs) { return &lhs.sa == rhs; } inline bool -operator!=(IPAddr const&lhs, IPEndpoint const&rhs) { +operator!=(IPAddr const& lhs, IPEndpoint const& rhs) { return !(lhs == &rhs.sa); } inline bool -operator!=(IPEndpoint const&lhs, IPAddr const&rhs) { +operator!=(IPEndpoint const& lhs, IPAddr const& rhs) { return !(rhs == &lhs.sa); } inline bool -operator<(IPAddr const&lhs, IPAddr const&rhs) { +operator<(IPAddr const& lhs, IPAddr const& rhs) { return -1 == lhs.cmp(rhs); } inline bool -operator>=(IPAddr const&lhs, IPAddr const&rhs) { +operator>=(IPAddr const& lhs, IPAddr const& rhs) { return lhs.cmp(rhs) >= 0; } inline bool -operator>(IPAddr const&lhs, IPAddr const&rhs) { +operator>(IPAddr const& lhs, IPAddr const& rhs) { return 1 == lhs.cmp(rhs); } inline bool -operator<=(IPAddr const&lhs, IPAddr const&rhs) { +operator<=(IPAddr const& lhs, IPAddr const& rhs) { return lhs.cmp(rhs) <= 0; } -inline in_addr_t -IPAddr::network_ip4() const { - return _addr._ip4.network_order(); -} +inline IP4Addr const& IPAddr::ip4() const { return _addr._ip4; } -inline in6_addr -IPAddr::network_ip6() const { - return _addr._ip6.network_order(); -} +inline IP6Addr const& IPAddr::ip6() const { return _addr._ip6; } /// ------------------------------------------------------------------------------------ @@ -1824,7 +1950,7 @@ inline IPEndpoint::IPEndpoint() { sa.sa_family = AF_UNSPEC; } -inline IPEndpoint::IPEndpoint(IPAddr const&addr) { +inline IPEndpoint::IPEndpoint(IPAddr const& addr) { this->assign(addr); } @@ -1845,7 +1971,7 @@ IPEndpoint::is_valid() const { } inline IPEndpoint& -IPEndpoint::operator=(self_type const&that) { +IPEndpoint::operator=(self_type const& that) { self_type::assign(&sa, &that.sa); return *this; } @@ -1916,31 +2042,31 @@ IPEndpoint::host_order_port(sockaddr const *sa) { inline constexpr IP4Addr::IP4Addr(in_addr_t addr) : _addr(addr) {} -inline IP4Addr::IP4Addr(std::string_view const&text) { +inline IP4Addr::IP4Addr(std::string_view const& text) { if (!this->load(text)) { _addr = INADDR_ANY; } } -inline IP4Addr::IP4Addr(IPAddr const&addr) : _addr( +inline IP4Addr::IP4Addr(IPAddr const& addr) : _addr( addr._family == AF_INET ? addr._addr._ip4._addr : INADDR_ANY) {} -inline IP4Addr&IP4Addr::operator<<=(unsigned n) { +inline IP4Addr& IP4Addr::operator<<=(unsigned n) { _addr <<= n; return *this; } -inline IP4Addr&IP4Addr::operator>>=(unsigned n) { +inline IP4Addr& IP4Addr::operator>>=(unsigned n) { _addr >>= n; return *this; } -inline IP4Addr&IP4Addr::operator&=(self_type const&that) { +inline IP4Addr& IP4Addr::operator&=(self_type const& that) { _addr &= that._addr; return *this; } -inline IP4Addr&IP4Addr::operator|=(self_type const&that) { +inline IP4Addr& IP4Addr::operator|=(self_type const& that) { _addr |= that._addr; return *this; } @@ -1971,36 +2097,36 @@ IP4Addr::operator=(in_addr_t ip) -> self_type& { return *this; } -inline bool operator==(IP4Addr const&lhs, IP4Addr const&rhs) { +inline bool operator==(IP4Addr const& lhs, IP4Addr const& rhs) { return lhs._addr == rhs._addr; } -inline bool operator!=(IP4Addr const&lhs, IP4Addr const&rhs) { +inline bool operator!=(IP4Addr const& lhs, IP4Addr const& rhs) { return lhs._addr != rhs._addr; } -inline bool operator<(IP4Addr const&lhs, IP4Addr const&rhs) { +inline bool operator<(IP4Addr const& lhs, IP4Addr const& rhs) { return lhs._addr < rhs._addr; } -inline bool operator<=(IP4Addr const&lhs, IP4Addr const&rhs) { +inline bool operator<=(IP4Addr const& lhs, IP4Addr const& rhs) { return lhs._addr <= rhs._addr; } -inline bool operator>(IP4Addr const&lhs, IP4Addr const&rhs) { +inline bool operator>(IP4Addr const& lhs, IP4Addr const& rhs) { return rhs < lhs; } -inline bool operator>=(IP4Addr const&lhs, IP4Addr const&rhs) { +inline bool operator>=(IP4Addr const& lhs, IP4Addr const& rhs) { return rhs <= lhs; } -inline IP4Addr&IP4Addr::operator&=(IPMask const&mask) { +inline IP4Addr& IP4Addr::operator&=(IPMask const& mask) { _addr &= mask.as_ip4()._addr; return *this; } -inline IP4Addr&IP4Addr::operator|=(IPMask const&mask) { +inline IP4Addr& IP4Addr::operator|=(IPMask const& mask) { _addr |= ~(mask.as_ip4()._addr); return *this; } @@ -2012,19 +2138,19 @@ constexpr in_addr_t IP4Addr::reorder(in_addr_t src) { // --- -inline IP6Addr::IP6Addr(in6_addr const&addr) { +inline IP6Addr::IP6Addr(in6_addr const& addr) { *this = addr; } -inline IP6Addr::IP6Addr(std::string_view const&text) { +inline IP6Addr::IP6Addr(std::string_view const& text) { if (!this->load(text)) { this->clear(); } } -inline IP6Addr::IP6Addr(IPAddr const&addr) : _addr{addr._addr._ip6._addr} {} +inline IP6Addr::IP6Addr(IPAddr const& addr) : _addr{addr._addr._ip6._addr} {} -inline in6_addr&IP6Addr::copy_to(in6_addr&addr) const { +inline in6_addr& IP6Addr::copy_to(in6_addr& addr) const { self_type::reorder(addr, _addr._raw); return addr; } @@ -2034,7 +2160,7 @@ inline in6_addr IP6Addr::network_order() const { return this->copy_to(zret); } -inline auto IP6Addr::operator=(in6_addr const&addr) -> self_type& { +inline auto IP6Addr::operator=(in6_addr const& addr) -> self_type& { self_type::reorder(_addr._raw, addr); return *this; } @@ -2068,35 +2194,35 @@ inline void IP6Addr::reorder(unsigned char dst[WORD_SIZE], unsigned char const s } } -inline bool operator==(IP6Addr const&lhs, IP6Addr const&rhs) { +inline bool operator==(IP6Addr const& lhs, IP6Addr const& rhs) { return lhs._addr._store[0] == rhs._addr._store[0] && lhs._addr._store[1] == rhs._addr._store[1]; } -inline bool operator!=(IP6Addr const&lhs, IP6Addr const&rhs) { +inline bool operator!=(IP6Addr const& lhs, IP6Addr const& rhs) { return lhs._addr._store[0] != rhs._addr._store[0] || lhs._addr._store[1] != rhs._addr._store[1]; } -inline bool operator<(IP6Addr const&lhs, IP6Addr const&rhs) { +inline bool operator<(IP6Addr const& lhs, IP6Addr const& rhs) { return lhs._addr._store[0] < rhs._addr._store[0] || (lhs._addr._store[0] == rhs._addr._store[0] && lhs._addr._store[1] < rhs._addr._store[1]); } -inline bool operator>(IP6Addr const&lhs, IP6Addr const&rhs) { +inline bool operator>(IP6Addr const& lhs, IP6Addr const& rhs) { return rhs < lhs; } -inline bool operator<=(IP6Addr const&lhs, IP6Addr const&rhs) { +inline bool operator<=(IP6Addr const& lhs, IP6Addr const& rhs) { return lhs._addr._store[0] < rhs._addr._store[0] || (lhs._addr._store[0] == rhs._addr._store[0] && lhs._addr._store[1] <= rhs._addr._store[1]); } -inline bool operator>=(IP6Addr const&lhs, IP6Addr const&rhs) { +inline bool operator>=(IP6Addr const& lhs, IP6Addr const& rhs) { return rhs <= lhs; } -inline IP6Addr&IP6Addr::operator&=(IPMask const&mask) { +inline IP6Addr& IP6Addr::operator&=(IPMask const& mask) { if (mask._cidr < WORD_WIDTH) { _addr._store[MSW] &= (~word_type{0} << (WORD_WIDTH - mask._cidr)); _addr._store[LSW] = 0; @@ -2106,7 +2232,7 @@ inline IP6Addr&IP6Addr::operator&=(IPMask const&mask) { return *this; } -inline IP6Addr&IP6Addr::operator|=(IPMask const&mask) { +inline IP6Addr& IP6Addr::operator|=(IPMask const& mask) { if (mask._cidr < WORD_WIDTH) { _addr._store[MSW] |= (~word_type{0} >> mask._cidr); _addr._store[LSW] = ~word_type{0}; @@ -2118,41 +2244,41 @@ inline IP6Addr&IP6Addr::operator|=(IPMask const&mask) { // Disambiguating comparisons. -inline bool operator==(IPAddr const&lhs, IP4Addr const&rhs) { +inline bool operator==(IPAddr const& lhs, IP4Addr const& rhs) { return lhs.is_ip4() && static_cast<IP4Addr const&>(lhs) == rhs; } -inline bool operator!=(IPAddr const&lhs, IP4Addr const&rhs) { +inline bool operator!=(IPAddr const& lhs, IP4Addr const& rhs) { return !lhs.is_ip4() || static_cast<IP4Addr const&>(lhs) != rhs; } -inline bool operator==(IP4Addr const&lhs, IPAddr const&rhs) { +inline bool operator==(IP4Addr const& lhs, IPAddr const& rhs) { return rhs.is_ip4() && lhs == static_cast<IP4Addr const&>(rhs); } -inline bool operator!=(IP4Addr const&lhs, IPAddr const&rhs) { +inline bool operator!=(IP4Addr const& lhs, IPAddr const& rhs) { return !rhs.is_ip4() || lhs != static_cast<IP4Addr const&>(rhs); } -inline bool operator==(IPAddr const&lhs, IP6Addr const&rhs) { +inline bool operator==(IPAddr const& lhs, IP6Addr const& rhs) { return lhs.is_ip6() && static_cast<IP6Addr const&>(lhs) == rhs; } -inline bool operator!=(IPAddr const&lhs, IP6Addr const&rhs) { +inline bool operator!=(IPAddr const& lhs, IP6Addr const& rhs) { return !lhs.is_ip6() || static_cast<IP6Addr const&>(lhs) != rhs; } -inline bool operator==(IP6Addr const&lhs, IPAddr const&rhs) { +inline bool operator==(IP6Addr const& lhs, IPAddr const& rhs) { return rhs.is_ip6() && lhs == static_cast<IP6Addr const&>(rhs); } -inline bool operator!=(IP6Addr const&lhs, IPAddr const&rhs) { +inline bool operator!=(IP6Addr const& lhs, IPAddr const& rhs) { return !rhs.is_ip6() || lhs != static_cast<IP6Addr const&>(rhs); } // +++ IPRange +++ -inline IP4Range::IP4Range(string_view const&text) { +inline IP4Range::IP4Range(string_view const& text) { this->load(text); } @@ -2160,7 +2286,7 @@ inline auto IP4Range::networks() const -> NetSource { return {NetSource{*this}}; } -inline IP6Range::IP6Range(string_view const&text) { +inline IP6Range::IP6Range(string_view const& text) { this->load(text); } @@ -2168,18 +2294,22 @@ inline auto IP6Range::networks() const -> NetSource { return {NetSource{*this}}; } -inline IPRange::IPRange(IP4Range const&range) : _family(AF_INET) { +inline IPRange::IPRange(IP4Range const& range) : _family(AF_INET) { _range._ip4 = range; } -inline IPRange::IPRange(IP6Range const&range) : _family(AF_INET6) { +inline IPRange::IPRange(IP6Range const& range) : _family(AF_INET6) { _range._ip6 = range; } -inline IPRange::IPRange(string_view const&text) { +inline IPRange::IPRange(string_view const& text) { this->load(text); } +inline auto IPRange::networks() const -> NetSource { + return {NetSource{*this}}; +} + inline bool IPRange::is(sa_family_t family) const { return family == _family; } // +++ IPMask +++ @@ -2193,17 +2323,17 @@ inline auto IPMask::width() const -> raw_type { } inline bool -operator==(IPMask const&lhs, IPMask const&rhs) { +operator==(IPMask const& lhs, IPMask const& rhs) { return lhs.width() == rhs.width(); } inline bool -operator!=(IPMask const&lhs, IPMask const&rhs) { +operator!=(IPMask const& lhs, IPMask const& rhs) { return lhs.width() != rhs.width(); } inline bool -operator<(IPMask const&lhs, IPMask const&rhs) { +operator<(IPMask const& lhs, IPMask const& rhs) { return lhs.width() < rhs.width(); } @@ -2218,27 +2348,27 @@ inline IP4Addr IPMask::as_ip4() const { // +++ mixed operators +++ -inline IP4Addr operator&(IP4Addr const&addr, IPMask const&mask) { +inline IP4Addr operator&(IP4Addr const& addr, IPMask const& mask) { return IP4Addr{addr} &= mask; } -inline IP4Addr operator|(IP4Addr const&addr, IPMask const&mask) { +inline IP4Addr operator|(IP4Addr const& addr, IPMask const& mask) { return IP4Addr{addr} |= mask; } -inline IP6Addr operator&(IP6Addr const&addr, IPMask const&mask) { +inline IP6Addr operator&(IP6Addr const& addr, IPMask const& mask) { return IP6Addr{addr} &= mask; } -inline IP6Addr operator|(IP6Addr const&addr, IPMask const&mask) { +inline IP6Addr operator|(IP6Addr const& addr, IPMask const& mask) { return IP6Addr{addr} |= mask; } -inline IPAddr operator&(IPAddr const&addr, IPMask const&mask) { +inline IPAddr operator&(IPAddr const& addr, IPMask const& mask) { return IPAddr{addr} &= mask; } -inline IPAddr operator|(IPAddr const&addr, IPMask const&mask) { +inline IPAddr operator|(IPAddr const& addr, IPMask const& mask) { return IPAddr{addr} |= mask; } @@ -2246,7 +2376,7 @@ inline IPAddr operator|(IPAddr const&addr, IPMask const&mask) { inline IP4Net::IP4Net(swoc::IP4Addr addr, swoc::IPMask mask) : _addr(addr & mask), _mask(mask) {} -inline IPMask const&IP4Net::mask() const { return _mask; } +inline IPMask const& IP4Net::mask() const { return _mask; } inline bool IP4Net::is_valid() const { return _mask.is_valid(); } @@ -2256,15 +2386,15 @@ inline IP4Addr IP4Net::upper_bound() const { return _addr | _mask; } inline IP4Range IP4Net::as_range() const { return {this->lower_bound(), this->upper_bound()}; } -inline bool IP4Net::operator==(self_type const&that) const { +inline bool IP4Net::operator==(self_type const& that) const { return _mask == that._mask && _addr == that._addr; } -inline bool IP4Net::operator!=(self_type const&that) const { +inline bool IP4Net::operator!=(self_type const& that) const { return _mask != that._mask || _addr != that._addr; } -inline IP4Net::self_type&IP4Net::assign(IP4Addr const&addr, IPMask const&mask) { +inline IP4Net::self_type& IP4Net::assign(IP4Addr const& addr, IPMask const& mask) { _addr = addr & mask; _mask = mask; return *this; @@ -2272,7 +2402,7 @@ inline IP4Net::self_type&IP4Net::assign(IP4Addr const&addr, IPMask const&mask) { inline IP6Net::IP6Net(swoc::IP6Addr addr, swoc::IPMask mask) : _addr(addr & mask), _mask(mask) {} -inline IPMask const&IP6Net::mask() const { return _mask; } +inline IPMask const& IP6Net::mask() const { return _mask; } inline bool IP6Net::is_valid() const { return _mask.is_valid(); } @@ -2282,43 +2412,65 @@ inline IP6Addr IP6Net::upper_bound() const { return _addr | _mask; } inline IP6Range IP6Net::as_range() const { return {this->lower_bound(), this->upper_bound()}; } -inline bool IP6Net::operator==(self_type const&that) const { +inline bool IP6Net::operator==(self_type const& that) const { return _mask == that._mask && _addr == that._addr; } -inline bool IP6Net::operator!=(self_type const&that) const { +inline bool IP6Net::operator!=(self_type const& that) const { return _mask != that._mask || _addr != that._addr; } -inline IP6Net::self_type&IP6Net::assign(IP6Addr const&addr, IPMask const&mask) { +inline IP6Net::self_type& IP6Net::assign(IP6Addr const& addr, IPMask const& mask) { _addr = addr & mask; _mask = mask; return *this; } -inline IPNet::IPNet(IPAddr const&addr, IPMask const&mask) : _addr(addr & mask), _mask(mask) {} +inline IPNet::IPNet(IPAddr const& addr, IPMask const& mask) : _addr(addr & mask), _mask(mask) {} -inline IPNet::operator IPAddr const&() const { - return _addr; +inline IPNet::IPNet(TextView text) { this->load(text); } + +inline bool IPNet::is_valid() const { return _mask.is_valid(); } + +inline IPAddr IPNet::lower_bound() const { return _addr; } + +inline IPAddr IPNet::upper_bound() const { return _addr | _mask; } + +inline IPMask::raw_type IPNet::width() const { return _mask.width(); } + +inline IPMask const& IPNet::mask() const { return _mask; } + +inline IPRange IPNet::as_range() const { return {this->lower_bound(), this->upper_bound()};} + +inline IPNet::self_type& IPNet::assign(IPAddr const& addr, IPMask const& mask) { + _addr = addr & mask; + _mask = mask; + return *this; } -inline IPNet::operator IPMask const&() const { - return _mask; +inline bool IPNet::operator==(IPNet::self_type const& that) const { + return _mask == that._mask && _addr == that._addr; } -inline IPAddr const& -IPNet::addr() const { - return _addr; +inline bool IPNet::operator!=(IPNet::self_type const& that) const { + return _mask != that._mask || _addr != that._addr; } -inline IPMask const& -IPNet::mask() const { - return _mask; +inline bool operator == (IPNet const& lhs, IP4Net const& rhs) { + return lhs.is_ip4() && lhs.ip4() == rhs; } -inline IPAddr IPNet::lower_bound() const { return _addr; } +inline bool operator == (IP4Net const& lhs, IPNet const& rhs) { + return rhs.is_ip4() && rhs.ip4() == lhs; +} -inline IPAddr IPNet::upper_bound() const { return _addr | _mask; } +inline bool operator == (IPNet const& lhs, IP6Net const& rhs) { + return lhs.is_ip6() && lhs.ip6() == rhs; +} + +inline bool operator == (IP6Net const& lhs, IPNet const& rhs) { + return rhs.is_ip6() && rhs.ip6() == lhs; +} // +++ Range -> Network classes +++ @@ -2343,22 +2495,22 @@ inline IPMask IP4Range::NetSource::mask() const { return IPMask{_cidr}; } inline auto IP4Range::NetSource::operator->() -> self_type * { return this; } -inline IP4Addr const&IP4Range::NetSource::addr() const { return _range.min(); } +inline IP4Addr const& IP4Range::NetSource::addr() const { return _range.min(); } -inline bool IP4Range::NetSource::operator==(IP4Range::NetSource::self_type const&that) { +inline bool IP4Range::NetSource::operator==(IP4Range::NetSource::self_type const& that) const { return ((_cidr == that._cidr) && (_range == that._range)) || (_range.empty() && that._range.empty()); } -inline bool IP4Range::NetSource::operator!=(IP4Range::NetSource::self_type const&that) { +inline bool IP4Range::NetSource::operator!=(IP4Range::NetSource::self_type const& that) const { return !(*this == that); } -inline IP6Range::NetSource::iterator IP6Range::NetSource::begin() const { +inline auto IP6Range::NetSource::begin() const -> iterator { return *this; } -inline IP6Range::NetSource::iterator IP6Range::NetSource::end() const { +inline auto IP6Range::NetSource::end() const -> iterator { return self_type{range_type{}}; } @@ -2368,49 +2520,120 @@ inline IP6Net IP6Range::NetSource::operator*() const { inline auto IP6Range::NetSource::operator->() -> self_type * { return this; } -inline bool IP6Range::NetSource::is_valid(IPMask const&mask) { +inline bool IP6Range::NetSource::is_valid(IPMask const& mask) { return ((_range.min() & mask) == _range.min()) && ((_range.min() | mask) <= _range.max()); } -inline bool IP6Range::NetSource::operator==(IP6Range::NetSource::self_type const&that) { +inline bool IP6Range::NetSource::operator==(IP6Range::NetSource::self_type const& that) const { return ((_mask == that._mask) && (_range == that._range)) || (_range.empty() && that._range.empty()); } -inline bool IP6Range::NetSource::operator!=(IP6Range::NetSource::self_type const&that) { +inline bool IP6Range::NetSource::operator!=(IP6Range::NetSource::self_type const& that) const { + return !(*this == that); +} + +inline IPRange::NetSource::NetSource(IPRange::NetSource::range_type const& range) { + if (range.is_ip4()) { + new (&_ip4) decltype(_ip4)(range.ip4()); + _family = AF_INET; + } else if (range.is_ip6()) { + new (&_ip6) decltype(_ip6)(range.ip6()); + _family = AF_INET6; + } +} + +inline auto IPRange::NetSource::begin() const -> iterator { + return *this; +} + +inline auto IPRange::NetSource::end() const -> iterator { + return AF_INET == _family ? self_type{IP4Range{}} + : AF_INET6 == _family ? self_type{IP6Range{}} + : self_type{IPRange{}}; +} + +inline IPAddr IPRange::NetSource::addr() const { + if (AF_INET == _family) { + return _ip4.addr(); + } else if (AF_INET6 == _family) { + return _ip6.addr(); + } + return {}; +} + +inline IPMask IPRange::NetSource::mask() const { + if (AF_INET == _family) { + return _ip4.mask(); + } else if (AF_INET6 == _family) { + return _ip6.mask(); + } + return {}; +} + +inline IPNet IPRange::NetSource::operator*() const { + return { this->addr(), this->mask() }; +} + +inline auto IPRange::NetSource::operator++() -> self_type & { + if (AF_INET == _family) { + ++_ip4; + } else if (AF_INET6 == _family) { + ++_ip6; + } + return *this; +} + +inline auto IPRange::NetSource::operator->() -> self_type * { return this; } + +inline bool IPRange::NetSource::operator==(self_type const& that) const { + if (_family != that._family) { + return false; + } + if (AF_INET == _family) { + return _ip4 == that._ip4; + } else if (AF_INET6 == _family) { + return _ip6 == that._ip6; + } else if (AF_UNSPEC == _family) { + return true; + } + return false; +} + +inline bool IPRange::NetSource::operator!=(self_type const& that) const { return !(*this == that); } // --- IPSpace template<typename PAYLOAD> -auto IPSpace<PAYLOAD>::mark(IPRange const&range, PAYLOAD const&payload) -> self_type& { +auto IPSpace<PAYLOAD>::mark(IPRange const& range, PAYLOAD const& payload) -> self_type& { if (range.is(AF_INET)) { - _ip4.mark(range, payload); + _ip4.mark(range.ip4(), payload); } else if (range.is(AF_INET6)) { - _ip6.mark(range, payload); + _ip6.mark(range.ip6(), payload); } return *this; } template<typename PAYLOAD> -auto IPSpace<PAYLOAD>::fill(IPRange const&range, PAYLOAD const&payload) -> self_type& { +auto IPSpace<PAYLOAD>::fill(IPRange const& range, PAYLOAD const& payload) -> self_type& { if (range.is(AF_INET6)) { - _ip6.fill(range, payload); + _ip6.fill(range.ip6(), payload); } else if (range.is(AF_INET)) { - _ip4.fill(range, payload); + _ip4.fill(range.ip4(), payload); } return *this; } template<typename PAYLOAD> template<typename F, typename U> -auto IPSpace<PAYLOAD>::blend(IPRange const&range, U const&color, F&&blender) -> self_type& { +auto IPSpace<PAYLOAD>::blend(IPRange const& range, U const& color, F&& blender) -> self_type& { if (range.is(AF_INET)) { - _ip4.blend(range, color, blender); + _ip4.blend(range.ip4(), color, blender); } else if (range.is(AF_INET6)) { - _ip6.blend(range, color, blender); + _ip6.blend(range.ip6(), color, blender); } return *this; } @@ -2437,6 +2660,7 @@ auto IPSpace<PAYLOAD>::end() const -> const_iterator { namespace std { +// -- Tuple support for IP4Net -- template<> class tuple_size<swoc::IP4Net> : public std::integral_constant<size_t, 2> { }; @@ -2454,6 +2678,7 @@ public: using type = swoc::IPMask; }; +// -- Tuple support for IP6Net -- template<> class tuple_size<swoc::IP6Net> : public std::integral_constant<size_t, 2> { }; @@ -2471,12 +2696,30 @@ public: using type = swoc::IPMask; }; +// -- Tuple support for IPNet -- +template<> class tuple_size<swoc::IPNet> : public std::integral_constant<size_t, 2> { +}; + +template<size_t IDX> class tuple_element<IDX, swoc::IPNet> { + static_assert("swoc::IPNet tuple index out of range"); +}; + +template<> class tuple_element<0, swoc::IPNet> { +public: + using type = swoc::IPAddr; +}; + +template<> class tuple_element<1, swoc::IPNet> { +public: + using type = swoc::IPMask; +}; + } // namespace std namespace swoc { template<size_t IDX> typename std::tuple_element<IDX, IP4Net>::type -get(swoc::IP4Net const&net) { +get(swoc::IP4Net const& net) { if constexpr (IDX == 0) { return net.lower_bound(); } else if constexpr (IDX == 1) { @@ -2485,7 +2728,16 @@ get(swoc::IP4Net const&net) { } template<size_t IDX> typename std::tuple_element<IDX, IP6Net>::type -get(swoc::IP6Net const&net) { +get(swoc::IP6Net const& net) { + if constexpr (IDX == 0) { + return net.lower_bound(); + } else if constexpr (IDX == 1) { + return net.mask(); + } +} + +template<size_t IDX> typename std::tuple_element<IDX, IPNet>::type +get(swoc::IPNet const& net) { if constexpr (IDX == 0) { return net.lower_bound(); } else if constexpr (IDX == 1) { diff --git a/swoc++/src/bw_ip_format.cc b/swoc++/src/bw_ip_format.cc index e0e8b58..9da2a77 100644 --- a/swoc++/src/bw_ip_format.cc +++ b/swoc++/src/bw_ip_format.cc @@ -280,7 +280,7 @@ bwformat(BufferWriter &w, Spec const &spec, IPAddr const &addr) if (addr.is_ip4()) { swoc::bwformat(w, spec, static_cast<IP4Addr const&>(addr)); } else if (addr.is_ip6()) { - swoc::bwformat(w, spec, addr.network_ip6()); + swoc::bwformat(w, spec, addr.ip6().network_order()); } else { w.print("*Not IP address [{}]*", addr.family()); } @@ -317,9 +317,9 @@ bwformat(BufferWriter & w, Spec const& spec, IP6Range const& range) { BufferWriter & bwformat(BufferWriter & w, Spec const& spec, IPRange const& range) { return range.is(AF_INET) - ? bwformat(w, spec, static_cast<IP4Range const&>(range)) + ? bwformat(w, spec, range.ip4()) : range.is(AF_INET6) - ? bwformat(w, spec, static_cast<IP6Range const&>(range)) + ? bwformat(w, spec, range.ip6()) : w.write("*-*"_tv) ; } diff --git a/swoc++/src/swoc_ip.cc b/swoc++/src/swoc_ip.cc index c53a0b0..59075a6 100644 --- a/swoc++/src/swoc_ip.cc +++ b/swoc++/src/swoc_ip.cc @@ -81,7 +81,7 @@ IPEndpoint::assign(IPAddr const&src, in_port_t port) { case AF_INET: { memset(&sa4, 0, sizeof sa4); sa4.sin_family = AF_INET; - sa4.sin_addr.s_addr = src.network_ip4(); + sa4.sin_addr.s_addr = src.ip4().network_order(); sa4.sin_port = port; Set_Sockaddr_Len(&sa4); } @@ -89,7 +89,7 @@ IPEndpoint::assign(IPAddr const&src, in_port_t port) { case AF_INET6: { memset(&sa6, 0, sizeof sa6); sa6.sin6_family = AF_INET6; - sa6.sin6_addr = src.network_ip6(); + sa6.sin6_addr = src.ip6().network_order(); sa6.sin6_port = port; Set_Sockaddr_Len(&sa6); } @@ -98,19 +98,6 @@ IPEndpoint::assign(IPAddr const&src, in_port_t port) { return *this; } -IPAddr& -IPAddr::assign(sockaddr const *addr) { - if (addr) { - switch (addr->sa_family) { - case AF_INET:return this->assign(reinterpret_cast<sockaddr_in const *>(addr)); - case AF_INET6:return this->assign(reinterpret_cast<sockaddr_in6 const *>(addr)); - default:break; - } - } - _family = AF_UNSPEC; - return *this; -} - bool IPEndpoint::tokenize(std::string_view str, std::string_view *addr, std::string_view *port , std::string_view *rest) { @@ -466,6 +453,37 @@ IPAddr::load(const std::string_view&text) { return this->is_valid(); } +IPAddr& +IPAddr::assign(sockaddr const *addr) { + if (addr) { + switch (addr->sa_family) { + case AF_INET:return this->assign(reinterpret_cast<sockaddr_in const *>(addr)); + case AF_INET6:return this->assign(reinterpret_cast<sockaddr_in6 const *>(addr)); + default:break; + } + } + _family = AF_UNSPEC; + return *this; +} + +IPAddr::self_type& IPAddr::operator&=(IPMask const& mask) { + if (_family == AF_INET) { + _addr._ip4 &= mask; + } else if (_family == AF_INET6) { + _addr._ip6 &= mask; + } + return *this; +} + +IPAddr::self_type& IPAddr::operator|=(IPMask const& mask) { + if (_family == AF_INET) { + _addr._ip4 |= mask; + } else if (_family == AF_INET6) { + _addr._ip6 |= mask; + } + return *this; +} + #if 0 bool operator==(IPAddr const &lhs, sockaddr const *rhs) @@ -660,6 +678,24 @@ bool IP6Net::load(TextView text) { return false; } +bool IPNet::load(TextView text) { + auto mask_text = text.split_suffix_at('/'); + if (!mask_text.empty()) { + IPMask mask; + if (mask.load(mask_text)) { + if (IP6Addr addr; addr.load(text)) { // load the address + this->assign(addr, mask); + return true; + } else if (IP4Addr addr; addr.load(text)) { + this->assign(addr, mask); + return true; + } + } + } + this->clear(); + return false; +} + // +++ IP4Range +++ IP4Range::IP4Range(swoc::IP4Addr const&addr, swoc::IPMask const&mask) { @@ -808,6 +844,16 @@ bool IP6Range::load(std::string_view text) { return false; } +IPRange::IPRange(IPAddr const& min, IPAddr const& max) { + if (min.is_ip4() && max.is_ip4()) { + _range._ip4.assign(min.ip4(), max.ip4()); + _family = AF_INET; + } else if (min.is_ip6() && max.is_ip6()) { + _range._ip6.assign(min.ip6(), max.ip6()); + _family = AF_INET6; + } +} + bool IPRange::load(std::string_view const&text) { static const string_view CHARS{".:"}; auto idx = text.find_first_of(CHARS); diff --git a/unit_tests/test_ip.cc b/unit_tests/test_ip.cc index 51f40d6..39616aa 100644 --- a/unit_tests/test_ip.cc +++ b/unit_tests/test_ip.cc @@ -304,7 +304,15 @@ TEST_CASE("IP ranges and networks", "[libswoc][ip][net][range]") { , "10.33.45.76/32"_tv }}; auto r4_net = r_4_nets.begin(); - for (auto const&net : r_4.networks()) { + for (auto const &net : r_4.networks()) { + REQUIRE(r4_net != r_4_nets.end()); + CHECK(*r4_net == net); + ++r4_net; + } + + // Let's try that again, with @c IPRange instead. + r4_net = r_4_nets.begin(); + for (auto const& net : IPRange{r_4}.networks()) { REQUIRE(r4_net != r_4_nets.end()); CHECK(*r4_net == net); ++r4_net; @@ -506,6 +514,14 @@ TEST_CASE("IP ranges and networks", "[libswoc][ip][net][range]") { CHECK(*r5_net == swoc::IP6Net{addr, mask}); ++r5_net; } + + // Try it again, using @c IPRange. + r5_net = r_5_nets.begin(); + for ( auto const&[addr, mask] : IPRange{r_5}.networks()) { + REQUIRE(r5_net != r_5_nets.end()); + CHECK(*r5_net == swoc::IPNet{addr, mask}); + ++r5_net; + } } TEST_CASE("IP Space Int", "[libswoc][ip][ipspace]") { @@ -575,7 +591,7 @@ TEST_CASE("IP Space Int", "[libswoc][ip][ipspace]") { REQUIRE(payload != nullptr); REQUIRE(*payload == 0x5); - space.blend({r_2.min(), r_3.max()}, 0x6, BF); + space.blend(IPRange{r_2.min(), r_3.max()}, 0x6, BF); REQUIRE(space.count() == 4); std::array<std::tuple<TextView, int>, 9> ranges = {
