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