LCOV - code coverage report
Current view: top level - root/contrail/src/contrail-common/base - address_util.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 152 229 66.4 %
Date: 2026-11-09 02:10:49 Functions: 17 19 89.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  * Copyright Contributors to the OpenSDN project
       4             :  */
       5             : #include "base/address_util.h"
       6             : 
       7             : #include <endian.h>
       8             : #include <boost/algorithm/string.hpp>
       9             : #include <boost/asio/io_service.hpp>
      10             : #include <boost/asio/ip/tcp.hpp>
      11             : #include <boost/asio/ip/host_name.hpp>
      12             : #include <boost/foreach.hpp>
      13             : 
      14             : /* Returns true if the given IPv4 address is member of the IPv4 subnet
      15             :  * indicated by IPv4 address and prefix length. Otherwise returns false.
      16             :  * We convert both the input IPv4 addresses to their subnet addresses and
      17             :  * then compare with each other to conclude whether the IPv4 address is
      18             :  * member of the subnet or not.
      19             :  */
      20       16932 : bool IsIp4SubnetMember(
      21             :     const Ip4Address &ip, const Ip4Address &prefix_ip, uint16_t plen) {
      22       16932 :     Ip4Address prefix = Address::GetIp4SubnetAddress(prefix_ip, plen);
      23       16932 :     return ((prefix.to_ulong() | ~(0xFFFFFFFF << (32 - plen))) ==
      24       16932 :             (ip.to_ulong() | ~(0xFFFFFFFF << (32 - plen))));
      25             : }
      26             : 
      27             : /* Returns true if the given IPv6 address is member of the IPv6 subnet
      28             :  * indicated by IPv6 address and prefix length. Otherwise returns false.
      29             :  */
      30       15191 : bool IsIp6SubnetMember(
      31             :     const Ip6Address &ip, const Ip6Address &subnet, uint8_t plen) {
      32       15191 :     Ip6Address mask = Address::GetIp6SubnetAddress(subnet, plen);
      33       15191 :     Ip6Address ip1 = Address::GetIp6SubnetAddress(ip, plen);
      34       30382 :     return (ip1 == mask);
      35             : }
      36             : 
      37             : /*
      38             :  * Returns the canonical hostname (FQDN)
      39             : */
      40             : 
      41          61 : std::string ResolveCanonicalName()
      42             : {
      43          61 :     boost::asio::io_context io_service;
      44          61 :     boost::system::error_code error;
      45          61 :     boost::asio::ip::tcp::resolver resolver (io_service);
      46         122 :     boost::asio::ip::tcp::resolver::query query(boost::asio::ip::host_name(),
      47         183 :         "", boost::asio::ip::resolver_query_base::canonical_name);
      48             :     boost::asio::ip::tcp::resolver::iterator iter =
      49         122 :         resolver.resolve (query,error), end;
      50          61 :     if (error) {
      51           0 :         return boost::asio::ip::host_name();
      52             :     }
      53          61 :     while (iter != end) {
      54          61 :         if (iter->host_name() != "") {
      55          61 :             return iter->host_name();
      56             :         }
      57           0 :         iter++;
      58             :     }
      59           0 :     return boost::asio::ip::host_name();
      60          61 : }
      61             : 
      62             : /*
      63             :  * Returns the canonical hostname (FQDN) by IPv4 address
      64             : */
      65       27098 : std::string ResolveCanonicalName(const std::string& ipv4)
      66             : {
      67       27098 :     if (boost::starts_with(ipv4, "127."))
      68       27098 :         return "localhost";
      69           0 :     boost::asio::ip::tcp::endpoint endpoint;
      70           0 :     boost::asio::io_context io_service;
      71             :     boost::asio::ip::address_v4 ip =
      72           0 :         boost::asio::ip::address_v4::from_string(ipv4);
      73           0 :     endpoint.address(ip);
      74           0 :     boost::asio::ip::tcp::resolver resolver(io_service);
      75             :     boost::asio::ip::tcp::resolver::iterator iter =
      76           0 :         resolver.resolve (endpoint), end;
      77           0 :     while (iter != end){
      78           0 :         if(iter->host_name() != ""){
      79           0 :             return iter->host_name();
      80             :         }
      81           0 :         iter++;
      82             :     }
      83           0 :     return boost::asio::ip::host_name();
      84           0 : }
      85             : 
      86             : /* This variant passes all tests
      87             :  * To be covered by more tests later
      88             :  * Returns the  canonical hostname (FQDN) by IPv6 address
      89             : */
      90           3 : std::string ResolveCanonicalNameIPv6(const std::string& ipv6)
      91             : {
      92           3 :     std::string loc_ip = ipv6;
      93           3 :     if (boost::starts_with(loc_ip, "::1"))
      94           3 :         return "localhost";
      95           0 :     unsigned int perc_pos = loc_ip.find("%");
      96             :     if (perc_pos != std::string::npos) {
      97           0 :         loc_ip = loc_ip.substr(0,perc_pos);
      98             :     }
      99           0 :     return loc_ip;
     100             : // Next code is incompatible with schema_transformer:
     101             : //    boost::asio::ip::tcp::endpoint endpoint;
     102             : //    boost::asio::io_context io_service;
     103             : //    boost::asio::ip::address_v6 ip =
     104             : //        boost::asio::ip::address_v6::from_string(loc_ip);
     105             : //    endpoint.address(ip);
     106             : //    boost::asio::ip::tcp::resolver resolver(io_service);
     107             : //    boost::asio::ip::tcp::resolver::iterator iter =
     108             : //        resolver.resolve (endpoint), end;
     109             : //    while (iter != end){
     110             : //        if(iter->host_name() != ""){
     111             : //            return iter->host_name();
     112             : //        }
     113             : //        iter++;
     114             : //    }
     115             : //    return boost::asio::ip::host_name();
     116           3 : }
     117             : 
     118             : /*
     119             :  * Returns boost::asio::ip::address if given string is either valid
     120             :  * IPv4, IPv6 or a resolvable FQDN
     121             : */
     122             : 
     123       15941 : IpAddress AddressFromString(
     124             :           const std::string &ip_address_str,
     125             :           boost::system::error_code *ec) {
     126             :     IpAddress addr =
     127       15941 :         boost::asio::ip::address::from_string(ip_address_str, *ec);
     128       15941 :     boost::system::error_code error_code = *ec;
     129       15941 :     if (error_code.value() != 0) {
     130         319 :         boost::asio::io_context io_service;
     131         319 :         std::string ip_string = GetHostIp(&io_service, ip_address_str);
     132         319 :         addr = boost::asio::ip::address::from_string(ip_string, *ec);
     133         319 :     }
     134       31882 :     return addr;
     135             : }
     136             : 
     137          23 : Ip4Address GetIp4SubnetBroadcastAddress(
     138             :               const Ip4Address &ip_prefix, uint16_t plen) {
     139          23 :     Ip4Address subnet(ip_prefix.to_ulong() | ~(0xFFFFFFFF << (32 - plen)));
     140          23 :     return subnet;
     141             : }
     142             : 
     143             : // Validate IPv4/IPv6 address string.
     144          11 : bool ValidateIPAddressString(std::string ip_address_str,
     145             :                              std::string *error_msg) {
     146          11 :     boost::system::error_code error;
     147          11 :     AddressFromString(ip_address_str, &error);
     148          11 :     if (error.value() != 0) {
     149           2 :        std::ostringstream out;
     150           2 :        out << "Invalid IP address: " << ip_address_str << std::endl;
     151           2 :        *error_msg = out.str();
     152           2 :        return false;
     153           2 :     }
     154           9 :     return true;
     155             : }
     156             : 
     157         330 : IpAddress PrefixToIpNetmask(uint32_t prefix_len) {
     158             :     uint32_t mask;
     159             : 
     160         330 :     if (prefix_len == 0) {
     161          12 :         mask = 0;
     162             :     } else {
     163         318 :         mask = (~((1 << (32 - prefix_len)) - 1));
     164             :     }
     165         330 :     return IpAddress(Ip4Address(mask));
     166             : }
     167             : 
     168           0 : uint32_t NetmaskToPrefix(uint32_t netmask) {
     169           0 :     uint32_t count = 0;
     170             : 
     171           0 :     while (netmask) {
     172           0 :         count++;
     173           0 :         netmask = (netmask - 1) & netmask;
     174             :     }
     175           0 :     return count;
     176             : }
     177             : 
     178          39 : IpAddress PrefixToIp6Netmask(uint32_t plen) {
     179          39 :     if (plen == 0) {
     180          38 :         return IpAddress(Ip6Address());
     181             :     }
     182             : 
     183           1 :     if (plen == 128) {
     184           1 :         boost::system::error_code ec;
     185             :         Ip6Address all_fs = Ip6Address::from_string
     186           1 :             ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", ec);
     187           1 :         return IpAddress(all_fs);
     188             :     }
     189             : 
     190             :     Ip6Address::bytes_type bytes;
     191             : 
     192           0 :     int index = (int) (plen / 8);
     193           0 :     int remain_mask = plen % 8;
     194             : 
     195           0 :     for (int i = 0; i < index; i++) {
     196           0 :         bytes.at(i) = 0xff;
     197             :     }
     198             : 
     199           0 :     switch (remain_mask) {
     200           0 :         case 0:
     201           0 :             bytes.at(index++) = 0;
     202           0 :             break;
     203           0 :         case 1:
     204           0 :             bytes.at(index++) = 0x80;
     205           0 :             break;
     206           0 :         case 2:
     207           0 :             bytes.at(index++) = 0xc0;
     208           0 :             break;
     209           0 :         case 3:
     210           0 :             bytes.at(index++) = 0xe0;
     211           0 :             break;
     212           0 :         case 4:
     213           0 :             bytes.at(index++) = 0xf0;
     214           0 :             break;
     215           0 :         case 5:
     216           0 :             bytes.at(index++) = 0xf8;
     217           0 :             break;
     218           0 :         case 6:
     219           0 :             bytes.at(index++) = 0xfc;
     220           0 :             break;
     221           0 :         case 7:
     222           0 :             bytes.at(index++) = 0xfe;
     223           0 :             break;
     224             :     }
     225             : 
     226           0 :     for (int i = index; i < 16; ++i) {
     227           0 :         bytes.at(i) = 0;
     228             :     }
     229             : 
     230           0 :     return IpAddress(Ip6Address(bytes));
     231             : }
     232             : 
     233             : // Validate a list of <ip-address>:<port> endpoints.
     234          13 : bool ValidateServerEndpoints(std::vector<std::string> list,
     235             :                              std::string *error_msg) {
     236          13 :     std::ostringstream out;
     237             : 
     238          47 :     BOOST_FOREACH(std::string endpoint, list) {
     239          19 :         std::vector<std::string> tokens;
     240          19 :         boost::split(tokens, endpoint, boost::is_any_of(":"));
     241          19 :         if (tokens.size() != 2) {
     242           1 :             out << "Invalid endpoint " << endpoint << std::endl;
     243           1 :             *error_msg = out.str();
     244           1 :             return false;
     245             :         }
     246             : 
     247          18 :         boost::system::error_code error;
     248          18 :         AddressFromString(tokens[0], &error);
     249             : 
     250          18 :         if (error) {
     251           1 :             out << "Invalid IP address: " << tokens[0] << std::endl;
     252           1 :             *error_msg = out.str();
     253           1 :             return false;
     254             :         }
     255             : 
     256          17 :         unsigned long port = strtoul(tokens[1].c_str(), NULL, 0);
     257          17 :         if (errno || port > 0xffFF) {
     258           0 :             out << "Invalid port : " << tokens[1];
     259           0 :             if (errno) {
     260           0 :                 out << " " << strerror(errno) << std::endl;
     261             :             }
     262           0 :             *error_msg = out.str();
     263           0 :             return false;
     264             :         }
     265          38 :     }
     266             : 
     267          11 :     return true;
     268          13 : }
     269             : 
     270             : // Return IP address string for a host if it is resolvable, empty string
     271             : // otherwise.
     272         463 : std::string GetHostIp(boost::asio::io_context *io_service,
     273             :                       const std::string &hostname) {
     274         463 :     boost::asio::ip::tcp::resolver::iterator iter, end;
     275         463 :     boost::system::error_code error;
     276         463 :     boost::asio::ip::tcp::resolver resolver(*io_service);
     277         926 :     boost::asio::ip::tcp::resolver::query query(hostname, "");
     278             : 
     279         463 :     std::string result;
     280             : 
     281         463 :     iter = resolver.resolve(query, error);
     282         463 :     if (error) {
     283          22 :         return result;
     284             :     }
     285             : 
     286         882 :     for (; iter != end; ++iter) {
     287         882 :         const boost::asio::ip::address &addr = iter->endpoint().address();
     288         882 :         if (addr.is_v6()) {
     289         441 :             boost::asio::ip::address_v6 addr6 = addr.to_v6();
     290         441 :             if (addr6.is_link_local()) {
     291         119 :                 continue;
     292             :             }
     293             :         }
     294         763 :         result = addr.to_string();
     295         763 :         if (addr.is_v4()) {
     296         441 :             return result;
     297             :         }
     298             :     }
     299           0 :     return result;
     300         463 : }
     301             : 
     302             : //
     303             : // Get VN name from routing instance
     304             : //
     305         336 : std::string GetVNFromRoutingInstance(const std::string &vn) {
     306         336 :     std::vector<std::string> tokens;
     307         336 :     boost::split(tokens, vn, boost::is_any_of(":"), boost::token_compress_on);
     308         336 :     if (tokens.size() < 3) return "";
     309           0 :     return tokens[0] + ":" + tokens[1] + ":" + tokens[2];
     310         336 : }
     311             : 
     312        7736 : void IpToU64(const IpAddress &sip, const IpAddress &dip,
     313             :              uint64_t *sip_u, uint64_t *sip_l,
     314             :              uint64_t *dip_u, uint64_t *dip_l) {
     315        7736 :     if (sip.is_v4()) {
     316        7582 :         *sip_l = htonl(sip.to_v4().to_ulong());
     317        7582 :         *sip_u = 0;
     318             :     } else {
     319             :         uint64_t data[2];
     320         153 :         Ip6AddressToU64Array(sip.to_v6(), data, 2);
     321         153 :         *sip_u = data[0];
     322         153 :         *sip_l = data[1];
     323             :     }
     324             : 
     325        7735 :     if (dip.is_v4()) {
     326        7582 :         *dip_l = htonl(dip.to_v4().to_ulong());
     327        7582 :         *dip_u = 0;
     328             :     } else {
     329             :         uint64_t data[2];
     330         153 :         Ip6AddressToU64Array(dip.to_v6(), data, 2);
     331         153 :         *dip_u = data[0];
     332         153 :         *dip_l = data[1];
     333             :     }
     334        7735 : }
     335             : 
     336         140 : void U64ToIpv6(uint64_t upper, uint64_t lower, IpAddress *ip) {
     337             :     boost::asio::ip::address_v6::bytes_type bytes;
     338         140 :     const unsigned char *ptr = (const unsigned char *)&lower;
     339        1260 :     for (unsigned int i = 0; i < sizeof(uint64_t); i++) {
     340        1120 :         bytes[i] = ptr[i];
     341             :     }
     342         140 :     ptr = (const unsigned char *)&upper;
     343        1260 :     for (unsigned int i = 0; i < sizeof(uint64_t); i++) {
     344        1120 :         bytes[8 + i] = ptr[i];
     345             :     }
     346         140 :     *ip = Ip6Address(bytes);
     347         140 : }
     348             : 
     349        3494 : void U64ToIp(uint64_t sip_u, uint64_t sip_l, uint64_t dip_u, uint64_t dip_l,
     350             :              int family, IpAddress *sip, IpAddress *dip) {
     351        3494 :     if (family == Address::INET) {
     352        3424 :         *sip = Ip4Address(ntohl(sip_l & 0xFFFFFFFF));
     353        3424 :         *dip = Ip4Address(ntohl(dip_l & 0xFFFFFFFF));
     354             :     } else {
     355          70 :         U64ToIpv6(sip_u, sip_l, sip);
     356          70 :         U64ToIpv6(dip_u, dip_l, dip);
     357             :     }
     358        3494 : }
     359             : 
     360       37910 : void Ip6AddressToU64Array(const Ip6Address &addr, uint64_t *arr, int size) {
     361             :     unsigned char b[16];
     362             :     uint64_t ip;
     363             :     unsigned int i, j, k;
     364             : 
     365       37910 :     if (size != 2)
     366           0 :         return;
     367             : 
     368       37910 :     memcpy(b, addr.to_bytes().data(), sizeof(b));
     369             : 
     370      189550 :     for (i = 0, j = 0, k = 0; i < 4; i++, j = j+4) {
     371      151640 :         ip = 0;
     372             : 
     373      151640 :         ip = ((((uint32_t)b[j]) << 24) & 0xFF000000) |
     374      151640 :              ((((uint32_t)b[j+1]) << 16) & 0x00FF0000) |
     375      151640 :              ((((uint32_t)b[j+2]) << 8) & 0x0000FF00) |
     376      151640 :              (((uint32_t)b[j+3]) & 0x000000FF);
     377             : 
     378      151640 :         if (i >= 2)
     379       75820 :             k = 1;
     380             : 
     381      151640 :         if (i%2) {
     382       75820 :             arr[k] = arr[k] | (ip & 0x00000000FFFFFFFFU);
     383             :         } else {
     384       75820 :             arr[k] = (ip << 32) & 0xFFFFFFFF00000000U;
     385             :         }
     386             :     }
     387             : 
     388             : 
     389       37910 :     arr[0] = htobe64(arr[0]);
     390       37910 :     arr[1] = htobe64(arr[1]);
     391             : }
     392             : 
     393           0 : std::string VectorIpv6ToString(const std::vector<signed char> &ipv6) {
     394             : 
     395           0 :     if (ipv6.size() != 16) {
     396           0 :         return "0000:0000:0000:0000";
     397             :     }
     398           0 :     std::ostringstream strm;
     399           0 :     int count = 1;
     400           0 :     for(std::vector<signed char>::const_iterator it = ipv6.begin();
     401           0 :         it != ipv6.end(); ++it) {
     402           0 :         strm << std::hex << (int)((uint8_t) *it);
     403           0 :         if((count % 4) ==0)
     404           0 :             strm << ":";
     405           0 :         count++;
     406             :     }
     407           0 :     return strm.str();
     408           0 : }

Generated by: LCOV version 1.14