1 #include "util.hpp"
2 
3 #include <arpa/inet.h>
4 #include <netinet/in.h>
5 
6 #include <cstddef>
7 #include <cstring>
8 #include <string>
9 #include <string_view>
10 #include <xyz/openbmc_project/Common/error.hpp>
11 
12 #include <gtest/gtest.h>
13 
14 namespace phosphor
15 {
16 namespace network
17 {
18 
19 using namespace std::literals;
20 using InternalFailure =
21     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
22 class TestUtil : public testing::Test
23 {
24   public:
25     TestUtil()
26     {
27         // Empty
28     }
29 };
30 
31 TEST_F(TestUtil, AddrFromBuf)
32 {
33     std::string tooSmall(1, 'a');
34     std::string tooLarge(24, 'a');
35 
36     struct in_addr ip1;
37     EXPECT_EQ(1, inet_pton(AF_INET, "192.168.10.1", &ip1));
38     std::string_view buf1(reinterpret_cast<char*>(&ip1), sizeof(ip1));
39     InAddrAny res1 = addrFromBuf(AF_INET, buf1);
40     EXPECT_EQ(0, memcmp(&ip1, &std::get<struct in_addr>(res1), sizeof(ip1)));
41     EXPECT_THROW(addrFromBuf(AF_INET, tooSmall), std::runtime_error);
42     EXPECT_THROW(addrFromBuf(AF_INET, tooLarge), std::runtime_error);
43     EXPECT_THROW(addrFromBuf(AF_UNSPEC, buf1), std::runtime_error);
44 
45     struct in6_addr ip2;
46     EXPECT_EQ(1, inet_pton(AF_INET6, "fdd8:b5ad:9d93:94ee::2:1", &ip2));
47     std::string_view buf2(reinterpret_cast<char*>(&ip2), sizeof(ip2));
48     InAddrAny res2 = addrFromBuf(AF_INET6, buf2);
49     EXPECT_EQ(0, memcmp(&ip2, &std::get<struct in6_addr>(res2), sizeof(ip2)));
50     EXPECT_THROW(addrFromBuf(AF_INET6, tooSmall), std::runtime_error);
51     EXPECT_THROW(addrFromBuf(AF_INET6, tooLarge), std::runtime_error);
52     EXPECT_THROW(addrFromBuf(AF_UNSPEC, buf2), std::runtime_error);
53 }
54 
55 TEST_F(TestUtil, IpToString)
56 {
57     struct in_addr ip1;
58     EXPECT_EQ(1, inet_pton(AF_INET, "192.168.10.1", &ip1));
59     EXPECT_EQ("192.168.10.1", toString(InAddrAny(ip1)));
60 
61     struct in6_addr ip2;
62     EXPECT_EQ(1, inet_pton(AF_INET6, "fdd8:b5ad:9d93:94ee::2:1", &ip2));
63     EXPECT_EQ("fdd8:b5ad:9d93:94ee::2:1", toString(InAddrAny(ip2)));
64 }
65 
66 TEST_F(TestUtil, IpValidation)
67 {
68     std::string ipaddress = "0.0.0.0";
69     EXPECT_EQ(true, isValidIP(AF_INET, ipaddress));
70 
71     ipaddress = "9.3.185.83";
72     EXPECT_EQ(true, isValidIP(AF_INET, ipaddress));
73 
74     ipaddress = "9.3.185.a";
75     EXPECT_EQ(false, isValidIP(AF_INET, ipaddress));
76 
77     ipaddress = "9.3.a.83";
78     EXPECT_EQ(false, isValidIP(AF_INET, ipaddress));
79 
80     ipaddress = "x.x.x.x";
81     EXPECT_EQ(false, isValidIP(AF_INET, ipaddress));
82 
83     ipaddress = "0:0:0:0:0:0:0:0";
84     EXPECT_EQ(true, isValidIP(AF_INET6, ipaddress));
85 
86     ipaddress = "1:0:0:0:0:0:0:8";
87     EXPECT_EQ(true, isValidIP(AF_INET6, ipaddress));
88 
89     ipaddress = "1::8";
90     EXPECT_EQ(true, isValidIP(AF_INET6, ipaddress));
91 
92     ipaddress = "0:0:0:0:0:FFFF:204.152.189.116";
93     EXPECT_EQ(true, isValidIP(AF_INET6, ipaddress));
94 
95     ipaddress = "::ffff:204.152.189.116";
96     EXPECT_EQ(true, isValidIP(AF_INET6, ipaddress));
97 
98     ipaddress = "a:0:0:0:0:FFFF:204.152.189.116";
99     EXPECT_EQ(true, isValidIP(AF_INET6, ipaddress));
100 
101     ipaddress = "1::8";
102     EXPECT_EQ(true, isValidIP(AF_INET6, ipaddress));
103 }
104 
105 TEST_F(TestUtil, PrefixValidation)
106 {
107     uint8_t prefixLength = 1;
108     EXPECT_EQ(true, isValidPrefix(AF_INET, prefixLength));
109 
110     prefixLength = 32;
111     EXPECT_EQ(true, isValidPrefix(AF_INET, prefixLength));
112 
113     prefixLength = 0;
114     EXPECT_EQ(false, isValidPrefix(AF_INET, prefixLength));
115 
116     prefixLength = 33;
117     EXPECT_EQ(false, isValidPrefix(AF_INET, prefixLength));
118 
119     prefixLength = 33;
120     EXPECT_EQ(true, isValidPrefix(AF_INET6, prefixLength));
121 
122     prefixLength = 65;
123     EXPECT_EQ(false, isValidPrefix(AF_INET, prefixLength));
124 }
125 
126 TEST_F(TestUtil, ConvertV4MasktoPrefix)
127 {
128     std::string mask = "255.255.255.0";
129     uint8_t prefix = toCidr(AF_INET, mask);
130     EXPECT_EQ(prefix, 24);
131 
132     mask = "255.255.0.0";
133     prefix = toCidr(AF_INET, mask);
134     EXPECT_EQ(prefix, 16);
135 
136     mask = "255.0.0.0";
137     prefix = toCidr(AF_INET, mask);
138     EXPECT_EQ(prefix, 8);
139 
140     mask = "255.224.0.0";
141     prefix = toCidr(AF_INET, mask);
142     EXPECT_EQ(prefix, 11);
143 
144     // Invalid Mask
145     mask = "255.0.255.0";
146     prefix = toCidr(AF_INET, mask);
147     EXPECT_EQ(prefix, 0);
148 }
149 
150 TEST_F(TestUtil, convertV6MasktoPrefix)
151 {
152     std::string mask = "ffff:ffff::";
153     uint8_t prefix = toCidr(AF_INET6, mask);
154     EXPECT_EQ(prefix, 32);
155 
156     mask = "ffff:ffff:ffff::";
157     prefix = toCidr(AF_INET6, mask);
158     EXPECT_EQ(prefix, 48);
159 
160     mask = "ffff:ffff:fc00::";
161     prefix = toCidr(AF_INET6, mask);
162     EXPECT_EQ(prefix, 38);
163 
164     // Invalid Mask
165     mask = "ffff:0fff::";
166     prefix = toCidr(AF_INET6, mask);
167     EXPECT_EQ(prefix, 0);
168 }
169 
170 TEST_F(TestUtil, isLinkLocaladdress)
171 {
172     std::string ipaddress = "fe80:fec0::";
173     EXPECT_TRUE(isLinkLocalIP(ipaddress));
174 
175     ipaddress = "2000:fe80:789::";
176     EXPECT_FALSE(isLinkLocalIP(ipaddress));
177 
178     ipaddress = "2000:fe80::";
179     EXPECT_FALSE(isLinkLocalIP(ipaddress));
180 
181     ipaddress = "169.254.3.3";
182     EXPECT_TRUE(isLinkLocalIP(ipaddress));
183 
184     ipaddress = "3.169.254.3";
185     EXPECT_FALSE(isLinkLocalIP(ipaddress));
186 
187     ipaddress = "3.3.169.254";
188     EXPECT_FALSE(isLinkLocalIP(ipaddress));
189 }
190 
191 TEST_F(TestUtil, convertPrefixToMask)
192 {
193     std::string mask = toMask(AF_INET, 24);
194     EXPECT_EQ(mask, "255.255.255.0");
195 
196     mask = toMask(AF_INET, 8);
197     EXPECT_EQ(mask, "255.0.0.0");
198 
199     mask = toMask(AF_INET, 27);
200     EXPECT_EQ(mask, "255.255.255.224");
201 }
202 
203 TEST_F(TestUtil, getNetworkAddress)
204 {
205     std::string address = getNetworkID(AF_INET, "9.3.23.251", 24);
206     EXPECT_EQ("9.3.23.0", address);
207 
208     address = getNetworkID(AF_INET, "9.3.23.251", 25);
209     EXPECT_EQ("9.3.23.128", address);
210 
211     address = getNetworkID(AF_INET6, "2001:db8:abcd:dd12::0", 64);
212     EXPECT_EQ("2001:db8:abcd:dd12::", address);
213 
214     EXPECT_THROW(getNetworkID(AF_INET, "a.b.c.d", 25), InternalFailure);
215 
216     EXPECT_THROW(getNetworkID(AF_INET6, "2001:db8:gghh:dd12::0", 64),
217                  InternalFailure);
218 
219     address = getNetworkID(AF_INET6, "fe80::201:6cff:fe80:228", 64);
220     EXPECT_EQ("fe80::", address);
221 }
222 
223 TEST_F(TestUtil, CopyFromTooSmall)
224 {
225     constexpr auto expected = "abcde"sv;
226     struct
227     {
228         uint8_t data[10];
229     } data;
230     static_assert(sizeof(data) > expected.size());
231     EXPECT_THROW(copyFrom<decltype(data)>(expected), std::runtime_error);
232 }
233 
234 TEST_F(TestUtil, CopyFromSome)
235 {
236     constexpr auto expected = "abcde"sv;
237     struct
238     {
239         uint8_t data[2];
240     } data;
241     static_assert(sizeof(data) < expected.size());
242     data = copyFrom<decltype(data)>(expected);
243     EXPECT_EQ(0, memcmp(&data, expected.data(), sizeof(data)));
244 }
245 
246 TEST_F(TestUtil, CopyFromAll)
247 {
248     constexpr auto expected = "abcde"sv;
249     struct
250     {
251         uint8_t data[5];
252     } data;
253     static_assert(sizeof(data) == expected.size());
254     data = copyFrom<decltype(data)>(expected);
255     EXPECT_EQ(0, memcmp(&data, expected.data(), sizeof(data)));
256 }
257 
258 TEST_F(TestUtil, ExtractSome)
259 {
260     constexpr auto expected = "abcde"sv;
261     auto buf = expected;
262     struct
263     {
264         uint8_t data[2];
265     } data;
266     static_assert(sizeof(data) < expected.size());
267     data = extract<decltype(data)>(buf);
268     EXPECT_EQ(0, memcmp(&data, expected.data(), sizeof(data)));
269     EXPECT_EQ(3, buf.size());
270     EXPECT_EQ(expected.substr(2), buf);
271 }
272 
273 TEST_F(TestUtil, ExtractAll)
274 {
275     constexpr auto expected = "abcde"sv;
276     auto buf = expected;
277     struct
278     {
279         uint8_t data[5];
280     } data;
281     static_assert(sizeof(data) == expected.size());
282     data = extract<decltype(data)>(buf);
283     EXPECT_EQ(0, memcmp(&data, expected.data(), sizeof(data)));
284     EXPECT_EQ(0, buf.size());
285 }
286 
287 TEST_F(TestUtil, Equal)
288 {
289     struct
290     {
291         int i;
292     } a, b{};
293     a.i = 4;
294     b.i = 4;
295 
296     EXPECT_TRUE(equal(a, b));
297 }
298 
299 TEST_F(TestUtil, NotEqual)
300 {
301     struct
302     {
303         int i;
304     } a, b{};
305     a.i = 2;
306     b.i = 4;
307 
308     EXPECT_FALSE(equal(a, b));
309 }
310 
311 namespace mac_address
312 {
313 
314 TEST(MacFromString, Bad)
315 {
316     EXPECT_THROW(fromString("0x:00:00:00:00:00"), std::runtime_error);
317     EXPECT_THROW(fromString("00:00:00:00:00"), std::runtime_error);
318     EXPECT_THROW(fromString(""), std::runtime_error);
319 }
320 
321 TEST(MacFromString, Valid)
322 {
323     EXPECT_TRUE(equal(ether_addr{}, fromString("00:00:00:00:00:00")));
324     EXPECT_TRUE(equal(ether_addr{0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa},
325                       fromString("FF:EE:DD:cc:bb:aa")));
326     EXPECT_TRUE(equal(ether_addr{0x00, 0x01, 0x02, 0x03, 0x04, 0x05},
327                       fromString("0:1:2:3:4:5")));
328 }
329 
330 TEST(MacToString, Valid)
331 {
332     EXPECT_EQ("11:22:33:44:55:66",
333               toString({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}));
334 }
335 
336 TEST(MacIsEmpty, True)
337 {
338     EXPECT_TRUE(isEmpty({}));
339 }
340 
341 TEST(MacIsEmpty, False)
342 {
343     EXPECT_FALSE(isEmpty(fromString("01:00:00:00:00:00")));
344     EXPECT_FALSE(isEmpty(fromString("00:00:00:10:00:00")));
345     EXPECT_FALSE(isEmpty(fromString("00:00:00:00:00:01")));
346 }
347 
348 TEST(MacIsMulticast, True)
349 {
350     EXPECT_TRUE(isMulticast(fromString("ff:ff:ff:ff:ff:ff")));
351     EXPECT_TRUE(isMulticast(fromString("01:00:00:00:00:00")));
352 }
353 
354 TEST(MacIsMulticast, False)
355 {
356     EXPECT_FALSE(isMulticast(fromString("00:11:22:33:44:55")));
357     EXPECT_FALSE(isMulticast(fromString("FE:11:22:33:44:55")));
358 }
359 
360 TEST(MacIsUnicast, True)
361 {
362     EXPECT_TRUE(isUnicast(fromString("00:11:22:33:44:55")));
363     EXPECT_TRUE(isUnicast(fromString("FE:11:22:33:44:55")));
364 }
365 
366 TEST(MacIsUnicast, False)
367 {
368     EXPECT_FALSE(isUnicast(fromString("00:00:00:00:00:00")));
369     EXPECT_FALSE(isUnicast(fromString("01:00:00:00:00:00")));
370     EXPECT_FALSE(isUnicast(fromString("ff:ff:ff:ff:ff:ff")));
371 }
372 
373 TEST(MacIsLocalAdmin, True)
374 {
375     EXPECT_TRUE(isLocalAdmin(fromString("02:11:22:33:44:55")));
376     EXPECT_TRUE(isLocalAdmin(fromString("FE:11:22:33:44:55")));
377 }
378 
379 TEST(MacIsLocalAdmin, False)
380 {
381     EXPECT_FALSE(isLocalAdmin(fromString("00:00:00:00:00:00")));
382     EXPECT_FALSE(isLocalAdmin(fromString("01:00:00:00:00:00")));
383     EXPECT_FALSE(isLocalAdmin(fromString("fd:ff:ff:ff:ff:ff")));
384 }
385 
386 } // namespace mac_address
387 } // namespace network
388 } // namespace phosphor
389