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

Generated by: LCOV version 1.14