1 #include "util.hpp"
2 
3 #include <arpa/inet.h>
4 #include <netinet/in.h>
5 
6 #include <cstddef>
7 #include <xyz/openbmc_project/Common/error.hpp>
8 
9 #include <gtest/gtest.h>
10 
11 namespace phosphor
12 {
13 namespace network
14 {
15 
16 using InternalFailure =
17     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
18 class TestUtil : public testing::Test
19 {
20   public:
21     TestUtil()
22     {
23         // Empty
24     }
25 };
26 
27 TEST_F(TestUtil, ToHex)
28 {
29     EXPECT_EQ('E', mac_address::internal::toHex(std::byte(0xfe)));
30     EXPECT_EQ('A', mac_address::internal::toHex(std::byte(10)));
31     EXPECT_EQ('4', mac_address::internal::toHex(std::byte(4)));
32 }
33 
34 TEST_F(TestUtil, MacToString)
35 {
36     MacAddr mac1{
37         std::byte(0x00), std::byte(0xDE), std::byte(0xAD),
38         std::byte(0x00), std::byte(0xBE), std::byte(0xEF),
39     };
40     EXPECT_EQ("00:DE:AD:00:BE:EF", mac_address::toString(mac1));
41     MacAddr mac2{
42         std::byte(0x70), std::byte(0xFF), std::byte(0x84),
43         std::byte(0x09), std::byte(0x35), std::byte(0x09),
44     };
45     EXPECT_EQ("70:FF:84:09:35:09", mac_address::toString(mac2));
46 }
47 
48 TEST_F(TestUtil, AddrFromBuf)
49 {
50     std::string tooSmall(1, 'a');
51     std::string tooLarge(24, 'a');
52 
53     struct in_addr ip1;
54     EXPECT_EQ(1, inet_pton(AF_INET, "192.168.10.1", &ip1));
55     std::string_view buf1(reinterpret_cast<char*>(&ip1), sizeof(ip1));
56     InAddrAny res1 = addrFromBuf(AF_INET, buf1);
57     EXPECT_EQ(0, memcmp(&ip1, &std::get<struct in_addr>(res1), sizeof(ip1)));
58     EXPECT_THROW(addrFromBuf(AF_INET, tooSmall), std::runtime_error);
59     EXPECT_THROW(addrFromBuf(AF_INET, tooLarge), std::runtime_error);
60     EXPECT_THROW(addrFromBuf(AF_UNSPEC, buf1), std::runtime_error);
61 
62     struct in6_addr ip2;
63     EXPECT_EQ(1, inet_pton(AF_INET6, "fdd8:b5ad:9d93:94ee::2:1", &ip2));
64     std::string_view buf2(reinterpret_cast<char*>(&ip2), sizeof(ip2));
65     InAddrAny res2 = addrFromBuf(AF_INET6, buf2);
66     EXPECT_EQ(0, memcmp(&ip2, &std::get<struct in6_addr>(res2), sizeof(ip2)));
67     EXPECT_THROW(addrFromBuf(AF_INET6, tooSmall), std::runtime_error);
68     EXPECT_THROW(addrFromBuf(AF_INET6, tooLarge), std::runtime_error);
69     EXPECT_THROW(addrFromBuf(AF_UNSPEC, buf2), std::runtime_error);
70 }
71 
72 TEST_F(TestUtil, IpToString)
73 {
74     struct in_addr ip1;
75     EXPECT_EQ(1, inet_pton(AF_INET, "192.168.10.1", &ip1));
76     EXPECT_EQ("192.168.10.1", toString(InAddrAny(ip1)));
77 
78     struct in6_addr ip2;
79     EXPECT_EQ(1, inet_pton(AF_INET6, "fdd8:b5ad:9d93:94ee::2:1", &ip2));
80     EXPECT_EQ("fdd8:b5ad:9d93:94ee::2:1", toString(InAddrAny(ip2)));
81 
82     InAddrAny ip3;
83     try
84     {
85         struct E
86         {
87             operator struct in6_addr()
88             {
89                 throw 1;
90             }
91         };
92         ip3.emplace<struct in6_addr>(E());
93         EXPECT_TRUE(false);
94     }
95     catch (...)
96     {
97     }
98     EXPECT_THROW(toString(ip3), std::runtime_error);
99 }
100 
101 TEST_F(TestUtil, IpValidation)
102 {
103     std::string ipaddress = "0.0.0.0";
104     EXPECT_EQ(true, isValidIP(AF_INET, ipaddress));
105 
106     ipaddress = "9.3.185.83";
107     EXPECT_EQ(true, isValidIP(AF_INET, ipaddress));
108 
109     ipaddress = "9.3.185.a";
110     EXPECT_EQ(false, isValidIP(AF_INET, ipaddress));
111 
112     ipaddress = "9.3.a.83";
113     EXPECT_EQ(false, isValidIP(AF_INET, ipaddress));
114 
115     ipaddress = "x.x.x.x";
116     EXPECT_EQ(false, isValidIP(AF_INET, ipaddress));
117 
118     ipaddress = "0:0:0:0:0:0:0:0";
119     EXPECT_EQ(true, isValidIP(AF_INET6, ipaddress));
120 
121     ipaddress = "1:0:0:0:0:0:0:8";
122     EXPECT_EQ(true, isValidIP(AF_INET6, ipaddress));
123 
124     ipaddress = "1::8";
125     EXPECT_EQ(true, isValidIP(AF_INET6, ipaddress));
126 
127     ipaddress = "0:0:0:0:0:FFFF:204.152.189.116";
128     EXPECT_EQ(true, isValidIP(AF_INET6, ipaddress));
129 
130     ipaddress = "::ffff:204.152.189.116";
131     EXPECT_EQ(true, isValidIP(AF_INET6, ipaddress));
132 
133     ipaddress = "a:0:0:0:0:FFFF:204.152.189.116";
134     EXPECT_EQ(true, isValidIP(AF_INET6, ipaddress));
135 
136     ipaddress = "1::8";
137     EXPECT_EQ(true, isValidIP(AF_INET6, ipaddress));
138 }
139 
140 TEST_F(TestUtil, PrefixValidation)
141 {
142     uint8_t prefixLength = 1;
143     EXPECT_EQ(true, isValidPrefix(AF_INET, prefixLength));
144 
145     prefixLength = 32;
146     EXPECT_EQ(true, isValidPrefix(AF_INET, prefixLength));
147 
148     prefixLength = 0;
149     EXPECT_EQ(false, isValidPrefix(AF_INET, prefixLength));
150 
151     prefixLength = 33;
152     EXPECT_EQ(false, isValidPrefix(AF_INET, prefixLength));
153 
154     prefixLength = 33;
155     EXPECT_EQ(true, isValidPrefix(AF_INET6, prefixLength));
156 
157     prefixLength = 65;
158     EXPECT_EQ(false, isValidPrefix(AF_INET, prefixLength));
159 }
160 
161 TEST_F(TestUtil, MacValidation)
162 {
163     std::string macaddress = "00:00:00:00:00:00";
164     EXPECT_EQ(false, phosphor::network::mac_address::validate(macaddress));
165 
166     macaddress = "F6:C6:E6:6:B0:D3";
167     EXPECT_EQ(false, phosphor::network::mac_address::validate(macaddress));
168 
169     macaddress = "F6:C6:E6:06:B0:D3";
170     EXPECT_EQ(true, phosphor::network::mac_address::validate(macaddress));
171 
172     macaddress = "hh:HH:HH:hh:HH:yy";
173     EXPECT_EQ(false, phosphor::network::mac_address::validate(macaddress));
174 
175     macaddress = "hhh:GGG:iii:jjj:kkk:lll";
176     EXPECT_EQ(false, phosphor::network::mac_address::validate(macaddress));
177 }
178 
179 TEST_F(TestUtil, ConvertV4MasktoPrefix)
180 {
181     std::string mask = "255.255.255.0";
182     uint8_t prefix = toCidr(AF_INET, mask);
183     EXPECT_EQ(prefix, 24);
184 
185     mask = "255.255.0.0";
186     prefix = toCidr(AF_INET, mask);
187     EXPECT_EQ(prefix, 16);
188 
189     mask = "255.0.0.0";
190     prefix = toCidr(AF_INET, mask);
191     EXPECT_EQ(prefix, 8);
192 
193     mask = "255.224.0.0";
194     prefix = toCidr(AF_INET, mask);
195     EXPECT_EQ(prefix, 11);
196 
197     // Invalid Mask
198     mask = "255.0.255.0";
199     prefix = toCidr(AF_INET, mask);
200     EXPECT_EQ(prefix, 0);
201 }
202 
203 TEST_F(TestUtil, convertV6MasktoPrefix)
204 {
205     std::string mask = "ffff:ffff::";
206     uint8_t prefix = toCidr(AF_INET6, mask);
207     EXPECT_EQ(prefix, 32);
208 
209     mask = "ffff:ffff:ffff::";
210     prefix = toCidr(AF_INET6, mask);
211     EXPECT_EQ(prefix, 48);
212 
213     mask = "ffff:ffff:fc00::";
214     prefix = toCidr(AF_INET6, mask);
215     EXPECT_EQ(prefix, 38);
216 
217     // Invalid Mask
218     mask = "ffff:0fff::";
219     prefix = toCidr(AF_INET6, mask);
220     EXPECT_EQ(prefix, 0);
221 }
222 
223 TEST_F(TestUtil, isLinkLocaladdress)
224 {
225     std::string ipaddress = "fe80:fec0::";
226     EXPECT_TRUE(isLinkLocalIP(ipaddress));
227 
228     ipaddress = "2000:fe80:789::";
229     EXPECT_FALSE(isLinkLocalIP(ipaddress));
230 
231     ipaddress = "2000:fe80::";
232     EXPECT_FALSE(isLinkLocalIP(ipaddress));
233 
234     ipaddress = "169.254.3.3";
235     EXPECT_TRUE(isLinkLocalIP(ipaddress));
236 
237     ipaddress = "3.169.254.3";
238     EXPECT_FALSE(isLinkLocalIP(ipaddress));
239 
240     ipaddress = "3.3.169.254";
241     EXPECT_FALSE(isLinkLocalIP(ipaddress));
242 }
243 
244 TEST_F(TestUtil, convertPrefixToMask)
245 {
246     std::string mask = toMask(AF_INET, 24);
247     EXPECT_EQ(mask, "255.255.255.0");
248 
249     mask = toMask(AF_INET, 8);
250     EXPECT_EQ(mask, "255.0.0.0");
251 
252     mask = toMask(AF_INET, 27);
253     EXPECT_EQ(mask, "255.255.255.224");
254 }
255 
256 TEST_F(TestUtil, getNetworkAddress)
257 {
258     std::string address = getNetworkID(AF_INET, "9.3.23.251", 24);
259     EXPECT_EQ("9.3.23.0", address);
260 
261     address = getNetworkID(AF_INET, "9.3.23.251", 25);
262     EXPECT_EQ("9.3.23.128", address);
263 
264     address = getNetworkID(AF_INET6, "2001:db8:abcd:dd12::0", 64);
265     EXPECT_EQ("2001:db8:abcd:dd12::", address);
266 
267     EXPECT_THROW(getNetworkID(AF_INET, "a.b.c.d", 25), InternalFailure);
268 
269     EXPECT_THROW(getNetworkID(AF_INET6, "2001:db8:gghh:dd12::0", 64),
270                  InternalFailure);
271 
272     address = getNetworkID(AF_INET6, "fe80::201:6cff:fe80:228", 64);
273     EXPECT_EQ("fe80::", address);
274 }
275 
276 } // namespace network
277 } // namespace phosphor
278