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