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