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, InterfaceToUbootEthAddr)
131 {
132     EXPECT_EQ(std::nullopt, interfaceToUbootEthAddr("et"));
133     EXPECT_EQ(std::nullopt, interfaceToUbootEthAddr("eth"));
134     EXPECT_EQ(std::nullopt, interfaceToUbootEthAddr("sit0"));
135     EXPECT_EQ(std::nullopt, interfaceToUbootEthAddr("ethh0"));
136     EXPECT_EQ(std::nullopt, interfaceToUbootEthAddr("eth0h"));
137     EXPECT_EQ("ethaddr", interfaceToUbootEthAddr("eth0"));
138     EXPECT_EQ("eth1addr", interfaceToUbootEthAddr("eth1"));
139     EXPECT_EQ("eth5addr", interfaceToUbootEthAddr("eth5"));
140     EXPECT_EQ("eth28addr", interfaceToUbootEthAddr("eth28"));
141 }
142 
143 namespace mac_address
144 {
145 
146 TEST(MacFromString, Bad)
147 {
148     EXPECT_THROW(fromString("0x:00:00:00:00:00"), std::invalid_argument);
149     EXPECT_THROW(fromString("00:00:00:00:00"), std::invalid_argument);
150     EXPECT_THROW(fromString(""), std::invalid_argument);
151     EXPECT_THROW(fromString("123456789XYZ"), std::invalid_argument);
152     EXPECT_THROW(fromString("123456789AB"), std::invalid_argument);
153     EXPECT_THROW(fromString("123456789ABCD"), std::invalid_argument);
154 }
155 
156 TEST(MacFromString, Valid)
157 {
158     EXPECT_TRUE(
159         stdplus::raw::equal(ether_addr{}, fromString("00:00:00:00:00:00")));
160     EXPECT_TRUE(
161         stdplus::raw::equal(ether_addr{0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa},
162                             fromString("FF:EE:DD:cc:bb:aa")));
163     EXPECT_TRUE(
164         stdplus::raw::equal(ether_addr{0x00, 0x01, 0x02, 0x03, 0x04, 0x05},
165                             fromString("0:1:2:3:4:5")));
166     EXPECT_TRUE(
167         stdplus::raw::equal(ether_addr{0x01, 0x23, 0x45, 0x67, 0x89, 0xab},
168                             fromString("0123456789AB")));
169     EXPECT_TRUE(
170         stdplus::raw::equal(ether_addr{0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa},
171                             fromString("FFEEDDccbbaa")));
172 }
173 
174 TEST(MacToString, Valid)
175 {
176     EXPECT_EQ("11:22:33:44:55:66",
177               toString({0x11, 0x22, 0x33, 0x44, 0x55, 0x66}));
178     EXPECT_EQ("01:02:03:04:05:67",
179               toString({0x01, 0x02, 0x03, 0x04, 0x05, 0x67}));
180     EXPECT_EQ("00:00:00:00:00:00",
181               toString({0x00, 0x00, 0x00, 0x00, 0x00, 0x00}));
182 }
183 
184 TEST(MacIsEmpty, True)
185 {
186     EXPECT_TRUE(isEmpty({}));
187 }
188 
189 TEST(MacIsEmpty, False)
190 {
191     EXPECT_FALSE(isEmpty(fromString("01:00:00:00:00:00")));
192     EXPECT_FALSE(isEmpty(fromString("00:00:00:10:00:00")));
193     EXPECT_FALSE(isEmpty(fromString("00:00:00:00:00:01")));
194 }
195 
196 TEST(MacIsMulticast, True)
197 {
198     EXPECT_TRUE(isMulticast(fromString("ff:ff:ff:ff:ff:ff")));
199     EXPECT_TRUE(isMulticast(fromString("01:00:00:00:00:00")));
200 }
201 
202 TEST(MacIsMulticast, False)
203 {
204     EXPECT_FALSE(isMulticast(fromString("00:11:22:33:44:55")));
205     EXPECT_FALSE(isMulticast(fromString("FE:11:22:33:44:55")));
206 }
207 
208 TEST(MacIsUnicast, True)
209 {
210     EXPECT_TRUE(isUnicast(fromString("00:11:22:33:44:55")));
211     EXPECT_TRUE(isUnicast(fromString("FE:11:22:33:44:55")));
212 }
213 
214 TEST(MacIsUnicast, False)
215 {
216     EXPECT_FALSE(isUnicast(fromString("00:00:00:00:00:00")));
217     EXPECT_FALSE(isUnicast(fromString("01:00:00:00:00:00")));
218     EXPECT_FALSE(isUnicast(fromString("ff:ff:ff:ff:ff:ff")));
219 }
220 
221 TEST(IgnoredInterfaces, Empty)
222 {
223     auto ret = internal::parseInterfaces({});
224     EXPECT_TRUE(ret.empty());
225 
226     ret = internal::parseInterfaces(" ,  ,, ");
227     EXPECT_TRUE(ret.empty());
228 }
229 
230 TEST(IgnoredInterfaces, NotEmpty)
231 {
232     using ::testing::ContainerEq;
233     std::set<std::string_view> expected = {"eth0"};
234     auto ret = internal::parseInterfaces("eth0");
235     EXPECT_THAT(ret, ContainerEq(expected));
236 
237     expected = {"eth0", "eth1", "bond1", "usb0"};
238     ret = internal::parseInterfaces(" ,eth0, eth1  ,bond1, usb0,,");
239     EXPECT_THAT(ret, ContainerEq(expected));
240 }
241 
242 } // namespace mac_address
243 } // namespace network
244 } // namespace phosphor
245