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 10 : CATCH_TEST_CASE( "ipv6::address", "[ipv6]" )
416 : {
417 16 : 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 16 : 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 :
643 16 : CATCH_GIVEN("addr_parser() with numeric only IPv6 addresses")
644 : {
645 4 : CATCH_SECTION("Simple numeric IPv6")
646 : {
647 2 : addr::addr_parser p;
648 1 : p.set_protocol(IPPROTO_TCP);
649 1 : p.set_allow(addr::addr_parser::flag_t::ADDRESS_LOOKUP, false);
650 2 : addr::addr_range::vector_t ips(p.parse("[4::f003:3001:20af]:5093"));
651 1 : CATCH_REQUIRE_FALSE(p.has_errors());
652 1 : CATCH_REQUIRE(ips.size() == 1);
653 :
654 1 : addr::addr_range const & r(ips[0]);
655 1 : CATCH_REQUIRE(r.has_from());
656 1 : CATCH_REQUIRE_FALSE(r.has_to());
657 1 : CATCH_REQUIRE_FALSE(r.is_range());
658 1 : CATCH_REQUIRE_FALSE(r.is_empty());
659 1 : addr::addr f(r.get_from());
660 1 : CATCH_REQUIRE_FALSE(f.is_ipv4());
661 : // getting an IPv4 would throw, which is checked somewhere else
662 : //CATCH_REQUIRE(f.to_ipv4_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "");
663 1 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "4::f003:3001:20af");
664 1 : CATCH_REQUIRE(f.get_port() == 5093);
665 1 : CATCH_REQUIRE(f.get_protocol() == IPPROTO_TCP);
666 1 : CATCH_REQUIRE(f.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_PUBLIC);
667 1 : uint8_t mask[16] = {};
668 1 : f.get_mask(mask);
669 17 : for(int idx(0); idx < 16; ++idx)
670 : {
671 16 : CATCH_REQUIRE(mask[idx] == 255);
672 : }
673 : }
674 :
675 4 : CATCH_SECTION("Invalid IPv6 domain name address when we only accept numeric IPs")
676 : {
677 : // this is exactly the same path as the IPv4 test...
678 : // if we have a named domain then IPv4 fails, IPv6 fails, then we err on it
679 : //
680 2 : addr::addr_parser p;
681 1 : p.set_protocol(IPPROTO_TCP);
682 1 : p.set_allow(addr::addr_parser::flag_t::ADDRESS_LOOKUP, false);
683 2 : addr::addr_range::vector_t ips(p.parse("ipv6.example.com:4471"));
684 1 : CATCH_REQUIRE(p.has_errors());
685 1 : CATCH_REQUIRE(p.error_count() == 1);
686 1 : CATCH_REQUIRE(p.error_messages() == "Unknown address in \"ipv6.example.com\" (no DNS lookup was allowed).\n");
687 1 : CATCH_REQUIRE(ips.size() == 0);
688 : }
689 : }
690 8 : }
691 :
692 :
693 7 : CATCH_TEST_CASE( "ipv6::ports", "[ipv6]" )
694 : {
695 : // by default addr() is an IPv6 address so we test the basic port
696 : // functions here, although it could be in a common place instead...
697 : //
698 10 : CATCH_GIVEN("addr()")
699 : {
700 3 : addr::addr a;
701 :
702 6 : CATCH_SECTION("default port")
703 : {
704 1 : CATCH_REQUIRE(a.get_port() == 0);
705 : }
706 :
707 6 : CATCH_SECTION("set_port()")
708 : {
709 : // setup a random port to start with
710 : //
711 1 : int const start_port(rand() & 0xFFFF);
712 1 : a.set_port(start_port);
713 :
714 : // test 100 invalid ports
715 : //
716 101 : for(int idx(0); idx < 100; ++idx)
717 : {
718 : // first try a negative port
719 : int port_too_small;
720 0 : do
721 : {
722 100 : port_too_small = -(rand() & 0xFFFF);
723 : }
724 100 : while(port_too_small == 0);
725 100 : CATCH_REQUIRE_THROWS_AS(a.set_port(port_too_small), addr::addr_invalid_argument);
726 :
727 : // first try a negative port
728 100 : int const port_too_large = (rand() & 0xFFFF) + 65536;
729 100 : CATCH_REQUIRE_THROWS_AS(a.set_port(port_too_large), addr::addr_invalid_argument);
730 :
731 : // make sure port does not get modified on errors
732 100 : CATCH_REQUIRE(a.get_port() == start_port);
733 : }
734 :
735 : // test all ports
736 : //
737 65537 : for(int port(0); port < 65536; ++port)
738 : {
739 65536 : a.set_port(port);
740 :
741 65536 : CATCH_REQUIRE(a.get_port() == port);
742 : }
743 : }
744 :
745 6 : CATCH_SECTION("known ports to test get_service()")
746 : {
747 1 : a.set_port(80);
748 1 : CATCH_REQUIRE(a.get_service() == "http");
749 :
750 1 : a.set_port(443);
751 1 : CATCH_REQUIRE(a.get_service() == "https");
752 :
753 : // again with UDP
754 : //
755 1 : a.set_protocol(IPPROTO_UDP);
756 :
757 1 : a.set_port(80);
758 2 : std::string service(a.get_service());
759 1 : CATCH_REQUIRE((service == "http" || service == "80"));
760 :
761 1 : a.set_port(443);
762 1 : service = a.get_service();
763 1 : CATCH_REQUIRE((service == "https"|| service == "443"));
764 : }
765 : }
766 :
767 10 : CATCH_GIVEN("addr_parser() with IPv6 addresses and port")
768 : {
769 4 : CATCH_SECTION("verify port")
770 : {
771 65537 : for(int port(0); port < 65536; ++port)
772 : {
773 65536 : int proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
774 131072 : addr::addr_parser p;
775 65536 : p.set_protocol(proto);
776 131072 : addr::addr_range::vector_t ips(p.parse("[ff01:2f3:f041:e301:f:10:11:12]:" + std::to_string(port)));
777 65536 : CATCH_REQUIRE_FALSE(p.has_errors());
778 65536 : CATCH_REQUIRE(ips.size() == 1);
779 65536 : addr::addr_range const & r(ips[0]);
780 65536 : addr::addr f(r.get_from());
781 65536 : CATCH_REQUIRE_FALSE(f.is_ipv4());
782 65536 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "ff01:2f3:f041:e301:f:10:11:12");
783 65536 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_BRACKETS) == "[ff01:2f3:f041:e301:f:10:11:12]");
784 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));
785 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));
786 65536 : CATCH_REQUIRE(f.get_port() == port);
787 65536 : CATCH_REQUIRE(f.get_protocol() == proto);
788 65536 : CATCH_REQUIRE(f.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LOOPBACK);
789 : }
790 : }
791 :
792 4 : CATCH_SECTION("default address with various port")
793 : {
794 101 : for(int idx(0); idx < 100; ++idx)
795 : {
796 100 : uint16_t const port(rand());
797 200 : addr::addr_parser p;
798 100 : p.set_protocol(IPPROTO_TCP);
799 100 : p.set_default_address("ff02:23:f41:e31:20:30:40:50");
800 200 : addr::addr_range::vector_t ips(p.parse(":" + std::to_string(static_cast<int>(port))));
801 100 : CATCH_REQUIRE_FALSE(p.has_errors());
802 100 : CATCH_REQUIRE(ips.size() == 1);
803 100 : addr::addr_range const & r(ips[0]);
804 100 : CATCH_REQUIRE(r.has_from());
805 100 : CATCH_REQUIRE_FALSE(r.has_to());
806 100 : CATCH_REQUIRE_FALSE(r.is_range());
807 100 : CATCH_REQUIRE_FALSE(r.is_empty());
808 100 : addr::addr f(r.get_from());
809 100 : CATCH_REQUIRE_FALSE(f.is_ipv4());
810 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)));
811 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)));
812 100 : CATCH_REQUIRE(f.get_port() == port);
813 100 : CATCH_REQUIRE(f.get_protocol() == IPPROTO_TCP);
814 100 : CATCH_REQUIRE(f.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LINK_LOCAL);
815 : }
816 : }
817 : }
818 5 : }
819 :
820 :
821 14 : CATCH_TEST_CASE( "ipv6::masks", "[ipv6]" )
822 : {
823 24 : CATCH_GIVEN("addr()")
824 : {
825 : // technically, a default addr object represents and IPv6 so the
826 : // dealing with the mask without an IPv4 is done by IPv6 tests
827 : //
828 3 : addr::addr a;
829 :
830 6 : CATCH_SECTION("default mask")
831 : {
832 1 : uint8_t mask[16] = {};
833 1 : a.get_mask(mask);
834 17 : for(int idx(0); idx < 16; ++idx)
835 : {
836 16 : CATCH_REQUIRE(mask[idx] == 255);
837 : }
838 : }
839 :
840 6 : CATCH_SECTION("set_mask()")
841 : {
842 1 : uint8_t mask[16], verify_mask[16];
843 6 : for(int idx(0); idx < 5; ++idx)
844 : {
845 85 : for(int j(0); j < 16; ++j)
846 : {
847 80 : mask[j] = rand();
848 : }
849 5 : a.set_mask(mask);
850 5 : a.get_mask(verify_mask);
851 85 : for(int j(0); j < 16; ++j)
852 : {
853 80 : CATCH_REQUIRE(mask[j] == verify_mask[j]);
854 : }
855 :
856 : // verify that a copy does copy the mask as expected
857 : //
858 5 : addr::addr b(a);
859 5 : b.get_mask(verify_mask);
860 85 : for(int j(0); j < 16; ++j)
861 : {
862 80 : CATCH_REQUIRE(mask[j] == verify_mask[j]);
863 : }
864 : }
865 : }
866 :
867 6 : CATCH_SECTION("set_mask()")
868 : {
869 1 : uint8_t mask[16];
870 1 : uint8_t verify_mask[16];
871 6 : for(int idx(0); idx < 5; ++idx)
872 : {
873 85 : for(int j(0); j < 16; ++j)
874 : {
875 80 : mask[j] = rand();
876 : }
877 5 : a.set_mask(mask);
878 5 : a.get_mask(verify_mask);
879 85 : for(int j(0); j < 16; ++j)
880 : {
881 80 : CATCH_REQUIRE(mask[j] == verify_mask[j]);
882 80 : verify_mask[j] = rand();
883 : }
884 :
885 : // verify that a copy does copy the mask as expected
886 : //
887 5 : addr::addr b(a);
888 5 : b.get_mask(verify_mask);
889 85 : for(int j(0); j < 16; ++j)
890 : {
891 80 : CATCH_REQUIRE(mask[j] == verify_mask[j]);
892 80 : verify_mask[j] = rand();
893 : }
894 :
895 : // verify that copying inside a range works too
896 : //
897 5 : addr::addr_range r;
898 5 : r.set_from(a);
899 5 : r.get_from().get_mask(verify_mask);
900 85 : for(int j(0); j < 16; ++j)
901 : {
902 80 : CATCH_REQUIRE(mask[j] == verify_mask[j]);
903 80 : verify_mask[j] = rand();
904 : }
905 :
906 : // then that a range copy works as expected
907 : //
908 5 : addr::addr_range c(r);
909 5 : c.get_from().get_mask(verify_mask);
910 85 : for(int j(0); j < 16; ++j)
911 : {
912 80 : CATCH_REQUIRE(mask[j] == verify_mask[j]);
913 80 : verify_mask[j] = rand();
914 : }
915 : }
916 : }
917 : }
918 :
919 24 : CATCH_GIVEN("addr_parser() of address:port/mask")
920 : {
921 18 : CATCH_SECTION("mask allowed, but no mask")
922 : {
923 1 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
924 1 : int const port(rand() & 0xFFFF);
925 2 : addr::addr_parser p;
926 1 : p.set_protocol(proto);
927 1 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
928 2 : addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port)));
929 1 : CATCH_REQUIRE_FALSE(p.has_errors());
930 1 : CATCH_REQUIRE(ips.size() == 1);
931 1 : addr::addr_range const & r(ips[0]);
932 1 : addr::addr f(r.get_from());
933 1 : CATCH_REQUIRE_FALSE(f.is_ipv4());
934 2 : std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]");
935 1 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
936 1 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
937 1 : CATCH_REQUIRE(f.get_port() == port);
938 1 : CATCH_REQUIRE(f.get_protocol() == proto);
939 : }
940 :
941 18 : CATCH_SECTION("empty mask")
942 : {
943 1 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
944 1 : int const port(rand() & 0xFFFF);
945 2 : addr::addr_parser p;
946 1 : p.set_protocol(proto);
947 1 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
948 2 : addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/"));
949 1 : CATCH_REQUIRE_FALSE(p.has_errors());
950 1 : CATCH_REQUIRE(ips.size() == 1);
951 1 : addr::addr_range const & r(ips[0]);
952 1 : addr::addr f(r.get_from());
953 1 : CATCH_REQUIRE_FALSE(f.is_ipv4());
954 2 : std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]");
955 1 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
956 1 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
957 1 : CATCH_REQUIRE(f.get_port() == port);
958 1 : CATCH_REQUIRE(f.get_protocol() == proto);
959 : }
960 :
961 18 : CATCH_SECTION("empty mask including the '[]'")
962 : {
963 1 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
964 1 : int const port(rand() & 0xFFFF);
965 2 : addr::addr_parser p;
966 1 : p.set_protocol(proto);
967 1 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
968 2 : addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[]"));
969 1 : CATCH_REQUIRE_FALSE(p.has_errors());
970 1 : CATCH_REQUIRE(ips.size() == 1);
971 1 : addr::addr_range const & r(ips[0]);
972 1 : addr::addr f(r.get_from());
973 1 : CATCH_REQUIRE_FALSE(f.is_ipv4());
974 2 : std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]");
975 1 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
976 1 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
977 1 : CATCH_REQUIRE(f.get_port() == port);
978 1 : CATCH_REQUIRE(f.get_protocol() == proto);
979 : }
980 :
981 18 : CATCH_SECTION("one number masks")
982 : {
983 130 : for(int idx(0); idx <= 128; ++idx)
984 : {
985 129 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
986 129 : int const port(rand() & 0xFFFF);
987 258 : addr::addr_parser p;
988 129 : p.set_protocol(proto);
989 129 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
990 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)));
991 129 : CATCH_REQUIRE_FALSE(p.has_errors());
992 129 : CATCH_REQUIRE(ips.size() == 1);
993 129 : addr::addr_range const & r(ips[0]);
994 129 : addr::addr f(r.get_from());
995 129 : CATCH_REQUIRE_FALSE(f.is_ipv4());
996 129 : uint8_t mask[16] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
997 129 : int j(15);
998 129 : int m(128 - idx);
999 2049 : for(; m > 8; m -= 8, --j)
1000 : {
1001 960 : mask[j] = 0;
1002 : }
1003 129 : if(j < 0)
1004 : {
1005 0 : throw std::logic_error("invalid j here");
1006 : }
1007 129 : mask[j] = 255 << m;
1008 129 : char buf[1024]; // really large buffer to make sure it does not get truncated
1009 129 : if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
1010 : {
1011 0 : throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
1012 : }
1013 258 : std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[" + buf + "]");
1014 129 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
1015 129 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
1016 129 : CATCH_REQUIRE(f.get_port() == port);
1017 129 : CATCH_REQUIRE(f.get_protocol() == proto);
1018 : }
1019 : }
1020 :
1021 18 : CATCH_SECTION("address like mask")
1022 : {
1023 26 : for(int idx(0); idx < 25; ++idx)
1024 : {
1025 25 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
1026 25 : int const port(rand() & 0xFFFF);
1027 50 : addr::addr_parser p;
1028 25 : p.set_protocol(proto);
1029 25 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
1030 : // when specified as an IP, the mask can be absolutely anything
1031 25 : uint8_t mask[16];
1032 425 : for(int j(0); j < 16; ++j)
1033 : {
1034 400 : mask[j] = rand();
1035 : }
1036 50 : std::stringstream smask;
1037 25 : smask << std::hex
1038 25 : << htons((mask[ 1] << 8) | mask[ 0])
1039 25 : << ":"
1040 25 : << htons((mask[ 3] << 8) | mask[ 2])
1041 25 : << ":"
1042 25 : << htons((mask[ 5] << 8) | mask[ 4])
1043 25 : << ":"
1044 25 : << htons((mask[ 7] << 8) | mask[ 6])
1045 25 : << ":"
1046 25 : << htons((mask[ 9] << 8) | mask[ 8])
1047 25 : << ":"
1048 25 : << htons((mask[11] << 8) | mask[10])
1049 25 : << ":"
1050 25 : << htons((mask[13] << 8) | mask[12])
1051 25 : << ":"
1052 25 : << htons((mask[15] << 8) | mask[14]);
1053 25 : char buf[1024]; // really large buffer to make sure it does not get truncated
1054 25 : if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
1055 : {
1056 0 : throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
1057 : }
1058 50 : addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[" + smask.str() + "]"));
1059 25 : CATCH_REQUIRE_FALSE(p.has_errors());
1060 25 : CATCH_REQUIRE(ips.size() == 1);
1061 25 : addr::addr_range const & r(ips[0]);
1062 25 : addr::addr f(r.get_from());
1063 25 : CATCH_REQUIRE_FALSE(f.is_ipv4());
1064 50 : std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[" + buf + "]");
1065 25 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
1066 25 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
1067 25 : CATCH_REQUIRE(f.get_port() == port);
1068 25 : CATCH_REQUIRE(f.get_protocol() == proto);
1069 : }
1070 : }
1071 :
1072 18 : CATCH_SECTION("address like default mask")
1073 : {
1074 26 : for(int idx(0); idx < 25; ++idx)
1075 : {
1076 25 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
1077 25 : int const port(rand() & 0xFFFF);
1078 50 : addr::addr_parser p;
1079 25 : p.set_protocol(proto);
1080 25 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
1081 : // when specified as an IP, the mask can be absolutely anything
1082 : // (here the mask is a string an it will be parsed by the
1083 : // parser if required)
1084 : //
1085 25 : uint8_t mask[16];
1086 425 : for(int j(0); j < 16; ++j)
1087 : {
1088 400 : mask[j] = rand();
1089 : }
1090 50 : std::stringstream smask;
1091 25 : smask << std::hex
1092 25 : << "["
1093 25 : << htons((mask[ 1] << 8) | mask[ 0])
1094 25 : << ":"
1095 25 : << htons((mask[ 3] << 8) | mask[ 2])
1096 25 : << ":"
1097 25 : << htons((mask[ 5] << 8) | mask[ 4])
1098 25 : << ":"
1099 25 : << htons((mask[ 7] << 8) | mask[ 6])
1100 25 : << ":"
1101 25 : << htons((mask[ 9] << 8) | mask[ 8])
1102 25 : << ":"
1103 25 : << htons((mask[11] << 8) | mask[10])
1104 25 : << ":"
1105 25 : << htons((mask[13] << 8) | mask[12])
1106 25 : << ":"
1107 25 : << htons((mask[15] << 8) | mask[14])
1108 25 : << "]";
1109 25 : char buf[1024]; // really large buffer to make sure it does not get truncated
1110 25 : if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
1111 : {
1112 0 : throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
1113 : }
1114 25 : p.set_default_mask(smask.str());
1115 50 : addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port)));
1116 25 : CATCH_REQUIRE_FALSE(p.has_errors());
1117 25 : CATCH_REQUIRE(ips.size() == 1);
1118 25 : addr::addr_range const & r(ips[0]);
1119 25 : addr::addr f(r.get_from());
1120 25 : CATCH_REQUIRE_FALSE(f.is_ipv4());
1121 50 : std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[" + buf + "]");
1122 25 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
1123 25 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
1124 25 : CATCH_REQUIRE(f.get_port() == port);
1125 25 : CATCH_REQUIRE(f.get_protocol() == proto);
1126 25 : uint8_t verify_mask[16];
1127 25 : f.get_mask(verify_mask);
1128 425 : for(int j(0); j < 16; ++j)
1129 : {
1130 400 : CATCH_REQUIRE(verify_mask[j] == mask[j]);
1131 : }
1132 : }
1133 : }
1134 :
1135 18 : CATCH_SECTION("address like mask with a default")
1136 : {
1137 26 : for(int idx(0); idx < 25; ++idx)
1138 : {
1139 25 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
1140 25 : int const port(rand() & 0xFFFF);
1141 50 : addr::addr_parser p;
1142 25 : p.set_protocol(proto);
1143 25 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
1144 :
1145 : // here we want a default and an IP with a specific mask
1146 : // to make sure that the specific mask has priority
1147 : //
1148 25 : uint8_t mask[16];
1149 425 : for(int j(0); j < 16; ++j)
1150 : {
1151 400 : mask[j] = rand();
1152 : }
1153 50 : std::stringstream smask;
1154 25 : smask << std::hex
1155 25 : << "["
1156 25 : << htons((mask[ 1] << 8) | mask[ 0])
1157 25 : << ":"
1158 25 : << htons((mask[ 3] << 8) | mask[ 2])
1159 25 : << ":"
1160 25 : << htons((mask[ 5] << 8) | mask[ 4])
1161 25 : << ":"
1162 25 : << htons((mask[ 7] << 8) | mask[ 6])
1163 25 : << ":"
1164 25 : << htons((mask[ 9] << 8) | mask[ 8])
1165 25 : << ":"
1166 25 : << htons((mask[11] << 8) | mask[10])
1167 25 : << ":"
1168 25 : << htons((mask[13] << 8) | mask[12])
1169 25 : << ":"
1170 25 : << htons((mask[15] << 8) | mask[14])
1171 25 : << "]";
1172 25 : char buf[1024]; // really large buffer to make sure it does not get truncated
1173 25 : if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
1174 : {
1175 0 : throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
1176 : }
1177 :
1178 25 : uint8_t default_mask[16];
1179 425 : for(int j(0); j < 16; ++j)
1180 : {
1181 400 : default_mask[j] = rand();
1182 : }
1183 : //std::stringstream default_smask;
1184 : //default_smask << std::hex
1185 : // << "["
1186 : // << htons((default_mask[ 1] << 8) | default_mask[ 0])
1187 : // << ":"
1188 : // << htons((default_mask[ 3] << 8) | default_mask[ 2])
1189 : // << ":"
1190 : // << htons((default_mask[ 5] << 8) | default_mask[ 4])
1191 : // << ":"
1192 : // << htons((default_mask[ 7] << 8) | default_mask[ 6])
1193 : // << ":"
1194 : // << htons((default_mask[ 9] << 8) | default_mask[ 8])
1195 : // << ":"
1196 : // << htons((default_mask[11] << 8) | default_mask[10])
1197 : // << ":"
1198 : // << htons((default_mask[13] << 8) | default_mask[12])
1199 : // << ":"
1200 : // << htons((default_mask[15] << 8) | default_mask[14])
1201 : // << "]";
1202 25 : char default_buf[1024]; // really large buffer to make sure it does not get truncated
1203 25 : if(inet_ntop(AF_INET6, default_mask, default_buf, sizeof(buf)) == nullptr)
1204 : {
1205 0 : throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
1206 : }
1207 25 : p.set_default_mask(default_buf);
1208 :
1209 50 : addr::addr_range::vector_t ips(p.parse("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/" + smask.str()));
1210 25 : CATCH_REQUIRE_FALSE(p.has_errors());
1211 25 : CATCH_REQUIRE(ips.size() == 1);
1212 25 : addr::addr_range const & r(ips[0]);
1213 25 : addr::addr f(r.get_from());
1214 25 : CATCH_REQUIRE_FALSE(f.is_ipv4());
1215 50 : std::string result("[55:33:22:11:0:cc:bb:aa]:" + std::to_string(port) + "/[" + buf + "]");
1216 25 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
1217 25 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
1218 25 : CATCH_REQUIRE(f.get_port() == port);
1219 25 : CATCH_REQUIRE(f.get_protocol() == proto);
1220 25 : uint8_t verify_mask[16];
1221 25 : f.get_mask(verify_mask);
1222 425 : for(int j(0); j < 16; ++j)
1223 : {
1224 400 : CATCH_REQUIRE(verify_mask[j] == mask[j]);
1225 : }
1226 : }
1227 : }
1228 :
1229 18 : CATCH_SECTION("no address, but one IPv6 number masks")
1230 : {
1231 : // with just a number, the mask is considered an IPv6 mask
1232 : // if it is 33 or more
1233 : //
1234 97 : for(int idx(33); idx <= 128; ++idx)
1235 : {
1236 96 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
1237 96 : int const port(rand() & 0xFFFF);
1238 192 : addr::addr_parser p;
1239 96 : p.set_protocol(proto);
1240 96 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
1241 : //p.set_default_address("55:33:22:11:0:cc:bb:aa");
1242 192 : addr::addr_range::vector_t ips(p.parse(":" + std::to_string(port) + "/" + std::to_string(idx)));
1243 96 : CATCH_REQUIRE_FALSE(p.has_errors());
1244 96 : CATCH_REQUIRE(ips.size() == 1);
1245 96 : addr::addr_range const & r(ips[0]);
1246 96 : addr::addr f(r.get_from());
1247 96 : CATCH_REQUIRE_FALSE(f.is_ipv4());
1248 96 : uint8_t mask[16] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
1249 96 : int j(15);
1250 96 : int m(128 - idx);
1251 1130 : for(; m > 8; m -= 8, --j)
1252 : {
1253 517 : mask[j] = 0;
1254 : }
1255 96 : if(j < 0)
1256 : {
1257 0 : throw std::logic_error("invalid j here");
1258 : }
1259 96 : mask[j] = 255 << m;
1260 96 : char buf[1024]; // really large buffer to make sure it does not get truncated
1261 96 : if(inet_ntop(AF_INET6, mask, buf, sizeof(buf)) == nullptr)
1262 : {
1263 0 : throw std::logic_error("somehow we could not convert our mask to an IPv6 address.");
1264 : }
1265 192 : std::string result("[::]:" + std::to_string(port) + "/[" + buf + "]");
1266 96 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
1267 96 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
1268 96 : CATCH_REQUIRE(f.get_port() == port);
1269 96 : CATCH_REQUIRE(f.get_protocol() == proto);
1270 : }
1271 : }
1272 :
1273 18 : CATCH_SECTION("no address, but one IPv6 masks")
1274 : {
1275 : // with just a number, the mask is considered an IPv6 mask
1276 : // if it is 33 or more
1277 : //
1278 6 : for(int idx(0); idx < 5; ++idx)
1279 : {
1280 5 : int const proto(rand() & 1 ? IPPROTO_TCP : IPPROTO_UDP);
1281 5 : int const port(rand() & 0xFFFF);
1282 10 : addr::addr_parser p;
1283 5 : p.set_protocol(proto);
1284 5 : p.set_allow(addr::addr_parser::flag_t::MASK, true);
1285 : //p.set_default_address("55:33:22:11:0:cc:bb:aa");
1286 10 : addr::addr_range::vector_t ips(p.parse(":" + std::to_string(port) + "/[1:2:3:4:5:6:7:8]"));
1287 5 : CATCH_REQUIRE_FALSE(p.has_errors());
1288 5 : CATCH_REQUIRE(ips.size() == 1);
1289 5 : addr::addr_range const & r(ips[0]);
1290 5 : addr::addr f(r.get_from());
1291 5 : CATCH_REQUIRE_FALSE(f.is_ipv4());
1292 10 : std::string result("[::]:" + std::to_string(port) + "/[1:2:3:4:5:6:7:8]");
1293 5 : CATCH_REQUIRE(f.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
1294 5 : CATCH_REQUIRE(f.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ALL) == result);
1295 5 : CATCH_REQUIRE(f.get_port() == port);
1296 5 : CATCH_REQUIRE(f.get_protocol() == proto);
1297 : }
1298 : }
1299 : }
1300 12 : }
1301 :
1302 :
1303 9 : CATCH_TEST_CASE( "ipv6::network_type", "[ipv6]" )
1304 : {
1305 14 : CATCH_GIVEN("addr()")
1306 : {
1307 7 : addr::addr a;
1308 :
1309 14 : CATCH_SECTION("any (::)")
1310 : {
1311 : {
1312 1 : struct sockaddr_in6 in6 = sockaddr_in6();
1313 1 : in6.sin6_family = AF_INET6;
1314 1 : in6.sin6_port = htons(rand());
1315 1 : in6.sin6_addr.s6_addr32[0] = 0;
1316 1 : in6.sin6_addr.s6_addr32[1] = 0;
1317 1 : in6.sin6_addr.s6_addr32[2] = 0;
1318 1 : in6.sin6_addr.s6_addr32[3] = 0;
1319 :
1320 : // verify network type
1321 : //
1322 1 : a.set_ipv6(in6);
1323 :
1324 1 : CATCH_REQUIRE(a.is_default());
1325 1 : CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_ANY);
1326 1 : CATCH_REQUIRE(a.get_network_type_string() == "Any");
1327 : }
1328 :
1329 : // make sure that if any byte is set to non-zero it is not
1330 : // viewed as the ANY address
1331 : //
1332 17 : for(int idx(0); idx < 16; ++idx)
1333 : {
1334 16 : struct sockaddr_in6 in6 = sockaddr_in6();
1335 16 : in6.sin6_family = AF_INET6;
1336 16 : in6.sin6_port = htons(rand());
1337 16 : in6.sin6_addr.s6_addr32[0] = 0;
1338 16 : in6.sin6_addr.s6_addr32[1] = 0;
1339 16 : in6.sin6_addr.s6_addr32[2] = 0;
1340 16 : in6.sin6_addr.s6_addr32[3] = 0;
1341 :
1342 : // change one byte only
1343 : //
1344 0 : do
1345 : {
1346 16 : in6.sin6_addr.s6_addr[idx] = rand();
1347 : }
1348 16 : while(in6.sin6_addr.s6_addr[idx] == 0);
1349 :
1350 : // verify network type
1351 : //
1352 16 : a.set_ipv6(in6);
1353 :
1354 16 : CATCH_REQUIRE(a.get_network_type() != addr::addr::network_type_t::NETWORK_TYPE_ANY);
1355 16 : CATCH_REQUIRE(a.get_network_type_string() != "Any");
1356 : }
1357 : }
1358 :
1359 14 : CATCH_SECTION("private address fd00::/8")
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(0xFD00 | (rand() & 255));
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_PRIVATE);
1379 10 : CATCH_REQUIRE(a.get_network_type_string() == "Private");
1380 : }
1381 : }
1382 :
1383 14 : CATCH_SECTION("private address fe80::/10")
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 10 : in6.sin6_addr.s6_addr16[0] = htons(0xFE80 | (rand() & 63));
1391 10 : in6.sin6_addr.s6_addr16[1] = rand();
1392 10 : in6.sin6_addr.s6_addr16[2] = rand();
1393 10 : in6.sin6_addr.s6_addr16[3] = rand();
1394 10 : in6.sin6_addr.s6_addr16[4] = rand();
1395 10 : in6.sin6_addr.s6_addr16[5] = rand();
1396 10 : in6.sin6_addr.s6_addr16[6] = rand();
1397 10 : in6.sin6_addr.s6_addr16[7] = rand();
1398 :
1399 : // verify network type
1400 : //
1401 10 : a.set_ipv6(in6);
1402 10 : CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LINK_LOCAL);
1403 10 : CATCH_REQUIRE(a.get_network_type_string() == "Local Link");
1404 : }
1405 : }
1406 :
1407 14 : CATCH_SECTION("private address ff02::/16")
1408 : {
1409 11 : for(int idx(0); idx < 10; ++idx)
1410 : {
1411 10 : struct sockaddr_in6 in6 = sockaddr_in6();
1412 10 : in6.sin6_family = AF_INET6;
1413 10 : in6.sin6_port = htons(rand());
1414 10 : in6.sin6_addr.s6_addr16[0] = htons(0xFF02);
1415 10 : in6.sin6_addr.s6_addr16[1] = rand();
1416 10 : in6.sin6_addr.s6_addr16[2] = rand();
1417 10 : in6.sin6_addr.s6_addr16[3] = rand();
1418 10 : in6.sin6_addr.s6_addr16[4] = rand();
1419 10 : in6.sin6_addr.s6_addr16[5] = rand();
1420 10 : in6.sin6_addr.s6_addr16[6] = rand();
1421 10 : in6.sin6_addr.s6_addr16[7] = rand();
1422 :
1423 : // verify network type
1424 : //
1425 10 : a.set_ipv6(in6);
1426 10 : CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LINK_LOCAL);
1427 10 : CATCH_REQUIRE(a.get_network_type_string() == "Local Link");
1428 : }
1429 : }
1430 :
1431 14 : CATCH_SECTION("private address ff00::/8")
1432 : {
1433 11 : for(int idx(0); idx < 10; ++idx)
1434 : {
1435 10 : struct sockaddr_in6 in6 = sockaddr_in6();
1436 10 : in6.sin6_family = AF_INET6;
1437 10 : in6.sin6_port = htons(rand());
1438 0 : do
1439 : {
1440 10 : in6.sin6_addr.s6_addr16[0] = htons(0xFF00 | (rand() & 255));
1441 : }
1442 10 : while((in6.sin6_addr.s6_addr16[0] & htons(0xFF0F)) == htons(0xFF01) // ffx1::/16
1443 10 : || (in6.sin6_addr.s6_addr16[0] & htons(0xFF0F)) == htons(0xFF02) // ffx2::/16
1444 10 : || (in6.sin6_addr.s6_addr16[0] & htons(0xFFC0)) == htons(0xFE80) // fe80::/10
1445 20 : || (in6.sin6_addr.s6_addr16[0] & htons(0xFF00)) == htons(0xFD00)); // fd00::/8
1446 10 : in6.sin6_addr.s6_addr16[1] = rand();
1447 10 : in6.sin6_addr.s6_addr16[2] = rand();
1448 10 : in6.sin6_addr.s6_addr16[3] = rand();
1449 10 : in6.sin6_addr.s6_addr16[4] = rand();
1450 10 : in6.sin6_addr.s6_addr16[5] = rand();
1451 10 : in6.sin6_addr.s6_addr16[6] = rand();
1452 10 : in6.sin6_addr.s6_addr16[7] = rand();
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_MULTICAST);
1458 10 : CATCH_REQUIRE(a.get_network_type_string() == "Multicast");
1459 : }
1460 : }
1461 :
1462 14 : CATCH_SECTION("private address ffx1::/8")
1463 : {
1464 11 : for(int idx(0); idx < 10; ++idx)
1465 : {
1466 10 : struct sockaddr_in6 in6 = sockaddr_in6();
1467 10 : in6.sin6_family = AF_INET6;
1468 10 : in6.sin6_port = htons(rand());
1469 10 : in6.sin6_addr.s6_addr16[0] = htons(0xFF01 | ((rand() & 15) << 4));
1470 10 : in6.sin6_addr.s6_addr16[1] = rand();
1471 10 : in6.sin6_addr.s6_addr16[2] = rand();
1472 10 : in6.sin6_addr.s6_addr16[3] = rand();
1473 10 : in6.sin6_addr.s6_addr16[4] = rand();
1474 10 : in6.sin6_addr.s6_addr16[5] = rand();
1475 10 : in6.sin6_addr.s6_addr16[6] = rand();
1476 10 : in6.sin6_addr.s6_addr16[7] = rand();
1477 :
1478 : // verify network type
1479 : //
1480 10 : a.set_ipv6(in6);
1481 10 : CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LOOPBACK);
1482 10 : CATCH_REQUIRE(a.get_network_type_string() == "Loopback");
1483 : }
1484 : }
1485 :
1486 14 : CATCH_SECTION("private address ::1")
1487 : {
1488 11 : for(int idx(0); idx < 10; ++idx)
1489 : {
1490 10 : struct sockaddr_in6 in6 = sockaddr_in6();
1491 10 : in6.sin6_family = AF_INET6;
1492 10 : in6.sin6_port = htons(rand());
1493 10 : in6.sin6_addr.s6_addr16[0] = 0;
1494 10 : in6.sin6_addr.s6_addr16[1] = 0;
1495 10 : in6.sin6_addr.s6_addr16[2] = 0;
1496 10 : in6.sin6_addr.s6_addr16[3] = 0;
1497 10 : in6.sin6_addr.s6_addr16[4] = 0;
1498 10 : in6.sin6_addr.s6_addr16[5] = 0;
1499 10 : in6.sin6_addr.s6_addr16[6] = 0;
1500 10 : in6.sin6_addr.s6_addr16[7] = htons(1);
1501 :
1502 : // verify network type
1503 : //
1504 10 : a.set_ipv6(in6);
1505 10 : CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LOOPBACK);
1506 10 : CATCH_REQUIRE(a.get_network_type_string() == "Loopback");
1507 :
1508 : // try again from a string to confirm
1509 : //
1510 10 : struct addrinfo * addrlist(nullptr);
1511 10 : int const port(rand() & 65535);
1512 10 : int const r(getaddrinfo("::1", std::to_string(port).c_str(), nullptr, &addrlist));
1513 10 : CATCH_REQUIRE(r == 0);
1514 10 : CATCH_REQUIRE(addrlist != nullptr);
1515 10 : CATCH_REQUIRE(addrlist->ai_family == AF_INET6);
1516 10 : CATCH_REQUIRE(addrlist->ai_addrlen == sizeof(struct sockaddr_in6));
1517 10 : a.set_ipv6(*reinterpret_cast<sockaddr_in6 *>(addrlist->ai_addr));
1518 10 : CATCH_REQUIRE(a.get_network_type() == addr::addr::network_type_t::NETWORK_TYPE_LOOPBACK);
1519 10 : CATCH_REQUIRE(a.get_network_type_string() == "Loopback");
1520 10 : freeaddrinfo(addrlist);
1521 : }
1522 : }
1523 : }
1524 7 : }
1525 :
1526 :
1527 5 : CATCH_TEST_CASE( "ipv6::network", "[ipv6]" )
1528 : {
1529 6 : CATCH_GIVEN("set_from_socket()")
1530 : {
1531 6 : CATCH_SECTION("create a server, but do not test it (yet)...")
1532 : {
1533 2 : addr::addr_parser p;
1534 2 : addr::addr_range::vector_t ips(p.parse("[::1]:49999"));
1535 1 : CATCH_REQUIRE(ips.size() >= 1);
1536 :
1537 1 : addr::addr & a(ips[0].get_from());
1538 1 : int s(a.create_socket(addr::addr::SOCKET_FLAG_NONBLOCK | addr::addr::SOCKET_FLAG_CLOEXEC | addr::addr::SOCKET_FLAG_REUSE));
1539 1 : CATCH_REQUIRE(s >= 0);
1540 2 : std::shared_ptr<int> auto_free(&s, socket_deleter);
1541 :
1542 1 : CATCH_REQUIRE(a.bind(s) == 0);
1543 : }
1544 :
1545 6 : CATCH_SECTION("connect with TCP to [::1]")
1546 : {
1547 1 : if(SNAP_CATCH2_NAMESPACE::g_tcp_port != -1)
1548 : {
1549 2 : addr::addr_parser p;
1550 2 : addr::addr_range::vector_t ips(p.parse("[::1]:" + std::to_string(SNAP_CATCH2_NAMESPACE::g_tcp_port)));
1551 1 : CATCH_REQUIRE(ips.size() >= 1);
1552 :
1553 1 : addr::addr & a(ips[0].get_from());
1554 1 : int s(a.create_socket(addr::addr::SOCKET_FLAG_CLOEXEC));// | addr::addr::SOCKET_FLAG_REUSE));
1555 1 : CATCH_REQUIRE(s >= 0);
1556 2 : std::shared_ptr<int> auto_free(&s, socket_deleter);
1557 :
1558 1 : CATCH_REQUIRE(a.connect(s) == 0);
1559 :
1560 : // get socket info from the other side (peer == true)
1561 : //
1562 1 : addr::addr b;
1563 1 : b.set_from_socket(s, true);
1564 1 : CATCH_REQUIRE_FALSE(b.is_ipv4());
1565 1 : CATCH_REQUIRE(b.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "::1");
1566 1 : CATCH_REQUIRE(b.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "::1");
1567 :
1568 : // in this case we know what the port is since we specified
1569 : // that when connecting
1570 : //
1571 1 : CATCH_REQUIRE(b.get_port() == SNAP_CATCH2_NAMESPACE::g_tcp_port);
1572 :
1573 : // now try this side (peer == false)
1574 : //
1575 1 : addr::addr c;
1576 1 : c.set_from_socket(s, false);
1577 1 : CATCH_REQUIRE_FALSE(c.is_ipv4());
1578 1 : CATCH_REQUIRE(c.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "::1");
1579 1 : CATCH_REQUIRE(c.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "::1");
1580 :
1581 : // we cannot be sure of the port, there is a range we could
1582 : // test better (more constraining) but for this test is
1583 : // certainly does not matter much; it has to be more than
1584 : // 1023, though
1585 : //
1586 1 : CATCH_REQUIRE(c.get_port() > 1023);
1587 : }
1588 : else
1589 : {
1590 : // avoid issue of no assertions
1591 : //
1592 0 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::g_tcp_port == -1);
1593 0 : std::cout << "connect to [::1] test skipped as no TCP port was specified on the command line." << std::endl;
1594 : }
1595 : }
1596 :
1597 6 : CATCH_SECTION("connect with UDP to [::1]")
1598 : {
1599 2 : addr::addr_parser p;
1600 1 : p.set_protocol("udp");
1601 2 : addr::addr_range::vector_t ips(p.parse("[::1]:53"));
1602 1 : CATCH_REQUIRE(ips.size() >= 1);
1603 :
1604 1 : addr::addr & a(ips[0].get_from());
1605 1 : int s(a.create_socket(addr::addr::SOCKET_FLAG_CLOEXEC));// | addr::addr::SOCKET_FLAG_REUSE));
1606 1 : CATCH_REQUIRE(s >= 0);
1607 2 : std::shared_ptr<int> auto_free(&s, socket_deleter);
1608 :
1609 1 : CATCH_REQUIRE(a.connect(s) == -1);
1610 :
1611 : // get socket info from the other side (peer == true)
1612 : //
1613 1 : addr::addr b;
1614 1 : CATCH_REQUIRE_THROWS_AS(b.set_from_socket(s, true), addr::addr_io_error);
1615 1 : CATCH_REQUIRE_FALSE(b.is_ipv4());
1616 1 : CATCH_REQUIRE(b.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "::");
1617 1 : CATCH_REQUIRE(b.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "::");
1618 :
1619 : // in this case we know what the port is since we specified
1620 : // that when connecting
1621 : //
1622 1 : CATCH_REQUIRE(b.get_port() == 0);
1623 :
1624 : // now try this side (peer == false)
1625 : //
1626 1 : addr::addr c;
1627 1 : c.set_from_socket(s, false);
1628 1 : CATCH_REQUIRE_FALSE(c.is_ipv4());
1629 1 : CATCH_REQUIRE(c.to_ipv6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "::");
1630 1 : CATCH_REQUIRE(c.to_ipv4or6_string(addr::addr::string_ip_t::STRING_IP_ONLY) == "::");
1631 :
1632 : // we cannot be sure of the port, there is a range we could
1633 : // test better (more constraining) but for this test is
1634 : // certainly does not matter much; it has to be more than
1635 : // 1023, though
1636 : //
1637 1 : CATCH_REQUIRE(c.get_port() == 0);
1638 : }
1639 : }
1640 9 : }
1641 :
1642 :
1643 : // vim: ts=4 sw=4 et
|