xref: /openbmc/bmcweb/features/redfish/include/utils/ip_utils.hpp (revision 033f1e4d7ffe66b742b2d3fb6f18f2ba2025afb8)
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