1 #include "util.hpp"
2 
3 #include <arpa/inet.h>
4 #include <netinet/in.h>
5 
6 #include <cstddef>
7 #include <cstring>
8 #include <stdexcept>
9 #include <stdplus/raw.hpp>
10 #include <string>
11 #include <string_view>
12 #include <xyz/openbmc_project/Common/error.hpp>
13 
14 #include <gmock/gmock.h>
15 #include <gtest/gtest.h>
16 
17 namespace phosphor
18 {
19 namespace network
20 {
21 
22 using namespace std::literals;
23 using InternalFailure =
24     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
25 class TestUtil : public testing::Test
26 {
27   public:
28     TestUtil()
29     {
30         // Empty
31     }
32 };
33 
34 TEST_F(TestUtil, AddrFromBuf)
35 {
36     std::string tooSmall(1, 'a');
37     std::string tooLarge(24, 'a');
38 
39     struct in_addr ip1;
40     EXPECT_EQ(1, inet_pton(AF_INET, "192.168.10.1", &ip1));
41     std::string_view buf1(reinterpret_cast<char*>(&ip1), sizeof(ip1));
42     InAddrAny res1 = addrFromBuf(AF_INET, buf1);
43     EXPECT_EQ(0, memcmp(&ip1, &std::get<struct in_addr>(res1), sizeof(ip1)));
44     EXPECT_THROW(addrFromBuf(AF_INET, tooSmall), std::runtime_error);
45     EXPECT_THROW(addrFromBuf(AF_INET, tooLarge), std::runtime_error);
46     EXPECT_THROW(addrFromBuf(AF_UNSPEC, buf1), std::invalid_argument);
47 
48     struct in6_addr ip2;
49     EXPECT_EQ(1, inet_pton(AF_INET6, "fdd8:b5ad:9d93:94ee::2:1", &ip2));
50     std::string_view buf2(reinterpret_cast<char*>(&ip2), sizeof(ip2));
51     InAddrAny res2 = addrFromBuf(AF_INET6, buf2);
52     EXPECT_EQ(0, memcmp(&ip2, &std::get<struct in6_addr>(res2), sizeof(ip2)));
53     EXPECT_THROW(addrFromBuf(AF_INET6, tooSmall), std::runtime_error);
54     EXPECT_THROW(addrFromBuf(AF_INET6, tooLarge), std::runtime_error);
55     EXPECT_THROW(addrFromBuf(AF_UNSPEC, buf2), std::invalid_argument);
56 }
57 
58 TEST_F(TestUtil, IpToString)
59 {
60     struct in_addr ip1;
61     EXPECT_EQ(1, inet_pton(AF_INET, "192.168.10.1", &ip1));
62     EXPECT_EQ("192.168.10.1", toString(ip1));
63     EXPECT_EQ("192.168.10.1", toString(InAddrAny(ip1)));
64 
65     struct in6_addr ip2;
66     EXPECT_EQ(1, inet_pton(AF_INET6, "fdd8:b5ad:9d93:94ee::2:1", &ip2));
67     EXPECT_EQ("fdd8:b5ad:9d93:94ee::2:1", toString(ip2));
68     EXPECT_EQ("fdd8:b5ad:9d93:94ee::2:1", toString(InAddrAny(ip2)));
69 }
70 
71 TEST_F(TestUtil, IpValidation)
72 {
73     EXPECT_TRUE(isValidIP(AF_INET, "0.0.0.0"));
74     EXPECT_TRUE(isValidIP("0.0.0.0"));
75 
76     EXPECT_TRUE(isValidIP(AF_INET, "9.3.185.83"));
77 
78     EXPECT_FALSE(isValidIP(AF_INET, "9.3.185.a"));
79     EXPECT_FALSE(isValidIP("9.3.185.a"));
80 
81     EXPECT_FALSE(isValidIP(AF_INET, "9.3.a.83"));
82 
83     EXPECT_FALSE(isValidIP(AF_INET, "x.x.x.x"));
84 
85     EXPECT_TRUE(isValidIP(AF_INET6, "0:0:0:0:0:0:0:0"));
86     EXPECT_TRUE(isValidIP("0:0:0:0:0:0:0:0"));
87 
88     EXPECT_TRUE(isValidIP(AF_INET6, "1:0:0:0:0:0:0:8"));
89 
90     EXPECT_TRUE(isValidIP(AF_INET6, "1::8"));
91 
92     EXPECT_TRUE(isValidIP(AF_INET6, "0:0:0:0:0:FFFF:204.152.189.116"));
93 
94     EXPECT_TRUE(isValidIP(AF_INET6, "::ffff:204.152.189.116"));
95 
96     EXPECT_TRUE(isValidIP(AF_INET6, "a:0:0:0:0:FFFF:204.152.189.116"));
97 
98     EXPECT_TRUE(isValidIP(AF_INET6, "1::8"));
99 }
100 
101 TEST_F(TestUtil, PrefixValidation)
102 {
103     EXPECT_TRUE(isValidPrefix(AF_INET, 0));
104     EXPECT_TRUE(isValidPrefix(AF_INET, 1));
105     EXPECT_TRUE(isValidPrefix(AF_INET, 32));
106     EXPECT_FALSE(isValidPrefix(AF_INET, 33));
107     EXPECT_FALSE(isValidPrefix(AF_INET, 64));
108 
109     EXPECT_TRUE(isValidPrefix(AF_INET6, 0));
110     EXPECT_TRUE(isValidPrefix(AF_INET6, 1));
111     EXPECT_TRUE(isValidPrefix(AF_INET6, 53));
112     EXPECT_TRUE(isValidPrefix(AF_INET6, 64));
113     EXPECT_TRUE(isValidPrefix(AF_INET6, 128));
114     EXPECT_FALSE(isValidPrefix(AF_INET6, 129));
115     EXPECT_FALSE(isValidPrefix(AF_INET6, 177));
116 
117     EXPECT_THROW(isValidPrefix(AF_UNSPEC, 1), std::invalid_argument);
118 }
119 
120 TEST_F(TestUtil, InterfaceToUbootEthAddr)
121 {
122     EXPECT_EQ(std::nullopt, interfaceToUbootEthAddr("et"));
123     EXPECT_EQ(std::nullopt, interfaceToUbootEthAddr("eth"));
124     EXPECT_EQ(std::nullopt, interfaceToUbootEthAddr("sit0"));
125     EXPECT_EQ(std::nullopt, interfaceToUbootEthAddr("ethh0"));
126     EXPECT_EQ(std::nullopt, interfaceToUbootEthAddr("eth0h"));
127     EXPECT_EQ("ethaddr", interfaceToUbootEthAddr("eth0"));
128     EXPECT_EQ("eth1addr", interfaceToUbootEthAddr("eth1"));
129     EXPECT_EQ("eth5addr", interfaceToUbootEthAddr("eth5"));
130     EXPECT_EQ("eth28addr", interfaceToUbootEthAddr("eth28"));
131 }
132 
133 namespace mac_address
134 {
135 
136 TEST(MacFromString, Bad)
137 {
138     EXPECT_THROW(fromString("0x:00:00:00:00:00"), std::invalid_argument);
139     EXPECT_THROW(fromString("00:00:00:00:00"), std::invalid_argument);
140     EXPECT_THROW(fromString("00:00:00:00:00:"), std::invalid_argument);
141     EXPECT_THROW(fromString("00:00:00:00::00"), std::invalid_argument);
142     EXPECT_THROW(fromString(":00:00:00:00:00"), std::invalid_argument);
143     EXPECT_THROW(fromString("00::00:00:00:00"), std::invalid_argument);
144     EXPECT_THROW(fromString(":::::"), std::invalid_argument);
145     EXPECT_THROW(fromString("00:0:0:0:0"), std::invalid_argument);
146     EXPECT_THROW(fromString("00:00:00:00:00:00:00"), std::invalid_argument);
147     EXPECT_THROW(fromString(""), std::invalid_argument);
148     EXPECT_THROW(fromString("123456789XYZ"), std::invalid_argument);
149     EXPECT_THROW(fromString("123456789AB"), std::invalid_argument);
150     EXPECT_THROW(fromString("123456789ABCD"), std::invalid_argument);
151 }
152 
153 TEST(MacFromString, Valid)
154 {
155     EXPECT_TRUE(
156         stdplus::raw::equal(ether_addr{}, fromString("00:00:00:00:00:00")));
157     EXPECT_TRUE(
158         stdplus::raw::equal(ether_addr{0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa},
159                             fromString("FF:EE:DD:cc:bb:aa")));
160     EXPECT_TRUE(
161         stdplus::raw::equal(ether_addr{0x00, 0x01, 0x02, 0x03, 0x04, 0x05},
162                             fromString("0:1:2:3:4:5")));
163     EXPECT_TRUE(
164         stdplus::raw::equal(ether_addr{0x01, 0x23, 0x45, 0x67, 0x89, 0xab},
165                             fromString("0123456789AB")));
166     EXPECT_TRUE(
167         stdplus::raw::equal(ether_addr{0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa},
168                             fromString("FFEEDDccbbaa")));
169 }
170 
171 TEST(MacToString, Valid)
172 {
173     EXPECT_EQ("11:22:33:44:55:66",
174               toString({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}));
175     EXPECT_EQ("01:02:03:04:05:67",
176               toString({0x01, 0x02, 0x03, 0x04, 0x05, 0x67}));
177     EXPECT_EQ("00:00:00:00:00:00",
178               toString({0x00, 0x00, 0x00, 0x00, 0x00, 0x00}));
179 }
180 
181 TEST(MacIsEmpty, True)
182 {
183     EXPECT_TRUE(isEmpty({}));
184 }
185 
186 TEST(MacIsEmpty, False)
187 {
188     EXPECT_FALSE(isEmpty(fromString("01:00:00:00:00:00")));
189     EXPECT_FALSE(isEmpty(fromString("00:00:00:10:00:00")));
190     EXPECT_FALSE(isEmpty(fromString("00:00:00:00:00:01")));
191 }
192 
193 TEST(MacIsMulticast, True)
194 {
195     EXPECT_TRUE(isMulticast(fromString("ff:ff:ff:ff:ff:ff")));
196     EXPECT_TRUE(isMulticast(fromString("01:00:00:00:00:00")));
197 }
198 
199 TEST(MacIsMulticast, False)
200 {
201     EXPECT_FALSE(isMulticast(fromString("00:11:22:33:44:55")));
202     EXPECT_FALSE(isMulticast(fromString("FE:11:22:33:44:55")));
203 }
204 
205 TEST(MacIsUnicast, True)
206 {
207     EXPECT_TRUE(isUnicast(fromString("00:11:22:33:44:55")));
208     EXPECT_TRUE(isUnicast(fromString("FE:11:22:33:44:55")));
209 }
210 
211 TEST(MacIsUnicast, False)
212 {
213     EXPECT_FALSE(isUnicast(fromString("00:00:00:00:00:00")));
214     EXPECT_FALSE(isUnicast(fromString("01:00:00:00:00:00")));
215     EXPECT_FALSE(isUnicast(fromString("ff:ff:ff:ff:ff:ff")));
216 }
217 
218 TEST(IgnoredInterfaces, Empty)
219 {
220     auto ret = internal::parseInterfaces({});
221     EXPECT_TRUE(ret.empty());
222 
223     ret = internal::parseInterfaces(" ,  ,, ");
224     EXPECT_TRUE(ret.empty());
225 }
226 
227 TEST(IgnoredInterfaces, NotEmpty)
228 {
229     using ::testing::ContainerEq;
230     std::unordered_set<std::string_view> expected = {"eth0"};
231     auto ret = internal::parseInterfaces("eth0");
232     EXPECT_THAT(ret, ContainerEq(expected));
233 
234     expected = {"eth0", "eth1", "bond1", "usb0"};
235     ret = internal::parseInterfaces(" ,eth0, eth1  ,bond1, usb0,,");
236     EXPECT_THAT(ret, ContainerEq(expected));
237 }
238 
239 } // namespace mac_address
240 } // namespace network
241 } // namespace phosphor
242