Line data Source code
1 : // Network Address -- classes functions to ease handling IP addresses
2 : // Copyright (c) 2012-2018 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_exceptions.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 264875 : addr::addr()
251 : {
252 : // keep default protocol (TCP)
253 264875 : }
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 65912 : addr::addr(struct sockaddr_in const & in)
264 : {
265 65912 : set_ipv4(in);
266 : // keep default protocol (TCP)
267 65887 : }
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 66597 : void addr::set_ipv4(struct sockaddr_in const & in)
295 : {
296 66597 : 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_exception("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 66547 : 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 anwway stack needs to support IPv4
311 : // in order to use that IP...
312 : //
313 66547 : f_address.sin6_family = AF_INET6;
314 66547 : f_address.sin6_port = in.sin_port;
315 66547 : f_address.sin6_addr.s6_addr16[5] = 0xFFFF;
316 66547 : f_address.sin6_addr.s6_addr32[3] = in.sin_addr.s_addr;
317 :
318 66547 : address_changed();
319 66547 : }
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_exception("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_exception("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_exception(
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_exception(
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 567 : void addr::set_mask(uint8_t const * mask)
438 : {
439 567 : memcpy(f_mask, mask, sizeof(f_mask));
440 567 : }
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)
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 14 : bool addr::is_default() const
489 : {
490 14 : return f_address.sin6_addr.s6_addr32[0] == 0
491 14 : && f_address.sin6_addr.s6_addr32[1] == 0
492 14 : && f_address.sin6_addr.s6_addr32[2] == 0
493 28 : && f_address.sin6_addr.s6_addr32[3] == 0;
494 : }
495 :
496 :
497 : /** \brief Check whether this address represents an IPv4 address.
498 : *
499 : * The IPv6 format supports embedding IPv4 addresses. This function
500 : * returns true if the embedded address is an IPv4. When this function
501 : * returns true, the get_ipv4() can be called. Otherwise, the get_ipv4()
502 : * function throws an exception.
503 : *
504 : * \return true if this address represents an IPv4 address.
505 : */
506 527603 : bool addr::is_ipv4() const
507 : {
508 527603 : return f_address.sin6_addr.s6_addr32[0] == 0
509 329879 : && f_address.sin6_addr.s6_addr32[1] == 0
510 329875 : && f_address.sin6_addr.s6_addr16[4] == 0
511 857476 : && f_address.sin6_addr.s6_addr16[5] == 0xFFFF;
512 : }
513 :
514 :
515 : /** \brief Retreive the IPv4 address.
516 : *
517 : * This function can be used to retrieve the IPv4 address of this addr
518 : * object. If the address is not an IPv4, then the function throws.
519 : *
520 : * \exception addr_invalid_structure_exception
521 : * This exception is raised if the address is not an IPv4 address.
522 : *
523 : * \param[out] in The structure where the IPv4 Internet address gets saved.
524 : */
525 35 : void addr::get_ipv4(struct sockaddr_in & in) const
526 : {
527 35 : if(is_ipv4())
528 : {
529 : // this is an IPv4 mapped in an IPv6, "unmap" that IP
530 : //
531 34 : memset(&in, 0, sizeof(in));
532 34 : in.sin_family = AF_INET;
533 34 : in.sin_port = f_address.sin6_port;
534 34 : in.sin_addr.s_addr = f_address.sin6_addr.s6_addr32[3];
535 68 : return;
536 : }
537 :
538 1 : throw addr_invalid_state_exception("Not an IPv4 compatible address.");
539 : }
540 :
541 :
542 : /** \brief Save the specified IPv6 address in this addr object.
543 : *
544 : * This function saves the specified IPv6 address in this addr object.
545 : * The function does not check the validity of the address. It is
546 : * expected to be valid.
547 : *
548 : * The address may be an embedded IPv4 address.
549 : *
550 : * \param[in] in6 The source IPv6 to save in the addr object.
551 : */
552 66169 : void addr::set_ipv6(struct sockaddr_in6 const & in6)
553 : {
554 66169 : if(in6.sin6_family != AF_INET6)
555 : {
556 2 : throw addr_invalid_argument_exception("addr::set_ipv6(): the input address does not represent an IPv6 address (family is not AF_INET6).");
557 : }
558 66167 : memcpy(&f_address, &in6, sizeof(in6));
559 :
560 66167 : address_changed();
561 66167 : }
562 :
563 :
564 : /** \brief Retrieve a copy of this addr IP address.
565 : *
566 : * This function returns the current IP address saved in this
567 : * addr object. The IP may represent an IPv4 address in which
568 : * case the is_ipv4() returns true.
569 : *
570 : * \param[out] in6 The structure where the address gets saved.
571 : */
572 21 : void addr::get_ipv6(struct sockaddr_in6 & in6) const
573 : {
574 21 : memcpy(&in6, &f_address, sizeof(in6));
575 21 : }
576 :
577 :
578 : /** \brief Retrive the IPv4 as a string.
579 : *
580 : * This function returns a string representing the IP address
581 : * defined in this addr object.
582 : *
583 : * The \p mode parameter defines what gets output.
584 : *
585 : * \li ip_string_t::IP_STRING_ONLY -- only the IP address
586 : * \li ip_string_t::IP_STRING_PORT -- the IP and port
587 : * \li ip_string_t::IP_STRING_MASK -- the IP and mask
588 : * \li ip_string_t::IP_STRING_ALL -- the IP, port, and mask
589 : *
590 : * The ip_string_t::IP_STRING_BRACKET is viewed as
591 : * ip_string_t::IP_STRING_ONLY.
592 : *
593 : * The ip_string_t::IP_STRING_BRACKET_MASK is viewed as
594 : * ip_string_t::IP_STRING_MASK.
595 : *
596 : * \exception addr_invalid_state_exception
597 : * If the addr object does not currently represent an IPv4 then
598 : * this exception is raised.
599 : *
600 : * \param[in] mode How the output string is to be built.
601 : */
602 131703 : std::string addr::to_ipv4_string(string_ip_t mode) const
603 : {
604 131703 : if(is_ipv4())
605 : {
606 : // this is an IPv4 mapped in an IPv6, "unmap" that IP
607 : // so the inet_ntop() can correctly generate an output IP
608 : //
609 : struct in_addr in;
610 131697 : memset(&in, 0, sizeof(in));
611 131697 : in.s_addr = f_address.sin6_addr.s6_addr32[3];
612 : char buf[INET_ADDRSTRLEN + 1];
613 131697 : if(inet_ntop(AF_INET, &in, buf, sizeof(buf)) != nullptr)
614 : {
615 131697 : if(mode != string_ip_t::STRING_IP_ONLY)
616 : {
617 1152 : std::stringstream result;
618 576 : result << buf;
619 576 : if(mode == string_ip_t::STRING_IP_PORT
620 266 : || mode == string_ip_t::STRING_IP_ALL)
621 : {
622 546 : result << ":";
623 546 : result << ntohs(f_address.sin6_port);
624 : }
625 576 : if(mode == string_ip_t::STRING_IP_MASK
626 566 : || mode == string_ip_t::STRING_IP_BRACKETS_MASK
627 556 : || mode == string_ip_t::STRING_IP_ALL)
628 : {
629 256 : memset(&in, 0, sizeof(in));
630 256 : in.s_addr = htonl((f_mask[12] << 24) | (f_mask[13] << 16) | (f_mask[14] << 8) | f_mask[15]);
631 256 : if(inet_ntop(AF_INET, &in, buf, sizeof(buf)) != nullptr)
632 : {
633 256 : result << "/";
634 256 : result << buf; // TODO: convert to simple number if possible
635 : }
636 : }
637 576 : return result.str();
638 : }
639 131121 : return std::string(buf);
640 : }
641 : // IPv4 should never fail converting the address unless the
642 : // buffer was too small...
643 : }
644 :
645 6 : throw addr_invalid_state_exception("Not an IPv4 compatible address.");
646 : }
647 :
648 :
649 : /** \brief Convert the addr object to a string.
650 : *
651 : * This function converts the addr object to a canonicalized string.
652 : * This can be used to compare two IPv6 together as strings, although
653 : * it is probably better to compare them using the < and == operators.
654 : *
655 : * By default the function returns with the IPv6 address defined
656 : * between square bracket, so the output of this function can be
657 : * used as the input of the set_addr_port() function. You may
658 : * also request the address without the brackets.
659 : *
660 : * \exception addr_invalid_state_exception
661 : * If the binary IP address cannot be converted to ASCII, this exception
662 : * is raised.
663 : *
664 : * \param[in] mode How the output string is to be built.
665 : *
666 : * \return The addr object converted to an IPv6 address.
667 : */
668 263054 : std::string addr::to_ipv6_string(string_ip_t mode) const
669 : {
670 : char buf[INET6_ADDRSTRLEN + 1];
671 263054 : if(inet_ntop(AF_INET6, &f_address.sin6_addr, buf, sizeof(buf)) != nullptr)
672 : {
673 : bool const include_brackets(mode == string_ip_t::STRING_IP_BRACKETS
674 197502 : || mode == string_ip_t::STRING_IP_BRACKETS_MASK
675 197490 : || mode == string_ip_t::STRING_IP_PORT // port requires us to add brackets
676 329260 : || mode == string_ip_t::STRING_IP_ALL);
677 :
678 526108 : std::stringstream result;
679 :
680 : // always insert the IP, even if ANY or "BROADCAST"
681 : //
682 263054 : if(include_brackets)
683 : {
684 197476 : result << "[";
685 : }
686 263054 : result << buf;
687 263054 : if(include_brackets)
688 : {
689 197476 : result << "]";
690 : }
691 :
692 : // got a port?
693 : //
694 263054 : if(mode == string_ip_t::STRING_IP_PORT
695 131770 : || mode == string_ip_t::STRING_IP_ALL)
696 : {
697 131912 : result << ":";
698 131912 : result << ntohs(f_address.sin6_port);
699 : }
700 :
701 : // got a mask?
702 : //
703 263054 : if(mode == string_ip_t::STRING_IP_MASK
704 263042 : || mode == string_ip_t::STRING_IP_BRACKETS_MASK
705 263030 : || mode == string_ip_t::STRING_IP_ALL)
706 : {
707 652 : if(inet_ntop(AF_INET6, f_mask, buf, sizeof(buf)) != nullptr)
708 : {
709 652 : result << "/";
710 652 : if(include_brackets)
711 : {
712 640 : result << "[";
713 : }
714 652 : result << buf; // TODO: convert to simple number if possible
715 652 : if(include_brackets)
716 : {
717 640 : result << "]";
718 : }
719 : }
720 : }
721 :
722 526108 : return result.str();
723 : }
724 :
725 : throw addr_invalid_state_exception("The address from this addr could not be converted to a valid canonicalized IPv6 address."); // LCOV_EXCL_LINE
726 : }
727 :
728 :
729 : /** \brief Return the address as IPv4 or IPv6.
730 : *
731 : * Depending on whether the address represents an IPv4 or an IPv6,
732 : * this function returns the corresponding address. Since the format
733 : * of both types of addresses can always be distinguished, it poses
734 : * no concerns.
735 : *
736 : * \exception
737 : * If include_brackets is false and include_port is true, this
738 : * exception is raised because we cannot furfill the request.
739 : *
740 : * \param[in] mode How the output string is to be built.
741 : *
742 : * \return The addr object converted to an IPv4 or an IPv6 address.
743 : */
744 131774 : std::string addr::to_ipv4or6_string(string_ip_t mode) const
745 : {
746 131774 : return is_ipv4() ? to_ipv4_string(mode)
747 131774 : : to_ipv6_string(mode);
748 : }
749 :
750 :
751 : /** \brief Determine the type of network this IP represents.
752 : *
753 : * The IP address may represent various type of networks. This
754 : * function returns that type.
755 : *
756 : * The function checks the address either as IPv4 when is_ipv4()
757 : * returns true, otherwise as IPv6.
758 : *
759 : * See:
760 : *
761 : * \li https://en.wikipedia.org/wiki/Reserved_IP_addresses
762 : * \li https://tools.ietf.org/html/rfc3330
763 : * \li https://tools.ietf.org/html/rfc5735 (IPv4)
764 : * \li https://tools.ietf.org/html/rfc5156 (IPv6)
765 : *
766 : * \return One of the possible network types as defined in the
767 : * network_type_t enumeration.
768 : */
769 131783 : addr::network_type_t addr::get_network_type() const
770 : {
771 131783 : if(f_private_network_defined == network_type_t::NETWORK_TYPE_UNDEFINED)
772 : {
773 131624 : f_private_network_defined = network_type_t::NETWORK_TYPE_UNKNOWN;
774 :
775 131624 : if(is_ipv4())
776 : {
777 : // get the address in host order
778 : //
779 : // we can use a simple mask + compare to know whether it is
780 : // this or that once in host order
781 : //
782 65892 : uint32_t const host_ip(ntohl(f_address.sin6_addr.s6_addr32[3]));
783 :
784 65892 : if((host_ip & 0xFF000000) == 0x0A000000 // 10.0.0.0/8
785 65878 : || (host_ip & 0xFFF00000) == 0xAC100000 // 172.16.0.0/12
786 65758 : || (host_ip & 0xFFFF0000) == 0xC0A80000) // 192.168.0.0/16
787 : {
788 65686 : f_private_network_defined = network_type_t::NETWORK_TYPE_PRIVATE;
789 : }
790 206 : else if((host_ip & 0xFFC00000) == 0x64400000) // 100.64.0.0/10
791 : {
792 10 : f_private_network_defined = network_type_t::NETWORK_TYPE_CARRIER;
793 : }
794 196 : else if((host_ip & 0xFFFF0000) == 0xA9FE0000) // 169.254.0.0/16
795 : {
796 10 : f_private_network_defined = network_type_t::NETWORK_TYPE_LINK_LOCAL; // i.e. DHCP
797 : }
798 186 : else if((host_ip & 0xF0000000) == 0xE0000000) // 224.0.0.0/4
799 : {
800 : // there are many sub-groups on this one which are probably
801 : // still in use...
802 : //
803 10 : f_private_network_defined = network_type_t::NETWORK_TYPE_MULTICAST;
804 : }
805 176 : else if((host_ip & 0xFF000000) == 0x7F000000) // 127.0.0.0/8
806 : {
807 14 : f_private_network_defined = network_type_t::NETWORK_TYPE_LOOPBACK; // i.e. localhost
808 : }
809 162 : else if(host_ip == 0x00000000)
810 : {
811 1 : f_private_network_defined = network_type_t::NETWORK_TYPE_ANY; // i.e. 0.0.0.0
812 : }
813 : }
814 : else //if(is_ipv6()) -- if not IPv4, we have an IPv6
815 : {
816 : // for IPv6 it was simplified by using a prefix for
817 : // all types; really way easier than IPv4
818 : //
819 65732 : if(f_address.sin6_addr.s6_addr32[0] == 0 // ::
820 35 : && f_address.sin6_addr.s6_addr32[1] == 0
821 31 : && f_address.sin6_addr.s6_addr32[2] == 0
822 27 : && f_address.sin6_addr.s6_addr32[3] == 0)
823 : {
824 : // this is the "any" IP address
825 2 : f_private_network_defined = network_type_t::NETWORK_TYPE_ANY;
826 : }
827 : else
828 : {
829 65730 : uint16_t const prefix(ntohs(f_address.sin6_addr.s6_addr16[0]));
830 :
831 65730 : if((prefix & 0xFF00) == 0xFD00) // fd00::/8
832 : {
833 10 : f_private_network_defined = network_type_t::NETWORK_TYPE_PRIVATE;
834 : }
835 65720 : else if((prefix & 0xFFC0) == 0xFE80 // fe80::/10
836 65707 : || (prefix & 0xFF0F) == 0xFF02) // ffx2::/16
837 : {
838 123 : f_private_network_defined = network_type_t::NETWORK_TYPE_LINK_LOCAL; // i.e. DHCP
839 : }
840 65597 : else if((prefix & 0xFF0F) == 0xFF01 // ffx1::/16
841 51 : || (f_address.sin6_addr.s6_addr32[0] == 0 // ::1
842 33 : && f_address.sin6_addr.s6_addr32[1] == 0
843 29 : && f_address.sin6_addr.s6_addr32[2] == 0
844 25 : && f_address.sin6_addr.s6_addr16[6] == 0
845 23 : && f_address.sin6_addr.s6_addr16[7] == htons(1)))
846 : {
847 65567 : f_private_network_defined = network_type_t::NETWORK_TYPE_LOOPBACK;
848 : }
849 30 : else if((prefix & 0xFF00) == 0xFF00) // ff00::/8
850 : {
851 : // this one must be after the link-local and loopback networks
852 10 : f_private_network_defined = network_type_t::NETWORK_TYPE_MULTICAST;
853 : }
854 : }
855 : }
856 : }
857 :
858 131783 : return f_private_network_defined;
859 : }
860 :
861 :
862 : /** \brief Get the network type string
863 : *
864 : * Translate the network type into a string, which can be really useful
865 : * to log that information.
866 : *
867 : * Note that PUBLIC is the same as UNKNOWN, this function returns
868 : * "Unknown" in that case, though.
869 : *
870 : * \return The string representing the type of network.
871 : */
872 159 : std::string addr::get_network_type_string() const
873 : {
874 159 : std::string name;
875 159 : switch( get_network_type() )
876 : {
877 : case addr::network_type_t::NETWORK_TYPE_UNDEFINED : name = "Undefined"; break; // LCOV_EXCL_LINE -- get_network_type() defines it...
878 40 : case addr::network_type_t::NETWORK_TYPE_PRIVATE : name = "Private"; break;
879 10 : case addr::network_type_t::NETWORK_TYPE_CARRIER : name = "Carrier"; break;
880 30 : case addr::network_type_t::NETWORK_TYPE_LINK_LOCAL : name = "Local Link"; break;
881 20 : case addr::network_type_t::NETWORK_TYPE_MULTICAST : name = "Multicast"; break;
882 40 : case addr::network_type_t::NETWORK_TYPE_LOOPBACK : name = "Loopback"; break;
883 3 : case addr::network_type_t::NETWORK_TYPE_ANY : name = "Any"; break;
884 16 : case addr::network_type_t::NETWORK_TYPE_UNKNOWN : name = "Unknown"; break; // == NETWORK_TYPE_PUBLIC
885 : }
886 159 : return name;
887 : }
888 :
889 :
890 : /** \brief Create a socket from the IP address held by this addr object.
891 : *
892 : * This function creates a socket that corresponds to the addr object
893 : * definitions, it takes the protocol and family information in account.
894 : *
895 : * The flags can be used to add one or more of the following flags:
896 : *
897 : * \li SOCKET_FLAG_NONBLOCK -- create socket as non-block
898 : * \li SOCKET_FLAG_CLOEXEC -- close socket on an execv()
899 : * \li SOCKET_FLAG_REUSE -- for TCP socket, mark the address as immediately
900 : * reusable, ignored for UDP; only useful for server (bind + listen after
901 : * this call)
902 : *
903 : * \note
904 : * The IP protocol is viewed as TCP in this function.
905 : *
906 : * \warning
907 : * This class does not hold the socket created by this function.
908 : *
909 : * \todo
910 : * Move this to our libsnapnetwork once we create that separate library.
911 : * Probably within a form of low level socket class.
912 : *
913 : * \param[in] flags A set of socket flags to use when creating the socket.
914 : * \param[in] reuse_address Set the reuse address flag.
915 : *
916 : * \return The socket file descriptor or -1 on errors.
917 : */
918 6 : int addr::create_socket(socket_flag_t flags) const
919 : {
920 : int const sock_flags(
921 6 : ((flags & SOCKET_FLAG_CLOEXEC) != 0 ? SOCK_CLOEXEC : 0)
922 6 : | ((flags & SOCKET_FLAG_NONBLOCK) != 0 ? SOCK_NONBLOCK : 0));
923 6 : int const family(is_ipv4() ? AF_INET : AF_INET6);
924 :
925 6 : switch(f_protocol)
926 : {
927 : case IPPROTO_IP: // interpret as TCP...
928 : case IPPROTO_TCP:
929 : {
930 4 : int s(socket(family, SOCK_STREAM | sock_flags, IPPROTO_TCP));
931 :
932 4 : if(s >= 0
933 4 : && (flags & SOCKET_FLAG_REUSE) != 0)
934 : {
935 : // set the "reuse that address immediately" flag, we totally
936 : // ignore errors on that one
937 : //
938 2 : int optval(1);
939 2 : socklen_t const optlen(sizeof(optval));
940 2 : static_cast<void>(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, optlen));
941 : }
942 4 : return s;
943 : }
944 :
945 : case IPPROTO_UDP:
946 2 : return socket(family, SOCK_DGRAM | sock_flags, IPPROTO_UDP);
947 :
948 : default:
949 : // this should never happen since we control the f_protocol field
950 : //
951 : return -1; // LCOV_EXCL_LINE
952 :
953 : }
954 : }
955 :
956 :
957 : /** \brief Connect the specified socket to this IP address.
958 : *
959 : * When you create a TCP client, you can connect to a server. This
960 : * is done by using the connect() function which makes use of the
961 : * address to connect to the server.
962 : *
963 : * This function makes sure to select the correct connect() function
964 : * depending on whether this IP address is an IPv4 or an IPv6 address
965 : * (although we could always try with the IPv6 structure, it may or
966 : * may not work properly on all systems, so for now we use the
967 : * distinction.)
968 : *
969 : * \todo
970 : * Move this to our libsnapnetwork once we create that separate library.
971 : * Probably within a form of low level socket class.
972 : *
973 : * \param[in] s The socket to connect to the address.
974 : *
975 : * \return 0 if the bind() succeeded, -1 on errors
976 : */
977 4 : int addr::connect(int s) const
978 : {
979 : // only TCP can connect, UDP binds and sends only
980 : //
981 4 : switch(f_protocol)
982 : {
983 : case IPPROTO_IP: // interpret as TCP...
984 : case IPPROTO_TCP:
985 2 : if(is_ipv4())
986 : {
987 : // this would most certainly work using the IPv6 address
988 : // as in the else part, but to be sure, we use the IPv4
989 : // as specified in the address (there could be other reasons
990 : // than just your OS for this to fail if using IPv6.)
991 : //
992 : // IMPORTANT NOTE: also the family is used in the socket()
993 : // call above and must match the address here...
994 : //
995 : sockaddr_in ipv4;
996 1 : get_ipv4(ipv4);
997 1 : return ::connect(s, reinterpret_cast<sockaddr const *>(&ipv4), sizeof(ipv4));
998 : }
999 : else
1000 : {
1001 1 : return ::connect(s, reinterpret_cast<sockaddr const *>(&f_address), sizeof(struct sockaddr_in6));
1002 : }
1003 : break;
1004 :
1005 : }
1006 :
1007 2 : return -1;
1008 : }
1009 :
1010 :
1011 : /** \brief Create a server with this socket listening on this IP address.
1012 : *
1013 : * This function will bind the socket \p s to the address defined in
1014 : * this addr object. This creates a server listening on that IP address.
1015 : *
1016 : * If the IP address is 127.0.0.1, then only local processes can connect
1017 : * to that server. If the IP address is 0.0.0.0, then anyone can connect
1018 : * to the server.
1019 : *
1020 : * This function works for TCP and UDP servers.
1021 : *
1022 : * If the IP address represents an IPv4 addressm then the bind() is done
1023 : * with an IPv4 address and not the IPv6 as it is stored.
1024 : *
1025 : * \todo
1026 : * Move this to our libsnapnetwork once we create that separate library.
1027 : * Probably within a form of low level socket class.
1028 : *
1029 : * \param[in] s The socket to bind to this address.
1030 : *
1031 : * \return 0 if the bind() succeeded, -1 on errors
1032 : */
1033 2 : int addr::bind(int s) const
1034 : {
1035 2 : if(is_ipv4())
1036 : {
1037 : sockaddr_in ipv4;
1038 1 : get_ipv4(ipv4);
1039 1 : return ::bind(s, reinterpret_cast<sockaddr const *>(&ipv4), sizeof(ipv4));
1040 : }
1041 : else
1042 : {
1043 1 : return ::bind(s, reinterpret_cast<sockaddr const *>(&f_address), sizeof(struct sockaddr_in6));
1044 : }
1045 : }
1046 :
1047 :
1048 : /** \brief Initializes this addr object from a socket information.
1049 : *
1050 : * When you connect to a server or a clients connect to your server, the
1051 : * socket defines two IP addresses and ports: one on your side and one on
1052 : * the other side.
1053 : *
1054 : * The other side is called the _peer name_.
1055 : *
1056 : * You side is called the _socket name_ (i.e. the IP address of your computer,
1057 : * representing the interface used to perform that connection.)
1058 : *
1059 : * If you call this function with \p peer set to false then you get the
1060 : * address and port from your side. If you set \p peer to true,
1061 : * you get the other side address and port details.
1062 : *
1063 : * \todo
1064 : * Move this to our libsnapnetwork once we create that separate library.
1065 : * Probably within a form of low level socket class.
1066 : *
1067 : * \param[in] s The socket from which you want to retrieve peer information.
1068 : * \param[in] peer Whether to retrieve the peer or socket name.
1069 : */
1070 14 : void addr::set_from_socket(int s, bool peer)
1071 : {
1072 : // make sure the socket is defined and well
1073 : //
1074 14 : if(s < 0)
1075 : {
1076 2 : throw addr_invalid_argument_exception("addr::set_from_socket(): the socket cannot be a negative number.");
1077 : }
1078 :
1079 12 : struct sockaddr_storage address = sockaddr_storage();
1080 12 : socklen_t length(sizeof(address));
1081 : int r;
1082 12 : if(peer)
1083 : {
1084 : // this retrieves the information from the other side
1085 : //
1086 6 : r = getpeername(s, reinterpret_cast<struct sockaddr *>(&address), &length);
1087 : }
1088 : else
1089 : {
1090 : // retrieve the local socket information
1091 : //
1092 6 : r = getsockname(s, reinterpret_cast<struct sockaddr *>(&address), &length);
1093 : }
1094 12 : if(r != 0)
1095 : {
1096 5 : int const e(errno);
1097 : throw addr_io_exception(
1098 : std::string("addr::set_from_socket(): ")
1099 10 : + (peer ? "getpeername()" : "getsockname()")
1100 10 : + " failed to retrieve IP address details (errno: "
1101 20 : + std::to_string(e)
1102 10 : + ", "
1103 15 : + strerror(e)
1104 15 : + ").");
1105 : }
1106 :
1107 7 : switch(address.ss_family)
1108 : {
1109 : case AF_INET:
1110 3 : set_ipv4(reinterpret_cast<struct sockaddr_in &>(address));
1111 3 : break;
1112 :
1113 : case AF_INET6:
1114 3 : set_ipv6(reinterpret_cast<struct sockaddr_in6 &>(address));
1115 3 : break;
1116 :
1117 : default:
1118 : throw addr_invalid_state_exception(
1119 : std::string("addr::set_from_socket(): ")
1120 2 : + (peer ? "getpeername()" : "getsockname()")
1121 3 : + " returned a type of address, which is not understood, i.e. not AF_INET or AF_INET6.");
1122 :
1123 : }
1124 6 : }
1125 :
1126 :
1127 : /** \brief Transform the IP into a domain name.
1128 : *
1129 : * This function transforms the IP address in this `addr` object in a
1130 : * name such as "snap.website".
1131 : *
1132 : * \note
1133 : * The function does not cache the result because it is rarely used (at least
1134 : * at this time). So you should cache the result and avoid calling this
1135 : * function more than once as the process can be very slow.
1136 : *
1137 : * \todo
1138 : * Speed enhancement can be achieved by using getaddrinfo_a(). That would
1139 : * work with a vector of addr objects.
1140 : *
1141 : * \return The domain name. If not available, an empty string.
1142 : */
1143 7 : std::string addr::get_name() const
1144 : {
1145 : char host[NI_MAXHOST];
1146 :
1147 7 : int flags(NI_NAMEREQD);
1148 7 : if(f_protocol == IPPROTO_UDP)
1149 : {
1150 4 : flags |= NI_DGRAM;
1151 : }
1152 :
1153 : // TODO: test with the NI_IDN* flags and make sure we know what we get
1154 : // (i.e. we want UTF-8 as a result)
1155 : //
1156 7 : int const r(getnameinfo(reinterpret_cast<sockaddr const *>(&f_address), sizeof(f_address), host, sizeof(host), nullptr, 0, flags));
1157 :
1158 : // return value is 0, then it worked
1159 : //
1160 7 : return r == 0 ? host : std::string();
1161 : }
1162 :
1163 :
1164 : /** \brief Transform the port into a service name.
1165 : *
1166 : * This function transforms the port in this `addr` object in a
1167 : * name such as "http".
1168 : *
1169 : * \note
1170 : * The function does not cache the result because it is rarely used (at least
1171 : * at this time). So you should cache the result and avoid calling this
1172 : * function more than once as the process is somewhat slow.
1173 : *
1174 : * \warning
1175 : * The getnameinfo() will return a string with a number if it does not
1176 : * know the server (i.e. this is the equivalent to std::to_string() of
1177 : * the port.) For port 0, the function always returns an empty string.
1178 : *
1179 : * \return The service name. If not available, an empty string.
1180 : */
1181 5 : std::string addr::get_service() const
1182 : {
1183 5 : if(f_address.sin6_port == 0)
1184 : {
1185 1 : return std::string();
1186 : }
1187 :
1188 : char service[NI_MAXSERV];
1189 :
1190 4 : int flags(NI_NAMEREQD);
1191 4 : if(f_protocol == IPPROTO_UDP)
1192 : {
1193 2 : flags |= NI_DGRAM;
1194 : }
1195 4 : int const r(getnameinfo(reinterpret_cast<sockaddr const *>(&f_address), sizeof(f_address), nullptr, 0, service, sizeof(service), flags));
1196 :
1197 : // return value is 0, then it worked
1198 : //
1199 : return r == 0 ? service
1200 4 : : std::string();
1201 : }
1202 :
1203 :
1204 : /** \brief Retrieve the port.
1205 : *
1206 : * This function retrieves the port of the IP address in host order.
1207 : *
1208 : * \return The port defined along this address.
1209 : */
1210 197592 : int addr::get_port() const
1211 : {
1212 197592 : return ntohs(f_address.sin6_port);
1213 : }
1214 :
1215 :
1216 : /** \brief Retrieve the protocol.
1217 : *
1218 : * This function retrieves the protocol as specified on the
1219 : * set_addr_port() function or corresponding constructor.
1220 : *
1221 : * You may change the protocol with the set_protocol() function.
1222 : *
1223 : * \return protocol such as IPPROTO_TCP or IPPROTO_UDP.
1224 : */
1225 132072 : int addr::get_protocol() const
1226 : {
1227 132072 : return f_protocol;
1228 : }
1229 :
1230 :
1231 : /** \brief Check whether an IP matches a CIDR.
1232 : *
1233 : * When an IP address is defined along a mask, it can match a set of
1234 : * other IP addresses. This function can be used to see whether
1235 : * \p ip matches \p this IP address and mask.
1236 : *
1237 : * So in other words, the mask of `this` addr object is used to mask
1238 : * both, `this` and `p` before comparing the masked result.
1239 : *
1240 : * \warning
1241 : * This function only checks the IP address. It totally ignores the
1242 : * port, family, protocol and other peripheral details.
1243 : *
1244 : * \param[in] ip The address to match against this IP/mask CIDR.
1245 : *
1246 : * \return true if \p ip is a match.
1247 : */
1248 140 : bool addr::match(addr const & ip) const
1249 : {
1250 1507 : for(int idx(0); idx < 16; ++idx)
1251 : {
1252 1493 : if((f_address.sin6_addr.s6_addr[idx] & f_mask[idx]) != (ip.f_address.sin6_addr.s6_addr[idx] & f_mask[idx]))
1253 : {
1254 126 : return false;
1255 : }
1256 : }
1257 :
1258 14 : return true;
1259 : }
1260 :
1261 :
1262 : /** \brief Check whether two addresses are equal.
1263 : *
1264 : * This function compares the left hand side (this) and the right
1265 : * hand side (rhs) for equality. If both represent the same IP
1266 : * address, then the function returns true.
1267 : *
1268 : * \warning
1269 : * The function only compares the address itself. The family, port,
1270 : * flow info, scope identifier, protocol are all ignored.
1271 : *
1272 : * \return true if \p this is equal to \p rhs.
1273 : */
1274 35 : bool addr::operator == (addr const & rhs) const
1275 : {
1276 35 : return f_address.sin6_addr == rhs.f_address.sin6_addr;
1277 : }
1278 :
1279 :
1280 : /** \brief Check whether two addresses are not equal.
1281 : *
1282 : * This function compares the left hand side (this) and the right
1283 : * hand side (rhs) for inequality. If both represent the same IP
1284 : * address, then the function returns false.
1285 : *
1286 : * \warning
1287 : * The function only compares the address itself. The family, port,
1288 : * flow info, scope identifier, protocol are all ignored.
1289 : *
1290 : * \return true if \p this is not equal to \p rhs.
1291 : */
1292 9 : bool addr::operator != (addr const & rhs) const
1293 : {
1294 9 : return f_address.sin6_addr != rhs.f_address.sin6_addr;
1295 : }
1296 :
1297 :
1298 : /** \brief Compare two addresses to know which one is smaller.
1299 : *
1300 : * This function compares the left hand side (this) and the right
1301 : * hand side (rhs) to know which one is the smallest. If both
1302 : * are equal or the left hand side is larger than the right hand
1303 : * side, then it returns false, otherwise it returns true.
1304 : *
1305 : * \warning
1306 : * The function only compares the address itself. The family, port,
1307 : * flow info, scope identifier, protocol are all ignored.
1308 : *
1309 : * \return true if \p this is smaller than \p rhs.
1310 : */
1311 7 : bool addr::operator < (addr const & rhs) const
1312 : {
1313 7 : return f_address.sin6_addr < rhs.f_address.sin6_addr;
1314 : }
1315 :
1316 :
1317 : /** \brief Compare two addresses to know which one is smaller or equal.
1318 : *
1319 : * This function compares the left hand side (this) and the right
1320 : * hand side (rhs) to know whether the left hand side is smaller or
1321 : * equal to thr right handside.
1322 : *
1323 : * \warning
1324 : * The function only compares the address itself. The family, port,
1325 : * flow info, scope identifier, protocol are all ignored.
1326 : *
1327 : * \return true if \p this is smaller than \p rhs.
1328 : */
1329 685 : bool addr::operator <= (addr const & rhs) const
1330 : {
1331 685 : return f_address.sin6_addr <= rhs.f_address.sin6_addr;
1332 : }
1333 :
1334 :
1335 : /** \brief Compare two addresses to know which one is smaller.
1336 : *
1337 : * This function compares the left hand side (this) and the right
1338 : * hand side (rhs) to know which one is the smallest. If both
1339 : * are equal or the left hand side is larger than the right hand
1340 : * side, then it returns false, otherwise it returns true.
1341 : *
1342 : * \warning
1343 : * The function only compares the address itself. The family, port,
1344 : * flow info, scope identifier, protocol are all ignored.
1345 : *
1346 : * \return true if \p this is smaller than \p rhs.
1347 : */
1348 27 : bool addr::operator > (addr const & rhs) const
1349 : {
1350 27 : return f_address.sin6_addr > rhs.f_address.sin6_addr;
1351 : }
1352 :
1353 :
1354 : /** \brief Compare two addresses to know which one is smaller.
1355 : *
1356 : * This function compares the left hand side (this) and the right
1357 : * hand side (rhs) to know which one is the smallest. If both
1358 : * are equal or the left hand side is larger than the right hand
1359 : * side, then it returns false, otherwise it returns true.
1360 : *
1361 : * \warning
1362 : * The function only compares the address itself. The family, port,
1363 : * flow info, scope identifier, protocol are all ignored.
1364 : *
1365 : * \return true if \p this is smaller than \p rhs.
1366 : */
1367 290 : bool addr::operator >= (addr const & rhs) const
1368 : {
1369 290 : return f_address.sin6_addr >= rhs.f_address.sin6_addr;
1370 : }
1371 :
1372 :
1373 : /** \brief Mark that the address changed.
1374 : *
1375 : * This functions makes sure that some of the parameters being cached
1376 : * get reset in such a way that checking the cache will again return
1377 : * the correct answer.
1378 : *
1379 : * \sa get_network_type()
1380 : */
1381 132717 : void addr::address_changed()
1382 : {
1383 132717 : f_private_network_defined = network_type_t::NETWORK_TYPE_UNDEFINED;
1384 132717 : }
1385 :
1386 :
1387 :
1388 :
1389 6 : }
1390 : // addr namespace
1391 : // vim: ts=4 sw=4 et
|