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