rippled
Loading...
Searching...
No Matches
IPEndpoint_test.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of Beast: https://github.com/vinniefalco/Beast
4 Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20// MODULES: ../impl/IPEndpoint.cpp ../impl/IPAddressV4.cpp
21// ../impl/IPAddressV6.cpp
22
23#include <test/beast/IPEndpointCommon.h>
24
25#include <xrpl/basics/random.h>
26#include <xrpl/beast/net/IPEndpoint.h>
27#include <xrpl/beast/unit_test.h>
28
29#include <boost/algorithm/string.hpp>
30#include <boost/asio/ip/address.hpp>
31#include <boost/predef.h>
32
33namespace beast {
34namespace IP {
35
36//------------------------------------------------------------------------------
37
39{
40public:
41 void
43 std::string const& s,
44 std::uint32_t value,
45 std::string const& normal = "")
46 {
47 boost::system::error_code ec;
48 Address const result{Address::from_string(s, ec)};
49 if (!BEAST_EXPECTS(!ec, ec.message()))
50 return;
51 if (!BEAST_EXPECTS(result.is_v4(), s + " not v4"))
52 return;
53 if (!BEAST_EXPECTS(
54 result.to_v4().to_ulong() == value, s + " value mismatch"))
55 return;
56 BEAST_EXPECTS(
57 result.to_string() == (normal.empty() ? s : normal),
58 s + " as string");
59 }
60
61 void
63 {
64 boost::system::error_code ec;
65 auto a = Address::from_string(s, ec);
66 BEAST_EXPECTS(ec, s + " parses as " + a.to_string());
67 }
68
69 void
71 {
72 testcase("AddressV4");
73
74 BEAST_EXPECT(AddressV4{}.to_ulong() == 0);
75 BEAST_EXPECT(is_unspecified(AddressV4{}));
76 BEAST_EXPECT(AddressV4{0x01020304}.to_ulong() == 0x01020304);
77
78 {
79 AddressV4::bytes_type d = {{1, 2, 3, 4}};
80 BEAST_EXPECT(AddressV4{d}.to_ulong() == 0x01020304);
81
83 }
84
85 AddressV4 const v1{1};
86 BEAST_EXPECT(AddressV4{v1}.to_ulong() == 1);
87
88 {
89 AddressV4 v;
90 v = v1;
91 BEAST_EXPECT(v.to_ulong() == v1.to_ulong());
92 }
93
94 {
95 AddressV4 v;
96 auto d = v.to_bytes();
97 d[0] = 1;
98 d[1] = 2;
99 d[2] = 3;
100 d[3] = 4;
101 v = AddressV4{d};
102 BEAST_EXPECT(v.to_ulong() == 0x01020304);
103 }
104
105 BEAST_EXPECT(AddressV4(0x01020304).to_string() == "1.2.3.4");
106
107 shouldParseAddrV4("1.2.3.4", 0x01020304);
108 shouldParseAddrV4("255.255.255.255", 0xffffffff);
109 shouldParseAddrV4("0.0.0.0", 0);
110
111 failParseAddr(".");
112 failParseAddr("..");
113 failParseAddr("...");
114 failParseAddr("....");
115#if BOOST_OS_WINDOWS
116 // WINDOWS bug in asio - I don't think these should parse
117 // at all, and in-fact they do not on mac/linux
118 shouldParseAddrV4("1", 0x00000001, "0.0.0.1");
119 shouldParseAddrV4("1.2", 0x01000002, "1.0.0.2");
120 shouldParseAddrV4("1.2.3", 0x01020003, "1.2.0.3");
121#else
122 failParseAddr("1");
123 failParseAddr("1.2");
124 failParseAddr("1.2.3");
125#endif
126 failParseAddr("1.");
127 failParseAddr("1.2.");
128 failParseAddr("1.2.3.");
129 failParseAddr("256.0.0.0");
130 failParseAddr("-1.2.3.4");
131 }
132
133 void
135 {
136 testcase("AddressV4::Bytes");
137
138 AddressV4::bytes_type d1 = {{10, 0, 0, 1}};
139 AddressV4 v4{d1};
140 BEAST_EXPECT(v4.to_bytes()[0] == 10);
141 BEAST_EXPECT(v4.to_bytes()[1] == 0);
142 BEAST_EXPECT(v4.to_bytes()[2] == 0);
143 BEAST_EXPECT(v4.to_bytes()[3] == 1);
144
145 BEAST_EXPECT((~((0xff) << 16)) == 0xff00ffff);
146
147 auto d2 = v4.to_bytes();
148 d2[1] = 10;
149 v4 = AddressV4{d2};
150 BEAST_EXPECT(v4.to_bytes()[0] == 10);
151 BEAST_EXPECT(v4.to_bytes()[1] == 10);
152 BEAST_EXPECT(v4.to_bytes()[2] == 0);
153 BEAST_EXPECT(v4.to_bytes()[3] == 1);
154 }
155
156 //--------------------------------------------------------------------------
157
158 void
160 {
161 testcase("Address");
162
163 boost::system::error_code ec;
164 Address result{Address::from_string("1.2.3.4", ec)};
165 AddressV4::bytes_type d = {{1, 2, 3, 4}};
166 BEAST_EXPECT(!ec);
167 BEAST_EXPECT(result.is_v4() && result.to_v4() == AddressV4{d});
168 }
169
170 //--------------------------------------------------------------------------
171
172 void
174 std::string const& s,
175 AddressV4::bytes_type const& value,
177 std::string const& normal = "")
178 {
179 auto const result = Endpoint::from_string_checked(s);
180 if (!BEAST_EXPECT(result))
181 return;
182 if (!BEAST_EXPECT(result->address().is_v4()))
183 return;
184 if (!BEAST_EXPECT(result->address().to_v4() == AddressV4{value}))
185 return;
186
187 BEAST_EXPECT(result->port() == p);
188 BEAST_EXPECT(to_string(*result) == (normal.empty() ? s : normal));
189 }
190
191 void
193 std::string const& s,
194 AddressV6::bytes_type const& value,
196 std::string const& normal = "")
197 {
198 auto result = Endpoint::from_string_checked(s);
199 if (!BEAST_EXPECT(result))
200 return;
201 if (!BEAST_EXPECT(result->address().is_v6()))
202 return;
203 if (!BEAST_EXPECT(result->address().to_v6() == AddressV6{value}))
204 return;
205
206 BEAST_EXPECT(result->port() == p);
207 BEAST_EXPECT(to_string(*result) == (normal.empty() ? s : normal));
208 }
209
210 void
212 {
213 auto a1 = Endpoint::from_string(s);
214 BEAST_EXPECTS(is_unspecified(a1), s + " parses as " + a1.to_string());
215
216 auto a2 = Endpoint::from_string(s);
217 BEAST_EXPECTS(is_unspecified(a2), s + " parses as " + a2.to_string());
218
219 boost::replace_last(s, ":", " ");
220 auto a3 = Endpoint::from_string(s);
221 BEAST_EXPECTS(is_unspecified(a3), s + " parses as " + a3.to_string());
222 }
223
224 void
226 {
227 testcase("Endpoint");
228
229 shouldParseEPV4("1.2.3.4", {{1, 2, 3, 4}}, 0);
230 shouldParseEPV4("1.2.3.4:5", {{1, 2, 3, 4}}, 5);
231 shouldParseEPV4("1.2.3.4 5", {{1, 2, 3, 4}}, 5, "1.2.3.4:5");
232 // leading, trailing space
233 shouldParseEPV4(" 1.2.3.4:5", {{1, 2, 3, 4}}, 5, "1.2.3.4:5");
234 shouldParseEPV4("1.2.3.4:5 ", {{1, 2, 3, 4}}, 5, "1.2.3.4:5");
235 shouldParseEPV4("1.2.3.4 ", {{1, 2, 3, 4}}, 0, "1.2.3.4");
236 shouldParseEPV4(" 1.2.3.4", {{1, 2, 3, 4}}, 0, "1.2.3.4");
238 "2001:db8:a0b:12f0::1",
239 {{32, 01, 13, 184, 10, 11, 18, 240, 0, 0, 0, 0, 0, 0, 0, 1}},
240 0);
242 "[2001:db8:a0b:12f0::1]:8",
243 {{32, 01, 13, 184, 10, 11, 18, 240, 0, 0, 0, 0, 0, 0, 0, 1}},
244 8);
246 "[2001:2002:2003:2004:2005:2006:2007:2008]:65535",
247 {{32, 1, 32, 2, 32, 3, 32, 4, 32, 5, 32, 6, 32, 7, 32, 8}},
248 65535);
250 "2001:2002:2003:2004:2005:2006:2007:2008 65535",
251 {{32, 1, 32, 2, 32, 3, 32, 4, 32, 5, 32, 6, 32, 7, 32, 8}},
252 65535,
253 "[2001:2002:2003:2004:2005:2006:2007:2008]:65535");
254
255 Endpoint ep;
256
257 AddressV4::bytes_type d = {{127, 0, 0, 1}};
258 ep = Endpoint(AddressV4{d}, 80);
259 BEAST_EXPECT(!is_unspecified(ep));
260 BEAST_EXPECT(!is_public(ep));
261 BEAST_EXPECT(is_private(ep));
262 BEAST_EXPECT(!is_multicast(ep));
263 BEAST_EXPECT(is_loopback(ep));
264 BEAST_EXPECT(to_string(ep) == "127.0.0.1:80");
265 // same address as v4 mapped in ipv6
266 ep = Endpoint(AddressV6::v4_mapped(AddressV4{d}), 80);
267 BEAST_EXPECT(!is_unspecified(ep));
268 BEAST_EXPECT(!is_public(ep));
269 BEAST_EXPECT(is_private(ep));
270 BEAST_EXPECT(!is_multicast(ep));
271 BEAST_EXPECT(!is_loopback(ep)); // mapped loopback is not a loopback
272 BEAST_EXPECTS(to_string(ep) == "[::ffff:127.0.0.1]:80", to_string(ep));
273
274 d = {{10, 0, 0, 1}};
275 ep = Endpoint(AddressV4{d});
276 BEAST_EXPECT(get_class(ep.to_v4()) == 'A');
277 BEAST_EXPECT(!is_unspecified(ep));
278 BEAST_EXPECT(!is_public(ep));
279 BEAST_EXPECT(is_private(ep));
280 BEAST_EXPECT(!is_multicast(ep));
281 BEAST_EXPECT(!is_loopback(ep));
282 BEAST_EXPECT(to_string(ep) == "10.0.0.1");
283 // same address as v4 mapped in ipv6
284 ep = Endpoint(AddressV6::v4_mapped(AddressV4{d}));
285 BEAST_EXPECT(get_class(ep.to_v6().to_v4()) == 'A');
286 BEAST_EXPECT(!is_unspecified(ep));
287 BEAST_EXPECT(!is_public(ep));
288 BEAST_EXPECT(is_private(ep));
289 BEAST_EXPECT(!is_multicast(ep));
290 BEAST_EXPECT(!is_loopback(ep));
291 BEAST_EXPECTS(to_string(ep) == "::ffff:10.0.0.1", to_string(ep));
292
293 d = {{166, 78, 151, 147}};
294 ep = Endpoint(AddressV4{d});
295 BEAST_EXPECT(!is_unspecified(ep));
296 BEAST_EXPECT(is_public(ep));
297 BEAST_EXPECT(!is_private(ep));
298 BEAST_EXPECT(!is_multicast(ep));
299 BEAST_EXPECT(!is_loopback(ep));
300 BEAST_EXPECT(to_string(ep) == "166.78.151.147");
301 // same address as v4 mapped in ipv6
302 ep = Endpoint(AddressV6::v4_mapped(AddressV4{d}));
303 BEAST_EXPECT(!is_unspecified(ep));
304 BEAST_EXPECT(is_public(ep));
305 BEAST_EXPECT(!is_private(ep));
306 BEAST_EXPECT(!is_multicast(ep));
307 BEAST_EXPECT(!is_loopback(ep));
308 BEAST_EXPECTS(to_string(ep) == "::ffff:166.78.151.147", to_string(ep));
309
310 // a private IPv6
311 AddressV6::bytes_type d2 = {
312 {253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}};
313 ep = Endpoint(AddressV6{d2});
314 BEAST_EXPECT(!is_unspecified(ep));
315 BEAST_EXPECT(!is_public(ep));
316 BEAST_EXPECT(is_private(ep));
317 BEAST_EXPECT(!is_multicast(ep));
318 BEAST_EXPECT(!is_loopback(ep));
319 BEAST_EXPECTS(to_string(ep) == "fd00::1", to_string(ep));
320
321 {
322 ep = Endpoint::from_string("192.0.2.112");
323 BEAST_EXPECT(!is_unspecified(ep));
324 BEAST_EXPECT(ep == Endpoint::from_string("192.0.2.112"));
325
326 auto const ep1 = Endpoint::from_string("192.0.2.112:2016");
327 BEAST_EXPECT(!is_unspecified(ep1));
328 BEAST_EXPECT(ep.address() == ep1.address());
329 BEAST_EXPECT(ep1.port() == 2016);
330
331 auto const ep2 = Endpoint::from_string("192.0.2.112:2016");
332 BEAST_EXPECT(!is_unspecified(ep2));
333 BEAST_EXPECT(ep.address() == ep2.address());
334 BEAST_EXPECT(ep2.port() == 2016);
335 BEAST_EXPECT(ep1 == ep2);
336
337 auto const ep3 = Endpoint::from_string("192.0.2.112 2016");
338 BEAST_EXPECT(!is_unspecified(ep3));
339 BEAST_EXPECT(ep.address() == ep3.address());
340 BEAST_EXPECT(ep3.port() == 2016);
341 BEAST_EXPECT(ep2 == ep3);
342
343 auto const ep4 = Endpoint::from_string("192.0.2.112 2016");
344 BEAST_EXPECT(!is_unspecified(ep4));
345 BEAST_EXPECT(ep.address() == ep4.address());
346 BEAST_EXPECT(ep4.port() == 2016);
347 BEAST_EXPECT(ep3 == ep4);
348
349 BEAST_EXPECT(to_string(ep1) == to_string(ep2));
350 BEAST_EXPECT(to_string(ep1) == to_string(ep3));
351 BEAST_EXPECT(to_string(ep1) == to_string(ep4));
352 }
353
354 {
355 ep = Endpoint::from_string("[::]:2017");
356 BEAST_EXPECT(is_unspecified(ep));
357 BEAST_EXPECT(ep.port() == 2017);
358 BEAST_EXPECT(ep.address() == AddressV6{});
359 }
360
361 // Failures:
362 failParseEP("192.0.2.112:port");
363 failParseEP("ip:port");
364 failParseEP("");
365 failParseEP("1.2.3.256");
366
367#if BOOST_OS_WINDOWS
368 // windows asio bugs...false positives
369 shouldParseEPV4("255", {{ 0, 0, 0, 255 }}, 0, "0.0.0.255");
370 shouldParseEPV4("512", {{ 0, 0, 2, 0 }}, 0, "0.0.2.0");
371 shouldParseEPV4("1.2.3:80", {{ 1, 2, 0, 3 }}, 80, "1.2.0.3:80");
372#else
373 failParseEP("255");
374 failParseEP("512");
375 failParseEP("1.2.3:80");
376#endif
377
378 failParseEP("1.2.3.4:65536");
379 failParseEP("1.2.3.4:89119");
380 failParseEP("1.2.3:89119");
381 failParseEP("[::1]:89119");
382 failParseEP("[::az]:1");
383 failParseEP("[1234:5678:90ab:cdef:1234:5678:90ab:cdef:1111]:1");
384 failParseEP("[1234:5678:90ab:cdef:1234:5678:90ab:cdef:1111]:12345");
385 failParseEP("abcdef:12345");
386 failParseEP("[abcdef]:12345");
387 failParseEP("foo.org 12345");
388
389 // test with hashed container
391 constexpr auto items{100};
392 float max_lf{0};
393 for (auto i = 0; i < items; ++i)
394 {
395 eps.insert(randomEP(ripple::rand_int(0, 1) == 1));
396 max_lf = std::max(max_lf, eps.load_factor());
397 }
398 BEAST_EXPECT(eps.bucket_count() >= items);
399 BEAST_EXPECT(max_lf > 0.90);
400 }
401
402 //--------------------------------------------------------------------------
403
404 template <typename T>
405 bool
406 parse(std::string const& text, T& t)
407 {
408 std::istringstream stream{text};
409 stream >> t;
410 return !stream.fail();
411 }
412
413 template <typename T>
414 void
415 shouldPass(std::string const& text, std::string const& normal = "")
416 {
417 using namespace std::literals;
418 T t;
419 BEAST_EXPECT(parse(text, t));
420 BEAST_EXPECTS(
421 to_string(t) == (normal.empty() ? text : normal),
422 "string mismatch for "s + text);
423 }
424
425 template <typename T>
426 void
428 {
429 T t;
430 unexpected(parse(text, t), text + " should not parse");
431 }
432
433 template <typename T>
434 void
435 testParse(char const* name)
436 {
437 testcase(name);
438
439 shouldPass<T>("0.0.0.0");
440 shouldPass<T>("192.168.0.1");
441 shouldPass<T>("168.127.149.132");
442 shouldPass<T>("168.127.149.132:80");
443 shouldPass<T>("168.127.149.132:54321");
444 shouldPass<T>("2001:db8:a0b:12f0::1");
445 shouldPass<T>("[2001:db8:a0b:12f0::1]:8");
446 shouldPass<T>("2001:db8:a0b:12f0::1 8", "[2001:db8:a0b:12f0::1]:8");
447 shouldPass<T>("[::1]:8");
448 shouldPass<T>("[2001:2002:2003:2004:2005:2006:2007:2008]:65535");
449
450 shouldFail<T>("1.2.3.256");
451 shouldFail<T>("");
452#if BOOST_OS_WINDOWS
453 // windows asio bugs...false positives
454 shouldPass<T>("512", "0.0.2.0");
455 shouldPass<T>("255", "0.0.0.255");
456 shouldPass<T>("1.2.3:80", "1.2.0.3:80");
457#else
458 shouldFail<T>("512");
459 shouldFail<T>("255");
460 shouldFail<T>("1.2.3:80");
461#endif
462 shouldFail<T>("1.2.3:65536");
463 shouldFail<T>("1.2.3:72131");
464 shouldFail<T>("[::1]:89119");
465 shouldFail<T>("[::az]:1");
466 shouldFail<T>("[1234:5678:90ab:cdef:1234:5678:90ab:cdef:1111]:1");
467 shouldFail<T>("[1234:5678:90ab:cdef:1234:5678:90ab:cdef:1111]:12345");
468 }
469
470 void
471 run() override
472 {
475 testAddress();
476 testEndpoint();
477 testParse<Endpoint>("Parse Endpoint");
478 }
479};
480
481BEAST_DEFINE_TESTSUITE(IPEndpoint, net, beast);
482
483} // namespace IP
484} // namespace beast
T bucket_count(T... args)
A version-independent IP address and port combination.
Definition: IPEndpoint.h:39
static std::optional< Endpoint > from_string_checked(std::string const &s)
Create an Endpoint from a string.
Definition: IPEndpoint.cpp:45
static Endpoint from_string(std::string const &s)
Definition: IPEndpoint.cpp:59
void run() override
Runs the suite.
void shouldPass(std::string const &text, std::string const &normal="")
void shouldParseEPV4(std::string const &s, AddressV4::bytes_type const &value, std::uint16_t p, std::string const &normal="")
bool parse(std::string const &text, T &t)
void shouldParseAddrV4(std::string const &s, std::uint32_t value, std::string const &normal="")
void failParseAddr(std::string const &s)
void shouldFail(std::string const &text)
void testParse(char const *name)
void failParseEP(std::string s)
void shouldParseEPV6(std::string const &s, AddressV6::bytes_type const &value, std::uint16_t p, std::string const &normal="")
A testsuite class.
Definition: suite.h:55
bool unexpected(Condition shouldBeFalse, String const &reason)
Definition: suite.h:499
testcase_t testcase
Memberspace for declaring test cases.
Definition: suite.h:155
T insert(T... args)
T load_factor(T... args)
T max(T... args)
bool is_multicast(Address const &addr)
Returns true if the address is a multicast address.
Definition: IPAddress.h:68
bool is_loopback(Address const &addr)
Returns true if this is a loopback address.
Definition: IPAddress.h:54
char get_class(AddressV4 const &address)
Returns the address class for the given address.
Definition: IPAddressV4.cpp:44
boost::asio::ip::address_v6 AddressV6
Definition: IPAddressV6.h:36
bool is_public(Address const &addr)
Returns true if the address is a public routable address.
Definition: IPAddress.h:82
Endpoint randomEP(bool v4=true)
bool is_unspecified(Address const &addr)
Returns true if the address is unspecified.
Definition: IPAddress.h:61
boost::asio::ip::address_v4 AddressV4
Definition: IPAddressV4.h:36
boost::asio::ip::address Address
Definition: IPAddress.h:43
bool is_private(Address const &addr)
Returns true if the address is a private unroutable address.
Definition: IPAddress.h:75
std::string to_string(Address const &addr)
Returns the address represented as a string.
Definition: IPAddress.h:47
std::enable_if_t< std::is_integral< Integral >::value, Integral > rand_int()