Skip to content

Commit

Permalink
IP: fix minor errors, expand network categorization utilities.
Browse files Browse the repository at this point in the history
  • Loading branch information
SolidWallOfCode committed Dec 13, 2023
1 parent 5cb7e29 commit e5a9536
Show file tree
Hide file tree
Showing 6 changed files with 264 additions and 51 deletions.
3 changes: 3 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions code/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ set(HEADER_FILES
include/swoc/IntrusiveDList.h
include/swoc/IntrusiveHashMap.h
include/swoc/swoc_ip.h
include/swoc/swoc_ip_util.h
include/swoc/IPEndpoint.h
include/swoc/IPAddr.h
include/swoc/IPSrv.h
Expand All @@ -36,7 +37,7 @@ set(HEADER_FILES
include/swoc/TextView.h
include/swoc/swoc_file.h
include/swoc/swoc_meta.h
include/swoc/string_view.h
include/swoc/string_view_util.h
include/swoc/Vectray.h
)

Expand All @@ -58,7 +59,7 @@ set(CC_FILES
src/string_view_util.cc
)

add_library(libswoc SHARED ${CC_FILES})
add_library(libswoc SHARED ${CC_FILES} ${HEADER_FILES})
set_target_properties(libswoc PROPERTIES OUTPUT_NAME swoc-${LIBSWOC_VERSION})
if (CMAKE_COMPILER_IS_GNUCXX)
target_compile_options(libswoc PRIVATE -fPIC -Wall -Wextra -Werror -Wnon-virtual-dtor -Wpedantic -Wshadow)
Expand Down
37 changes: 9 additions & 28 deletions code/include/swoc/IPAddr.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@

#pragma once

#include <netinet/in.h>
#include <sys/socket.h>

#include <cstddef>

#include "swoc/swoc_version.h"
#include "swoc/swoc_meta.h"
#include "swoc/MemSpan.h"
#include "swoc/swoc_ip_util.h"

namespace swoc { inline namespace SWOC_VERSION_NS {

Expand Down Expand Up @@ -901,16 +899,12 @@ IP4Addr::is_multicast() const {

inline bool
IP4Addr::is_link_local() const {
return (_addr & 0xFFFF0000) == 0xA9FE0000; // 169.254.0.0/16
return ip::is_link_local_host_order(_addr);
}

inline bool
IP4Addr::is_private() const {
return (((_addr & 0xFF000000) == 0x0A000000) || // 10.0.0.0/8
((_addr & 0xFFC00000) == 0x64400000) || // 100.64.0.0/10
((_addr & 0xFFF00000) == 0xAC100000) || // 172.16.0.0/12
((_addr & 0xFFFF0000) == 0xC0A80000) // 192.168.0.0/16
);
return ip::is_private_host_order(_addr);
}

inline uint8_t
Expand Down Expand Up @@ -1389,14 +1383,12 @@ inline IPAddr::operator IP6Addr() const {

inline bool
IPAddr::operator==(self_type const &that) const {
switch (_family) {
case AF_INET:
return that._family == AF_INET && _addr._ip4 == that._addr._ip4;
case AF_INET6:
return that._family == AF_INET6 && _addr._ip6 == that._addr._ip6;
default:
return !that.is_valid();
}
return _family == that.family() &&
(
( this->is_ip4() && _addr._ip4 == that._addr._ip4 ) ||
( this->is_ip6() && _addr._ip6 == that._addr._ip6 ) ||
_family == AF_UNSPEC
);
}

inline bool
Expand Down Expand Up @@ -1491,14 +1483,3 @@ template <> struct hash<swoc::IPAddr> {
};

} // namespace std

// These have to be global namespace, unfortunately.
inline bool
operator==(in6_addr const& lhs, in6_addr const& rhs) {
return 0 == memcmp(&lhs, &rhs, sizeof(in6_addr));
}

inline bool
operator!=(in6_addr const& lhs, in6_addr const& rhs) {
return 0 != memcmp(&lhs, &rhs, sizeof(in6_addr));
}
71 changes: 65 additions & 6 deletions code/include/swoc/IPEndpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@

#pragma once

#include <netinet/in.h>
#include <sys/socket.h>

#include <stdexcept>

#include "swoc/swoc_version.h"
#include "swoc/MemSpan.h"
#include "swoc/TextView.h"
#include "swoc/string_view_util.h"
#include "swoc/swoc_ip_util.h"

namespace swoc { inline namespace SWOC_VERSION_NS {

Expand Down Expand Up @@ -198,6 +196,24 @@ union IPEndpoint {
/// @return @c true if this is a loopback address, @c false if not.
bool is_loopback() const;

/// @return @c true if the address is in the link local network.
bool is_link_local() const;

/// @return @c true if the address is in the link local network.
static bool is_link_local(sockaddr const * sa);

/// @return @c true if the address is private.
bool is_private() const;

/// @return @c true if the address is private.
static bool is_private(sockaddr const * sa);

/// @return @c true if the address is multicast.
bool is_multicast() const;

/// @return @c true if the address is multicast.
static bool is_multicast(sockaddr const * sa);

/** Port in network order.
*
* @return The port or 0 if not a valid IP address.
Expand All @@ -217,8 +233,9 @@ union IPEndpoint {
static bool is_valid(sockaddr const *sa);

/// Direct access to port.
/// @return Refernec to the port in the socket address.
/// @return Reference to the port in the socket address.
/// @note If @a sa is not a valid IP address an assertion is thrown.
/// @note The raw port is in network order.
/// @a is_valid
static in_port_t &port(sockaddr *sa);

Expand All @@ -237,10 +254,16 @@ union IPEndpoint {
static in_port_t host_order_port(sockaddr const *sa);

/// Automatic conversion to @c sockaddr.
operator sockaddr *() { return &sa; }
operator sockaddr *();

/// Automatic conversion to @c sockaddr.
operator sockaddr const *() const { return &sa; }
operator sockaddr const *() const;

/// Size of the sockaddr variant based on the family.
size_t sa_size() const;

/// Size of the sockaddr based on the family.
static size_t sa_size(sockaddr const* sa);

/** The address as a byte sequence.
*
Expand Down Expand Up @@ -401,4 +424,40 @@ IPEndpoint::raw_addr() const {
return {};
}

inline bool IPEndpoint::is_link_local() const {
return swoc::ip::is_link_local(&sa);
}

inline bool IPEndpoint::is_link_local(sockaddr const * sa) {
return swoc::ip::is_link_local(sa);
}

inline bool IPEndpoint::is_private() const {
return swoc::ip::is_private(&sa);
}

inline bool IPEndpoint::is_private(sockaddr const * sa) {
return swoc::ip::is_private(sa);
}

inline bool IPEndpoint::is_multicast() const {
return swoc::ip::is_multicast(&sa);
}

inline bool IPEndpoint::is_multicast(sockaddr const * sa) {
return swoc::ip::is_multicast(sa);
}

inline IPEndpoint::operator sockaddr *() { return &sa; }

inline IPEndpoint::operator sockaddr const *() const { return &sa; }

inline size_t IPEndpoint::sa_size() const {
return sa_size(&sa);
}

inline size_t IPEndpoint::sa_size(sockaddr const* sa) {
return AF_INET == sa->sa_family ? sizeof(sockaddr_in) : AF_INET6 == sa->sa_family ? sizeof(sockaddr_in6) : sizeof(sockaddr);
}

}} // namespace swoc::SWOC_VERSION_NS
148 changes: 148 additions & 0 deletions code/include/swoc/swoc_ip_util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Network Geographics 2014
/** @file
Shared utilities for IP address classes.
*/

#pragma once
#include <netinet/in.h>

#include "swoc/swoc_version.h"

// These have to be global namespace, unfortunately.
inline bool
operator==(in6_addr const& lhs, in6_addr const& rhs) {
return 0 == memcmp(&lhs, &rhs, sizeof(in6_addr));
}

inline bool
operator!=(in6_addr const& lhs, in6_addr const& rhs) {
return 0 != memcmp(&lhs, &rhs, sizeof(in6_addr));
}

namespace swoc { inline namespace SWOC_VERSION_NS {

/// Internal IP address utilities.
namespace ip {

inline bool is_loopback_host_order(in_addr_t addr) {
return (addr & 0xFF000000) == 0x7F000000;
}

inline bool is_link_local_host_order(in_addr_t addr) {
return (addr & 0xFFFF0000) == 0xA9FE0000; // 169.254.0.0/16
}

inline bool is_multicast_host_order(in_addr_t addr) {
return IN_MULTICAST(addr);
}

inline bool is_private_host_order(in_addr_t addr) {
return (((addr & 0xFF000000) == 0x0A000000) || // 10.0.0.0/8
((addr & 0xFFC00000) == 0x64400000) || // 100.64.0.0/10
((addr & 0xFFF00000) == 0xAC100000) || // 172.16.0.0/12
((addr & 0xFFFF0000) == 0xC0A80000) // 192.168.0.0/16
);
}

// There really is no "host order" for IPv6, so only the network order utilities are defined.
// @c IP6Addr uses an idiosyncratic ordering for performance, not really useful to expose to
// clients.

inline bool is_loopback_network_order(in6_addr const& addr) {
return addr == in6addr_loopback;
}

inline bool is_multicast_network_order(in6_addr const& addr) {
return addr.s6_addr[0] == 0xFF;
}

inline bool is_link_local_network_order(in6_addr const& addr) {
return addr.s6_addr[0] == 0xFE && (addr.s6_addr[1] & 0xC0) == 0x80; // fe80::/10
}

inline bool is_private_network_order(in6_addr const& addr) {
return (addr.s6_addr[0] & 0xFE) == 0xFC; // fc00::/7
}

#if BYTE_ORDER == LITTLE_ENDIAN

inline bool is_loopback_network_order(in_addr_t addr) {
return (addr & 0xFF) == 0x7F;
}

inline bool is_private_network_order(in_addr_t addr) {
return (((addr & 0xFF) == 0x0A) || // 10.0.0.0/8
((addr & 0xC0FF) == 0x4064) || // 100.64.0.0/10
((addr & 0xF0FF) == 0x10AC) || // 172.16.0.0/12
((addr & 0xFFFF) == 0xA8C0) // 192.168.0.0/16
);
}

inline bool is_link_local_network_order(in_addr_t addr) {
return (addr & 0xFFFF) == 0xFEA9; // 169.254.0.0/16
}

inline bool is_multicast_network_order(in_addr_t addr) {
return (addr & 0xF0) == 0xE0;
}

#else

inline bool is_loopback_network_order(in_addr_t addr) {
return is_loopback_host_order(addr);
}

inline bool is_link_local_network_order(inaddr_t addr) {
return is_link_local_host_order(addr);
}

inline bool is_private_network_order(in_addr_t addr) {
return is_link_local_host_order(addr);
}

inline bool is_multicast_network_order(in_addr_t addr) {
return is_multicast_host_order(addr);
}

#endif

/** Check if the address in a socket address is a loopback address..
* @return @c true if so, @c false if not.
*/
inline bool is_loopback(sockaddr const * sa) {
return ( sa->sa_family == AF_INET && is_loopback_network_order(reinterpret_cast<sockaddr_in const *>(sa)->sin_addr.s_addr)) ||
( sa->sa_family == AF_INET6 && is_loopback_network_order(reinterpret_cast<sockaddr_in6 const *>(sa)->sin6_addr))
;
}

/** Check if the address in a socket address is multicast.
* @return @c true if so, @c false if not.
*/
inline bool is_multicast(sockaddr const * sa) {
return ( sa->sa_family == AF_INET && is_multicast_network_order(reinterpret_cast<sockaddr_in const *>(sa)->sin_addr.s_addr)) ||
( sa->sa_family == AF_INET6 && is_multicast_network_order(reinterpret_cast<sockaddr_in6 const *>(sa)->sin6_addr))
;
}

/** Check if the IP address in a socket address is link local.
* @return @c true if link local, @c false if not.
*/
inline bool is_link_local(sockaddr const* sa) {
return ( sa->sa_family == AF_INET && is_link_local_network_order(reinterpret_cast<sockaddr_in const *>(sa)->sin_addr.s_addr)) ||
( sa->sa_family == AF_INET6 && is_link_local_network_order(reinterpret_cast<sockaddr_in6 const *>(sa)->sin6_addr))
;
}

/** Check if the IP address in a socket address is private (non-routable)
* @return @c true if private, @c false if not.
*/
inline bool is_private(sockaddr const* sa) {
return ( sa->sa_family == AF_INET && is_private_network_order(reinterpret_cast<sockaddr_in const *>(sa)->sin_addr.s_addr)) ||
( sa->sa_family == AF_INET6 && is_private_network_order(reinterpret_cast<sockaddr_in6 const *>(sa)->sin6_addr))
;
}

} // hnamespace ip

}} // namespace swoc::SWOC_VERSION_NS
Loading

0 comments on commit e5a9536

Please sign in to comment.