Line data Source code
1 : // Copyright (c) 2012-2021 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/libaddr
4 : //
5 : // Permission is hereby granted, free of charge, to any person obtaining a
6 : // copy of this software and associated documentation files (the
7 : // "Software"), to deal in the Software without restriction, including
8 : // without limitation the rights to use, copy, modify, merge, publish,
9 : // distribute, sublicense, and/or sell copies of the Software, and to
10 : // permit persons to whom the Software is furnished to do so, subject to
11 : // the following conditions:
12 : //
13 : // The above copyright notice and this permission notice shall be included
14 : // in all copies or substantial portions of the Software.
15 : //
16 : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 : // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 : // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 : // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 : // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 : // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 : // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 :
24 :
25 : /** \file
26 : * \brief The implementation of the addr class.
27 : *
28 : * This file includes the implementation of the addr class. The one that
29 : * deals with low level classes.
30 : */
31 :
32 : // self
33 : //
34 : #include "libaddr/addr.h"
35 : #include "libaddr/addr_exception.h"
36 :
37 :
38 : // C++ library
39 : //
40 : #include <sstream>
41 : #include <iostream>
42 :
43 :
44 : // C library
45 : //
46 : #include <netdb.h>
47 :
48 :
49 : // last include
50 : //
51 : #include <snapdev/poison.h>
52 :
53 :
54 :
55 : /** \mainpage
56 : * \brief libaddr, a C++ library to handle network IP addresses in IPv4 and IPv6.
57 : *
58 : * ### Introduction
59 : *
60 : * This library is used to parse strings of IP addresses to lists of
61 : * binary IP addresses ready to be used by functions such as bind(),
62 : * send(), recv(), etc.
63 : *
64 : * The library supports multiple addresses separated by commas and/or
65 : * spaces, ports, and CIDR masks. It can check whether an address matches
66 : * another taking the mask in account. It can sort IPs numerically. It
67 : * can determine the type of an IP address (i.e. is it a local address,
68 : * a private address, a public address?)
69 : *
70 : * The library also has a function to read IP addresses from your
71 : * computer interfaces and return that list. Very practical to know
72 : * whether an IP address represents your computer or not.
73 : *
74 : * ### Usage
75 : *
76 : * The library is composed of three main classes:
77 : *
78 : * \li addr
79 : *
80 : * The address class holds one address, a port, a protocol and a few
81 : * other parts. This is what one uses to connect or listen with an
82 : * address.
83 : *
84 : * The address is kept by addr in an IPv6 address structure.
85 : *
86 : * By default the CIDR of the address is all 1s (i.e. no masking, all
87 : * bits considered important.) The mask is always 128 bits. If you are
88 : * dealing with IPv4, make sure that the first 12 bytes are set to 255.
89 : *
90 : * The class also offers a set of functions to transform the binary
91 : * address it is holding to a string.
92 : *
93 : * \li addr_range
94 : *
95 : * It is possible to define a range of addresses and ports. This class
96 : * holds a 'from' address and a 'to' address. By default neither is
97 : * defined. You have to call the set_from() and set_to() functions.
98 : *
99 : * The addr_range::vector_t is what the addr_parser returns after
100 : * parsing a string representing one of more addresses.
101 : *
102 : * \note
103 : * The range is functional, however, the parser does not yet support
104 : * parsing range of addresses and ports.
105 : *
106 : * \li addr_parser
107 : *
108 : * The parser is used to transform a string to an address.
109 : *
110 : * It supports many variations of its input, which are handled by
111 : * the 'allow' flags. The set_allow() and get_allow() functions can
112 : * be used to tweak the parser in supporting such and such feature.
113 : *
114 : * By default, the input is expected to be an address and a port
115 : * separated by a colon (i.e. `"1.2.3.4:1234"` in IPv4 and `"[::1]:1234"`
116 : * in IPv6.)
117 : *
118 : * ### Parser
119 : *
120 : * The parser supports the following syntax (ranges are not yet supported
121 : * and they do not appear in the following list):
122 : *
123 : * \code
124 : * start: address_list
125 : *
126 : * address_list: address_cidr
127 : * | address_list address_list_separators address_cidr
128 : *
129 : * address_list_separators: ' '
130 : * | ','
131 : * | address_list_separators address_list_separators
132 : *
133 : * address_cidr: address_port
134 : * | address_port '/' cidr
135 : *
136 : * address_port: address
137 : * | address ':' port
138 : *
139 : * address: ipv4
140 : * | ipv6
141 : *
142 : * cidr: decimal_number
143 : * | ipv4
144 : * | ipv6
145 : *
146 : * ipv4: decimal_number '.' decimal_number '.' decimal_number '.' decimal_number
147 : *
148 : * ipv6: '[' hexadecimal_number_list ']'
149 : *
150 : * port: decimal_number
151 : *
152 : * hexadecimal_number_list: hexadecimal_number
153 : * | hexadecimal_number_list ':' hexadecimal_number
154 : *
155 : * decimal_number: [0-9]+
156 : *
157 : * hexadecimal_number: [0-9a-fA-F]+
158 : * \endcode
159 : *
160 : * When accepting multiple addresses separated by commas or spaces, the
161 : * number of commas and spaces separating two address is not significant.
162 : * The input string can also start or end with commas and spaces. The
163 : * following variable defines exactly two IP address:
164 : *
165 : * \code
166 : * addresses= ,1.2.3.4, ,5.6.7.8,,
167 : * \endcode
168 : *
169 : * (note that the parser should not be passed the "addresses=" part.)
170 : */
171 :
172 :
173 : /** \brief The libaddr classes are all defined in this namespace.
174 : *
175 : * The addr namespace includes all the addr classes.
176 : */
177 : namespace addr
178 : {
179 :
180 : /*
181 : * Various sytem address structures
182 :
183 : // Any address is 16 bytes or less
184 : struct sockaddr {
185 : unsigned short sa_family; // address family, AF_xxx
186 : char sa_data[14]; // 14 bytes of protocol address
187 : };
188 :
189 : struct sockaddr_storage {
190 : sa_family_t ss_family; // address family
191 :
192 : // all this is padding, implementation specific, ignore it:
193 : char __ss_pad1[_SS_PAD1SIZE];
194 : int64_t __ss_align;
195 : char __ss_pad2[_SS_PAD2SIZE];
196 : };
197 :
198 :
199 : typedef uint32_t in_addr_t; // or `__be32`
200 : struct in_addr {
201 : in_addr_t s_addr;
202 : };
203 :
204 :
205 : // IPv4
206 : struct sockaddr_in {
207 : short sin_family; // e.g. AF_INET, AF_INET6
208 : unsigned short sin_port; // e.g. htons(3490)
209 : struct in_addr sin_addr; // see struct in_addr, below
210 : char sin_zero[8]; // zero this if you want to
211 : };
212 :
213 :
214 : // IPv6
215 : struct sockaddr_in6 {
216 : u_int16_t sin6_family; // address family, AF_INET6
217 : u_int16_t sin6_port; // port number, Network Byte Order
218 : u_int32_t sin6_flowinfo; // IPv6 flow information
219 : struct in6_addr sin6_addr; // IPv6 address
220 : u_int32_t sin6_scope_id; // Scope ID
221 : };
222 :
223 : struct in6_addr
224 : {
225 : union
226 : {
227 : uint8_t __u6_addr8[16];
228 : #ifdef __USE_MISC
229 : uint16_t __u6_addr16[8];
230 : uint32_t __u6_addr32[4];
231 : #endif
232 : } __in6_u;
233 : #define s6_addr __in6_u.__u6_addr8
234 : #ifdef __USE_MISC
235 : # define s6_addr16 __in6_u.__u6_addr16
236 : # define s6_addr32 __in6_u.__u6_addr32
237 : #endif
238 : };
239 :
240 :
241 : */
242 :
243 :
244 :
245 :
246 :
247 : /** \brief Create an addr object that represents an ANY address.
248 : *
249 : * This function initializes the addr object with the ANY address.
250 : * The port is set to 0 and the protocol to TCP.
251 : *
252 : * It is strongly suggested that you change those parameters
253 : * before really using this address since a port of zero and
254 : * the protocol may be wrong.
255 : */
256 265504 : addr::addr()
257 : {
258 : // keep default protocol (TCP)
259 265504 : }
260 :
261 :
262 : /** \brief Create an addr object from a binary IPv4 address.
263 : *
264 : * This function initializes this addr object with the specified IPv4
265 : * address. The is_ipv4() function will return true.
266 : *
267 : * \param[in] in The binary IPv4 address.
268 : */
269 66039 : addr::addr(sockaddr_in const & in)
270 : {
271 66039 : set_ipv4(in);
272 : // keep default protocol (TCP)
273 66014 : }
274 :
275 :
276 : /** \brief Create an addr object from a binary IPv6 address.
277 : *
278 : * This function initializes this addr object with the specified IPv6
279 : * address. The is_ipv4() function will return false.
280 : *
281 : * \param[in] in6 The binary IPv6 address.
282 : */
283 65990 : addr::addr(sockaddr_in6 const & in6)
284 : {
285 65990 : set_ipv6(in6);
286 : // keep default protocol (TCP)
287 65989 : }
288 :
289 :
290 : /** \brief Save an IPv4 in this addr object.
291 : *
292 : * This function saves the specified IPv4 in this addr object.
293 : *
294 : * Since we save the data in an IPv6 structure, it is kept in
295 : * the addr as an IPv4 mapped in an IPv6 address. It can still
296 : * be retrieved right back as an IPv4 with the get_ipv4() function.
297 : *
298 : * \param[in] in The IPv4 address to save in this addr object.
299 : */
300 66975 : void addr::set_ipv4(sockaddr_in const & in)
301 : {
302 66975 : if(in.sin_family != AF_INET)
303 : {
304 : // although we convert the IPv4 to an IPv6 below, we really only
305 : // support AF_INET on entry
306 : //
307 50 : throw addr_invalid_argument("addr::set_ipv4(): the input address does not represent an IPv4 address (family is not AF_INET).");
308 : }
309 :
310 : // reset the address first
311 66925 : memset(&f_address, 0, sizeof(f_address));
312 :
313 : // then transform the IPv4 to an IPv6
314 : //
315 : // Note: this is not an IPv6 per se, it is an IPv4 mapped within an
316 : // IPv6 and your network stack needs to support IPv4 anyway
317 : // in order to use that IP...
318 : //
319 66925 : f_address.sin6_family = AF_INET6;
320 66925 : f_address.sin6_port = in.sin_port;
321 66925 : f_address.sin6_addr.s6_addr16[5] = 0xFFFF;
322 66925 : f_address.sin6_addr.s6_addr32[3] = in.sin_addr.s_addr;
323 :
324 66925 : address_changed();
325 66925 : }
326 :
327 :
328 : /** \brief Set the port of this address.
329 : *
330 : * This function changes the port of this address to \p port.
331 : *
332 : * \exception addr_invalid_argument
333 : * This exception is raised whenever the \p port parameter is set to
334 : * an invalid number (negative or larger than 65535.)
335 : *
336 : * \param[in] port The new port to save in this address.
337 : */
338 65741 : void addr::set_port(int port)
339 : {
340 65741 : if(port > 65535
341 65641 : || port < 0)
342 : {
343 200 : throw addr_invalid_argument("port to set_port() cannot be out of the allowed range [0..65535].");
344 : }
345 65541 : f_address.sin6_port = htons(port);
346 65541 : }
347 :
348 :
349 : /** \brief Change the protocol using a string.
350 : *
351 : * This function is used to change the current protocol defined in
352 : * this addr object.
353 : *
354 : * \exception addr_invalid_argument
355 : * We currently support "tcp", "udp", and "ip". Any other protocol
356 : * name generates this exception.
357 : *
358 : * \param[in] protocol The name of the protocol ("tcp", "udp", or "ip")
359 : */
360 7 : void addr::set_protocol(char const * protocol)
361 : {
362 7 : if(protocol == nullptr)
363 : {
364 1 : throw addr_invalid_argument("protocol pointer to set_protocol() cannot be a nullptr.");
365 : }
366 :
367 6 : if(strcmp(protocol, "ip") == 0)
368 : {
369 1 : f_protocol = IPPROTO_IP;
370 : }
371 5 : else if(strcmp(protocol, "tcp") == 0)
372 : {
373 1 : f_protocol = IPPROTO_TCP;
374 : }
375 4 : else if(strcmp(protocol, "udp") == 0)
376 : {
377 1 : f_protocol = IPPROTO_UDP;
378 : }
379 : else
380 : {
381 : throw addr_invalid_argument(
382 6 : std::string("unknown protocol \"")
383 6 : + protocol
384 9 : + "\", expected \"tcp\" or \"udp\" (string).");
385 : }
386 :
387 3 : address_changed();
388 3 : }
389 :
390 :
391 : /** \brief Set the protocol numerically.
392 : *
393 : * This function sets the protocol from a number instead of a name.
394 : *
395 : * Note that we only support IPPROTO_TCP and IPPROTO_UDP for now.
396 : * Any other protocol will make this function raise an exception.
397 : *
398 : * \todo
399 : * We may want to support any protocol number at this level. If your
400 : * application is limited then it should verify the protocol and
401 : * make sure it supports it before using this address. At the same
402 : * time, the IP protocol is pretty much locked up with just TCP
403 : * and UDP these days (there is the IP protocol, but that's not
404 : * useful at our level.)
405 : *
406 : * \exception addr_invalid_argument
407 : * This exception is raised if the specified protocol is not currently
408 : * supported by the addr implementation.
409 : *
410 : * \param[in] protocol The new numeric protocol.
411 : */
412 131961 : void addr::set_protocol(int protocol)
413 : {
414 131961 : switch(protocol)
415 : {
416 131861 : case IPPROTO_IP:
417 : case IPPROTO_TCP:
418 : case IPPROTO_UDP:
419 131861 : f_protocol = protocol;
420 131861 : break;
421 :
422 100 : default:
423 : throw addr_invalid_argument(
424 : "unknown protocol number "
425 200 : + std::to_string(protocol)
426 200 : + ", expected \"tcp\" ("
427 400 : + std::to_string(static_cast<int>(IPPROTO_TCP))
428 200 : + ") or \"udp\" ("
429 400 : + std::to_string(static_cast<int>(IPPROTO_UDP))
430 300 : + ") (numeric).");
431 :
432 : }
433 131861 : }
434 :
435 :
436 : /** \brief Set the mask.
437 : *
438 : * The input mask must be exactly 16 bytes. If you are dealing with an
439 : * IPv4, make sure the first 12 bytes are 255.
440 : *
441 : * \param[in] mask The mask to save in this address.
442 : */
443 754 : void addr::set_mask(uint8_t const * mask)
444 : {
445 754 : memcpy(f_mask, mask, sizeof(f_mask));
446 754 : }
447 :
448 :
449 : /** \brief Apply the mask to the IP address.
450 : *
451 : * This function applies the mask to this address IP address. This means
452 : * the bits that are 0 in the mask will also be 0 in the address once
453 : * the function returns.
454 : *
455 : * This should be called if you are trying to canonicalize an IP/mask.
456 : */
457 1 : void addr::apply_mask()
458 : {
459 17 : for(int idx(0); idx < 16; ++idx)
460 : {
461 16 : f_address.sin6_addr.s6_addr[idx] &= f_mask[idx];
462 : }
463 1 : }
464 :
465 :
466 : /** \brief Get the mask.
467 : *
468 : * The output buffer for the mask must be at least 16 bytes. If you are
469 : * dealing with an IPv4, all the bytes are expected to be 255 except
470 : * the bottom 4 bytes (offset 12, 13, 14, 15).
471 : *
472 : * \param[out] mask The buffer where the mask gets copied.
473 : */
474 154 : void addr::get_mask(uint8_t * mask) const
475 : {
476 154 : memcpy(mask, f_mask, sizeof(f_mask));
477 154 : }
478 :
479 :
480 : /** \brief Check whether this address represents the ANY address.
481 : *
482 : * The IPv4 and IPv6 have an ANY address also called the default address.
483 : * This function returns true if this address represents the ANY address.
484 : *
485 : * The any address is represented by `"0.0.0.0"` in IPv4 and `"::"` in
486 : * IPv6. (i.e. all zeroes)
487 : *
488 : * \note
489 : * You can also determine this by calling the get_network_type() function
490 : * and compare the result against `network_type_t::NETWORK_TYPE_ANY`.
491 : *
492 : * \return true if this addr represents the any address.
493 : */
494 52 : bool addr::is_default() const
495 : {
496 : // this is for IPv4 or IPv6
497 : //
498 52 : return f_address.sin6_addr.s6_addr32[0] == 0
499 52 : && f_address.sin6_addr.s6_addr32[1] == 0
500 52 : && f_address.sin6_addr.s6_addr16[4] == 0
501 52 : && (f_address.sin6_addr.s6_addr16[5] == 0 || f_address.sin6_addr.s6_addr16[5] == 0xFFFF)
502 104 : && f_address.sin6_addr.s6_addr32[3] == 0;
503 : }
504 :
505 :
506 : /** \brief Check whether this address represents an IPv4 address.
507 : *
508 : * The IPv6 format supports embedding IPv4 addresses. This function
509 : * returns true if the embedded address is an IPv4. When this function
510 : * returns true, the get_ipv4() can be called. Otherwise, the get_ipv4()
511 : * function throws an exception.
512 : *
513 : * \return true if this address represents an IPv4 address.
514 : */
515 527655 : bool addr::is_ipv4() const
516 : {
517 527655 : return f_address.sin6_addr.s6_addr32[0] == 0
518 329930 : && f_address.sin6_addr.s6_addr32[1] == 0
519 329926 : && f_address.sin6_addr.s6_addr16[4] == 0
520 857579 : && f_address.sin6_addr.s6_addr16[5] == 0xFFFF;
521 : }
522 :
523 :
524 : /** \brief Retreive the IPv4 address.
525 : *
526 : * This function can be used to retrieve the IPv4 address of this addr
527 : * object. If the address is not an IPv4, then the function throws.
528 : *
529 : * \exception addr_invalid_state
530 : * This exception is raised if the address is not an IPv4 address.
531 : *
532 : * \param[out] in The structure where the IPv4 Internet address gets saved.
533 : */
534 78 : void addr::get_ipv4(sockaddr_in & in) const
535 : {
536 78 : if(is_ipv4())
537 : {
538 : // this is an IPv4 mapped in an IPv6, "unmap" that IP
539 : //
540 77 : memset(&in, 0, sizeof(in));
541 77 : in.sin_family = AF_INET;
542 77 : in.sin_port = f_address.sin6_port;
543 77 : in.sin_addr.s_addr = f_address.sin6_addr.s6_addr32[3];
544 154 : return;
545 : }
546 :
547 1 : throw addr_invalid_state("Not an IPv4 compatible address.");
548 : }
549 :
550 :
551 : /** \brief Save the specified IPv6 address in this addr object.
552 : *
553 : * This function saves the specified IPv6 address in this addr object.
554 : * The function does not check the validity of the address. It is
555 : * expected to be valid.
556 : *
557 : * The address may be an embedded IPv4 address.
558 : *
559 : * \param[in] in6 The source IPv6 to save in the addr object.
560 : */
561 66188 : void addr::set_ipv6(sockaddr_in6 const & in6)
562 : {
563 66188 : if(in6.sin6_family != AF_INET6)
564 : {
565 2 : throw addr_invalid_argument("addr::set_ipv6(): the input address does not represent an IPv6 address (family is not AF_INET6).");
566 : }
567 66186 : memcpy(&f_address, &in6, sizeof(in6));
568 :
569 66186 : address_changed();
570 66186 : }
571 :
572 :
573 : /** \brief Retrieve a copy of this addr IP address.
574 : *
575 : * This function returns the current IP address saved in this
576 : * addr object. The IP may represent an IPv4 address in which
577 : * case the is_ipv4() returns true.
578 : *
579 : * \param[out] in6 The structure where the address gets saved.
580 : */
581 21 : void addr::get_ipv6(sockaddr_in6 & in6) const
582 : {
583 21 : memcpy(&in6, &f_address, sizeof(in6));
584 21 : }
585 :
586 :
587 : /** \brief Retrive the IPv4 as a string.
588 : *
589 : * This function returns a string representing the IP address
590 : * defined in this addr object.
591 : *
592 : * The \p mode parameter defines what gets output.
593 : *
594 : * \li ip_string_t::IP_STRING_ONLY -- only the IP address
595 : * \li ip_string_t::IP_STRING_PORT -- the IP and port
596 : * \li ip_string_t::IP_STRING_MASK -- the IP and mask
597 : * \li ip_string_t::IP_STRING_ALL -- the IP, port, and mask
598 : *
599 : * The ip_string_t::IP_STRING_BRACKET is viewed as
600 : * ip_string_t::IP_STRING_ONLY.
601 : *
602 : * The ip_string_t::IP_STRING_BRACKET_MASK is viewed as
603 : * ip_string_t::IP_STRING_MASK.
604 : *
605 : * \exception addr_invalid_state_exception
606 : * If the addr object does not currently represent an IPv4 then
607 : * this exception is raised.
608 : *
609 : * \param[in] mode How the output string is to be built.
610 : */
611 131703 : std::string addr::to_ipv4_string(string_ip_t mode) const
612 : {
613 131703 : if(is_ipv4())
614 : {
615 : // this is an IPv4 mapped in an IPv6, "unmap" that IP
616 : // so the inet_ntop() can correctly generate an output IP
617 : //
618 : in_addr in;
619 131697 : memset(&in, 0, sizeof(in));
620 131697 : in.s_addr = f_address.sin6_addr.s6_addr32[3];
621 : char buf[INET_ADDRSTRLEN + 1];
622 131697 : if(inet_ntop(AF_INET, &in, buf, sizeof(buf)) != nullptr)
623 : {
624 131697 : if(mode != string_ip_t::STRING_IP_ONLY)
625 : {
626 1152 : std::stringstream result;
627 576 : result << buf;
628 576 : if(mode == string_ip_t::STRING_IP_PORT
629 266 : || mode == string_ip_t::STRING_IP_ALL)
630 : {
631 546 : result << ":";
632 546 : result << ntohs(f_address.sin6_port);
633 : }
634 576 : if(mode == string_ip_t::STRING_IP_MASK
635 566 : || mode == string_ip_t::STRING_IP_BRACKETS_MASK
636 556 : || mode == string_ip_t::STRING_IP_ALL)
637 : {
638 256 : memset(&in, 0, sizeof(in));
639 256 : in.s_addr = htonl((f_mask[12] << 24) | (f_mask[13] << 16) | (f_mask[14] << 8) | f_mask[15]);
640 256 : if(inet_ntop(AF_INET, &in, buf, sizeof(buf)) != nullptr)
641 : {
642 256 : result << "/";
643 256 : result << buf; // TODO: convert to simple number if possible
644 : }
645 : }
646 576 : return result.str();
647 : }
648 131121 : return std::string(buf);
649 : }
650 : // IPv4 should never fail converting the address unless the
651 : // buffer was too small...
652 : }
653 :
654 6 : throw addr_invalid_state("Not an IPv4 compatible address.");
655 : }
656 :
657 :
658 : /** \brief Convert the addr object to a string.
659 : *
660 : * This function converts the addr object to a canonicalized string.
661 : * This can be used to compare two IPv6 together as strings, although
662 : * it is probably better to compare them using the < and == operators.
663 : *
664 : * By default the function returns with the IPv6 address defined
665 : * between square bracket, so the output of this function can be
666 : * used as the input of the set_addr_port() function. You may
667 : * also request the address without the brackets.
668 : *
669 : * \exception addr_invalid_state_exception
670 : * If the binary IP address cannot be converted to ASCII, this exception
671 : * is raised.
672 : *
673 : * \param[in] mode How the output string is to be built.
674 : *
675 : * \return The addr object converted to an IPv6 address.
676 : */
677 263054 : std::string addr::to_ipv6_string(string_ip_t mode) const
678 : {
679 : char buf[INET6_ADDRSTRLEN + 1];
680 263054 : if(inet_ntop(AF_INET6, &f_address.sin6_addr, buf, sizeof(buf)) != nullptr)
681 : {
682 263054 : bool const include_brackets(mode == string_ip_t::STRING_IP_BRACKETS
683 197502 : || mode == string_ip_t::STRING_IP_BRACKETS_MASK
684 197490 : || mode == string_ip_t::STRING_IP_PORT // port requires us to add brackets
685 329260 : || mode == string_ip_t::STRING_IP_ALL);
686 :
687 526108 : std::stringstream result;
688 :
689 : // always insert the IP, even if ANY or "BROADCAST"
690 : //
691 263054 : if(include_brackets)
692 : {
693 197476 : result << "[";
694 : }
695 263054 : result << buf;
696 263054 : if(include_brackets)
697 : {
698 197476 : result << "]";
699 : }
700 :
701 : // got a port?
702 : //
703 263054 : if(mode == string_ip_t::STRING_IP_PORT
704 131770 : || mode == string_ip_t::STRING_IP_ALL)
705 : {
706 131912 : result << ":";
707 131912 : result << ntohs(f_address.sin6_port);
708 : }
709 :
710 : // got a mask?
711 : //
712 263054 : if(mode == string_ip_t::STRING_IP_MASK
713 263042 : || mode == string_ip_t::STRING_IP_BRACKETS_MASK
714 263030 : || mode == string_ip_t::STRING_IP_ALL)
715 : {
716 652 : if(inet_ntop(AF_INET6, f_mask, buf, sizeof(buf)) != nullptr)
717 : {
718 652 : result << "/";
719 652 : if(include_brackets)
720 : {
721 640 : result << "[";
722 : }
723 652 : result << buf; // TODO: convert to simple number if possible
724 652 : if(include_brackets)
725 : {
726 640 : result << "]";
727 : }
728 : }
729 : }
730 :
731 526108 : return result.str();
732 : }
733 :
734 : throw addr_invalid_state("The address from this addr could not be converted to a valid canonicalized IPv6 address."); // LCOV_EXCL_LINE
735 : }
736 :
737 :
738 : /** \brief Return the address as IPv4 or IPv6.
739 : *
740 : * Depending on whether the address represents an IPv4 or an IPv6,
741 : * this function returns the corresponding address. Since the format
742 : * of both types of addresses can always be distinguished, it poses
743 : * no concerns.
744 : *
745 : * \exception
746 : * If include_brackets is false and include_port is true, this
747 : * exception is raised because we cannot furfill the request.
748 : *
749 : * \param[in] mode How the output string is to be built.
750 : *
751 : * \return The addr object converted to an IPv4 or an IPv6 address.
752 : */
753 131774 : std::string addr::to_ipv4or6_string(string_ip_t mode) const
754 : {
755 131774 : return is_ipv4() ? to_ipv4_string(mode)
756 131774 : : to_ipv6_string(mode);
757 : }
758 :
759 :
760 : /** \brief Determine the type of network this IP represents.
761 : *
762 : * The IP address may represent various type of networks. This
763 : * function returns that type.
764 : *
765 : * The function checks the address either as IPv4 when is_ipv4()
766 : * returns true, otherwise as IPv6.
767 : *
768 : * See:
769 : *
770 : * \li https://en.wikipedia.org/wiki/Reserved_IP_addresses
771 : * \li https://tools.ietf.org/html/rfc3330
772 : * \li https://tools.ietf.org/html/rfc5735 (IPv4)
773 : * \li https://tools.ietf.org/html/rfc5156 (IPv6)
774 : *
775 : * \return One of the possible network types as defined in the
776 : * network_type_t enumeration.
777 : */
778 131792 : addr::network_type_t addr::get_network_type() const
779 : {
780 131792 : if(f_private_network_defined == network_type_t::NETWORK_TYPE_UNDEFINED)
781 : {
782 131633 : f_private_network_defined = network_type_t::NETWORK_TYPE_UNKNOWN;
783 :
784 131633 : if(is_ipv4())
785 : {
786 : // get the address in host order
787 : //
788 : // we can use a simple mask + compare to know whether it is
789 : // this or that once in host order
790 : //
791 65900 : uint32_t const host_ip(ntohl(f_address.sin6_addr.s6_addr32[3]));
792 :
793 65900 : if((host_ip & 0xFF000000) == 0x0A000000 // 10.0.0.0/8
794 65885 : || (host_ip & 0xFFF00000) == 0xAC100000 // 172.16.0.0/12
795 65759 : || (host_ip & 0xFFFF0000) == 0xC0A80000) // 192.168.0.0/16
796 : {
797 65694 : f_private_network_defined = network_type_t::NETWORK_TYPE_PRIVATE;
798 : }
799 206 : else if((host_ip & 0xFFC00000) == 0x64400000) // 100.64.0.0/10
800 : {
801 10 : f_private_network_defined = network_type_t::NETWORK_TYPE_CARRIER;
802 : }
803 196 : else if((host_ip & 0xFFFF0000) == 0xA9FE0000) // 169.254.0.0/16
804 : {
805 10 : f_private_network_defined = network_type_t::NETWORK_TYPE_LINK_LOCAL; // i.e. DHCP
806 : }
807 186 : else if((host_ip & 0xF0000000) == 0xE0000000) // 224.0.0.0/4
808 : {
809 : // there are many sub-groups on this one which are probably
810 : // still in use...
811 : //
812 10 : f_private_network_defined = network_type_t::NETWORK_TYPE_MULTICAST;
813 : }
814 176 : else if((host_ip & 0xFF000000) == 0x7F000000) // 127.0.0.0/8
815 : {
816 14 : f_private_network_defined = network_type_t::NETWORK_TYPE_LOOPBACK; // i.e. localhost
817 : }
818 162 : else if(host_ip == 0x00000000)
819 : {
820 1 : f_private_network_defined = network_type_t::NETWORK_TYPE_ANY; // i.e. 0.0.0.0
821 : }
822 : }
823 : else //if(is_ipv6()) -- if not IPv4, we have an IPv6
824 : {
825 : // for IPv6 it was simplified by using a prefix for
826 : // all types; really way easier than IPv4
827 : //
828 65733 : if(f_address.sin6_addr.s6_addr32[0] == 0 // ::
829 35 : && f_address.sin6_addr.s6_addr32[1] == 0
830 31 : && f_address.sin6_addr.s6_addr32[2] == 0
831 27 : && f_address.sin6_addr.s6_addr32[3] == 0)
832 : {
833 : // this is the "any" IP address
834 2 : f_private_network_defined = network_type_t::NETWORK_TYPE_ANY;
835 : }
836 : else
837 : {
838 65731 : uint16_t const prefix(ntohs(f_address.sin6_addr.s6_addr16[0]));
839 :
840 65731 : if((prefix & 0xFF00) == 0xFD00) // fd00::/8
841 : {
842 10 : f_private_network_defined = network_type_t::NETWORK_TYPE_PRIVATE;
843 : }
844 65721 : else if((prefix & 0xFFC0) == 0xFE80 // fe80::/10
845 65709 : || (prefix & 0xFF0F) == 0xFF02) // ffx2::/16
846 : {
847 122 : f_private_network_defined = network_type_t::NETWORK_TYPE_LINK_LOCAL; // i.e. DHCP
848 : }
849 65599 : else if((prefix & 0xFF0F) == 0xFF01 // ffx1::/16
850 53 : || (f_address.sin6_addr.s6_addr32[0] == 0 // ::1
851 33 : && f_address.sin6_addr.s6_addr32[1] == 0
852 29 : && f_address.sin6_addr.s6_addr32[2] == 0
853 25 : && f_address.sin6_addr.s6_addr16[6] == 0
854 23 : && f_address.sin6_addr.s6_addr16[7] == htons(1)))
855 : {
856 65567 : f_private_network_defined = network_type_t::NETWORK_TYPE_LOOPBACK;
857 : }
858 32 : else if((prefix & 0xFF00) == 0xFF00) // ff00::/8
859 : {
860 : // this one must be after the link-local and loopback networks
861 10 : f_private_network_defined = network_type_t::NETWORK_TYPE_MULTICAST;
862 : }
863 : }
864 : }
865 : }
866 :
867 131792 : return f_private_network_defined;
868 : }
869 :
870 :
871 : /** \brief Get the network type string
872 : *
873 : * Translate the network type into a string, which can be really useful
874 : * to log that information.
875 : *
876 : * Note that PUBLIC is the same as UNKNOWN, this function returns
877 : * "Unknown" in that case, though.
878 : *
879 : * \return The string representing the type of network.
880 : */
881 159 : std::string addr::get_network_type_string() const
882 : {
883 159 : std::string name;
884 159 : switch( get_network_type() )
885 : {
886 : case addr::network_type_t::NETWORK_TYPE_UNDEFINED : name = "Undefined"; break; // LCOV_EXCL_LINE -- get_network_type() defines it...
887 40 : case addr::network_type_t::NETWORK_TYPE_PRIVATE : name = "Private"; break;
888 10 : case addr::network_type_t::NETWORK_TYPE_CARRIER : name = "Carrier"; break;
889 30 : case addr::network_type_t::NETWORK_TYPE_LINK_LOCAL : name = "Local Link"; break;
890 20 : case addr::network_type_t::NETWORK_TYPE_MULTICAST : name = "Multicast"; break;
891 40 : case addr::network_type_t::NETWORK_TYPE_LOOPBACK : name = "Loopback"; break;
892 3 : case addr::network_type_t::NETWORK_TYPE_ANY : name = "Any"; break;
893 16 : case addr::network_type_t::NETWORK_TYPE_UNKNOWN : name = "Unknown"; break; // == NETWORK_TYPE_PUBLIC
894 : }
895 159 : return name;
896 : }
897 :
898 :
899 : /** \brief Create a socket from the IP address held by this addr object.
900 : *
901 : * This function creates a socket that corresponds to the addr object
902 : * definitions, it takes the protocol and family information in account.
903 : *
904 : * The flags can be used to add one or more of the following flags:
905 : *
906 : * \li SOCKET_FLAG_NONBLOCK -- create socket as non-block
907 : * \li SOCKET_FLAG_CLOEXEC -- close socket on an execv()
908 : * \li SOCKET_FLAG_REUSE -- for TCP socket, mark the address as immediately
909 : * reusable, ignored for UDP; only useful for server (bind + listen after
910 : * this call)
911 : *
912 : * \note
913 : * The IP protocol is viewed as TCP in this function.
914 : *
915 : * \warning
916 : * This class does not hold the socket created by this function.
917 : *
918 : * \param[in] flags A set of socket flags to use when creating the socket.
919 : * \param[in] reuse_address Set the reuse address flag.
920 : *
921 : * \return The socket file descriptor or -1 on errors.
922 : */
923 6 : int addr::create_socket(socket_flag_t flags) const
924 : {
925 6 : int const sock_flags(
926 6 : ((flags & SOCKET_FLAG_CLOEXEC) != 0 ? SOCK_CLOEXEC : 0)
927 6 : | ((flags & SOCKET_FLAG_NONBLOCK) != 0 ? SOCK_NONBLOCK : 0));
928 6 : int const family(is_ipv4() ? AF_INET : AF_INET6);
929 :
930 6 : switch(f_protocol)
931 : {
932 4 : case IPPROTO_IP: // interpret as TCP...
933 : case IPPROTO_TCP:
934 : {
935 4 : int s(socket(family, SOCK_STREAM | sock_flags, IPPROTO_TCP));
936 :
937 4 : if(s >= 0
938 4 : && (flags & SOCKET_FLAG_REUSE) != 0)
939 : {
940 : // set the "reuse that address immediately" flag, we totally
941 : // ignore errors on that one
942 : //
943 2 : int optval(1);
944 2 : socklen_t const optlen(sizeof(optval));
945 2 : static_cast<void>(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, optlen));
946 : }
947 4 : return s;
948 : }
949 :
950 2 : case IPPROTO_UDP:
951 2 : return socket(family, SOCK_DGRAM | sock_flags, IPPROTO_UDP);
952 :
953 : default: // LCOV_EXCL_LINE
954 : // this should never happen since we control the f_protocol field
955 : //
956 : return -1; // LCOV_EXCL_LINE
957 :
958 : }
959 : }
960 :
961 :
962 : /** \brief Connect the specified socket to this IP address.
963 : *
964 : * When you create a TCP client, you can connect to a server. This
965 : * is done by using the connect() function which makes use of the
966 : * address to connect to the server.
967 : *
968 : * This function makes sure to select the correct connect() function
969 : * depending on whether this IP address is an IPv4 or an IPv6 address
970 : * (although we could always try with the IPv6 structure, it may or
971 : * may not work properly on all systems, so for now we use the
972 : * distinction.)
973 : *
974 : * \param[in] s The socket to connect to the address.
975 : *
976 : * \return 0 if the bind() succeeded, -1 on errors
977 : */
978 4 : int addr::connect(int s) const
979 : {
980 : // only TCP can connect, UDP binds and sends only
981 : //
982 4 : switch(f_protocol)
983 : {
984 2 : case IPPROTO_IP: // interpret as TCP...
985 : case IPPROTO_TCP:
986 2 : if(is_ipv4())
987 : {
988 : // this would most certainly work using the IPv6 address
989 : // as in the else part, but to be sure, we use the IPv4
990 : // as specified in the address (there could be other reasons
991 : // than just your OS for this to fail if using IPv6.)
992 : //
993 : // IMPORTANT NOTE: also the family is used in the socket()
994 : // call above and must match the address here...
995 : //
996 : sockaddr_in ipv4;
997 1 : get_ipv4(ipv4);
998 1 : return ::connect(s, reinterpret_cast<sockaddr const *>(&ipv4), sizeof(ipv4));
999 : }
1000 : else
1001 : {
1002 1 : return ::connect(s, reinterpret_cast<sockaddr const *>(&f_address), sizeof(sockaddr_in6));
1003 : }
1004 : break;
1005 :
1006 : }
1007 :
1008 2 : return -1;
1009 : }
1010 :
1011 :
1012 : /** \brief Create a server with this socket listening on this IP address.
1013 : *
1014 : * This function will bind the socket \p s to the address defined in
1015 : * this addr object. This creates a server listening on that IP address.
1016 : *
1017 : * If the IP address is 127.0.0.1, then only local processes can connect
1018 : * to that server. If the IP address is 0.0.0.0, then anyone can connect
1019 : * to the server.
1020 : *
1021 : * This function works for TCP and UDP servers.
1022 : *
1023 : * If the IP address represents an IPv4 addressm then the bind() is done
1024 : * with an IPv4 address and not the IPv6 as it is stored.
1025 : *
1026 : * \param[in] s The socket to bind to this address.
1027 : *
1028 : * \return 0 if the bind() succeeded, -1 on errors
1029 : */
1030 2 : int addr::bind(int s) const
1031 : {
1032 2 : if(is_ipv4())
1033 : {
1034 : sockaddr_in ipv4;
1035 1 : get_ipv4(ipv4);
1036 1 : return ::bind(s, reinterpret_cast<sockaddr const *>(&ipv4), sizeof(ipv4));
1037 : }
1038 : else
1039 : {
1040 1 : return ::bind(s, reinterpret_cast<sockaddr const *>(&f_address), sizeof(sockaddr_in6));
1041 : }
1042 : }
1043 :
1044 :
1045 : /** \brief Initializes this addr object from a socket information.
1046 : *
1047 : * When you connect to a server or a clients connect to your server, the
1048 : * socket defines two IP addresses and ports: one on your side and one on
1049 : * the other side.
1050 : *
1051 : * The other side is called the _peer name_.
1052 : *
1053 : * You side is called the _socket name_ (i.e. the IP address of your computer,
1054 : * representing the interface used to perform that connection.)
1055 : *
1056 : * If you call this function with \p peer set to false then you get the
1057 : * address and port from your side. If you set \p peer to true,
1058 : * you get the other side address and port details.
1059 : *
1060 : * \todo
1061 : * Move this to our eventdispatcher once we create that separate library.
1062 : * Probably within a form of low level socket class.
1063 : *
1064 : * \param[in] s The socket from which you want to retrieve peer information.
1065 : * \param[in] peer Whether to retrieve the peer or socket name.
1066 : */
1067 14 : void addr::set_from_socket(int s, bool peer)
1068 : {
1069 : // make sure the socket is defined and well
1070 : //
1071 14 : if(s < 0)
1072 : {
1073 2 : throw addr_invalid_argument("addr::set_from_socket(): the socket cannot be a negative number.");
1074 : }
1075 :
1076 12 : sockaddr_storage address = sockaddr_storage();
1077 12 : socklen_t length(sizeof(address));
1078 : int r;
1079 12 : if(peer)
1080 : {
1081 : // this retrieves the information from the other side
1082 : //
1083 6 : r = getpeername(s, reinterpret_cast<sockaddr *>(&address), &length);
1084 : }
1085 : else
1086 : {
1087 : // retrieve the local socket information
1088 : //
1089 6 : r = getsockname(s, reinterpret_cast<sockaddr *>(&address), &length);
1090 : }
1091 12 : if(r != 0)
1092 : {
1093 5 : int const e(errno);
1094 : throw addr_io_error(
1095 10 : std::string("addr::set_from_socket(): ")
1096 15 : + (peer ? "getpeername()" : "getsockname()")
1097 10 : + " failed to retrieve IP address details (errno: "
1098 20 : + std::to_string(e)
1099 10 : + ", "
1100 15 : + strerror(e)
1101 15 : + ").");
1102 : }
1103 :
1104 7 : switch(address.ss_family)
1105 : {
1106 3 : case AF_INET:
1107 3 : set_ipv4(reinterpret_cast<sockaddr_in &>(address));
1108 3 : break;
1109 :
1110 3 : case AF_INET6:
1111 3 : set_ipv6(reinterpret_cast<sockaddr_in6 &>(address));
1112 3 : break;
1113 :
1114 1 : default:
1115 : throw addr_invalid_state(
1116 2 : std::string("addr::set_from_socket(): ")
1117 3 : + (peer ? "getpeername()" : "getsockname()")
1118 3 : + " returned a type of address, which is not understood, i.e. not AF_INET or AF_INET6.");
1119 :
1120 : }
1121 6 : }
1122 :
1123 :
1124 : /** \brief Transform the IP into a domain name.
1125 : *
1126 : * This function transforms the IP address in this `addr` object in a
1127 : * name such as "snap.website".
1128 : *
1129 : * \note
1130 : * The function does not cache the result because it is rarely used (at least
1131 : * at this time). So you should cache the result and avoid calling this
1132 : * function more than once as the process can be very slow.
1133 : *
1134 : * \todo
1135 : * Speed enhancement can be achieved by using getaddrinfo_a(). That would
1136 : * work with a vector of addr objects.
1137 : *
1138 : * \return The domain name. If not available, an empty string.
1139 : */
1140 7 : std::string addr::get_name() const
1141 : {
1142 : char host[NI_MAXHOST];
1143 :
1144 7 : int flags(NI_NAMEREQD);
1145 7 : if(f_protocol == IPPROTO_UDP)
1146 : {
1147 4 : flags |= NI_DGRAM;
1148 : }
1149 :
1150 : // TODO: test with the NI_IDN* flags and make sure we know what we get
1151 : // (i.e. we want UTF-8 as a result)
1152 : //
1153 7 : int const r(getnameinfo(reinterpret_cast<sockaddr const *>(&f_address), sizeof(f_address), host, sizeof(host), nullptr, 0, flags));
1154 :
1155 : // return value is 0, then it worked
1156 : //
1157 7 : return r == 0 ? host : std::string();
1158 : }
1159 :
1160 :
1161 : /** \brief Transform the port into a service name.
1162 : *
1163 : * This function transforms the port in this `addr` object in a
1164 : * name such as "http".
1165 : *
1166 : * \note
1167 : * The function does not cache the result because it is rarely used (at least
1168 : * at this time). So you should cache the result and avoid calling this
1169 : * function more than once as the process is somewhat slow.
1170 : *
1171 : * \warning
1172 : * The getnameinfo() will return a string with a number if it does not
1173 : * know the server (i.e. this is the equivalent to std::to_string() of
1174 : * the port.) For port 0, the function always returns an empty string.
1175 : *
1176 : * \return The service name. If not available, an empty string.
1177 : */
1178 5 : std::string addr::get_service() const
1179 : {
1180 5 : if(f_address.sin6_port == 0)
1181 : {
1182 1 : return std::string();
1183 : }
1184 :
1185 : char service[NI_MAXSERV];
1186 :
1187 4 : int flags(NI_NAMEREQD);
1188 4 : if(f_protocol == IPPROTO_UDP)
1189 : {
1190 2 : flags |= NI_DGRAM;
1191 : }
1192 : int const r(getnameinfo(
1193 4 : reinterpret_cast<sockaddr const *>(&f_address)
1194 : , sizeof(f_address)
1195 : , nullptr
1196 : , 0
1197 : , service
1198 : , sizeof(service)
1199 4 : , flags));
1200 :
1201 : // return value is 0, then it worked
1202 : //
1203 : return r == 0 ? service
1204 4 : : std::string();
1205 : }
1206 :
1207 :
1208 : /** \brief Retrieve the port.
1209 : *
1210 : * This function retrieves the port of the IP address in host order.
1211 : *
1212 : * \return The port defined along this address.
1213 : */
1214 197592 : int addr::get_port() const
1215 : {
1216 197592 : return ntohs(f_address.sin6_port);
1217 : }
1218 :
1219 :
1220 : /** \brief Retrieve the protocol.
1221 : *
1222 : * This function retrieves the protocol as specified on the
1223 : * set_addr_port() function or corresponding constructor.
1224 : *
1225 : * You may change the protocol with the set_protocol() function.
1226 : *
1227 : * \return protocol such as IPPROTO_TCP or IPPROTO_UDP.
1228 : */
1229 132072 : int addr::get_protocol() const
1230 : {
1231 132072 : return f_protocol;
1232 : }
1233 :
1234 :
1235 : /** \brief Check whether an IP matches a CIDR.
1236 : *
1237 : * When an IP address is defined along a mask, it can match a set of
1238 : * other IP addresses. This function can be used to see whether
1239 : * \p ip matches \p this IP address and mask.
1240 : *
1241 : * So in other words, the mask of `this` addr object is used to mask
1242 : * both, `this` and `p` before comparing the masked result.
1243 : *
1244 : * \warning
1245 : * This function only checks the IP address. It totally ignores the
1246 : * port, family, protocol and other peripheral details.
1247 : *
1248 : * \param[in] ip The address to match against this IP/mask CIDR.
1249 : *
1250 : * \return true if \p ip is a match.
1251 : */
1252 266 : bool addr::match(addr const & ip) const
1253 : {
1254 2838 : for(int idx(0); idx < 16; ++idx)
1255 : {
1256 2824 : if((f_address.sin6_addr.s6_addr[idx] & f_mask[idx]) != (ip.f_address.sin6_addr.s6_addr[idx] & f_mask[idx]))
1257 : {
1258 252 : return false;
1259 : }
1260 : }
1261 :
1262 14 : return true;
1263 : }
1264 :
1265 :
1266 : /** \brief Check whether two addresses are equal.
1267 : *
1268 : * This function compares the left hand side (this) and the right
1269 : * hand side (rhs) for equality. If both represent the same IP
1270 : * address, then the function returns true.
1271 : *
1272 : * \warning
1273 : * The function only compares the address itself. The family, port,
1274 : * flow info, scope identifier, protocol are all ignored.
1275 : *
1276 : * \return true if \p this is equal to \p rhs.
1277 : */
1278 35 : bool addr::operator == (addr const & rhs) const
1279 : {
1280 35 : return f_address.sin6_addr == rhs.f_address.sin6_addr;
1281 : }
1282 :
1283 :
1284 : /** \brief Check whether two addresses are not equal.
1285 : *
1286 : * This function compares the left hand side (this) and the right
1287 : * hand side (rhs) for inequality. If both represent the same IP
1288 : * address, then the function returns false.
1289 : *
1290 : * \warning
1291 : * The function only compares the address itself. The family, port,
1292 : * flow info, scope identifier, protocol are all ignored.
1293 : *
1294 : * \return true if \p this is not equal to \p rhs.
1295 : */
1296 9 : bool addr::operator != (addr const & rhs) const
1297 : {
1298 9 : return f_address.sin6_addr != rhs.f_address.sin6_addr;
1299 : }
1300 :
1301 :
1302 : /** \brief Compare two addresses to know which one is smaller.
1303 : *
1304 : * This function compares the left hand side (this) and the right
1305 : * hand side (rhs) to know which one is the smallest. If both
1306 : * are equal or the left hand side is larger than the right hand
1307 : * side, then it returns false, otherwise it returns true.
1308 : *
1309 : * \warning
1310 : * The function only compares the address itself. The family, port,
1311 : * flow info, scope identifier, protocol are all ignored.
1312 : *
1313 : * \return true if \p this is smaller than \p rhs.
1314 : */
1315 7 : bool addr::operator < (addr const & rhs) const
1316 : {
1317 7 : return f_address.sin6_addr < rhs.f_address.sin6_addr;
1318 : }
1319 :
1320 :
1321 : /** \brief Compare two addresses to know which one is smaller or equal.
1322 : *
1323 : * This function compares the left hand side (this) and the right
1324 : * hand side (rhs) to know whether the left hand side is smaller or
1325 : * equal to thr right handside.
1326 : *
1327 : * \warning
1328 : * The function only compares the address itself. The family, port,
1329 : * flow info, scope identifier, protocol are all ignored.
1330 : *
1331 : * \return true if \p this is smaller than \p rhs.
1332 : */
1333 685 : bool addr::operator <= (addr const & rhs) const
1334 : {
1335 685 : return f_address.sin6_addr <= rhs.f_address.sin6_addr;
1336 : }
1337 :
1338 :
1339 : /** \brief Compare two addresses to know which one is smaller.
1340 : *
1341 : * This function compares the left hand side (this) and the right
1342 : * hand side (rhs) to know which one is the smallest. If both
1343 : * are equal or the left hand side is larger than the right hand
1344 : * side, then it returns false, otherwise it returns true.
1345 : *
1346 : * \warning
1347 : * The function only compares the address itself. The family, port,
1348 : * flow info, scope identifier, protocol are all ignored.
1349 : *
1350 : * \return true if \p this is smaller than \p rhs.
1351 : */
1352 27 : bool addr::operator > (addr const & rhs) const
1353 : {
1354 27 : return f_address.sin6_addr > rhs.f_address.sin6_addr;
1355 : }
1356 :
1357 :
1358 : /** \brief Compare two addresses to know which one is smaller.
1359 : *
1360 : * This function compares the left hand side (this) and the right
1361 : * hand side (rhs) to know which one is the smallest. If both
1362 : * are equal or the left hand side is larger than the right hand
1363 : * side, then it returns false, otherwise it returns true.
1364 : *
1365 : * \warning
1366 : * The function only compares the address itself. The family, port,
1367 : * flow info, scope identifier, protocol are all ignored.
1368 : *
1369 : * \return true if \p this is smaller than \p rhs.
1370 : */
1371 290 : bool addr::operator >= (addr const & rhs) const
1372 : {
1373 290 : return f_address.sin6_addr >= rhs.f_address.sin6_addr;
1374 : }
1375 :
1376 :
1377 : /** \brief Mark that the address changed.
1378 : *
1379 : * This functions makes sure that some of the parameters being cached
1380 : * get reset in such a way that checking the cache will again return
1381 : * the correct answer.
1382 : *
1383 : * \sa get_network_type()
1384 : */
1385 133114 : void addr::address_changed()
1386 : {
1387 133114 : f_private_network_defined = network_type_t::NETWORK_TYPE_UNDEFINED;
1388 133114 : }
1389 :
1390 :
1391 :
1392 :
1393 6 : }
1394 : // namespace addr
1395 : // vim: ts=4 sw=4 et
|