1 #pragma once 2 3 #include <boost/algorithm/string/classification.hpp> 4 #include <boost/algorithm/string/split.hpp> 5 #include <boost/asio/ip/address.hpp> 6 #include <boost/asio/ip/address_v4.hpp> 7 #include <boost/asio/ip/address_v6.hpp> 8 9 #include <string> 10 11 namespace redfish 12 { 13 namespace ip_util 14 { 15 16 /** 17 * @brief Converts boost::asio::ip::address to string 18 * Will automatically convert IPv4-mapped IPv6 address back to IPv4. 19 * 20 * @param[in] ipAddr IP address to convert 21 * 22 * @return IP address string 23 */ 24 inline std::string toString(const boost::asio::ip::address& ipAddr) 25 { 26 if (ipAddr.is_v6() && ipAddr.to_v6().is_v4_mapped()) 27 { 28 return boost::asio::ip::make_address_v4(boost::asio::ip::v4_mapped, 29 ipAddr.to_v6()) 30 .to_string(); 31 } 32 return ipAddr.to_string(); 33 } 34 35 /** 36 * @brief Helper function that verifies IP address to check if it is in 37 * proper format. If bits pointer is provided, also calculates active 38 * bit count for Subnet Mask. 39 * 40 * @param[in] ip IP that will be verified 41 * @param[out] bits Calculated mask in bits notation 42 * 43 * @return true in case of success, false otherwise 44 */ 45 inline bool ipv4VerifyIpAndGetBitcount(const std::string& ip, 46 uint8_t* bits = nullptr) 47 { 48 std::vector<std::string> bytesInMask; 49 50 boost::split(bytesInMask, ip, boost::is_any_of(".")); 51 52 static const constexpr int ipV4AddressSectionsCount = 4; 53 if (bytesInMask.size() != ipV4AddressSectionsCount) 54 { 55 return false; 56 } 57 58 if (bits != nullptr) 59 { 60 *bits = 0; 61 } 62 63 char* endPtr = nullptr; 64 long previousValue = 255; 65 bool firstZeroInByteHit = false; 66 for (const std::string& byte : bytesInMask) 67 { 68 if (byte.empty()) 69 { 70 return false; 71 } 72 73 // Use strtol instead of stroi to avoid exceptions 74 long value = std::strtol(byte.c_str(), &endPtr, 10); 75 76 // endPtr should point to the end of the string, otherwise given string 77 // is not 100% number 78 if (*endPtr != '\0') 79 { 80 return false; 81 } 82 83 // Value should be contained in byte 84 if (value < 0 || value > 255) 85 { 86 return false; 87 } 88 89 if (bits != nullptr) 90 { 91 // Mask has to be continuous between bytes 92 if (previousValue != 255 && value != 0) 93 { 94 return false; 95 } 96 97 // Mask has to be continuous inside bytes 98 firstZeroInByteHit = false; 99 100 // Count bits 101 for (long bitIdx = 7; bitIdx >= 0; bitIdx--) 102 { 103 if ((value & (1L << bitIdx)) != 0) 104 { 105 if (firstZeroInByteHit) 106 { 107 // Continuity not preserved 108 return false; 109 } 110 (*bits)++; 111 } 112 else 113 { 114 firstZeroInByteHit = true; 115 } 116 } 117 } 118 119 previousValue = value; 120 } 121 122 return true; 123 } 124 125 } // namespace ip_util 126 } // namespace redfish 127