Line data Source code
1 : // Copyright (c) 2011-2021 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // Project: https://snapwebsites.org/project/libaddr
4 : //
5 : // Permission is hereby granted, free of charge, to any
6 : // person obtaining a copy of this software and
7 : // associated documentation files (the "Software"), to
8 : // deal in the Software without restriction, including
9 : // without limitation the rights to use, copy, modify,
10 : // merge, publish, distribute, sublicense, and/or sell
11 : // copies of the Software, and to permit persons to whom
12 : // the Software is furnished to do so, subject to the
13 : // following conditions:
14 : //
15 : // The above copyright notice and this permission notice
16 : // shall be included in all copies or substantial
17 : // portions of the Software.
18 : //
19 : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
20 : // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
21 : // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
22 : // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
23 : // EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 : // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 : // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26 : // ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27 : // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 : // SOFTWARE.
29 :
30 :
31 : /** \file
32 : * \brief Test the IPv6 interface.
33 : *
34 : * These test verify that the IPv6 side of things function as expected.
35 : *
36 : * Note that some of the tests between the IPv4 and IPv6 overlap. Here
37 : * you mainly find the IPv6 side of things.
38 : *
39 : * Also, the IPv6 tests include a certain number of default/global
40 : * tests because internally the addr class implements an IPv6 object.
41 : */
42 :
43 : // self
44 : //
45 : #include "catch_main.h"
46 :
47 :
48 : // addr lib
49 : //
50 : #include <libaddr/iface.h>
51 :
52 :
53 : // last include
54 : //
55 : #include <snapdev/poison.h>
56 :
57 :
58 :
59 :
60 : /** \brief Details used by the addr class implementation.
61 : *
62 : * We have a function to check whether an address is part of
63 : * the interfaces of your computer. This check requires the
64 : * use of a `struct ifaddrs` and as such it requires to
65 : * delete that structure. We define a deleter for that
66 : * strucure here.
67 : */
68 : namespace
69 : {
70 :
71 : /** \brief Close a socket.
72 : *
73 : * This deleter is used to make sure all the sockets get closed on exit.
74 : *
75 : * \param[in] s The socket to close.
76 : */
77 3 : void socket_deleter(int * s)
78 : {
79 3 : close(*s);
80 3 : }
81 :
82 :
83 : }
84 : // no name namespace
85 :
86 :
87 :
88 16 : CATCH_TEST_CASE( "ipv6::invalid_input", "[ipv6]" )
89 : {
90 28 : CATCH_GIVEN("addr()")
91 : {
92 1 : addr::addr a;
93 :
94 2 : CATCH_SECTION("set IPv6 with an invalid family")
95 : {
96 1 : struct sockaddr_in6 in6 = sockaddr_in6();
97 0 : do
98 : {
99 1 : in6.sin6_family = rand();
100 : }
101 1 : while(in6.sin6_family == AF_INET6);
102 1 : in6.sin6_port = rand();
103 9 : for(int idx(0); idx < 8; ++idx)
104 : {
105 8 : in6.sin6_addr.s6_addr16[idx] = rand();
106 : }
107 1 : CATCH_REQUIRE_THROWS_AS(a.set_ipv6(in6), addr::addr_invalid_argument);
108 1 : CATCH_REQUIRE_THROWS_AS(addr::addr(in6), addr::addr_invalid_argument);
109 : }
110 : }
111 :
112 28 : CATCH_GIVEN("addr_parser() with IPv6 addresses")
113 : {
114 6 : CATCH_SECTION("bad address")
115 : {
116 2 : addr::addr_parser p;
117 2 : addr::addr_range::vector_t ips(p.parse("[{bad-ip}]"));
118 1 : CATCH_REQUIRE(p.has_errors());
119 1 : CATCH_REQUIRE(p.error_count() == 1);
120 1 : CATCH_REQUIRE(p.error_messages() == "Invalid address in \"{bad-ip}\" error -2 -- Name or service not known (errno: 2 -- No such file or directory).\n");
121 1 : CATCH_REQUIRE(ips.size() == 0);
122 : }
123 :
124 6 : CATCH_SECTION("missing ']'")
125 : {
126 2 : addr::addr_parser p;
127 2 : addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7"));
128 1 : CATCH_REQUIRE(p.has_errors());
129 1 : CATCH_REQUIRE(p.error_count() == 1);
130 1 : CATCH_REQUIRE(p.error_messages() == "IPv6 is missing the ']' ([1:2:3:4:5:6:7).\n");
131 1 : CATCH_REQUIRE(ips.size() == 0);
132 : }
133 :
134 6 : CATCH_SECTION("required address")
135 : {
136 2 : addr::addr_parser p;
137 1 : p.set_protocol(IPPROTO_TCP);
138 1 : p.set_allow(addr::addr_parser::flag_t::REQUIRED_ADDRESS, true);
139 2 : addr::addr_range::vector_t ips(p.parse("[]"));
140 1 : CATCH_REQUIRE(p.has_errors());
141 1 : CATCH_REQUIRE(p.error_count() == 1);
142 1 : CATCH_REQUIRE(p.error_messages() == "Required address is missing.\n");
143 1 : CATCH_REQUIRE(ips.size() == 0);
144 : }
145 : }
146 :
147 28 : CATCH_GIVEN("addr_parser() with IPv4 ports")
148 : {
149 4 : CATCH_SECTION("required port")
150 : {
151 : // optional + required -> required
152 : {
153 2 : addr::addr_parser p;
154 1 : p.set_protocol(IPPROTO_TCP);
155 1 : p.set_allow(addr::addr_parser::flag_t::REQUIRED_PORT, true);
156 2 : addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]"));
157 1 : CATCH_REQUIRE(p.has_errors());
158 1 : CATCH_REQUIRE(p.error_count() == 1);
159 1 : CATCH_REQUIRE(p.error_messages() == "Required port is missing.\n");
160 1 : CATCH_REQUIRE(ips.size() == 0);
161 : }
162 :
163 : // only required -> required just the same
164 : {
165 2 : addr::addr_parser p;
166 1 : p.set_protocol(IPPROTO_TCP);
167 1 : p.set_allow(addr::addr_parser::flag_t::PORT, false);
168 1 : p.set_allow(addr::addr_parser::flag_t::REQUIRED_PORT, true);
169 2 : addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]"));
170 1 : CATCH_REQUIRE(p.has_errors());
171 1 : CATCH_REQUIRE(p.error_count() == 1);
172 1 : CATCH_REQUIRE(p.error_messages() == "Required port is missing.\n");
173 1 : CATCH_REQUIRE(ips.size() == 0);
174 : }
175 : }
176 :
177 4 : CATCH_SECTION("port not allowed")
178 : {
179 : {
180 2 : addr::addr_parser p;
181 1 : p.set_protocol(IPPROTO_TCP);
182 1 : p.set_allow(addr::addr_parser::flag_t::PORT, false);
183 2 : addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]:123"));
184 1 : CATCH_REQUIRE(p.has_errors());
185 1 : CATCH_REQUIRE(p.error_count() == 1);
186 1 : CATCH_REQUIRE(p.error_messages() == "Port not allowed ([1:2:3:4:5:6:7:8]:123).\n");
187 1 : CATCH_REQUIRE(ips.size() == 0);
188 : }
189 :
190 : {
191 2 : addr::addr_parser p;
192 1 : p.set_protocol(IPPROTO_TCP);
193 1 : p.set_allow(addr::addr_parser::flag_t::PORT, false);
194 2 : addr::addr_range::vector_t ips(p.parse("1:2:3:4:5:6:7:8:123.5"));
195 1 : CATCH_REQUIRE(p.has_errors());
196 1 : CATCH_REQUIRE(p.error_count() == 1);
197 1 : CATCH_REQUIRE(p.error_messages() == "Port not allowed (1:2:3:4:5:6:7:8:123.5).\n");
198 1 : CATCH_REQUIRE(ips.size() == 0);
199 : }
200 : }
201 : }
202 :
203 28 : CATCH_GIVEN("addr_parser() with invalid masks")
204 : {
205 16 : CATCH_SECTION("really large numbers (over 1000)")
206 : {
207 6 : for(int idx(0); idx < 5; ++idx)
208 : {
209 5 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
210 5 : int const port(rand() & 0xFFFF);
211 5 : int const mask((rand() & 0xFF) + 1001);
212 10 : addr::addr_parser p;
213 5 : p.set_protocol(proto);
214 5 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
215 10 : addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]:" + std::to_string(port) + "/" + std::to_string(mask)));
216 5 : CATCH_REQUIRE(p.has_errors());
217 5 : CATCH_REQUIRE(p.error_count() == 1);
218 5 : CATCH_REQUIRE(p.error_messages() == "Mask number too large (" + std::to_string(mask) + ", expected a maximum of 128).\n");
219 5 : CATCH_REQUIRE(ips.size() == 0);
220 : }
221 :
222 : // in case the number is between square brackets it looks like
223 : // an IPv4 to getaddrinfo() so we get a different error...
224 : // (i.e. the '[' is not a digit so we do not get the "too large"
225 : // error...)
226 : //
227 6 : for(int idx(0); idx < 5; ++idx)
228 : {
229 5 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
230 5 : int const port(rand() & 0xFFFF);
231 5 : int const mask((rand() & 0xFF) + 1001);
232 10 : addr::addr_parser p;
233 5 : p.set_protocol(proto);
234 5 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
235 10 : addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]:" + std::to_string(port) + "/[" + std::to_string(mask) + "]"));
236 5 : CATCH_REQUIRE(p.has_errors());
237 5 : CATCH_REQUIRE(p.error_count() == 1);
238 5 : CATCH_REQUIRE(p.error_messages() == "Incompatible address between the address and mask address (first was an IPv6 second an IPv4).\n");
239 5 : CATCH_REQUIRE(ips.size() == 0);
240 : }
241 :
242 : // an empty address with a mask too large gets us to another place
243 : //
244 6 : for(int idx(0); idx < 5; ++idx)
245 : {
246 5 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
247 5 : int const port(rand() & 0xFFFF);
248 5 : int const mask((rand() & 0xFF) + 1001);
249 10 : addr::addr_parser p;
250 5 : p.set_protocol(proto);
251 5 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
252 10 : addr::addr_range::vector_t ips(p.parse(":" + std::to_string(port) + "/" + std::to_string(mask)));
253 5 : CATCH_REQUIRE(p.has_errors());
254 5 : CATCH_REQUIRE(p.error_count() == 1);
255 5 : CATCH_REQUIRE(p.error_messages() == "Mask number too large (" + std::to_string(mask) + ", expected a maximum of 128).\n");
256 5 : CATCH_REQUIRE(ips.size() == 0);
257 : }
258 :
259 : // an empty address with a mask too large gets us to another place
260 : //
261 6 : for(int idx(0); idx < 5; ++idx)
262 : {
263 5 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
264 5 : int const port(rand() & 0xFFFF);
265 5 : int const mask((rand() & 0xFF));
266 10 : addr::addr_parser p;
267 5 : p.set_protocol(proto);
268 5 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
269 10 : addr::addr_range::vector_t ips(p.parse(":" + std::to_string(port) + "/" + std::to_string(mask) + "q"));
270 5 : CATCH_REQUIRE(p.has_errors());
271 5 : CATCH_REQUIRE(p.error_count() == 1);
272 5 : CATCH_REQUIRE(p.error_messages() == "Invalid mask in \"/" + std::to_string(mask) + "q\", error -2 -- Name or service not known (errno: 0 -- Success).\n");
273 5 : CATCH_REQUIRE(ips.size() == 0);
274 : }
275 : }
276 :
277 16 : CATCH_SECTION("ipv6 mask is limited between 0 and 128")
278 : {
279 6 : for(int idx(0); idx < 5; ++idx)
280 : {
281 5 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
282 5 : int const port(rand() & 0xFFFF);
283 5 : int const mask((rand() & 0xFF) + 129);
284 10 : addr::addr_parser p;
285 5 : p.set_protocol(proto);
286 5 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
287 10 : addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]:" + std::to_string(port) + "/" + std::to_string(mask)));
288 5 : CATCH_REQUIRE(p.has_errors());
289 5 : CATCH_REQUIRE(p.error_count() == 1);
290 5 : CATCH_REQUIRE(p.error_messages() == "Unsupported mask size (" + std::to_string(mask) + ", expected 128 at the most for an IPv6).\n");
291 5 : CATCH_REQUIRE(ips.size() == 0);
292 : }
293 : }
294 :
295 16 : CATCH_SECTION("ipv6 mask cannot use name")
296 : {
297 6 : for(int idx(0); idx < 5; ++idx)
298 : {
299 5 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
300 5 : int const port(rand() & 0xFFFF);
301 10 : addr::addr_parser p;
302 5 : p.set_protocol(proto);
303 5 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
304 10 : addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]:" + std::to_string(port) + "/[localhost]"));
305 5 : CATCH_REQUIRE(p.has_errors());
306 5 : CATCH_REQUIRE(p.error_count() == 1);
307 5 : CATCH_REQUIRE(p.error_messages() == "Invalid mask in \"/[localhost]\", error -2 -- Name or service not known (errno: 0 -- Success).\n");
308 5 : CATCH_REQUIRE(ips.size() == 0);
309 : }
310 : }
311 :
312 16 : CATCH_SECTION("ipv6 mask must be between '[...]'")
313 : {
314 1 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
315 1 : int const port(rand() & 0xFFFF);
316 2 : addr::addr_parser p;
317 1 : p.set_protocol(proto);
318 1 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
319 2 : addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]:" + std::to_string(port) + "/::3"));
320 1 : CATCH_REQUIRE(p.has_errors());
321 1 : CATCH_REQUIRE(p.error_count() == 1);
322 1 : CATCH_REQUIRE(p.error_messages() == "The address uses the IPv6 syntax, the mask cannot use IPv4.\n");
323 1 : CATCH_REQUIRE(ips.size() == 0);
324 : }
325 :
326 16 : CATCH_SECTION("ipv6 mask missing the ']'")
327 : {
328 1 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
329 1 : int const port(rand() & 0xFFFF);
330 2 : addr::addr_parser p;
331 1 : p.set_protocol(proto);
332 1 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
333 2 : addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]:" + std::to_string(port) + "/[::3"));
334 1 : CATCH_REQUIRE(p.has_errors());
335 1 : CATCH_REQUIRE(p.error_count() == 1);
336 1 : CATCH_REQUIRE(p.error_messages() == "The IPv6 mask is missing the ']' ([::3).\n");
337 1 : CATCH_REQUIRE(ips.size() == 0);
338 : }
339 :
340 16 : CATCH_SECTION("ipv6 mask with an ipv4 in the '[...]'")
341 : {
342 1 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
343 1 : int const port(rand() & 0xFFFF);
344 2 : addr::addr_parser p;
345 1 : p.set_protocol(proto);
346 1 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
347 2 : addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]:" + std::to_string(port) + "/[1.2.3.4]"));
348 1 : CATCH_REQUIRE(p.has_errors());
349 1 : CATCH_REQUIRE(p.error_count() == 1);
350 1 : CATCH_REQUIRE(p.error_messages() == "Incompatible address between the address and mask address (first was an IPv6 second an IPv4).\n");
351 1 : CATCH_REQUIRE(ips.size() == 0);
352 : }
353 :
354 16 : CATCH_SECTION("verify default mask")
355 : {
356 2 : addr::addr_parser p;
357 :
358 1 : CATCH_REQUIRE_THROWS_AS(p.set_default_address("[4:5:4:5:7:8:7:8"), addr::addr_invalid_argument);
359 1 : CATCH_REQUIRE(p.get_default_address4() == "");
360 1 : CATCH_REQUIRE(p.get_default_address6() == "");
361 :
362 1 : p.set_default_address("[1:7:1:7:1:7:1:7]");
363 1 : CATCH_REQUIRE(p.get_default_address4() == "");
364 1 : CATCH_REQUIRE(p.get_default_address6() == "1:7:1:7:1:7:1:7");
365 :
366 1 : CATCH_REQUIRE_THROWS_AS(p.set_default_address("[9:5:9:5:9:8:9:8"), addr::addr_invalid_argument);
367 1 : CATCH_REQUIRE(p.get_default_address4() == "");
368 1 : CATCH_REQUIRE(p.get_default_address6() == "1:7:1:7:1:7:1:7");
369 :
370 1 : p.set_default_address("12.55.1.9");
371 1 : CATCH_REQUIRE(p.get_default_address4() == "12.55.1.9");
372 1 : CATCH_REQUIRE(p.get_default_address6() == "1:7:1:7:1:7:1:7");
373 :
374 1 : CATCH_REQUIRE_THROWS_AS(p.set_default_address("[9:f00f:9:e00e:9:d00d:9:c00c"), addr::addr_invalid_argument);
375 1 : CATCH_REQUIRE(p.get_default_address4() == "12.55.1.9");
376 1 : CATCH_REQUIRE(p.get_default_address6() == "1:7:1:7:1:7:1:7");
377 :
378 1 : p.set_default_address("");
379 1 : CATCH_REQUIRE(p.get_default_address4() == "");
380 1 : CATCH_REQUIRE(p.get_default_address6() == "");
381 : }
382 :
383 16 : CATCH_SECTION("verify default mask")
384 : {
385 2 : addr::addr_parser p;
386 :
387 1 : CATCH_REQUIRE_THROWS_AS(p.set_default_mask("[4:5:4:5:7:8:7:8"), addr::addr_invalid_argument);
388 1 : CATCH_REQUIRE(p.get_default_mask4() == "");
389 1 : CATCH_REQUIRE(p.get_default_mask6() == "");
390 :
391 1 : p.set_default_mask("[1:7:1:7:1:7:1:7]");
392 1 : CATCH_REQUIRE(p.get_default_mask4() == "");
393 1 : CATCH_REQUIRE(p.get_default_mask6() == "1:7:1:7:1:7:1:7");
394 :
395 1 : CATCH_REQUIRE_THROWS_AS(p.set_default_mask("[9:5:9:5:9:8:9:8"), addr::addr_invalid_argument);
396 1 : CATCH_REQUIRE(p.get_default_mask4() == "");
397 1 : CATCH_REQUIRE(p.get_default_mask6() == "1:7:1:7:1:7:1:7");
398 :
399 1 : p.set_default_mask("12.55.1.9");
400 1 : CATCH_REQUIRE(p.get_default_mask4() == "12.55.1.9");
401 1 : CATCH_REQUIRE(p.get_default_mask6() == "1:7:1:7:1:7:1:7");
402 :
403 1 : CATCH_REQUIRE_THROWS_AS(p.set_default_mask("[9:f00f:9:e00e:9:d00d:9:c00c"), addr::addr_invalid_argument);
404 1 : CATCH_REQUIRE(p.get_default_mask4() == "12.55.1.9");
405 1 : CATCH_REQUIRE(p.get_default_mask6() == "1:7:1:7:1:7:1:7");
406 :
407 1 : p.set_default_mask("");
408 1 : CATCH_REQUIRE(p.get_default_mask4() == "");
409 1 : CATCH_REQUIRE(p.get_default_mask6() == "");
410 : }
411 : }
412 14 : }
413 :
414 :
415 8 : CATCH_TEST_CASE( "ipv6::address", "[ipv6]" )
416 : {
417 12 : CATCH_GIVEN("addr() with an IPv6")
418 : {
419 3 : addr::addr a;
420 :
421 6 : CATCH_SECTION("set_ipv6() / get_ipv6()")
422 : {
423 11 : for(int idx(0); idx < 10; ++idx)
424 : {
425 10 : struct sockaddr_in6 in6 = sockaddr_in6();
426 10 : in6.sin6_family = AF_INET6;
427 10 : in6.sin6_port = htons(rand());
428 10 : in6.sin6_addr.s6_addr16[0] = rand();
429 10 : in6.sin6_addr.s6_addr16[1] = rand();
430 10 : in6.sin6_addr.s6_addr16[2] = rand();
431 10 : in6.sin6_addr.s6_addr16[3] = rand();
432 10 : in6.sin6_addr.s6_addr16[4] = rand();
433 10 : in6.sin6_addr.s6_addr16[5] = rand();
434 10 : in6.sin6_addr.s6_addr16[6] = rand();
435 10 : in6.sin6_addr.s6_addr16[7] = rand();
436 :
437 : // verify network type
438 : //
439 10 : a.set_ipv6(in6);
440 :
441 : // test constructor
442 : //
443 10 : addr::addr b(in6);
444 10 : struct sockaddr_in6 out6;
445 10 : b.get_ipv6(out6);
446 10 : CATCH_REQUIRE(memcmp(&out6, &in6, sizeof(struct sockaddr_in)) == 0);
447 :
448 : // test set
449 : //
450 10 : a.set_ipv6(in6);
451 10 : a.get_ipv6(out6);
452 10 : CATCH_REQUIRE(memcmp(&out6, &in6, sizeof(struct sockaddr_in)) == 0);
453 : }
454 : }
455 :
456 6 : CATCH_SECTION("set_ipv6() check to_ipv6_string()")
457 : {
458 11 : for(int idx(0); idx < 10; ++idx)
459 : {
460 10 : struct sockaddr_in6 in6 = sockaddr_in6();
461 10 : in6.sin6_family = AF_INET6;
462 10 : in6.sin6_port = htons(rand());
463 90 : for(int j(0); j < 8; ++j)
464 : {
465 : // avoid any zeroes so that way we do not have
466 : // to handle the "::" syntax
467 0 : do
468 : {
469 80 : in6.sin6_addr.s6_addr16[j] = rand();
470 : }
471 80 : while(in6.sin6_addr.s6_addr16[j] == 0);
472 : }
473 :
474 20 : std::stringstream ip_buf;
475 10 : ip_buf << std::hex
476 10 : << ntohs(in6.sin6_addr.s6_addr16[0])
477 10 : << ":"
478 10 : << ntohs(in6.sin6_addr.s6_addr16[1])
479 10 : << ":"
480 10 : << ntohs(in6.sin6_addr.s6_addr16[2])
481 10 : << ":"
482 10 : << ntohs(in6.sin6_addr.s6_addr16[3])
483 10 : << ":"
484 10 : << ntohs(in6.sin6_addr.s6_addr16[4])
485 10 : << ":"
486 10 : << ntohs(in6.sin6_addr.s6_addr16[5])
487 10 : << ":"
488 10 : << ntohs(in6.sin6_addr.s6_addr16[6])
489 10 : << ":"
490 10 : << ntohs(in6.sin6_addr.s6_addr16[7]);
491 20 : std::string const ip(ip_buf.str());
492 :
493 20 : std::string port_str(std::to_string(static_cast<int>(htons(in6.sin6_port))));
494 :
495 : // check IPv6 as a string
496 : //
497 10 : a.set_ipv6(in6);
498 10 : CATCH_REQUIRE(a.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == ip);
499 10 : CATCH_REQUIRE(a.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_BRACKETS) == "[" + ip + "]");
500 10 : CATCH_REQUIRE(a.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_PORT) == "[" + ip + "]:" + port_str);
501 10 : CATCH_REQUIRE(a.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_MASK) == ip + "/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); // will change to 128 at some point
502 10 : CATCH_REQUIRE(a.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_BRACKETS_MASK) == "[" + ip + "]/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]");
503 10 : CATCH_REQUIRE(a.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == "[" + ip + "]:" + port_str + "/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]");
504 : }
505 : }
506 :
507 6 : CATCH_SECTION("name of various IPs")
508 : {
509 1 : struct sockaddr_in6 in6 = sockaddr_in6();
510 1 : in6.sin6_family = AF_INET6;
511 1 : in6.sin6_port = htons(rand());
512 :
513 : // verify network type
514 : //
515 1 : a.set_ipv6(in6);
516 1 : CATCH_REQUIRE(a.get_name() == std::string()); // no name for "any" (TCP)
517 :
518 1 : a.set_protocol(IPPROTO_UDP);
519 1 : CATCH_REQUIRE(a.get_name() == std::string()); // no name for "any" (UDP)
520 :
521 1 : in6 = sockaddr_in6();
522 1 : in6.sin6_family = AF_INET6;
523 1 : in6.sin6_port = htons(rand());
524 1 : in6.sin6_addr.s6_addr16[7] = htons(1);
525 1 : a.set_ipv6(in6);
526 1 : char hostname[HOST_NAME_MAX + 1];
527 1 : hostname[HOST_NAME_MAX] = '\0';
528 1 : CATCH_REQUIRE(gethostname(hostname, sizeof(hostname)) == 0);
529 1 : CATCH_REQUIRE(hostname[0] != '\0');
530 2 : std::string localhost(a.get_name());
531 1 : bool const localhost_flag(localhost == hostname || localhost == "ip6-localhost");
532 1 : CATCH_REQUIRE(localhost_flag);
533 :
534 1 : CATCH_REQUIRE(addr::find_addr_interface(a, false) != nullptr);
535 : }
536 : }
537 :
538 12 : CATCH_GIVEN("addr_parser() with IPv6 addresses")
539 : {
540 6 : CATCH_SECTION("verify basics")
541 : {
542 2 : addr::addr_parser p;
543 1 : p.set_protocol(IPPROTO_TCP);
544 2 : addr::addr_range::vector_t ips(p.parse("[1:2:3:4:5:6:7:8]"));
545 1 : CATCH_REQUIRE_FALSE(p.has_errors());
546 1 : CATCH_REQUIRE(ips.size() == 1);
547 1 : addr::addr_range const & r(ips[0]);
548 1 : CATCH_REQUIRE(r.has_from());
549 1 : CATCH_REQUIRE_FALSE(r.has_to());
550 1 : CATCH_REQUIRE_FALSE(r.is_range());
551 1 : CATCH_REQUIRE_FALSE(r.is_empty());
552 1 : addr::addr f(r.get_from());
553 1 : CATCH_REQUIRE_FALSE(f.is_ipv4());
554 1 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "1:2:3:4:5:6:7:8");
555 1 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_BRACKETS) == "[1:2:3:4:5:6:7:8]");
556 1 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "1:2:3:4:5:6:7:8");
557 1 : CATCH_REQUIRE(f.get_port() == 0);
558 1 : CATCH_REQUIRE(f.get_protocol() == IPPROTO_TCP);
559 1 : CATCH_REQUIRE(f.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_PUBLIC);
560 1 : uint8_t mask[16] = {};
561 1 : f.get_mask(mask);
562 17 : for(int idx(0); idx < 16; ++idx)
563 : {
564 16 : CATCH_REQUIRE(mask[idx] == 255);
565 : }
566 : }
567 :
568 6 : CATCH_SECTION("default address")
569 : {
570 2 : addr::addr_parser p;
571 1 : p.set_protocol(IPPROTO_TCP);
572 1 : p.set_default_address("5:5:5:5:5:5:5:5");
573 2 : addr::addr_range::vector_t ips(p.parse(""));
574 1 : CATCH_REQUIRE_FALSE(p.has_errors());
575 1 : CATCH_REQUIRE(ips.size() == 1);
576 1 : addr::addr_range const & r(ips[0]);
577 1 : CATCH_REQUIRE(r.has_from());
578 1 : CATCH_REQUIRE_FALSE(r.has_to());
579 1 : CATCH_REQUIRE_FALSE(r.is_range());
580 1 : CATCH_REQUIRE_FALSE(r.is_empty());
581 1 : addr::addr f(r.get_from());
582 1 : CATCH_REQUIRE_FALSE(f.is_ipv4());
583 1 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "5:5:5:5:5:5:5:5");
584 1 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_BRACKETS) == "[5:5:5:5:5:5:5:5]");
585 1 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "5:5:5:5:5:5:5:5");
586 1 : CATCH_REQUIRE(f.get_port() == 0);
587 1 : CATCH_REQUIRE(f.get_protocol() == IPPROTO_TCP);
588 1 : CATCH_REQUIRE(f.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_PUBLIC);
589 : }
590 :
591 6 : CATCH_SECTION("address, not port allowed")
592 : {
593 : // specific address with a default
594 : {
595 2 : addr::addr_parser p;
596 1 : p.set_allow(addr::addr_parser::flag_t::PORT, false);
597 1 : p.set_protocol(IPPROTO_TCP);
598 1 : p.set_default_address("8:7:6:5:4:3:2:1");
599 2 : addr::addr_range::vector_t ips(p.parse("[9:9:9:9:4:3:2:1]"));
600 1 : CATCH_REQUIRE_FALSE(p.has_errors());
601 1 : CATCH_REQUIRE(ips.size() == 1);
602 1 : addr::addr_range const & r(ips[0]);
603 1 : CATCH_REQUIRE(r.has_from());
604 1 : CATCH_REQUIRE_FALSE(r.has_to());
605 1 : CATCH_REQUIRE_FALSE(r.is_range());
606 1 : CATCH_REQUIRE_FALSE(r.is_empty());
607 1 : addr::addr f(r.get_from());
608 1 : CATCH_REQUIRE_FALSE(f.is_ipv4());
609 1 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "9:9:9:9:4:3:2:1");
610 1 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_BRACKETS) == "[9:9:9:9:4:3:2:1]");
611 1 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "9:9:9:9:4:3:2:1");
612 1 : CATCH_REQUIRE(f.get_port() == 0);
613 1 : CATCH_REQUIRE(f.get_protocol() == IPPROTO_TCP);
614 1 : CATCH_REQUIRE(f.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_PUBLIC);
615 : }
616 :
617 : // only a default address
618 : {
619 2 : addr::addr_parser p;
620 1 : p.set_allow(addr::addr_parser::flag_t::PORT, false);
621 1 : p.set_protocol(IPPROTO_TCP);
622 1 : p.set_default_address("5:1:6:2:7:3:8:4");
623 2 : addr::addr_range::vector_t ips(p.parse(""));
624 1 : CATCH_REQUIRE_FALSE(p.has_errors());
625 1 : CATCH_REQUIRE(ips.size() == 1);
626 1 : addr::addr_range const & r(ips[0]);
627 1 : CATCH_REQUIRE(r.has_from());
628 1 : CATCH_REQUIRE_FALSE(r.has_to());
629 1 : CATCH_REQUIRE_FALSE(r.is_range());
630 1 : CATCH_REQUIRE_FALSE(r.is_empty());
631 1 : addr::addr f(r.get_from());
632 1 : CATCH_REQUIRE_FALSE(f.is_ipv4());
633 1 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "5:1:6:2:7:3:8:4");
634 1 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_BRACKETS) == "[5:1:6:2:7:3:8:4]");
635 1 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "5:1:6:2:7:3:8:4");
636 1 : CATCH_REQUIRE(f.get_port() == 0);
637 1 : CATCH_REQUIRE(f.get_protocol() == IPPROTO_TCP);
638 1 : CATCH_REQUIRE(f.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_PUBLIC);
639 : }
640 : }
641 : }
642 6 : }
643 :
644 :
645 7 : CATCH_TEST_CASE( "ipv6::ports", "[ipv6]" )
646 : {
647 : // by default addr() is an IPv6 address so we test the basic port
648 : // functions here, although it could be in a common place instead...
649 : //
650 10 : CATCH_GIVEN("addr()")
651 : {
652 3 : addr::addr a;
653 :
654 6 : CATCH_SECTION("default port")
655 : {
656 1 : CATCH_REQUIRE(a.get_port() == 0);
657 : }
658 :
659 6 : CATCH_SECTION("set_port()")
660 : {
661 : // setup a random port to start with
662 : //
663 1 : int const start_port(rand() & 0xFFFF);
664 1 : a.set_port(start_port);
665 :
666 : // test 100 invalid ports
667 : //
668 101 : for(int idx(0); idx < 100; ++idx)
669 : {
670 : // first try a negative port
671 : int port_too_small;
672 0 : do
673 : {
674 100 : port_too_small = -(rand() & 0xFFFF);
675 : }
676 100 : while(port_too_small == 0);
677 100 : CATCH_REQUIRE_THROWS_AS(a.set_port(port_too_small), addr::addr_invalid_argument);
678 :
679 : // first try a negative port
680 100 : int const port_too_large = (rand() & 0xFFFF) + 65536;
681 100 : CATCH_REQUIRE_THROWS_AS(a.set_port(port_too_large), addr::addr_invalid_argument);
682 :
683 : // make sure port does not get modified on errors
684 100 : CATCH_REQUIRE(a.get_port() == start_port);
685 : }
686 :
687 : // test all ports
688 : //
689 65537 : for(int port(0); port < 65536; ++port)
690 : {
691 65536 : a.set_port(port);
692 :
693 65536 : CATCH_REQUIRE(a.get_port() == port);
694 : }
695 : }
696 :
697 6 : CATCH_SECTION("known ports to test get_service()")
698 : {
699 1 : a.set_port(80);
700 1 : CATCH_REQUIRE(a.get_service() == "http");
701 :
702 1 : a.set_port(443);
703 1 : CATCH_REQUIRE(a.get_service() == "https");
704 :
705 : // again with UDP
706 : //
707 1 : a.set_protocol(IPPROTO_UDP);
708 :
709 1 : a.set_port(80);
710 2 : std::string service(a.get_service());
711 1 : CATCH_REQUIRE((service == "http" || service == "80"));
712 :
713 1 : a.set_port(443);
714 1 : service = a.get_service();
715 1 : CATCH_REQUIRE((service == "https"|| service == "443"));
716 : }
717 : }
718 :
719 10 : CATCH_GIVEN("addr_parser() with IPv6 addresses and port")
720 : {
721 4 : CATCH_SECTION("verify port")
722 : {
723 65537 : for(int port(0); port < 65536; ++port)
724 : {
725 65536 : int proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
726 131072 : addr::addr_parser p;
727 65536 : p.set_protocol(proto);
728 131072 : addr::addr_range::vector_t ips(p.parse("[ff01:2f3:f041:e301:f:10:11:12]:" + std::to_string(port)));
729 65536 : CATCH_REQUIRE_FALSE(p.has_errors());
730 65536 : CATCH_REQUIRE(ips.size() == 1);
731 65536 : addr::addr_range const & r(ips[0]);
732 65536 : addr::addr f(r.get_from());
733 65536 : CATCH_REQUIRE_FALSE(f.is_ipv4());
734 65536 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "ff01:2f3:f041:e301:f:10:11:12");
735 65536 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_BRACKETS) == "[ff01:2f3:f041:e301:f:10:11:12]");
736 65536 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_PORT) == "[ff01:2f3:f041:e301:f:10:11:12]:" + std::to_string(port));
737 65536 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_PORT) == "[ff01:2f3:f041:e301:f:10:11:12]:" + std::to_string(port));
738 65536 : CATCH_REQUIRE(f.get_port() == port);
739 65536 : CATCH_REQUIRE(f.get_protocol() == proto);
740 65536 : CATCH_REQUIRE(f.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LOOPBACK);
741 : }
742 : }
743 :
744 4 : CATCH_SECTION("default address with various port")
745 : {
746 101 : for(int idx(0); idx < 100; ++idx)
747 : {
748 100 : uint16_t const port(rand());
749 200 : addr::addr_parser p;
750 100 : p.set_protocol(IPPROTO_TCP);
751 100 : p.set_default_address("ff02:23:f41:e31:20:30:40:50");
752 200 : addr::addr_range::vector_t ips(p.parse(":" + std::to_string(static_cast<int>(port))));
753 100 : CATCH_REQUIRE_FALSE(p.has_errors());
754 100 : CATCH_REQUIRE(ips.size() == 1);
755 100 : addr::addr_range const & r(ips[0]);
756 100 : CATCH_REQUIRE(r.has_from());
757 100 : CATCH_REQUIRE_FALSE(r.has_to());
758 100 : CATCH_REQUIRE_FALSE(r.is_range());
759 100 : CATCH_REQUIRE_FALSE(r.is_empty());
760 100 : addr::addr f(r.get_from());
761 100 : CATCH_REQUIRE_FALSE(f.is_ipv4());
762 100 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_PORT) == "[ff02:23:f41:e31:20:30:40:50]:" + std::to_string(static_cast<int>(port)));
763 100 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_PORT) == "[ff02:23:f41:e31:20:30:40:50]:" + std::to_string(static_cast<int>(port)));
764 100 : CATCH_REQUIRE(f.get_port() == port);
765 100 : CATCH_REQUIRE(f.get_protocol() == IPPROTO_TCP);
766 100 : CATCH_REQUIRE(f.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LINK_LOCAL);
767 : }
768 : }
769 : }
770 5 : }
771 :
772 :
773 14 : CATCH_TEST_CASE( "ipv6::masks", "[ipv6]" )
774 : {
775 24 : CATCH_GIVEN("addr()")
776 : {
777 : // technically, a default addr object represents and IPv6 so the
778 : // dealing with the mask without an IPv4 is done by IPv6 tests
779 : //
780 3 : addr::addr a;
781 :
782 6 : CATCH_SECTION("default mask")
783 : {
784 1 : uint8_t mask[16] = {};
785 1 : a.get_mask(mask);
786 17 : for(int idx(0); idx < 16; ++idx)
787 : {
788 16 : CATCH_REQUIRE(mask[idx] == 255);
789 : }
790 : }
791 :
792 6 : CATCH_SECTION("set_mask()")
793 : {
794 1 : uint8_t mask[16], verify_mask[16];
795 6 : for(int idx(0); idx < 5; ++idx)
796 : {
797 85 : for(int j(0); j < 16; ++j)
798 : {
799 80 : mask[j] = rand();
800 : }
801 5 : a.set_mask(mask);
802 5 : a.get_mask(verify_mask);
803 85 : for(int j(0); j < 16; ++j)
804 : {
805 80 : CATCH_REQUIRE(mask[j] == verify_mask[j]);
806 : }
807 :
808 : // verify that a copy does copy the mask as expected
809 : //
810 5 : addr::addr b(a);
811 5 : b.get_mask(verify_mask);
812 85 : for(int j(0); j < 16; ++j)
813 : {
814 80 : CATCH_REQUIRE(mask[j] == verify_mask[j]);
815 : }
816 : }
817 : }
818 :
819 6 : CATCH_SECTION("set_mask()")
820 : {
821 1 : uint8_t mask[16];
822 1 : uint8_t verify_mask[16];
823 6 : for(int idx(0); idx < 5; ++idx)
824 : {
825 85 : for(int j(0); j < 16; ++j)
826 : {
827 80 : mask[j] = rand();
828 : }
829 5 : a.set_mask(mask);
830 5 : a.get_mask(verify_mask);
831 85 : for(int j(0); j < 16; ++j)
832 : {
833 80 : CATCH_REQUIRE(mask[j] == verify_mask[j]);
834 80 : verify_mask[j] = rand();
835 : }
836 :
837 : // verify that a copy does copy the mask as expected
838 : //
839 5 : addr::addr b(a);
840 5 : b.get_mask(verify_mask);
841 85 : for(int j(0); j < 16; ++j)
842 : {
843 80 : CATCH_REQUIRE(mask[j] == verify_mask[j]);
844 80 : verify_mask[j] = rand();
845 : }
846 :
847 : // verify that copying inside a range works too
848 : //
849 5 : addr::addr_range r;
850 5 : r.set_from(a);
851 5 : r.get_from().get_mask(verify_mask);
852 85 : for(int j(0); j < 16; ++j)
853 : {
854 80 : CATCH_REQUIRE(mask[j] == verify_mask[j]);
855 80 : verify_mask[j] = rand();
856 : }
857 :
858 : // then that a range copy works as expected
859 : //
860 5 : addr::addr_range c(r);
861 5 : c.get_from().get_mask(verify_mask);
862 85 : for(int j(0); j < 16; ++j)
863 : {
864 80 : CATCH_REQUIRE(mask[j] == verify_mask[j]);
865 80 : verify_mask[j] = rand();
866 : }
867 : }
868 : }
869 : }
870 :
871 24 : CATCH_GIVEN("addr_parser() of address:port/mask")
872 : {
873 18 : CATCH_SECTION("mask allowed, but no mask")
874 : {
875 1 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
876 1 : int const port(rand() & 0xFFFF);
877 2 : addr::addr_parser p;
878 1 : p.set_protocol(proto);
879 1 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
880 2 : addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port)));
881 1 : CATCH_REQUIRE_FALSE(p.has_errors());
882 1 : CATCH_REQUIRE(ips.size() == 1);
883 1 : addr::addr_range const & r(ips[0]);
884 1 : addr::addr f(r.get_from());
885 1 : CATCH_REQUIRE_FALSE(f.is_ipv4());
886 2 : std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]");
887 1 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
888 1 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
889 1 : CATCH_REQUIRE(f.get_port() == port);
890 1 : CATCH_REQUIRE(f.get_protocol() == proto);
891 : }
892 :
893 18 : CATCH_SECTION("empty mask")
894 : {
895 1 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
896 1 : int const port(rand() & 0xFFFF);
897 2 : addr::addr_parser p;
898 1 : p.set_protocol(proto);
899 1 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
900 2 : addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/"));
901 1 : CATCH_REQUIRE_FALSE(p.has_errors());
902 1 : CATCH_REQUIRE(ips.size() == 1);
903 1 : addr::addr_range const & r(ips[0]);
904 1 : addr::addr f(r.get_from());
905 1 : CATCH_REQUIRE_FALSE(f.is_ipv4());
906 2 : std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]");
907 1 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
908 1 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
909 1 : CATCH_REQUIRE(f.get_port() == port);
910 1 : CATCH_REQUIRE(f.get_protocol() == proto);
911 : }
912 :
913 18 : CATCH_SECTION("empty mask including the '[]'")
914 : {
915 1 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
916 1 : int const port(rand() & 0xFFFF);
917 2 : addr::addr_parser p;
918 1 : p.set_protocol(proto);
919 1 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
920 2 : addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[]"));
921 1 : CATCH_REQUIRE_FALSE(p.has_errors());
922 1 : CATCH_REQUIRE(ips.size() == 1);
923 1 : addr::addr_range const & r(ips[0]);
924 1 : addr::addr f(r.get_from());
925 1 : CATCH_REQUIRE_FALSE(f.is_ipv4());
926 2 : std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]");
927 1 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
928 1 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
929 1 : CATCH_REQUIRE(f.get_port() == port);
930 1 : CATCH_REQUIRE(f.get_protocol() == proto);
931 : }
932 :
933 18 : CATCH_SECTION("one number masks")
934 : {
935 130 : for(int idx(0); idx <= 128; ++idx)
936 : {
937 129 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
938 129 : int const port(rand() & 0xFFFF);
939 258 : addr::addr_parser p;
940 129 : p.set_protocol(proto);
941 129 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
942 258 : addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/" + std::to_string(idx)));
943 129 : CATCH_REQUIRE_FALSE(p.has_errors());
944 129 : CATCH_REQUIRE(ips.size() == 1);
945 129 : addr::addr_range const & r(ips[0]);
946 129 : addr::addr f(r.get_from());
947 129 : CATCH_REQUIRE_FALSE(f.is_ipv4());
948 129 : uint8_t mask[16] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
949 129 : int j(15);
950 129 : int m(128 - idx);
951 2049 : for(; m > 8; m -= 8, --j)
952 : {
953 960 : mask[j] = 0;
954 : }
955 129 : if(j < 0)
956 : {
957 0 : throw std::logic_error("invalid j here");
958 : }
959 129 : mask[j] = 255 << m;
960 129 : char buf[1024]; // really large buffer to make sure it does not get truncated
961 129 : if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
962 : {
963 0 : throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
964 : }
965 258 : std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[" + buf + "]");
966 129 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
967 129 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
968 129 : CATCH_REQUIRE(f.get_port() == port);
969 129 : CATCH_REQUIRE(f.get_protocol() == proto);
970 : }
971 : }
972 :
973 18 : CATCH_SECTION("address like mask")
974 : {
975 26 : for(int idx(0); idx < 25; ++idx)
976 : {
977 25 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
978 25 : int const port(rand() & 0xFFFF);
979 50 : addr::addr_parser p;
980 25 : p.set_protocol(proto);
981 25 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
982 : // when specified as an IP, the mask can be absolutely anything
983 25 : uint8_t mask[16];
984 425 : for(int j(0); j < 16; ++j)
985 : {
986 400 : mask[j] = rand();
987 : }
988 50 : std::stringstream smask;
989 25 : smask << std::hex
990 25 : << htons((mask[ 1] << 8) | mask[ 0])
991 25 : << ":"
992 25 : << htons((mask[ 3] << 8) | mask[ 2])
993 25 : << ":"
994 25 : << htons((mask[ 5] << 8) | mask[ 4])
995 25 : << ":"
996 25 : << htons((mask[ 7] << 8) | mask[ 6])
997 25 : << ":"
998 25 : << htons((mask[ 9] << 8) | mask[ 8])
999 25 : << ":"
1000 25 : << htons((mask[11] << 8) | mask[10])
1001 25 : << ":"
1002 25 : << htons((mask[13] << 8) | mask[12])
1003 25 : << ":"
1004 25 : << htons((mask[15] << 8) | mask[14]);
1005 25 : char buf[1024]; // really large buffer to make sure it does not get truncated
1006 25 : if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
1007 : {
1008 0 : throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
1009 : }
1010 50 : addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[" + smask.str() + "]"));
1011 25 : CATCH_REQUIRE_FALSE(p.has_errors());
1012 25 : CATCH_REQUIRE(ips.size() == 1);
1013 25 : addr::addr_range const & r(ips[0]);
1014 25 : addr::addr f(r.get_from());
1015 25 : CATCH_REQUIRE_FALSE(f.is_ipv4());
1016 50 : std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[" + buf + "]");
1017 25 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
1018 25 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
1019 25 : CATCH_REQUIRE(f.get_port() == port);
1020 25 : CATCH_REQUIRE(f.get_protocol() == proto);
1021 : }
1022 : }
1023 :
1024 18 : CATCH_SECTION("address like default mask")
1025 : {
1026 26 : for(int idx(0); idx < 25; ++idx)
1027 : {
1028 25 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
1029 25 : int const port(rand() & 0xFFFF);
1030 50 : addr::addr_parser p;
1031 25 : p.set_protocol(proto);
1032 25 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
1033 : // when specified as an IP, the mask can be absolutely anything
1034 : // (here the mask is a string an it will be parsed by the
1035 : // parser if required)
1036 : //
1037 25 : uint8_t mask[16];
1038 425 : for(int j(0); j < 16; ++j)
1039 : {
1040 400 : mask[j] = rand();
1041 : }
1042 50 : std::stringstream smask;
1043 25 : smask << std::hex
1044 25 : << "["
1045 25 : << htons((mask[ 1] << 8) | mask[ 0])
1046 25 : << ":"
1047 25 : << htons((mask[ 3] << 8) | mask[ 2])
1048 25 : << ":"
1049 25 : << htons((mask[ 5] << 8) | mask[ 4])
1050 25 : << ":"
1051 25 : << htons((mask[ 7] << 8) | mask[ 6])
1052 25 : << ":"
1053 25 : << htons((mask[ 9] << 8) | mask[ 8])
1054 25 : << ":"
1055 25 : << htons((mask[11] << 8) | mask[10])
1056 25 : << ":"
1057 25 : << htons((mask[13] << 8) | mask[12])
1058 25 : << ":"
1059 25 : << htons((mask[15] << 8) | mask[14])
1060 25 : << "]";
1061 25 : char buf[1024]; // really large buffer to make sure it does not get truncated
1062 25 : if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
1063 : {
1064 0 : throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
1065 : }
1066 25 : p.set_default_mask(smask.str());
1067 50 : addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port)));
1068 25 : CATCH_REQUIRE_FALSE(p.has_errors());
1069 25 : CATCH_REQUIRE(ips.size() == 1);
1070 25 : addr::addr_range const & r(ips[0]);
1071 25 : addr::addr f(r.get_from());
1072 25 : CATCH_REQUIRE_FALSE(f.is_ipv4());
1073 50 : std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[" + buf + "]");
1074 25 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
1075 25 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
1076 25 : CATCH_REQUIRE(f.get_port() == port);
1077 25 : CATCH_REQUIRE(f.get_protocol() == proto);
1078 25 : uint8_t verify_mask[16];
1079 25 : f.get_mask(verify_mask);
1080 425 : for(int j(0); j < 16; ++j)
1081 : {
1082 400 : CATCH_REQUIRE(verify_mask[j] == mask[j]);
1083 : }
1084 : }
1085 : }
1086 :
1087 18 : CATCH_SECTION("address like mask with a default")
1088 : {
1089 26 : for(int idx(0); idx < 25; ++idx)
1090 : {
1091 25 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
1092 25 : int const port(rand() & 0xFFFF);
1093 50 : addr::addr_parser p;
1094 25 : p.set_protocol(proto);
1095 25 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
1096 :
1097 : // here we want a default and an IP with a specific mask
1098 : // to make sure that the specific mask has priority
1099 : //
1100 25 : uint8_t mask[16];
1101 425 : for(int j(0); j < 16; ++j)
1102 : {
1103 400 : mask[j] = rand();
1104 : }
1105 50 : std::stringstream smask;
1106 25 : smask << std::hex
1107 25 : << "["
1108 25 : << htons((mask[ 1] << 8) | mask[ 0])
1109 25 : << ":"
1110 25 : << htons((mask[ 3] << 8) | mask[ 2])
1111 25 : << ":"
1112 25 : << htons((mask[ 5] << 8) | mask[ 4])
1113 25 : << ":"
1114 25 : << htons((mask[ 7] << 8) | mask[ 6])
1115 25 : << ":"
1116 25 : << htons((mask[ 9] << 8) | mask[ 8])
1117 25 : << ":"
1118 25 : << htons((mask[11] << 8) | mask[10])
1119 25 : << ":"
1120 25 : << htons((mask[13] << 8) | mask[12])
1121 25 : << ":"
1122 25 : << htons((mask[15] << 8) | mask[14])
1123 25 : << "]";
1124 25 : char buf[1024]; // really large buffer to make sure it does not get truncated
1125 25 : if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
1126 : {
1127 0 : throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
1128 : }
1129 :
1130 25 : uint8_t default_mask[16];
1131 425 : for(int j(0); j < 16; ++j)
1132 : {
1133 400 : default_mask[j] = rand();
1134 : }
1135 : //std::stringstream default_smask;
1136 : //default_smask << std::hex
1137 : // << "["
1138 : // << htons((default_mask[ 1] << 8) | default_mask[ 0])
1139 : // << ":"
1140 : // << htons((default_mask[ 3] << 8) | default_mask[ 2])
1141 : // << ":"
1142 : // << htons((default_mask[ 5] << 8) | default_mask[ 4])
1143 : // << ":"
1144 : // << htons((default_mask[ 7] << 8) | default_mask[ 6])
1145 : // << ":"
1146 : // << htons((default_mask[ 9] << 8) | default_mask[ 8])
1147 : // << ":"
1148 : // << htons((default_mask[11] << 8) | default_mask[10])
1149 : // << ":"
1150 : // << htons((default_mask[13] << 8) | default_mask[12])
1151 : // << ":"
1152 : // << htons((default_mask[15] << 8) | default_mask[14])
1153 : // << "]";
1154 25 : char default_buf[1024]; // really large buffer to make sure it does not get truncated
1155 25 : if(inet_ntop(AF_INET6, default_mask, default_buf, sizeof(buf)) == nullptr)
1156 : {
1157 0 : throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
1158 : }
1159 25 : p.set_default_mask(default_buf);
1160 :
1161 50 : addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/" + smask.str()));
1162 25 : CATCH_REQUIRE_FALSE(p.has_errors());
1163 25 : CATCH_REQUIRE(ips.size() == 1);
1164 25 : addr::addr_range const & r(ips[0]);
1165 25 : addr::addr f(r.get_from());
1166 25 : CATCH_REQUIRE_FALSE(f.is_ipv4());
1167 50 : std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[" + buf + "]");
1168 25 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
1169 25 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
1170 25 : CATCH_REQUIRE(f.get_port() == port);
1171 25 : CATCH_REQUIRE(f.get_protocol() == proto);
1172 25 : uint8_t verify_mask[16];
1173 25 : f.get_mask(verify_mask);
1174 425 : for(int j(0); j < 16; ++j)
1175 : {
1176 400 : CATCH_REQUIRE(verify_mask[j] == mask[j]);
1177 : }
1178 : }
1179 : }
1180 :
1181 18 : CATCH_SECTION("no address, but one IPv6 number masks")
1182 : {
1183 : // with just a number, the mask is considered an IPv6 mask
1184 : // if it is 33 or more
1185 : //
1186 97 : for(int idx(33); idx <= 128; ++idx)
1187 : {
1188 96 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
1189 96 : int const port(rand() & 0xFFFF);
1190 192 : addr::addr_parser p;
1191 96 : p.set_protocol(proto);
1192 96 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
1193 : //p.set_default_address("55:33:22:11:0:cc:bb:aa");
1194 192 : addr::addr_range::vector_t ips(p.parse(":" + std::to_string(port) + "/" + std::to_string(idx)));
1195 96 : CATCH_REQUIRE_FALSE(p.has_errors());
1196 96 : CATCH_REQUIRE(ips.size() == 1);
1197 96 : addr::addr_range const & r(ips[0]);
1198 96 : addr::addr f(r.get_from());
1199 96 : CATCH_REQUIRE_FALSE(f.is_ipv4());
1200 96 : uint8_t mask[16] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
1201 96 : int j(15);
1202 96 : int m(128 - idx);
1203 1130 : for(; m > 8; m -= 8, --j)
1204 : {
1205 517 : mask[j] = 0;
1206 : }
1207 96 : if(j < 0)
1208 : {
1209 0 : throw std::logic_error("invalid j here");
1210 : }
1211 96 : mask[j] = 255 << m;
1212 96 : char buf[1024]; // really large buffer to make sure it does not get truncated
1213 96 : if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
1214 : {
1215 0 : throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
1216 : }
1217 192 : std::string result("[::]:" + std::to_string(port) + "/[" + buf + "]");
1218 96 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
1219 96 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
1220 96 : CATCH_REQUIRE(f.get_port() == port);
1221 96 : CATCH_REQUIRE(f.get_protocol() == proto);
1222 : }
1223 : }
1224 :
1225 18 : CATCH_SECTION("no address, but one IPv6 masks")
1226 : {
1227 : // with just a number, the mask is considered an IPv6 mask
1228 : // if it is 33 or more
1229 : //
1230 6 : for(int idx(0); idx < 5; ++idx)
1231 : {
1232 5 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
1233 5 : int const port(rand() & 0xFFFF);
1234 10 : addr::addr_parser p;
1235 5 : p.set_protocol(proto);
1236 5 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
1237 : //p.set_default_address("55:33:22:11:0:cc:bb:aa");
1238 10 : addr::addr_range::vector_t ips(p.parse(":" + std::to_string(port) + "/[1:2:3:4:5:6:7:8]"));
1239 5 : CATCH_REQUIRE_FALSE(p.has_errors());
1240 5 : CATCH_REQUIRE(ips.size() == 1);
1241 5 : addr::addr_range const & r(ips[0]);
1242 5 : addr::addr f(r.get_from());
1243 5 : CATCH_REQUIRE_FALSE(f.is_ipv4());
1244 10 : std::string result("[::]:" + std::to_string(port) + "/[1:2:3:4:5:6:7:8]");
1245 5 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
1246 5 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
1247 5 : CATCH_REQUIRE(f.get_port() == port);
1248 5 : CATCH_REQUIRE(f.get_protocol() == proto);
1249 : }
1250 : }
1251 : }
1252 12 : }
1253 :
1254 :
1255 9 : CATCH_TEST_CASE( "ipv6::network_type", "[ipv6]" )
1256 : {
1257 14 : CATCH_GIVEN("addr()")
1258 : {
1259 7 : addr::addr a;
1260 :
1261 14 : CATCH_SECTION("any (::)")
1262 : {
1263 : {
1264 1 : struct sockaddr_in6 in6 = sockaddr_in6();
1265 1 : in6.sin6_family = AF_INET6;
1266 1 : in6.sin6_port = htons(rand());
1267 1 : in6.sin6_addr.s6_addr32[0] = 0;
1268 1 : in6.sin6_addr.s6_addr32[1] = 0;
1269 1 : in6.sin6_addr.s6_addr32[2] = 0;
1270 1 : in6.sin6_addr.s6_addr32[3] = 0;
1271 :
1272 : // verify network type
1273 : //
1274 1 : a.set_ipv6(in6);
1275 :
1276 1 : CATCH_REQUIRE(a.is_default());
1277 1 : CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_ANY);
1278 1 : CATCH_REQUIRE(a.get_network_type_string() == "Any");
1279 : }
1280 :
1281 : // make sure that if any byte is set to non-zero it is not
1282 : // viewed as the ANY address
1283 : //
1284 17 : for(int idx(0); idx < 16; ++idx)
1285 : {
1286 16 : struct sockaddr_in6 in6 = sockaddr_in6();
1287 16 : in6.sin6_family = AF_INET6;
1288 16 : in6.sin6_port = htons(rand());
1289 16 : in6.sin6_addr.s6_addr32[0] = 0;
1290 16 : in6.sin6_addr.s6_addr32[1] = 0;
1291 16 : in6.sin6_addr.s6_addr32[2] = 0;
1292 16 : in6.sin6_addr.s6_addr32[3] = 0;
1293 :
1294 : // change one byte only
1295 : //
1296 0 : do
1297 : {
1298 16 : in6.sin6_addr.s6_addr[idx] = rand();
1299 : }
1300 16 : while(in6.sin6_addr.s6_addr[idx] == 0);
1301 :
1302 : // verify network type
1303 : //
1304 16 : a.set_ipv6(in6);
1305 :
1306 16 : CATCH_REQUIRE(a.get_network_type() != addr::addr::network_type_t::NETWORK_TYPE_ANY);
1307 16 : CATCH_REQUIRE(a.get_network_type_string() != "Any");
1308 : }
1309 : }
1310 :
1311 14 : CATCH_SECTION("private address fd00::/8")
1312 : {
1313 11 : for(int idx(0); idx < 10; ++idx)
1314 : {
1315 10 : struct sockaddr_in6 in6 = sockaddr_in6();
1316 10 : in6.sin6_family = AF_INET6;
1317 10 : in6.sin6_port = htons(rand());
1318 10 : in6.sin6_addr.s6_addr16[0] = htons(0xFD00 | (rand() & 255));
1319 10 : in6.sin6_addr.s6_addr16[1] = rand();
1320 10 : in6.sin6_addr.s6_addr16[2] = rand();
1321 10 : in6.sin6_addr.s6_addr16[3] = rand();
1322 10 : in6.sin6_addr.s6_addr16[4] = rand();
1323 10 : in6.sin6_addr.s6_addr16[5] = rand();
1324 10 : in6.sin6_addr.s6_addr16[6] = rand();
1325 10 : in6.sin6_addr.s6_addr16[7] = rand();
1326 :
1327 : // verify network type
1328 : //
1329 10 : a.set_ipv6(in6);
1330 10 : CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_PRIVATE);
1331 10 : CATCH_REQUIRE(a.get_network_type_string() == "Private");
1332 : }
1333 : }
1334 :
1335 14 : CATCH_SECTION("private address fe80::/10")
1336 : {
1337 11 : for(int idx(0); idx < 10; ++idx)
1338 : {
1339 10 : struct sockaddr_in6 in6 = sockaddr_in6();
1340 10 : in6.sin6_family = AF_INET6;
1341 10 : in6.sin6_port = htons(rand());
1342 10 : in6.sin6_addr.s6_addr16[0] = htons(0xFE80 | (rand() & 63));
1343 10 : in6.sin6_addr.s6_addr16[1] = rand();
1344 10 : in6.sin6_addr.s6_addr16[2] = rand();
1345 10 : in6.sin6_addr.s6_addr16[3] = rand();
1346 10 : in6.sin6_addr.s6_addr16[4] = rand();
1347 10 : in6.sin6_addr.s6_addr16[5] = rand();
1348 10 : in6.sin6_addr.s6_addr16[6] = rand();
1349 10 : in6.sin6_addr.s6_addr16[7] = rand();
1350 :
1351 : // verify network type
1352 : //
1353 10 : a.set_ipv6(in6);
1354 10 : CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LINK_LOCAL);
1355 10 : CATCH_REQUIRE(a.get_network_type_string() == "Local Link");
1356 : }
1357 : }
1358 :
1359 14 : CATCH_SECTION("private address ff02::/16")
1360 : {
1361 11 : for(int idx(0); idx < 10; ++idx)
1362 : {
1363 10 : struct sockaddr_in6 in6 = sockaddr_in6();
1364 10 : in6.sin6_family = AF_INET6;
1365 10 : in6.sin6_port = htons(rand());
1366 10 : in6.sin6_addr.s6_addr16[0] = htons(0xFF02);
1367 10 : in6.sin6_addr.s6_addr16[1] = rand();
1368 10 : in6.sin6_addr.s6_addr16[2] = rand();
1369 10 : in6.sin6_addr.s6_addr16[3] = rand();
1370 10 : in6.sin6_addr.s6_addr16[4] = rand();
1371 10 : in6.sin6_addr.s6_addr16[5] = rand();
1372 10 : in6.sin6_addr.s6_addr16[6] = rand();
1373 10 : in6.sin6_addr.s6_addr16[7] = rand();
1374 :
1375 : // verify network type
1376 : //
1377 10 : a.set_ipv6(in6);
1378 10 : CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LINK_LOCAL);
1379 10 : CATCH_REQUIRE(a.get_network_type_string() == "Local Link");
1380 : }
1381 : }
1382 :
1383 14 : CATCH_SECTION("private address ff00::/8")
1384 : {
1385 11 : for(int idx(0); idx < 10; ++idx)
1386 : {
1387 10 : struct sockaddr_in6 in6 = sockaddr_in6();
1388 10 : in6.sin6_family = AF_INET6;
1389 10 : in6.sin6_port = htons(rand());
1390 0 : do
1391 : {
1392 10 : in6.sin6_addr.s6_addr16[0] = htons(0xFF00 | (rand() & 255));
1393 : }
1394 10 : while((in6.sin6_addr.s6_addr16[0] & htons(0xFF0F)) == htons(0xFF01) // ffx1::/16
1395 10 : || (in6.sin6_addr.s6_addr16[0] & htons(0xFF0F)) == htons(0xFF02) // ffx2::/16
1396 10 : || (in6.sin6_addr.s6_addr16[0] & htons(0xFFC0)) == htons(0xFE80) // fe80::/10
1397 20 : || (in6.sin6_addr.s6_addr16[0] & htons(0xFF00)) == htons(0xFD00)); // fd00::/8
1398 10 : in6.sin6_addr.s6_addr16[1] = rand();
1399 10 : in6.sin6_addr.s6_addr16[2] = rand();
1400 10 : in6.sin6_addr.s6_addr16[3] = rand();
1401 10 : in6.sin6_addr.s6_addr16[4] = rand();
1402 10 : in6.sin6_addr.s6_addr16[5] = rand();
1403 10 : in6.sin6_addr.s6_addr16[6] = rand();
1404 10 : in6.sin6_addr.s6_addr16[7] = rand();
1405 :
1406 : // verify network type
1407 : //
1408 10 : a.set_ipv6(in6);
1409 10 : CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_MULTICAST);
1410 10 : CATCH_REQUIRE(a.get_network_type_string() == "Multicast");
1411 : }
1412 : }
1413 :
1414 14 : CATCH_SECTION("private address ffx1::/8")
1415 : {
1416 11 : for(int idx(0); idx < 10; ++idx)
1417 : {
1418 10 : struct sockaddr_in6 in6 = sockaddr_in6();
1419 10 : in6.sin6_family = AF_INET6;
1420 10 : in6.sin6_port = htons(rand());
1421 10 : in6.sin6_addr.s6_addr16[0] = htons(0xFF01 | ((rand() & 15) << 4));
1422 10 : in6.sin6_addr.s6_addr16[1] = rand();
1423 10 : in6.sin6_addr.s6_addr16[2] = rand();
1424 10 : in6.sin6_addr.s6_addr16[3] = rand();
1425 10 : in6.sin6_addr.s6_addr16[4] = rand();
1426 10 : in6.sin6_addr.s6_addr16[5] = rand();
1427 10 : in6.sin6_addr.s6_addr16[6] = rand();
1428 10 : in6.sin6_addr.s6_addr16[7] = rand();
1429 :
1430 : // verify network type
1431 : //
1432 10 : a.set_ipv6(in6);
1433 10 : CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LOOPBACK);
1434 10 : CATCH_REQUIRE(a.get_network_type_string() == "Loopback");
1435 : }
1436 : }
1437 :
1438 14 : CATCH_SECTION("private address ::1")
1439 : {
1440 11 : for(int idx(0); idx < 10; ++idx)
1441 : {
1442 10 : struct sockaddr_in6 in6 = sockaddr_in6();
1443 10 : in6.sin6_family = AF_INET6;
1444 10 : in6.sin6_port = htons(rand());
1445 10 : in6.sin6_addr.s6_addr16[0] = 0;
1446 10 : in6.sin6_addr.s6_addr16[1] = 0;
1447 10 : in6.sin6_addr.s6_addr16[2] = 0;
1448 10 : in6.sin6_addr.s6_addr16[3] = 0;
1449 10 : in6.sin6_addr.s6_addr16[4] = 0;
1450 10 : in6.sin6_addr.s6_addr16[5] = 0;
1451 10 : in6.sin6_addr.s6_addr16[6] = 0;
1452 10 : in6.sin6_addr.s6_addr16[7] = htons(1);
1453 :
1454 : // verify network type
1455 : //
1456 10 : a.set_ipv6(in6);
1457 10 : CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LOOPBACK);
1458 10 : CATCH_REQUIRE(a.get_network_type_string() == "Loopback");
1459 :
1460 : // try again from a string to confirm
1461 : //
1462 10 : struct addrinfo * addrlist(nullptr);
1463 10 : int const port(rand() & 65535);
1464 10 : int const r(getaddrinfo("::1", std::to_string(port).c_str(), nullptr, &addrlist));
1465 10 : CATCH_REQUIRE(r == 0);
1466 10 : CATCH_REQUIRE(addrlist != nullptr);
1467 10 : CATCH_REQUIRE(addrlist->ai_family == AF_INET6);
1468 10 : CATCH_REQUIRE(addrlist->ai_addrlen == sizeof(struct sockaddr_in6));
1469 10 : a.set_ipv6(*reinterpret_cast<sockaddr_in6 *>(addrlist->ai_addr));
1470 10 : CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LOOPBACK);
1471 10 : CATCH_REQUIRE(a.get_network_type_string() == "Loopback");
1472 10 : freeaddrinfo(addrlist);
1473 : }
1474 : }
1475 : }
1476 7 : }
1477 :
1478 :
1479 5 : CATCH_TEST_CASE( "ipv6::network", "[ipv6]" )
1480 : {
1481 6 : CATCH_GIVEN("set_from_socket()")
1482 : {
1483 6 : CATCH_SECTION("create a server, but do not test it (yet)...")
1484 : {
1485 2 : addr::addr_parser p;
1486 2 : addr::addr_range::vector_t ips(p.parse("[::1]:49999"));
1487 1 : CATCH_REQUIRE(ips.size() >= 1);
1488 :
1489 1 : addr::addr & a(ips[0].get_from());
1490 1 : int s(a.create_socket(addr::addr::SOCKET_FLAG_NONBLOCK | addr::addr::SOCKET_FLAG_CLOEXEC | addr::addr::SOCKET_FLAG_REUSE));
1491 1 : CATCH_REQUIRE(s >= 0);
1492 2 : std::shared_ptr<int> auto_free(&s, socket_deleter);
1493 :
1494 1 : CATCH_REQUIRE(a.bind(s) == 0);
1495 : }
1496 :
1497 6 : CATCH_SECTION("connect with TCP to [::1]")
1498 : {
1499 1 : if(SNAP_CATCH2_NAMESPACE::g_tcp_port != -1)
1500 : {
1501 2 : addr::addr_parser p;
1502 2 : addr::addr_range::vector_t ips(p.parse("[::1]:" + std::to_string(SNAP_CATCH2_NAMESPACE::g_tcp_port)));
1503 1 : CATCH_REQUIRE(ips.size() >= 1);
1504 :
1505 1 : addr::addr & a(ips[0].get_from());
1506 1 : int s(a.create_socket(addr::addr::SOCKET_FLAG_CLOEXEC));// | addr::addr::SOCKET_FLAG_REUSE));
1507 1 : CATCH_REQUIRE(s >= 0);
1508 2 : std::shared_ptr<int> auto_free(&s, socket_deleter);
1509 :
1510 1 : CATCH_REQUIRE(a.connect(s) == 0);
1511 :
1512 : // get socket info from the other side (peer == true)
1513 : //
1514 1 : addr::addr b;
1515 1 : b.set_from_socket(s, true);
1516 1 : CATCH_REQUIRE_FALSE(b.is_ipv4());
1517 1 : CATCH_REQUIRE(b.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "::1");
1518 1 : CATCH_REQUIRE(b.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "::1");
1519 :
1520 : // in this case we know what the port is since we specified
1521 : // that when connecting
1522 : //
1523 1 : CATCH_REQUIRE(b.get_port() == SNAP_CATCH2_NAMESPACE::g_tcp_port);
1524 :
1525 : // now try this side (peer == false)
1526 : //
1527 1 : addr::addr c;
1528 1 : c.set_from_socket(s, false);
1529 1 : CATCH_REQUIRE_FALSE(c.is_ipv4());
1530 1 : CATCH_REQUIRE(c.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "::1");
1531 1 : CATCH_REQUIRE(c.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "::1");
1532 :
1533 : // we cannot be sure of the port, there is a range we could
1534 : // test better (more constraining) but for this test is
1535 : // certainly does not matter much; it has to be more than
1536 : // 1023, though
1537 : //
1538 1 : CATCH_REQUIRE(c.get_port() > 1023);
1539 : }
1540 : else
1541 : {
1542 : // avoid issue of no assertions
1543 : //
1544 0 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::g_tcp_port == -1);
1545 0 : std::cout << "connect to [::1] test skipped as no TCP port was specified on the command line." << std::endl;
1546 : }
1547 : }
1548 :
1549 6 : CATCH_SECTION("connect with UDP to [::1]")
1550 : {
1551 2 : addr::addr_parser p;
1552 1 : p.set_protocol("udp");
1553 2 : addr::addr_range::vector_t ips(p.parse("[::1]:53"));
1554 1 : CATCH_REQUIRE(ips.size() >= 1);
1555 :
1556 1 : addr::addr & a(ips[0].get_from());
1557 1 : int s(a.create_socket(addr::addr::SOCKET_FLAG_CLOEXEC));// | addr::addr::SOCKET_FLAG_REUSE));
1558 1 : CATCH_REQUIRE(s >= 0);
1559 2 : std::shared_ptr<int> auto_free(&s, socket_deleter);
1560 :
1561 1 : CATCH_REQUIRE(a.connect(s) == -1);
1562 :
1563 : // get socket info from the other side (peer == true)
1564 : //
1565 1 : addr::addr b;
1566 1 : CATCH_REQUIRE_THROWS_AS(b.set_from_socket(s, true), addr::addr_io_error);
1567 1 : CATCH_REQUIRE_FALSE(b.is_ipv4());
1568 1 : CATCH_REQUIRE(b.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "::");
1569 1 : CATCH_REQUIRE(b.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "::");
1570 :
1571 : // in this case we know what the port is since we specified
1572 : // that when connecting
1573 : //
1574 1 : CATCH_REQUIRE(b.get_port() == 0);
1575 :
1576 : // now try this side (peer == false)
1577 : //
1578 1 : addr::addr c;
1579 1 : c.set_from_socket(s, false);
1580 1 : CATCH_REQUIRE_FALSE(c.is_ipv4());
1581 1 : CATCH_REQUIRE(c.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "::");
1582 1 : CATCH_REQUIRE(c.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "::");
1583 :
1584 : // we cannot be sure of the port, there is a range we could
1585 : // test better (more constraining) but for this test is
1586 : // certainly does not matter much; it has to be more than
1587 : // 1023, though
1588 : //
1589 1 : CATCH_REQUIRE(c.get_port() == 0);
1590 : }
1591 : }
1592 9 : }
1593 :
1594 :
1595 : // vim: ts=4 sw=4 et
|