141d61c82SJiaqing Zhao #pragma once 241d61c82SJiaqing Zhao 3*033f1e4dSEd Tanous #include <boost/algorithm/string/classification.hpp> 4*033f1e4dSEd Tanous #include <boost/algorithm/string/split.hpp> 541d61c82SJiaqing Zhao #include <boost/asio/ip/address.hpp> 6d5c80ad9SNan Zhou #include <boost/asio/ip/address_v4.hpp> 7d5c80ad9SNan Zhou #include <boost/asio/ip/address_v6.hpp> 841d61c82SJiaqing Zhao 941d61c82SJiaqing Zhao #include <string> 1041d61c82SJiaqing Zhao 1141d61c82SJiaqing Zhao namespace redfish 1241d61c82SJiaqing Zhao { 1341d61c82SJiaqing Zhao namespace ip_util 1441d61c82SJiaqing Zhao { 1541d61c82SJiaqing Zhao 1641d61c82SJiaqing Zhao /** 1741d61c82SJiaqing Zhao * @brief Converts boost::asio::ip::address to string 1841d61c82SJiaqing Zhao * Will automatically convert IPv4-mapped IPv6 address back to IPv4. 1941d61c82SJiaqing Zhao * 2041d61c82SJiaqing Zhao * @param[in] ipAddr IP address to convert 2141d61c82SJiaqing Zhao * 2241d61c82SJiaqing Zhao * @return IP address string 2341d61c82SJiaqing Zhao */ 2441d61c82SJiaqing Zhao inline std::string toString(const boost::asio::ip::address& ipAddr) 2541d61c82SJiaqing Zhao { 2641d61c82SJiaqing Zhao if (ipAddr.is_v6() && ipAddr.to_v6().is_v4_mapped()) 2741d61c82SJiaqing Zhao { 2841d61c82SJiaqing Zhao return boost::asio::ip::make_address_v4(boost::asio::ip::v4_mapped, 2941d61c82SJiaqing Zhao ipAddr.to_v6()) 3041d61c82SJiaqing Zhao .to_string(); 3141d61c82SJiaqing Zhao } 3241d61c82SJiaqing Zhao return ipAddr.to_string(); 3341d61c82SJiaqing Zhao } 3441d61c82SJiaqing Zhao 35*033f1e4dSEd Tanous /** 36*033f1e4dSEd Tanous * @brief Helper function that verifies IP address to check if it is in 37*033f1e4dSEd Tanous * proper format. If bits pointer is provided, also calculates active 38*033f1e4dSEd Tanous * bit count for Subnet Mask. 39*033f1e4dSEd Tanous * 40*033f1e4dSEd Tanous * @param[in] ip IP that will be verified 41*033f1e4dSEd Tanous * @param[out] bits Calculated mask in bits notation 42*033f1e4dSEd Tanous * 43*033f1e4dSEd Tanous * @return true in case of success, false otherwise 44*033f1e4dSEd Tanous */ 45*033f1e4dSEd Tanous inline bool ipv4VerifyIpAndGetBitcount(const std::string& ip, 46*033f1e4dSEd Tanous uint8_t* bits = nullptr) 47*033f1e4dSEd Tanous { 48*033f1e4dSEd Tanous std::vector<std::string> bytesInMask; 49*033f1e4dSEd Tanous 50*033f1e4dSEd Tanous boost::split(bytesInMask, ip, boost::is_any_of(".")); 51*033f1e4dSEd Tanous 52*033f1e4dSEd Tanous static const constexpr int ipV4AddressSectionsCount = 4; 53*033f1e4dSEd Tanous if (bytesInMask.size() != ipV4AddressSectionsCount) 54*033f1e4dSEd Tanous { 55*033f1e4dSEd Tanous return false; 56*033f1e4dSEd Tanous } 57*033f1e4dSEd Tanous 58*033f1e4dSEd Tanous if (bits != nullptr) 59*033f1e4dSEd Tanous { 60*033f1e4dSEd Tanous *bits = 0; 61*033f1e4dSEd Tanous } 62*033f1e4dSEd Tanous 63*033f1e4dSEd Tanous char* endPtr = nullptr; 64*033f1e4dSEd Tanous long previousValue = 255; 65*033f1e4dSEd Tanous bool firstZeroInByteHit = false; 66*033f1e4dSEd Tanous for (const std::string& byte : bytesInMask) 67*033f1e4dSEd Tanous { 68*033f1e4dSEd Tanous if (byte.empty()) 69*033f1e4dSEd Tanous { 70*033f1e4dSEd Tanous return false; 71*033f1e4dSEd Tanous } 72*033f1e4dSEd Tanous 73*033f1e4dSEd Tanous // Use strtol instead of stroi to avoid exceptions 74*033f1e4dSEd Tanous long value = std::strtol(byte.c_str(), &endPtr, 10); 75*033f1e4dSEd Tanous 76*033f1e4dSEd Tanous // endPtr should point to the end of the string, otherwise given string 77*033f1e4dSEd Tanous // is not 100% number 78*033f1e4dSEd Tanous if (*endPtr != '\0') 79*033f1e4dSEd Tanous { 80*033f1e4dSEd Tanous return false; 81*033f1e4dSEd Tanous } 82*033f1e4dSEd Tanous 83*033f1e4dSEd Tanous // Value should be contained in byte 84*033f1e4dSEd Tanous if (value < 0 || value > 255) 85*033f1e4dSEd Tanous { 86*033f1e4dSEd Tanous return false; 87*033f1e4dSEd Tanous } 88*033f1e4dSEd Tanous 89*033f1e4dSEd Tanous if (bits != nullptr) 90*033f1e4dSEd Tanous { 91*033f1e4dSEd Tanous // Mask has to be continuous between bytes 92*033f1e4dSEd Tanous if (previousValue != 255 && value != 0) 93*033f1e4dSEd Tanous { 94*033f1e4dSEd Tanous return false; 95*033f1e4dSEd Tanous } 96*033f1e4dSEd Tanous 97*033f1e4dSEd Tanous // Mask has to be continuous inside bytes 98*033f1e4dSEd Tanous firstZeroInByteHit = false; 99*033f1e4dSEd Tanous 100*033f1e4dSEd Tanous // Count bits 101*033f1e4dSEd Tanous for (long bitIdx = 7; bitIdx >= 0; bitIdx--) 102*033f1e4dSEd Tanous { 103*033f1e4dSEd Tanous if ((value & (1L << bitIdx)) != 0) 104*033f1e4dSEd Tanous { 105*033f1e4dSEd Tanous if (firstZeroInByteHit) 106*033f1e4dSEd Tanous { 107*033f1e4dSEd Tanous // Continuity not preserved 108*033f1e4dSEd Tanous return false; 109*033f1e4dSEd Tanous } 110*033f1e4dSEd Tanous (*bits)++; 111*033f1e4dSEd Tanous } 112*033f1e4dSEd Tanous else 113*033f1e4dSEd Tanous { 114*033f1e4dSEd Tanous firstZeroInByteHit = true; 115*033f1e4dSEd Tanous } 116*033f1e4dSEd Tanous } 117*033f1e4dSEd Tanous } 118*033f1e4dSEd Tanous 119*033f1e4dSEd Tanous previousValue = value; 120*033f1e4dSEd Tanous } 121*033f1e4dSEd Tanous 122*033f1e4dSEd Tanous return true; 123*033f1e4dSEd Tanous } 124*033f1e4dSEd Tanous 12541d61c82SJiaqing Zhao } // namespace ip_util 12641d61c82SJiaqing Zhao } // namespace redfish 127