1 #pragma once
2 
3 #include <boost/asio/ip/address.hpp>
4 #include <boost/asio/ip/address_v4.hpp>
5 #include <boost/asio/ip/address_v6.hpp>
6 
7 #include <string>
8 
9 namespace redfish
10 {
11 namespace ip_util
12 {
13 
14 /**
15  * @brief Converts boost::asio::ip::address to string
16  * Will automatically convert IPv4-mapped IPv6 address back to IPv4.
17  *
18  * @param[in] ipAddr IP address to convert
19  *
20  * @return IP address string
21  */
22 inline std::string toString(const boost::asio::ip::address& ipAddr)
23 {
24     if (ipAddr.is_v6() && ipAddr.to_v6().is_v4_mapped())
25     {
26         return boost::asio::ip::make_address_v4(boost::asio::ip::v4_mapped,
27                                                 ipAddr.to_v6())
28             .to_string();
29     }
30     return ipAddr.to_string();
31 }
32 
33 /**
34  * @brief Helper function that verifies IP address to check if it is in
35  *        proper format. If bits pointer is provided, also calculates active
36  *        bit count for Subnet Mask.
37  *
38  * @param[in]  ip     IP that will be verified
39  * @param[out] bits   Calculated mask in bits notation
40  *
41  * @return true in case of success, false otherwise
42  */
43 inline bool ipv4VerifyIpAndGetBitcount(const std::string& ip,
44                                        uint8_t* prefixLength = nullptr)
45 {
46     boost::system::error_code ec;
47     boost::asio::ip::address_v4 addr = boost::asio::ip::make_address_v4(ip, ec);
48     if (ec)
49     {
50         return false;
51     }
52 
53     if (prefixLength != nullptr)
54     {
55         uint8_t prefix = 0;
56         boost::asio::ip::address_v4::bytes_type maskBytes = addr.to_bytes();
57         bool maskFinished = false;
58         for (unsigned char byte : maskBytes)
59         {
60             if (maskFinished)
61             {
62                 if (byte != 0U)
63                 {
64                     return false;
65                 }
66                 continue;
67             }
68             switch (byte)
69             {
70                 case 255:
71                     prefix += 8;
72                     break;
73                 case 254:
74                     prefix += 7;
75                     maskFinished = true;
76                     break;
77                 case 252:
78                     prefix += 6;
79                     maskFinished = true;
80                     break;
81                 case 248:
82                     prefix += 5;
83                     maskFinished = true;
84                     break;
85                 case 240:
86                     prefix += 4;
87                     maskFinished = true;
88                     break;
89                 case 224:
90                     prefix += 3;
91                     maskFinished = true;
92                     break;
93                 case 192:
94                     prefix += 2;
95                     maskFinished = true;
96                     break;
97                 case 128:
98                     prefix += 1;
99                     maskFinished = true;
100                     break;
101                 case 0:
102                     maskFinished = true;
103                     break;
104                 default:
105                     // Invalid netmask
106                     return false;
107             }
108         }
109         *prefixLength = prefix;
110     }
111 
112     return true;
113 }
114 
115 } // namespace ip_util
116 } // namespace redfish
117