LCOV - code coverage report
Current view: top level - cpp2ethernet/include/ip - IPAddress.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 124 124 100.0 %
Date: 2025-08-28 06:39:11 Functions: 15 15 100.0 %

          Line data    Source code
       1             : // Copyright 2025 Accenture.
       2             : 
       3             : #pragma once
       4             : 
       5             : #include <etl/span.h>
       6             : #include <util/estd/big_endian.h>
       7             : 
       8             : #include <platform/estdint.h>
       9             : 
      10             : #include <cstring>
      11             : 
      12             : namespace ip
      13             : {
      14             : struct IPAddress
      15             : {
      16             :     enum Family
      17             :     {
      18             :         FAMILY_UNKNOWN = 0U, ///< \deprecated FAMILY_UNKNOWN will be removed in future
      19             :         IPV4           = 4U,
      20             :         IPV6           = 6U
      21             :     };
      22             : 
      23             :     static constexpr uint8_t IP4LENGTH = 4U;
      24             :     static constexpr uint8_t IP6LENGTH = 16U;
      25             : 
      26             : #ifndef OPENBSW_NO_IPV6
      27             :     static constexpr size_t MAX_IP_LENGTH = IP6LENGTH;
      28             : #else
      29             :     static constexpr size_t MAX_IP_LENGTH = IP4LENGTH;
      30             : #endif
      31             : 
      32             :     ::estd::be_uint32_t raw[MAX_IP_LENGTH / sizeof(uint32_t)];
      33             : };
      34             : 
      35             : constexpr IPAddress make_ip4(uint32_t ip4addr);
      36             : 
      37             : IPAddress make_ip4(::etl::span<uint8_t const> const& ip4addr);
      38             : 
      39             : #ifndef OPENBSW_NO_IPV6
      40             : constexpr IPAddress make_ip6(uint32_t addr0, uint32_t addr1, uint32_t addr2, uint32_t addr3);
      41             : 
      42             : constexpr IPAddress make_ip6(uint32_t const ip6addr[IPAddress::IP6LENGTH / sizeof(uint32_t)]);
      43             : 
      44             : IPAddress make_ip6(::etl::span<uint8_t const> const& ip6addr);
      45             : #endif
      46             : 
      47             : /** \deprecated  Use one of the other make_ip4 factory functions instead. */
      48             : constexpr IPAddress make_ip4(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3);
      49             : 
      50             : ::etl::span<uint8_t const> packed(IPAddress const& ipAddr);
      51             : 
      52             : uint32_t ip4_to_u32(IPAddress const& ipAddr);
      53             : 
      54             : #ifndef OPENBSW_NO_IPV6
      55             : uint32_t ip6_to_u32(IPAddress const& ipAddr, size_t offset);
      56             : #endif
      57             : 
      58             : bool isUnspecified(IPAddress const& ipAddr);
      59             : 
      60             : /** \deprecated  Test (addressFamilyOf(ipAddr) != IPAddress::IPV4) instead. */
      61             : bool isIp4Address(IPAddress const& ipAddr);
      62             : 
      63             : /** \deprecated  Test (addressFamilyOf(ipAddr) != IPAddress::IPV6) instead.  */
      64             : bool isIp6Address(IPAddress const& ipAddr);
      65             : 
      66             : bool isMulticastAddress(IPAddress const& ipAddr);
      67             : 
      68             : bool isLinkLocalAddress(IPAddress const& ipAddr);
      69             : 
      70             : bool isLoopbackAddress(IPAddress const& ipAddr);
      71             : 
      72             : bool isNetworkLocal(IPAddress const& ipAddr1, IPAddress const& ipAddr2, uint8_t networkId);
      73             : 
      74             : IPAddress::Family addressFamilyOf(IPAddress const& ipAddr);
      75             : 
      76             : bool operator==(IPAddress const& ip1, IPAddress const& ip2);
      77             : 
      78             : bool operator!=(IPAddress const& ip1, IPAddress const& ip2);
      79             : 
      80             : /** \deprecated  Implement your own comparator logic if needed */
      81             : struct IPAddressCompareLess
      82             : {
      83             :     bool operator()(IPAddress const& ipAddr1, IPAddress const& ipAddr2) const;
      84             : };
      85             : 
      86             : namespace internal
      87             : {
      88             : static constexpr size_t RAW_IP4_IDX
      89             :     = IPAddress::MAX_IP_LENGTH / static_cast<uint8_t>(sizeof(uint32_t)) - 1U;
      90             : } // namespace internal
      91             : 
      92          15 : inline constexpr IPAddress make_ip4(uint32_t const ip4addr)
      93             : {
      94          15 :     return {{
      95             : #ifndef OPENBSW_NO_IPV6
      96             :         {{0x00U, 0x00U, 0x00U, 0x00U}},
      97             :         {{0x00U, 0x00U, 0x00U, 0x00U}},
      98             :         {{0x00U, 0x00U, 0xFFU, 0xFFU}},
      99             : #endif
     100          15 :         {{static_cast<uint8_t>(ip4addr >> 24),
     101          15 :           static_cast<uint8_t>(ip4addr >> 16),
     102          15 :           static_cast<uint8_t>(ip4addr >> 8),
     103          15 :           static_cast<uint8_t>(ip4addr)}}}};
     104             : }
     105             : 
     106             : inline constexpr IPAddress
     107         254 : make_ip4(uint8_t const byte0, uint8_t const byte1, uint8_t const byte2, uint8_t const byte3)
     108             : {
     109         254 :     return {{
     110             : #ifndef OPENBSW_NO_IPV6
     111             :         {{0x00U, 0x00U, 0x00U, 0x00U}},
     112             :         {{0x00U, 0x00U, 0x00U, 0x00U}},
     113             :         {{0x00U, 0x00U, 0xFFU, 0xFFU}},
     114             : #endif
     115         254 :         {{byte0, byte1, byte2, byte3}}}};
     116             : }
     117             : 
     118           6 : inline IPAddress make_ip4(::etl::span<uint8_t const> const& ip4addr)
     119             : {
     120           6 :     estd_assert(ip4addr.size() == IPAddress::IP4LENGTH);
     121             : 
     122             :     // clang-format off
     123           5 :     IPAddress const newAddr = {{
     124             : #ifndef OPENBSW_NO_IPV6
     125             :         {{0x00U, 0x00U, 0x00U, 0x00U}},
     126             :         {{0x00U, 0x00U, 0x00U, 0x00U}},
     127             :         {{0x00U, 0x00U, 0xFFU, 0xFFU}},
     128             : #endif
     129           5 :         {{ip4addr[0U], ip4addr[1U], ip4addr[2U], ip4addr[3U]}}
     130           5 :     }};
     131             :     // clang-format on
     132             : 
     133           5 :     return newAddr;
     134             : }
     135             : 
     136             : #ifndef OPENBSW_NO_IPV6
     137             : inline constexpr IPAddress
     138             : make_ip6(uint32_t const addr0, uint32_t const addr1, uint32_t const addr2, uint32_t const addr3)
     139             : {
     140             :     return {
     141             :         {{{static_cast<uint8_t>(addr0 >> 24),
     142             :            static_cast<uint8_t>(addr0 >> 16),
     143             :            static_cast<uint8_t>(addr0 >> 8),
     144             :            static_cast<uint8_t>(addr0)}},
     145             :          {{static_cast<uint8_t>(addr1 >> 24),
     146             :            static_cast<uint8_t>(addr1 >> 16),
     147             :            static_cast<uint8_t>(addr1 >> 8),
     148             :            static_cast<uint8_t>(addr1)}},
     149             :          {{static_cast<uint8_t>(addr2 >> 24),
     150             :            static_cast<uint8_t>(addr2 >> 16),
     151             :            static_cast<uint8_t>(addr2 >> 8),
     152             :            static_cast<uint8_t>(addr2)}},
     153             :          {{static_cast<uint8_t>(addr3 >> 24),
     154             :            static_cast<uint8_t>(addr3 >> 16),
     155             :            static_cast<uint8_t>(addr3 >> 8),
     156             :            static_cast<uint8_t>(addr3)}}}};
     157             : }
     158             : 
     159          16 : inline constexpr IPAddress make_ip6(uint32_t const ip6addr[IPAddress::IP6LENGTH / sizeof(uint32_t)])
     160             : {
     161          16 :     return {
     162          16 :         {{{static_cast<uint8_t>(ip6addr[0] >> 24),
     163          16 :            static_cast<uint8_t>(ip6addr[0] >> 16),
     164          16 :            static_cast<uint8_t>(ip6addr[0] >> 8),
     165             :            static_cast<uint8_t>(ip6addr[0])}},
     166          16 :          {{static_cast<uint8_t>(ip6addr[1] >> 24),
     167          16 :            static_cast<uint8_t>(ip6addr[1] >> 16),
     168          16 :            static_cast<uint8_t>(ip6addr[1] >> 8),
     169             :            static_cast<uint8_t>(ip6addr[1])}},
     170          16 :          {{static_cast<uint8_t>(ip6addr[2] >> 24),
     171          16 :            static_cast<uint8_t>(ip6addr[2] >> 16),
     172          16 :            static_cast<uint8_t>(ip6addr[2] >> 8),
     173             :            static_cast<uint8_t>(ip6addr[2])}},
     174          16 :          {{static_cast<uint8_t>(ip6addr[3] >> 24),
     175          16 :            static_cast<uint8_t>(ip6addr[3] >> 16),
     176          16 :            static_cast<uint8_t>(ip6addr[3] >> 8),
     177          16 :            static_cast<uint8_t>(ip6addr[3])}}}};
     178             : }
     179             : 
     180           9 : inline IPAddress make_ip6(::etl::span<uint8_t const> const& ip6addr)
     181             : {
     182           9 :     estd_assert(ip6addr.size() == IPAddress::IP6LENGTH);
     183             : 
     184           8 :     IPAddress newAddr;
     185           8 :     (void)memcpy(newAddr.raw[0U].bytes, ip6addr.data(), IPAddress::IP6LENGTH);
     186           8 :     return newAddr;
     187             : }
     188             : #endif
     189             : 
     190           2 : inline ::etl::span<uint8_t const, IPAddress::IP4LENGTH> ip4_bytes(IPAddress const& ipAddr)
     191             : {
     192           2 :     return ::etl::span<uint8_t const, IPAddress::IP4LENGTH>(
     193           1 :         &ipAddr.raw[internal::RAW_IP4_IDX].bytes[0], IPAddress::IP4LENGTH);
     194             : }
     195             : 
     196           2 : inline ::etl::span<uint8_t const, IPAddress::IP6LENGTH> ip6_bytes(IPAddress const& ipAddr)
     197             : {
     198           2 :     return ::etl::span<uint8_t const, IPAddress::IP6LENGTH>(
     199           1 :         &ipAddr.raw[0].bytes[0], IPAddress::IP6LENGTH);
     200             : }
     201             : 
     202           2 : inline ::etl::span<uint8_t const> packed(IPAddress const& ipAddr)
     203             : {
     204           2 :     if (addressFamilyOf(ipAddr) == IPAddress::IPV4)
     205             :     {
     206           1 :         return ip4_bytes(ipAddr);
     207             :     }
     208           1 :     return ip6_bytes(ipAddr);
     209             : }
     210             : 
     211           8 : inline uint32_t ip4_to_u32(IPAddress const& ipAddr) { return ipAddr.raw[internal::RAW_IP4_IDX]; }
     212             : 
     213             : #ifndef OPENBSW_NO_IPV6
     214           5 : inline uint32_t ip6_to_u32(IPAddress const& ipAddr, size_t const offset)
     215             : {
     216           5 :     estd_assert(offset <= 3U);
     217           4 :     return ipAddr.raw[offset];
     218             : }
     219             : #endif
     220             : 
     221         343 : inline bool isUnspecified(IPAddress const& ipAddr)
     222             : {
     223         343 :     if (addressFamilyOf(ipAddr) == IPAddress::IPV4)
     224             :     {
     225          77 :         return (ipAddr.raw[internal::RAW_IP4_IDX] == 0U);
     226             :     }
     227             : 
     228         281 :     for (auto const i : ipAddr.raw)
     229             :     {
     230         278 :         if (0U != i)
     231             :         {
     232         343 :             return false;
     233             :         }
     234             :     }
     235             :     return true;
     236             : }
     237             : 
     238           2 : inline bool isIp4Address(IPAddress const& ipAddr)
     239             : {
     240           2 :     return (IPAddress::IPV4 == addressFamilyOf(ipAddr));
     241             : }
     242             : 
     243           2 : inline bool isIp6Address(IPAddress const& ipAddr)
     244             : {
     245           2 :     return (IPAddress::IPV6 == addressFamilyOf(ipAddr));
     246             : }
     247             : 
     248           4 : inline bool isMulticastAddress(IPAddress const& ipAddr)
     249             : {
     250           4 :     IPAddress::Family const family = addressFamilyOf(ipAddr);
     251             : 
     252           4 :     if (IPAddress::IPV6 == family)
     253             :     {
     254           2 :         uint8_t const IP6_MULTICAST_PREFIX = 0xFFU;
     255           2 :         return (ipAddr.raw[0U].bytes[0U] == IP6_MULTICAST_PREFIX);
     256             :     }
     257             : 
     258             :     // IPAddress::IPv4
     259           2 :     uint32_t const IP4_MULTICAST_MASK   = 0xF0000000U;
     260           2 :     uint32_t const IP4_MULTICAST_PREFIX = 0xE0000000U;
     261           2 :     uint32_t const addressPrefix        = (ipAddr.raw[internal::RAW_IP4_IDX] & IP4_MULTICAST_MASK);
     262           2 :     return (addressPrefix == IP4_MULTICAST_PREFIX);
     263             : }
     264             : 
     265           6 : inline bool isLinkLocalAddress(IPAddress const& ipAddr)
     266             : {
     267           6 :     IPAddress::Family const family = addressFamilyOf(ipAddr);
     268             : 
     269           6 :     if (IPAddress::IPV6 == family)
     270             :     {
     271           3 :         uint32_t const IP6_LINK_LOCAL_MASK   = 0xFFC00000U;
     272           3 :         uint32_t const IP6_LINK_LOCAL_PREFIX = 0xFE800000U;
     273           3 :         uint32_t const addressPrefix         = (ipAddr.raw[0U] & IP6_LINK_LOCAL_MASK);
     274           3 :         return (addressPrefix == IP6_LINK_LOCAL_PREFIX);
     275             :     }
     276             : 
     277             :     // IPAddress::IPv4
     278           3 :     uint32_t const IP4_LINK_LOCAL_MASK   = 0xFFFF0000U;
     279           3 :     uint32_t const IP4_LINK_LOCAL_PREFIX = 0xA9FE0000U;
     280           3 :     uint32_t const addressPrefix = (ipAddr.raw[internal::RAW_IP4_IDX] & IP4_LINK_LOCAL_MASK);
     281           3 :     return (addressPrefix == IP4_LINK_LOCAL_PREFIX);
     282             : }
     283             : 
     284         259 : inline bool isLoopbackAddress(IPAddress const& ipAddr)
     285             : {
     286         259 :     IPAddress::Family const family = addressFamilyOf(ipAddr);
     287             : 
     288         259 :     if (IPAddress::IPV6 == family)
     289             :     {
     290           3 :         return (ipAddr.raw[0U] == 0U) && (ipAddr.raw[1U] == 0U) && (ipAddr.raw[2U] == 0U)
     291           6 :                && (ipAddr.raw[3U] == 1U);
     292             :     }
     293             : 
     294             :     // IPAddress::IPv4
     295         256 :     uint32_t const IP4_LOOPBACK_PREFIX = 0x7F000000U;
     296         256 :     uint32_t const IP4_LOOPBACK_MASK   = 0xFFFFFF00U;
     297         256 :     uint32_t const addressPrefix       = (ipAddr.raw[internal::RAW_IP4_IDX] & IP4_LOOPBACK_MASK);
     298         256 :     bool const hasLastByteSet          = (ipAddr.raw[internal::RAW_IP4_IDX].bytes[3U] != 0U);
     299         256 :     return ((addressPrefix == IP4_LOOPBACK_PREFIX) && hasLastByteSet);
     300             : }
     301             : 
     302             : inline bool
     303         172 : isNetworkLocal(IPAddress const& ipAddr1, IPAddress const& ipAddr2, uint8_t const networkId)
     304             : {
     305         172 :     IPAddress::Family const family1 = addressFamilyOf(ipAddr1);
     306         172 :     IPAddress::Family const family2 = addressFamilyOf(ipAddr2);
     307             : 
     308         172 :     if ((family1 != family2) || isUnspecified(ipAddr1) || isUnspecified(ipAddr2))
     309             :     {
     310             :         return false; // invalid IPs or IPv4/6 mix
     311             :     }
     312             : 
     313         167 :     if (networkId == 0U)
     314             :     {
     315             :         return true; // don't care
     316             :     }
     317             : 
     318         163 :     size_t const ip4PrefixLengthInBits = internal::RAW_IP4_IDX * sizeof(uint32_t) * 8U;
     319         326 :     size_t const netMaskBits
     320         163 :         = (IPAddress::IPV6 == family1) ? networkId : (networkId + ip4PrefixLengthInBits);
     321             : 
     322         163 :     if (netMaskBits > (IPAddress::MAX_IP_LENGTH * 8U))
     323             :     {
     324             :         return false; // invalid networkId
     325             :     }
     326             : 
     327         161 :     size_t const netMaskFullBytes = netMaskBits / 8U;
     328         161 :     if (0 != memcmp(&ipAddr1.raw[0U], &ipAddr2.raw[0U], netMaskFullBytes))
     329             :     {
     330             :         return false;
     331             :     }
     332             : 
     333         160 :     uint8_t const mask = ~(0xFFU >> (netMaskBits % 8U));
     334         160 :     if (mask == 0U)
     335             :     {
     336             :         return true;
     337             :     }
     338             : 
     339         140 :     return (
     340         140 :         (ipAddr1.raw[netMaskFullBytes / 4].bytes[netMaskFullBytes % 4] & mask)
     341         140 :         == (ipAddr2.raw[netMaskFullBytes / 4].bytes[netMaskFullBytes % 4] & mask));
     342             : }
     343             : 
     344        1000 : inline IPAddress::Family addressFamilyOf(IPAddress const& ipAddr)
     345             : {
     346             : #ifndef OPENBSW_NO_IPV6
     347        1000 :     uint32_t const IP4_PREFIX[] = {0U, 0U, 0xFFFFU};
     348             : 
     349        1000 :     bool const isIp4MappedIp6 = (IP4_PREFIX[0U] == ipAddr.raw[0U])
     350         451 :                                 && (IP4_PREFIX[1U] == ipAddr.raw[1U])
     351        1451 :                                 && (IP4_PREFIX[2U] == ipAddr.raw[2U]);
     352             : 
     353        1000 :     return isIp4MappedIp6 ? IPAddress::IPV4 : IPAddress::IPV6;
     354             : #else
     355             :     return IPAddress::IPV4;
     356             : #endif
     357             : }
     358             : 
     359          55 : inline bool operator==(IPAddress const& ip1, IPAddress const& ip2)
     360             : {
     361             : #ifndef OPENBSW_NO_IPV6
     362          55 :     return (
     363          55 :         (ip1.raw[3] == ip2.raw[3]) && (ip1.raw[2] == ip2.raw[2]) && (ip1.raw[1] == ip2.raw[1])
     364         106 :         && (ip1.raw[0] == ip2.raw[0]));
     365             : #else
     366             :     return (ip1.raw[0] == ip2.raw[0]);
     367             : #endif
     368             : }
     369             : 
     370           1 : inline bool operator!=(IPAddress const& ip1, IPAddress const& ip2) { return !(ip1 == ip2); }
     371             : 
     372             : inline bool
     373           9 : IPAddressCompareLess::operator()(IPAddress const& ipAddr1, IPAddress const& ipAddr2) const
     374             : {
     375           9 :     IPAddress::Family const family1 = addressFamilyOf(ipAddr1);
     376           9 :     IPAddress::Family const family2 = addressFamilyOf(ipAddr2);
     377             : 
     378           9 :     if (family1 != family2)
     379             :     {
     380           2 :         return (static_cast<uint8_t>(family1) < static_cast<uint8_t>(family2));
     381             :     }
     382             : 
     383          24 :     for (uint8_t i = 0U; i < (IPAddress::MAX_IP_LENGTH / sizeof(uint32_t)); ++i)
     384             :     {
     385          22 :         if (ipAddr1.raw[i] != ipAddr2.raw[i])
     386             :         {
     387           5 :             return ipAddr1.raw[i] < ipAddr2.raw[i];
     388             :         }
     389             :     }
     390             : 
     391             :     return false;
     392             : }
     393             : 
     394             : } // namespace ip

Generated by: LCOV version 1.14