Line data Source code
1 : // Network Address -- classes functions to ease handling IP addresses
2 : // Copyright (C) 2012-2017 Made to Order Software Corp.
3 : //
4 : // http://snapwebsites.org/project/libaddr
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License
17 : // along with this program; if not, write to the Free Software
18 : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 :
20 : // self
21 : //
22 : #include "libaddr/addr.h"
23 :
24 : // C++ lib
25 : //
26 : #include <algorithm>
27 : #include <sstream>
28 : #include <iostream>
29 :
30 : // C lib
31 : //
32 : #include <ifaddrs.h>
33 : #include <netdb.h>
34 :
35 :
36 :
37 : namespace addr
38 : {
39 :
40 :
41 : namespace
42 : {
43 :
44 :
45 : /** \brief Delete an addrinfo structure.
46 : *
47 : * This deleter is used to make sure all the addinfo get released when
48 : * an exception occurs or the function using such exists.
49 : *
50 : * \param[in] ai The addrinfo structure to free.
51 : */
52 131973 : void addrinfo_deleter(struct addrinfo * ai)
53 : {
54 131973 : freeaddrinfo(ai);
55 131973 : }
56 :
57 :
58 : }
59 :
60 :
61 :
62 :
63 :
64 : /** \brief Set the default IP addresses.
65 : *
66 : * This function sets the default IP addresses to be used by the parser
67 : * when the input string of the parse() function does not include an IP
68 : * address.
69 : *
70 : * The function expects either an IPv4 or an IPv6 address. It can be
71 : * called twice if you need to define both types of addresses (which
72 : * is often a good idea.)
73 : *
74 : * For example, the following input is considered valid when a default
75 : * address is defined:
76 : *
77 : * \code
78 : * parser.parse(":123");
79 : * \endcode
80 : *
81 : * It returns the default address and port 123. Note that by default
82 : * an address is mandatory unless a default address is defined.
83 : *
84 : * To prevent the parser from working when no default and no address
85 : * are specified, then make sure to set the REQUIRED_ADDRESS allow
86 : * flag to true:
87 : *
88 : * \code
89 : * parser.set_allow(parser.flag_t::REQUIRED_ADDRESS, true);
90 : * // now address is mandatory
91 : * \endcode
92 : *
93 : * To completely prevent the use of an address in an input string, set
94 : * the `ADDRESS` and `REQUIRED_ADDRESS` values to false:
95 : *
96 : * \code
97 : * parser.set_allow(parser.flag_t::ADDRESS, false);
98 : * parser.set_allow(parser.flag_t::REQUIRED_ADDRESS, false);
99 : * \endcode
100 : *
101 : * To remove both default IP addresses, call this function with an empty
102 : * string:
103 : *
104 : * \code
105 : * parser.set_default_address(std::string());
106 : * \endcode
107 : *
108 : * \param[in] addr The new address.
109 : */
110 217 : void addr_parser::set_default_address(std::string const & addr)
111 : {
112 217 : if(addr.empty())
113 : {
114 3 : f_default_address4.clear();
115 3 : f_default_address6.clear();
116 : }
117 214 : else if(addr[0] == '[')
118 : {
119 : // remove the '[' and ']'
120 : //
121 5 : if(addr.back() != ']')
122 : {
123 3 : throw addr_invalid_argument_exception("an IPv6 address starting with '[' must end with ']'.");
124 : }
125 2 : f_default_address6 = addr.substr(1, addr.length() - 2);
126 : }
127 209 : else if(addr.find(':') != std::string::npos)
128 : {
129 103 : f_default_address6 = addr;
130 : }
131 : else
132 : {
133 106 : f_default_address4 = addr;
134 : }
135 214 : }
136 :
137 :
138 : /** \brief Retrieve the default IP address for IPv4 parsing.
139 : *
140 : * This function returns a copy of the default IP address used by
141 : * the parser when the input string does not include an IP address.
142 : *
143 : * If the function returns an empty string, then no default address
144 : * is defined.
145 : *
146 : * \return The default IPv4 address.
147 : *
148 : * \sa get_default_address6()
149 : * \sa set_default_address()
150 : */
151 115 : std::string const & addr_parser::get_default_address4() const
152 : {
153 115 : return f_default_address4;
154 : }
155 :
156 :
157 : /** \brief Retrieve the default IP address for IPv4 parsing.
158 : *
159 : * This function returns a copy of the default IP address used by
160 : * the parser when the input string does not include an IP address.
161 : *
162 : * If the function returns an empty string, then no default address
163 : * is defined.
164 : *
165 : * \return The default IPv6 address, without square brackets.
166 : *
167 : * \sa get_default_address4()
168 : * \sa set_default_address()
169 : */
170 115 : std::string const & addr_parser::get_default_address6() const
171 : {
172 115 : return f_default_address6;
173 : }
174 :
175 :
176 : /** \brief Define the default port.
177 : *
178 : * This function is used to define the default port to use in the address
179 : * parser object. By default this is set to -1 meaning: no default port.
180 : *
181 : * This function accepts any port number from 0 to 65535. It also accepts
182 : * -1 to reset the port back to "no default".
183 : *
184 : * To prevent the parser from working when no default and no port
185 : * are specified, then make sure to set the REQUIRED_PORT allow
186 : * flag to true:
187 : *
188 : * \code
189 : * parser.set_allow(parser.flag_t::REQUIRED_PORT, true);
190 : * // now port is mandatory
191 : * \endcode
192 : *
193 : * To completely prevent the use of a port in an input string, set
194 : * the `PORT` and `REQUIRED_PORT` values to false:
195 : *
196 : * \code
197 : * parser.set_allow(parser.flag_t::PORT, false);
198 : * parser.set_allow(parser.flag_t::REQUIRED_PORT, false);
199 : * \endcode
200 : *
201 : * \exception addr_invalid_argument_exception
202 : * If the port number is out of range, then this expcetion is raised.
203 : * The allowed range for a port is 0 to 65535. This function also
204 : * accepts -1 meaning that no default port is specified.
205 : *
206 : * \param[in] port The new default port.
207 : */
208 76 : void addr_parser::set_default_port(int const port)
209 : {
210 76 : if(port < -1
211 63 : || port > 65535)
212 : {
213 25 : throw addr_invalid_argument_exception("addr_parser::set_default_port(): port must be in range [-1..65535].");
214 : }
215 :
216 51 : f_default_port = port;
217 51 : }
218 :
219 :
220 : /** \brief Retrieve the default port.
221 : *
222 : * This function retrieves the default port as defined by the
223 : * set_default_port() function.
224 : */
225 76 : int addr_parser::get_default_port() const
226 : {
227 76 : return f_default_port;
228 : }
229 :
230 :
231 : /** \brief Define the default mask.
232 : *
233 : * This function is used to define the default mask. Note that the
234 : * default mask will not be used at all if the flag_t::MASK allow
235 : * flag is not set to true:
236 : *
237 : * \code
238 : * parser.set_allow(parser.flag_t::MASK, true);
239 : * parser.set_default_mask("255.255.0.0");
240 : * parser.set_default_mask("[ffff:ffff:ffff::]");
241 : * \endcode
242 : *
243 : * The IPv6 mask does not require the square brackets (`'['` and `']'`).
244 : *
245 : * To remove the default mask, call this function with an empty
246 : * string:
247 : *
248 : * \code
249 : * parser.set_default_mask(std::string());
250 : * \endcode
251 : *
252 : * \bug
253 : * At this time the default mask can only be an IPv4 or an IPv6
254 : * mask and therefore you may have problems if it does not match
255 : * the input string with a missing mask. At some point we may
256 : * offer two default masks: one for IPv4 and one for IPv6.
257 : *
258 : * \note
259 : * As you can see, here we espect the mask as a string. This is because
260 : * it gets parsed as if it came from the input string. This also means
261 : * that if the mask is invalid, it won't be detected until you attempt
262 : * to parse an input string that does not include a mask.
263 : *
264 : * \param[in] mask The mask to use by default.
265 : */
266 111 : void addr_parser::set_default_mask(std::string const & mask)
267 : {
268 111 : if(mask.empty())
269 : {
270 3 : f_default_mask4.clear();
271 3 : f_default_mask6.clear();
272 : }
273 108 : else if(mask[0] == '[')
274 : {
275 : // remove the '[' and ']'
276 : //
277 30 : if(mask.back() != ']')
278 : {
279 3 : throw addr_invalid_argument_exception("an IPv6 mask starting with '[' must end with ']'.");
280 : }
281 27 : f_default_mask6 = mask.substr(1, mask.length() - 2);
282 : }
283 78 : else if(mask.find(':') != std::string::npos)
284 : {
285 25 : f_default_mask6 = mask;
286 : }
287 : else
288 : {
289 53 : f_default_mask4 = mask;
290 : }
291 108 : }
292 :
293 :
294 : /** \brief Retrieve the default mask.
295 : *
296 : * This function returns a reference to the mask as set by the
297 : * set_default_mask() function. The value is an empty string by
298 : * default.
299 : *
300 : * The default mask will be used if no mask is specified in the
301 : * input string to the parse() function. When no default mask
302 : * is defined, the mask is set to all 1s.
303 : *
304 : * \note
305 : * The default mask is a string, not a binary mask. It gets
306 : * converted by the parser at the time it is required.
307 : *
308 : * \return The default mask.
309 : *
310 : * \sa get_default_mask6()
311 : * \sa set_default_mask()
312 : */
313 12 : std::string const & addr_parser::get_default_mask4() const
314 : {
315 12 : return f_default_mask4;
316 : }
317 :
318 :
319 : /** \brief Retrieve the default mask.
320 : *
321 : * This function returns a reference to the mask as set by the
322 : * set_default_mask() function. The value is an empty string by
323 : * default.
324 : *
325 : * The default mask will be used if no mask is specified in the
326 : * input string to the parse() function. When no default mask
327 : * is defined, the mask is set to all 1s.
328 : *
329 : * \note
330 : * The default mask is a string, not a binary mask. It gets
331 : * converted by the parser at the time it is required.
332 : *
333 : * \return The default mask.
334 : *
335 : * \sa get_default_mask4()
336 : * \sa set_default_mask()
337 : */
338 12 : std::string const & addr_parser::get_default_mask6() const
339 : {
340 12 : return f_default_mask6;
341 : }
342 :
343 :
344 : /** \brief Set the protocol to use to filter addresses.
345 : *
346 : * This function sets the protocol as one of the following:
347 : *
348 : * \li "ip" -- only return IP address supporting the IP protocol
349 : * (this is offered because getaddrinfo() may return such IP addresses.)
350 : * \li "tcp" -- only return IP address supporting TCP
351 : * \li "udp" -- only return IP address supporting UDP
352 : *
353 : * Any other value is refused. To reset the protocol to the default,
354 : * which is "do not filter by protocol", call the clear_protocol().
355 : *
356 : * \exception addr_invalid_argument_exception
357 : * If the string passed to this function is not one of the acceptable
358 : * protocols (ip, tcp, udp), then this exception is raised.
359 : *
360 : * \param[in] protocol The default protocol for this parser.
361 : *
362 : * \sa clear_protocol()
363 : * \sa get_protocol()
364 : */
365 109 : void addr_parser::set_protocol(std::string const & protocol)
366 : {
367 109 : if(protocol == "ip")
368 : {
369 2 : f_protocol = IPPROTO_IP;
370 : }
371 107 : else if(protocol == "tcp")
372 : {
373 103 : f_protocol = IPPROTO_TCP;
374 : }
375 4 : else if(protocol == "udp")
376 : {
377 2 : f_protocol = IPPROTO_UDP;
378 : }
379 : else
380 : {
381 : // not a protocol we support
382 : //
383 : throw addr_invalid_argument_exception(
384 : std::string("unknown protocol \"")
385 4 : + protocol
386 6 : + "\", expected \"tcp\" or \"udp\".");
387 : }
388 107 : }
389 :
390 :
391 : /** \brief Set the protocol to use to filter addresses.
392 : *
393 : * This function sets the protocol as one of the following:
394 : *
395 : * \li IPPROTO_IP -- only return IP address supporting the IP protocol
396 : * (this is offered because getaddrinfo() may return such IP addresses.)
397 : * \li IPPROTO_TCP -- only return IP address supporting TCP
398 : * \li IPPROTO_UDP -- only return IP address supporting UDP
399 : *
400 : * Any other value is refused. To reset the protocol to the default,
401 : * which is "do not filter by protocol", call the clear_protocol().
402 : *
403 : * \exception addr_invalid_argument_exception
404 : * If the string passed to this function is not one of the acceptable
405 : * protocols (ip, tcp, udp), then this exception is raised.
406 : *
407 : * \param[in] protocol The default protocol for this parser.
408 : *
409 : * \sa clear_protocol()
410 : * \sa get_protocol()
411 : */
412 132016 : void addr_parser::set_protocol(int const protocol)
413 : {
414 : // make sure that's a protocol we support
415 : //
416 132016 : switch(protocol)
417 : {
418 : case IPPROTO_IP:
419 : case IPPROTO_TCP:
420 : case IPPROTO_UDP:
421 131816 : break;
422 :
423 : default:
424 : throw addr_invalid_argument_exception(
425 : std::string("unknown protocol \"")
426 400 : + std::to_string(protocol)
427 600 : + "\", expected \"tcp\" or \"udp\".");
428 :
429 : }
430 :
431 131816 : f_protocol = protocol;
432 131816 : }
433 :
434 :
435 : /** \brief Use this function to reset the protocol back to "no default."
436 : *
437 : * This function sets the protocol to -1 (which is something you cannot
438 : * do by callingt he set_protocol() functions above.)
439 : *
440 : * The -1 special value means that the protocol is not defined, that
441 : * there is no default. In most cases this means all the addresses
442 : * that match, ignoring the protocol, will be returned by the parse()
443 : * function.
444 : *
445 : * \sa set_protocol()
446 : * \sa get_protocol()
447 : */
448 3 : void addr_parser::clear_protocol()
449 : {
450 3 : f_protocol = -1;
451 3 : }
452 :
453 :
454 : /** \brief Retrieve the protocol as defined by the set_protocol().
455 : *
456 : * This function returns the protocol number as defined by the
457 : * set_protocol.
458 : *
459 : * When defined, the protocol is used whenever we call the
460 : * getaddrinfo() function. In general, this means the IP addresses
461 : * returned will have to match that protocol.
462 : *
463 : * This function may return -1. The value -1 is used as "do not
464 : * filter by protocol". The protocol can be set to -1 by calling
465 : * the clear_protocol() function.
466 : *
467 : * \return The parser default protocol.
468 : *
469 : * \sa set_protocol()
470 : * \sa clear_protocol()
471 : */
472 216 : int addr_parser::get_protocol() const
473 : {
474 216 : return f_protocol;
475 : }
476 :
477 :
478 : /** \brief Set or clear allow flags in the parser.
479 : *
480 : * This parser has a set of flags it uses to know whether the input
481 : * string can include certain things such as a port or a mask.
482 : *
483 : * This function is used to allow or require certain parameters and
484 : * to disallow others.
485 : *
486 : * By default, the ADDRESS and PORT flags are set, meaning that an
487 : * address and a port can appear, but either or both are optinal.
488 : * If unspecified, then the default will be used. If not default
489 : * is defined, then the parser may fail in this situation.
490 : *
491 : * One problem is that we include contradictory syntatical features.
492 : * The parser supports lists of addresses separated by commas and
493 : * lists of ports separated by commas. Both are not supported
494 : * simultaneously. This means you want to allow multiple addresses
495 : * separated by commas, the function makes sure that the multiple
496 : * port separated by commas support is turned of.
497 : *
498 : * \li ADDRESS -- the IP address is allowed, but optional
499 : * \li REQUIRED_ADDRESS -- the IP address is mandatory
500 : * \li PORT -- the port is allowed, but optional
501 : * \li REQUIRED_PORT -- the port is mandatory
502 : * \li MASK -- the mask is allowed, but optional
503 : * \li MULTI_ADDRESSES_COMMAS -- the input can have multiple addresses
504 : * separated by commas, spaces are not allowed (prevents MULTI_PORTS_COMMAS)
505 : * \li MULTI_ADDRESSES_SPACES -- the input can have multiple addresses
506 : * separated by spaces
507 : * \li MULTI_ADDRESSES_COMMAS_AND_SPACES -- the input can have multiple
508 : * addresses separated by spaces and commas (prevents MULTI_PORTS_COMMAS)
509 : * \li MULTI_PORTS_SEMICOLONS -- the input can have multiple ports
510 : * separated by semicolons _NOT IMPLEMENTED YET_
511 : * \li MULTI_PORTS_COMMAS -- the input can have multiple ports separated
512 : * by commas (prevents MULTI_ADDRESSES_COMMAS and
513 : * MULTI_ADDRESSES_COMMAS_AND_SPACES) _NOT IMPLEMENTED YET_
514 : * \li PORT_RANGE -- the input supports port ranges (p1-p2) _NOT
515 : * IMPLEMENTED YET_
516 : * \li ADDRESS_RANGE -- the input supports address ranges (addr-addr) _NOT
517 : * IMPLEMENTED YET_
518 : *
519 : * \param[in] flag The flag to set or clear.
520 : * \param[in] allow Whether to allow (true) or disallow (false).
521 : *
522 : * \sa get_allow()
523 : */
524 534 : void addr_parser::set_allow(flag_t const flag, bool const allow)
525 : {
526 534 : if(flag < static_cast<flag_t>(0)
527 514 : || flag >= flag_t::FLAG_max)
528 : {
529 40 : throw addr_invalid_argument_exception("addr_parser::set_allow(): flag has to be one of the valid flags.");
530 : }
531 :
532 494 : f_flags[static_cast<int>(flag)] = allow;
533 :
534 : // if we just set a certain flag, others may need to go to false
535 : //
536 494 : if(allow)
537 : {
538 : // we can only support one type of commas
539 : //
540 485 : switch(flag)
541 : {
542 : case flag_t::MULTI_ADDRESSES_COMMAS:
543 : case flag_t::MULTI_ADDRESSES_COMMAS_AND_SPACES:
544 7 : f_flags[static_cast<int>(flag_t::MULTI_PORTS_COMMAS)] = false;
545 7 : break;
546 :
547 : case flag_t::MULTI_PORTS_COMMAS:
548 2 : f_flags[static_cast<int>(flag_t::MULTI_ADDRESSES_COMMAS)] = false;
549 2 : f_flags[static_cast<int>(flag_t::MULTI_ADDRESSES_COMMAS_AND_SPACES)] = false;
550 2 : break;
551 :
552 : default:
553 476 : break;
554 :
555 : }
556 : }
557 494 : }
558 :
559 :
560 : /** \brief Retrieve the current statius of an allow flag.
561 : *
562 : * This function returns the current status of the allow flags.
563 : *
564 : * By default, the `ADDRESS` and `PORT` flags are set to true.
565 : * All the other flags are set to false.
566 : *
567 : * You may change the value of an allow flag by calling the
568 : * set_allow() function.
569 : *
570 : * \param[in] flag Which flag is to be checked.
571 : *
572 : * \return The value of the flag: true or false.
573 : *
574 : * \sa set_allow()
575 : */
576 57 : bool addr_parser::get_allow(flag_t const flag) const
577 : {
578 57 : if(flag < static_cast<flag_t>(0)
579 47 : || flag >= flag_t::FLAG_max)
580 : {
581 20 : throw addr_invalid_argument_exception("addr_parser::get_allow(): flag has to be one of the valid flags.");
582 : }
583 :
584 37 : return f_flags[static_cast<int>(flag)];
585 : }
586 :
587 :
588 : /** \brief Check whether errors were registered so far.
589 : *
590 : * This function returns true if the system detected errors in one
591 : * of the previous calls to parse(). The flag can be cleared using
592 : * the clear_errors() function.
593 : *
594 : * On construction and after a call to clear_error(), this flag is
595 : * always false. If you are to call parser() multiple times with
596 : * the same addr_parser object, then you want to make sure to call
597 : * the clear_errors() function before calling the parse() function.
598 : * Otherwise you won't know whether errors occurred in a earlier
599 : * or later call.
600 : *
601 : * \code
602 : * // first time, not required
603 : * parser.parse(...);
604 : * ...
605 : *
606 : * // next time, required
607 : * parser.clear_errors();
608 : * parser.parse(...);
609 : * ...
610 : * \endcode
611 : *
612 : * \return true if errors were generated.
613 : */
614 131827 : bool addr_parser::has_errors() const
615 : {
616 131827 : return !f_error.empty();
617 : }
618 :
619 :
620 : /** \brief Emit an error and save it in this class.
621 : *
622 : * This function adds the message to the error string part of this
623 : * object. A newline is also added at the end of the message.
624 : *
625 : * Next the function increments the error counter.
626 : *
627 : * \note
628 : * You are expected to emit one error at a time. If you want to
629 : * emit several messages in a row, that will work and properly
630 : * count each message.
631 : *
632 : * \param[in] msg The message to add to the parser error messages.
633 : *
634 : * \sa error_messages()
635 : */
636 62 : void addr_parser::emit_error(std::string const & msg)
637 : {
638 62 : f_error += msg;
639 62 : f_error += "\n";
640 62 : ++f_error_count;
641 62 : }
642 :
643 :
644 : /** \brief Return the current error messages.
645 : *
646 : * The error messages are added to the addr_parser using the
647 : * emit_error() function.
648 : *
649 : * This function does not clear the list of error messages.
650 : * To do that, call the clear_errors() function.
651 : *
652 : * The number of messages can be determined by counting the
653 : * number of "\n" characters in the string. The error_count()
654 : * will return that same number (assuming no message included
655 : * a '\n' character when emit_error() was called.)
656 : *
657 : * \return A string with the list of messages.
658 : *
659 : * \sa emit_error()
660 : * \sa clear_errors()
661 : */
662 62 : std::string const & addr_parser::error_messages() const
663 : {
664 62 : return f_error;
665 : }
666 :
667 :
668 : /** \brief Return the number of error messages that were emitted.
669 : *
670 : * Each time the emit_error() function is called, the error
671 : * counter is incremented by 1. This function returns that
672 : * error counter.
673 : *
674 : * The clear_errors() function can be used to clear the
675 : * counter back to zero.
676 : *
677 : * \return The number of errors that were emitted so far.
678 : *
679 : * \sa emit_error()
680 : */
681 62 : int addr_parser::error_count() const
682 : {
683 62 : return f_error_count;
684 : }
685 :
686 :
687 : /** \brief Clear the error message and error counter.
688 : *
689 : * This function clears all the error messages and reset the
690 : * counter back to zero. In order words, it will be possible
691 : * to tell how many times the emit_error() was called since
692 : * the start or the last clear_errors() call.
693 : *
694 : * To retrieve a copy of the error counter, use the error_count()
695 : * function.
696 : *
697 : * \sa error_count()
698 : */
699 5 : void addr_parser::clear_errors()
700 : {
701 5 : f_error.clear();
702 5 : f_error_count = 0;
703 5 : }
704 :
705 :
706 : /** \brief Parse a string of addresses, ports, and masks.
707 : *
708 : * This function is used to parse the list of addresses defined
709 : * in the \p in parameter.
710 : *
711 : * One address is composed of one to three elements:
712 : *
713 : * \code
714 : * [ address ] [ ':' port ] [ '/' mask ]
715 : * \endcode
716 : *
717 : * Although all three elements are optional (at least by default),
718 : * a valid address is expected to include at least one of the
719 : * three elements. (i.e. an empty string is just skipped silently.)
720 : *
721 : * ### Multiple Addresses
722 : *
723 : * Multiple addresses can be defined if at least one of the
724 : * `MULTI_ADDRESSES_COMMAS`, `MULTI_ADDRESSES_SPACES`, or
725 : * `MULTI_ADDRESSES_COMMAS_AND_SPACES` allow flags is set to true.
726 : *
727 : * Note that the `MULTI_ADDRESSES_COMMAS_AND_SPACES` has priotity. If
728 : * set to true, then both, commas and spaces are allowed between
729 : * addresses.
730 : *
731 : * Next comes `MULTI_ADDRESSES_COMMAS`: if set to true, addresses
732 : * must be separated by commas and spaces are not allowed.
733 : *
734 : * Finally we have `MULTI_ADDRESSES_SPACES`. If that one is true, then
735 : * addresses must be separated by spaces and commas are not allowed.
736 : *
737 : * ### Make Address Field Required
738 : *
739 : * To make the address field a required field, set the
740 : * `REQUIRED_ADDRESS` flag (see set_allow()) to true and do not define a
741 : * default address (see set_default_address()).
742 : *
743 : * ### Make Port Field Required
744 : *
745 : * To make the port field a required fiel, set the `REQUIRED_PORT`
746 : * flag (see set_allow()) to true and do not define a default port
747 : * (see set_default_port()).
748 : *
749 : * ### Allow Mask
750 : *
751 : * The mask cannot be made mandatory. However, you have to set
752 : * the `MASK` flag to true to allow it. By default it is not
753 : * allowed.
754 : *
755 : * ### Ranges
756 : *
757 : * At this time we do not need support for ranges so it did not yet
758 : * get implemented.
759 : *
760 : * \param[in] in The input string to be parsed.
761 : */
762 131817 : addr_range::vector_t addr_parser::parse(std::string const & in)
763 : {
764 131817 : addr_range::vector_t result;
765 :
766 131817 : if(f_flags[static_cast<int>(flag_t::MULTI_ADDRESSES_COMMAS_AND_SPACES)])
767 : {
768 2 : std::string comma_space(", ");
769 1 : std::string::size_type s(0);
770 17 : while(s < in.length())
771 : {
772 : // since C++11 we have a way to search for a set of character
773 : // in a string with an algorithm!
774 : //
775 8 : auto const it(std::find_first_of(in.begin() + s, in.end(), comma_space.begin(), comma_space.end()));
776 8 : std::string::size_type const e(it == in.end() ? in.length() : it - in.begin());
777 8 : if(e > s)
778 : {
779 3 : parse_cidr(in.substr(s, e - s), result);
780 : }
781 8 : s = e + 1;
782 : }
783 : }
784 131816 : else if(f_flags[static_cast<int>(flag_t::MULTI_ADDRESSES_COMMAS)]
785 131815 : || f_flags[static_cast<int>(flag_t::MULTI_ADDRESSES_SPACES)])
786 : {
787 2 : char sep(f_flags[static_cast<int>(flag_t::MULTI_ADDRESSES_COMMAS)] ? ',' : ' ');
788 2 : std::string::size_type s(0);
789 24 : while(s < in.length())
790 : {
791 11 : std::string::size_type e(in.find(sep, s));
792 11 : if(e == std::string::npos)
793 : {
794 2 : e = in.length();
795 : }
796 11 : if(e > s)
797 : {
798 6 : parse_cidr(in.substr(s, e - s), result);
799 : }
800 11 : s = e + 1;
801 2 : }
802 : }
803 : else
804 : {
805 131814 : parse_cidr(in, result);
806 : }
807 :
808 131817 : return result;
809 : }
810 :
811 :
812 : /** \brief Check one address.
813 : *
814 : * This function checks one address, although if it is a name, it could
815 : * represent multiple IP addresses.
816 : *
817 : * This function separate the address:port from the mask if the mask is
818 : * allowed. Then it parses the address:port part and the mask separately.
819 : *
820 : * \param[in] in The address to parse.
821 : * \param[in,out] result The list of resulting addresses.
822 : */
823 131823 : void addr_parser::parse_cidr(std::string const & in, addr_range::vector_t & result)
824 : {
825 131823 : if(f_flags[static_cast<int>(flag_t::MASK)])
826 : {
827 : // check whether there is a mask
828 : //
829 942 : std::string mask;
830 :
831 942 : std::string address;
832 471 : std::string::size_type const p(in.find('/'));
833 471 : if(p != std::string::npos)
834 : {
835 418 : address = in.substr(0, p);
836 418 : mask = in.substr(p + 1);
837 : }
838 : else
839 : {
840 53 : address = in;
841 : }
842 :
843 471 : int const errcnt(f_error_count);
844 :
845 : // handle the address first
846 : //
847 942 : addr_range::vector_t addr_mask;
848 471 : parse_address(address, mask, addr_mask);
849 :
850 : // now check for the mask
851 : //
852 942 : for(auto & am : addr_mask)
853 : {
854 942 : std::string m(mask);
855 471 : if(m.empty())
856 : {
857 : // the mask was not defined in the input, then adapt it to
858 : // the type of address we got in 'am'
859 : //
860 55 : if(am.get_from().is_ipv4())
861 : {
862 28 : m = f_default_mask4;
863 : }
864 : else
865 : {
866 : // parse_mask() expects '[...]' around IPv6 addresses
867 : //
868 27 : m = "[" + f_default_mask6 + "]";
869 : }
870 : }
871 :
872 471 : parse_mask(m, am.get_from());
873 : }
874 :
875 : // now append the list to the result if no errors occurred
876 : //
877 471 : if(errcnt == f_error_count)
878 : {
879 421 : result.insert(result.end(), addr_mask.begin(), addr_mask.end());
880 : }
881 : }
882 : else
883 : {
884 : // no mask allowed, if there is one, this call will fail
885 : //
886 131352 : parse_address(in, std::string(), result);
887 : }
888 131823 : }
889 :
890 :
891 : /** \brief Parse one address.
892 : *
893 : * This function is called with one address. It determines whether we
894 : * are dealing with an IPv4 or an IPv6 address and call the
895 : * corresponding sub-function.
896 : *
897 : * An address is considered an IPv6 address if it starts with a '['
898 : * character.
899 : *
900 : * \note
901 : * The input cannot include a mask. It has to already have been
902 : * removed.
903 : *
904 : * \note
905 : * The mask parameter is only used to determine whether this function
906 : * is being called with an IPv6 or not. It is otherwise ignored.
907 : *
908 : * \param[in] in The input address eventually including a port.
909 : * \param[in] mask The mask used to determine whether we are dealing with
910 : * an IPv6 or not.
911 : * \param[in,out] result The list of resulting addresses.
912 : */
913 131823 : void addr_parser::parse_address(std::string const & in, std::string const & mask, addr_range::vector_t & result)
914 : {
915 : // With our only supported format, ipv6 addresses must be between square
916 : // brackets. The address may just be a mask in which case the '[' may
917 : // not be at the very start (i.e. "/[ffff:ffff::]")
918 : //
919 263646 : if(in.empty()
920 131823 : || in[0] == ':') // if it start with ':' then there is no address
921 : {
922 : // if the address is empty, then use the mask to determine the
923 : // type of IP address (note: if the address starts with ':'
924 : // it is considered empty since an IPv6 would have a '[' at
925 : // the start)
926 : //
927 316 : if(!mask.empty())
928 : {
929 111 : if(mask[0] == '[')
930 : {
931 : // IPv6 parsing
932 : //
933 5 : parse_address6(in, result);
934 : }
935 : else
936 : {
937 : // if the number is 33 or more, it has to be IPv6, otherwise
938 : // we cannot know...
939 : //
940 106 : int mask_count(0);
941 355 : for(char const * s(mask.c_str()); *s != '\0'; ++s)
942 : {
943 259 : if(*s >= '0' && *s <= '9')
944 : {
945 254 : mask_count = mask_count * 10 + *s - '0';
946 503 : if(mask_count > 1000)
947 : {
948 : // not valid
949 : //
950 5 : mask_count = -1;
951 5 : break;;
952 : }
953 : }
954 : else
955 : {
956 : // not a valid decimal number
957 : //
958 5 : mask_count = -1;
959 5 : break;
960 : }
961 : }
962 106 : if(mask_count > 32)
963 : {
964 96 : parse_address6(in, result);
965 : }
966 : else
967 : {
968 10 : parse_address4(in, result);
969 : }
970 : }
971 : }
972 : else
973 : {
974 410 : if(f_default_address4.empty()
975 205 : && !f_default_address6.empty())
976 : {
977 102 : parse_address6(in, result);
978 : }
979 : else
980 : {
981 103 : parse_address4(in, result);
982 : }
983 : }
984 : }
985 : else
986 : {
987 : // if an address has a ']' then it is IPv6 even if the '['
988 : // is missing, that being said, it is still considered
989 : // invalid as per our processes
990 : //
991 263014 : if(in[0] == '['
992 131507 : || in.find(']') != std::string::npos)
993 : {
994 65774 : parse_address6(in, result);
995 : }
996 : else
997 : {
998 : // if there is no port, then a ':' can be viewed as an IPv6
999 : // address because there is no other ':', but if there are
1000 : // '.' before the ':' then we assume that it is IPv4 still
1001 : //
1002 65733 : if(!f_flags[static_cast<int>(flag_t::PORT)]
1003 4 : && !f_flags[static_cast<int>(flag_t::REQUIRED_PORT)])
1004 : {
1005 3 : std::string::size_type const p(in.find(':'));
1006 3 : if(p != std::string::npos
1007 3 : && in.find('.') > p)
1008 : {
1009 1 : parse_address6(in, result);
1010 : }
1011 : else
1012 : {
1013 2 : parse_address4(in, result);
1014 3 : }
1015 : }
1016 : else
1017 : {
1018 65730 : parse_address4(in, result);
1019 : }
1020 : }
1021 : }
1022 131823 : }
1023 :
1024 :
1025 : /** \brief Parse one IPv4 address.
1026 : *
1027 : * This function checks the input parameter \p in and extracts the
1028 : * address and port. There is a port if the input strings includes
1029 : * a `':'` character.
1030 : *
1031 : * If this function detects that a port is not allowed and yet
1032 : * a `':'` character is found, then it generates an error and
1033 : * returns without adding anything to `result`.
1034 : *
1035 : * \param[in] in The input string with the address and optional port.
1036 : * \param[in,out] result The list of resulting addresses.
1037 : */
1038 65845 : void addr_parser::parse_address4(std::string const & in, addr_range::vector_t & result)
1039 : {
1040 131689 : std::string address(f_default_address4);
1041 131689 : std::string port_str(f_default_port == -1 ? std::string() : std::to_string(f_default_port));
1042 :
1043 65845 : std::string::size_type const p(in.find(':'));
1044 :
1045 65845 : if(f_flags[static_cast<int>(flag_t::PORT)]
1046 4 : || f_flags[static_cast<int>(flag_t::REQUIRED_PORT)])
1047 : {
1048 : // the address can include a port
1049 : //
1050 131684 : if(p != std::string::npos)
1051 : {
1052 : // get the address only if not empty (otherwise we want to
1053 : // keep the default)
1054 : //
1055 65807 : if(p > 0)
1056 : {
1057 65697 : address = in.substr(0, p);
1058 : }
1059 :
1060 : // get the port only if not empty (otherwise we want to
1061 : // keep the default)
1062 : //
1063 65807 : if(p + 1 < in.length())
1064 : {
1065 65782 : port_str = in.substr(p + 1);
1066 : }
1067 : }
1068 35 : else if(!in.empty())
1069 : {
1070 33 : address = in;
1071 : }
1072 : }
1073 : else
1074 : {
1075 3 : if(p != std::string::npos
1076 1 : && !f_flags[static_cast<int>(flag_t::PORT)]
1077 1 : && !f_flags[static_cast<int>(flag_t::REQUIRED_PORT)])
1078 : {
1079 1 : emit_error("Port not allowed (" + in + ").");
1080 1 : return;
1081 : }
1082 :
1083 2 : if(!in.empty())
1084 : {
1085 1 : address = in;
1086 : }
1087 : }
1088 :
1089 65844 : parse_address_port(address, port_str, result, "0.0.0.0");
1090 : }
1091 :
1092 :
1093 : /** \brief Parse one IPv6 address.
1094 : *
1095 : * This function checks the input parameter \p in and extracts the
1096 : * address and port. There is a port if the input strings includes
1097 : * a `':'` character after the closing square bracket (`']'`).
1098 : *
1099 : * If this function detects that a port is not allowed and yet
1100 : * a `':'` character is found, then it generates an error and
1101 : * returns without adding anything to `result`.
1102 : *
1103 : * \note
1104 : * This function can be called with an IPv6
1105 : *
1106 : * \param[in] in The input string with the address and optional port.
1107 : * \param[in,out] result The list of resulting addresses.
1108 : */
1109 65978 : void addr_parser::parse_address6(std::string const & in, addr_range::vector_t & result)
1110 : {
1111 65978 : std::string::size_type p(0);
1112 :
1113 131953 : std::string address(f_default_address6);
1114 131953 : std::string port_str(f_default_port == -1 ? std::string() : std::to_string(f_default_port));
1115 :
1116 : // if there is an address extract it otherwise put the default
1117 : //
1118 131956 : if(!in.empty()
1119 65978 : && in[0] == '[')
1120 : {
1121 65774 : p = in.find(']');
1122 :
1123 65774 : if(p == std::string::npos)
1124 : {
1125 1 : emit_error("IPv6 is missing the ']' (" + in + ").");
1126 1 : return;
1127 : }
1128 :
1129 65773 : if(p != 1)
1130 : {
1131 : // get the address only if not empty (otherwise we want to
1132 : // keep the default) -- so we actually support "[]" to
1133 : // represent "use the default address if defined".
1134 : //
1135 65772 : address = in.substr(1, p - 1);
1136 : }
1137 : }
1138 :
1139 : // on entry 'p' is either 0 or the position of the ']' character
1140 : //
1141 65977 : p = in.find(':', p);
1142 :
1143 65977 : if(p != std::string::npos)
1144 : {
1145 65969 : if(f_flags[static_cast<int>(flag_t::PORT)]
1146 2 : || f_flags[static_cast<int>(flag_t::REQUIRED_PORT)])
1147 : {
1148 : // there is also a port, extract it
1149 : //
1150 65967 : port_str = in.substr(p + 1);
1151 : }
1152 2 : else if(!f_flags[static_cast<int>(flag_t::PORT)]
1153 2 : && !f_flags[static_cast<int>(flag_t::REQUIRED_PORT)])
1154 : {
1155 2 : emit_error("Port not allowed (" + in + ").");
1156 2 : return;
1157 : }
1158 : }
1159 :
1160 65975 : parse_address_port(address, port_str, result, "::");
1161 : }
1162 :
1163 :
1164 : /** \brief Parse the address and port.
1165 : *
1166 : * This function receives an address and a port string and
1167 : * convert them in an addr object which gets saved in
1168 : * the specified result range vector.
1169 : *
1170 : * The address can be an IPv4 or an IPv6 address.
1171 : *
1172 : * The port may be numeric or a name such as `"http"`.
1173 : *
1174 : * \note
1175 : * This function is not responsible for handling the default address
1176 : * and default port. This is expected to be dealt with by the caller
1177 : * if required.
1178 : *
1179 : * \param[in] address The address to convert to binary.
1180 : */
1181 131819 : void addr_parser::parse_address_port(std::string address, std::string const & port_str, addr_range::vector_t & result, std::string const & default_address)
1182 : {
1183 : // make sure the port is good
1184 : //
1185 263638 : if(port_str.empty()
1186 131819 : && f_flags[static_cast<int>(flag_t::REQUIRED_PORT)])
1187 : {
1188 4 : emit_error("Required port is missing.");
1189 12 : return;
1190 : }
1191 :
1192 : // make sure the address is good
1193 : //
1194 131815 : if(address.empty())
1195 : {
1196 113 : if(f_flags[static_cast<int>(flag_t::REQUIRED_ADDRESS)])
1197 : {
1198 2 : emit_error("Required address is missing.");
1199 2 : return;
1200 : }
1201 : // internal default if no address was defined
1202 : // (TBD: should it be an IPv6 instead?)
1203 : //
1204 111 : address = default_address;
1205 : }
1206 :
1207 : // prepare hints for the the getaddrinfo() function
1208 : //
1209 : struct addrinfo hints;
1210 131813 : memset(&hints, 0, sizeof(hints));
1211 131813 : hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG | AI_V4MAPPED;
1212 131813 : hints.ai_family = AF_UNSPEC;
1213 :
1214 131813 : switch(f_protocol)
1215 : {
1216 : case IPPROTO_TCP:
1217 65775 : hints.ai_socktype = SOCK_STREAM;
1218 65775 : hints.ai_protocol = IPPROTO_TCP;
1219 65775 : break;
1220 :
1221 : case IPPROTO_UDP:
1222 66035 : hints.ai_socktype = SOCK_DGRAM;
1223 66035 : hints.ai_protocol = IPPROTO_UDP;
1224 66035 : break;
1225 :
1226 : }
1227 :
1228 : // convert address to binary
1229 : //
1230 131813 : struct addrinfo * addrlist(nullptr);
1231 : {
1232 131813 : errno = 0;
1233 131813 : int const r(getaddrinfo(address.c_str(), port_str.c_str(), &hints, &addrlist));
1234 131813 : if(r != 0)
1235 : {
1236 : // break on invalid addresses
1237 : //
1238 2 : int const e(errno); // if r == EAI_SYSTEM, then 'errno' is consistent here
1239 : emit_error("Invalid address in \""
1240 4 : + address
1241 6 : + (port_str.empty() ? "" : ":")
1242 4 : + port_str
1243 4 : + "\" error "
1244 8 : + std::to_string(r)
1245 4 : + " -- "
1246 6 : + gai_strerror(r)
1247 4 : + " (errno: "
1248 8 : + std::to_string(e)
1249 4 : + " -- "
1250 6 : + strerror(e)
1251 2 : + ").");
1252 2 : return;
1253 : }
1254 : }
1255 263622 : std::shared_ptr<struct addrinfo> ai(addrlist, addrinfo_deleter);
1256 :
1257 131811 : bool first(true);
1258 395437 : while(addrlist != nullptr)
1259 : {
1260 : // go through the addresses and create ranges and save that in the result
1261 : //
1262 131813 : if(addrlist->ai_family == AF_INET)
1263 : {
1264 65842 : if(addrlist->ai_addrlen != sizeof(struct sockaddr_in))
1265 : {
1266 : emit_error("Unsupported address size (" // LCOV_EXCL_LINE
1267 : + std::to_string(addrlist->ai_addrlen) // LCOV_EXCL_LINE
1268 : + ", expected" // LCOV_EXCL_LINE
1269 : + std::to_string(sizeof(struct sockaddr_in)) // LCOV_EXCL_LINE
1270 : + ")."); // LCOV_EXCL_LINE
1271 : }
1272 : else
1273 : {
1274 131684 : addr a(*reinterpret_cast<struct sockaddr_in *>(addrlist->ai_addr));
1275 : // in most cases we do not get a protocol from
1276 : // the getaddrinfo() function...
1277 65842 : if(addrlist->ai_protocol != 0)
1278 : {
1279 65841 : a.set_protocol(addrlist->ai_protocol);
1280 : }
1281 131684 : addr_range r;
1282 65842 : r.set_from(a);
1283 65842 : result.push_back(r);
1284 : }
1285 : }
1286 65971 : else if(addrlist->ai_family == AF_INET6)
1287 : {
1288 65971 : if(addrlist->ai_addrlen != sizeof(struct sockaddr_in6))
1289 : {
1290 : emit_error("Unsupported address size (" // LCOV_EXCL_LINE
1291 : + std::to_string(addrlist->ai_addrlen) // LCOV_EXCL_LINE
1292 : + ", expected " // LCOV_EXCL_LINE
1293 : + std::to_string(sizeof(struct sockaddr_in6)) // LCOV_EXCL_LINE
1294 : + ")."); // LCOV_EXCL_LINE
1295 : }
1296 : else
1297 : {
1298 131942 : addr a(*reinterpret_cast<struct sockaddr_in6 *>(addrlist->ai_addr));
1299 65971 : a.set_protocol(addrlist->ai_protocol);
1300 131942 : addr_range r;
1301 65971 : r.set_from(a);
1302 65971 : result.push_back(r);
1303 : }
1304 : }
1305 : else if(first) // LCOV_EXCL_LINE
1306 : {
1307 : // ignore errors from further addresses
1308 : //
1309 : emit_error("Unsupported address family " // LCOV_EXCL_LINE
1310 : + std::to_string(addrlist->ai_family) // LCOV_EXCL_LINE
1311 : + "."); // LCOV_EXCL_LINE
1312 : }
1313 :
1314 131813 : first = false;
1315 :
1316 131813 : addrlist = addrlist->ai_next;
1317 : }
1318 : }
1319 :
1320 :
1321 : /** \brief Parse a mask.
1322 : *
1323 : * If the input string is a decimal number, then use that as the
1324 : * number of bits to clear.
1325 : *
1326 : * If the mask is not just one decimal number, try to convert it
1327 : * as an address.
1328 : *
1329 : * If the string is neither a decimal number nor a valid IP address
1330 : * then the parser adds an error string to the f_error variable.
1331 : *
1332 : * \param[in] mask The mask to transform to binary.
1333 : * \param[in,out] cidr The address to which the mask will be added.
1334 : */
1335 471 : void addr_parser::parse_mask(std::string const & mask, addr & cidr)
1336 : {
1337 : // no mask?
1338 : //
1339 471 : if(mask.empty())
1340 : {
1341 : // in the current implementation this cannot happen since we
1342 : // do not call this function when mask is empty
1343 : //
1344 : // hwoever, the algorithm below expect that 'mask' is not
1345 : // empty (otherwise we get the case of 0 even though it
1346 : // may not be correct.)
1347 : //
1348 : return; // LCOV_EXCL_LINE
1349 : }
1350 :
1351 : // the mask may be a decimal number or an address, if just one number
1352 : // then it's not an address, so test that first
1353 : //
1354 468 : uint8_t mask_bits[16] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
1355 :
1356 : // convert the mask to an integer, if possible
1357 : //
1358 468 : int mask_count(0);
1359 : {
1360 1309 : for(char const * s(mask.c_str()); *s != '\0'; ++s)
1361 : {
1362 1039 : if(*s >= '0' && *s <= '9')
1363 : {
1364 856 : mask_count = mask_count * 10 + *s - '0';
1365 1697 : if(mask_count > 1000)
1366 : {
1367 : emit_error("Mask number too large ("
1368 30 : + mask
1369 15 : + ", expected a maximum of 128).");
1370 15 : return;
1371 : }
1372 : }
1373 : else
1374 : {
1375 183 : mask_count = -1;
1376 183 : break;
1377 : }
1378 : }
1379 : }
1380 :
1381 : // the conversion to an integer worked if mask_count != -1
1382 : //
1383 453 : if(mask_count != -1)
1384 : {
1385 270 : if(cidr.is_ipv4())
1386 : {
1387 40 : if(mask_count > 32)
1388 : {
1389 : emit_error("Unsupported mask size ("
1390 10 : + std::to_string(mask_count)
1391 5 : + ", expected 32 at the most for an IPv4).");
1392 5 : return;
1393 : }
1394 35 : mask_count = 32 - mask_count;
1395 : }
1396 : else
1397 : {
1398 230 : if(mask_count > 128)
1399 : {
1400 : emit_error("Unsupported mask size ("
1401 10 : + std::to_string(mask_count)
1402 5 : + ", expected 128 at the most for an IPv6).");
1403 5 : return;
1404 : }
1405 225 : mask_count = 128 - mask_count;
1406 : }
1407 :
1408 : // clear a few bits at the bottom of mask_bits
1409 : //
1410 260 : int idx(15);
1411 3314 : for(; mask_count > 8; mask_count -= 8, --idx)
1412 : {
1413 1527 : mask_bits[idx] = 0;
1414 : }
1415 260 : mask_bits[idx] = 255 << mask_count;
1416 : }
1417 : else //if(mask_count < 0)
1418 : {
1419 : // prepare hints for the the getaddrinfo() function
1420 : //
1421 : struct addrinfo hints;
1422 183 : memset(&hints, 0, sizeof(hints));
1423 183 : hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV | AI_ADDRCONFIG | AI_V4MAPPED;
1424 183 : hints.ai_family = AF_UNSPEC;
1425 :
1426 183 : switch(cidr.get_protocol())
1427 : {
1428 : case IPPROTO_TCP:
1429 89 : hints.ai_socktype = SOCK_STREAM;
1430 89 : hints.ai_protocol = IPPROTO_TCP;
1431 89 : break;
1432 :
1433 : case IPPROTO_UDP:
1434 94 : hints.ai_socktype = SOCK_DGRAM;
1435 94 : hints.ai_protocol = IPPROTO_UDP;
1436 94 : break;
1437 :
1438 : }
1439 :
1440 338 : std::string const port_str(std::to_string(cidr.get_port()));
1441 :
1442 : // if the mask is an IPv6, then it has to have the '[...]'
1443 338 : std::string m(mask);
1444 183 : if(cidr.is_ipv4())
1445 : {
1446 87 : if(mask[0] == '[')
1447 : {
1448 1 : emit_error("The address uses the IPv4 syntax, the mask cannot use IPv6.");
1449 1 : return;
1450 : }
1451 : }
1452 : else //if(!cidr.is_ipv4())
1453 : {
1454 96 : if(mask[0] != '[')
1455 : {
1456 1 : emit_error("The address uses the IPv6 syntax, the mask cannot use IPv4.");
1457 1 : return;
1458 : }
1459 95 : if(mask.back() != ']')
1460 : {
1461 1 : emit_error("The IPv6 mask is missing the ']' (" + mask + ").");
1462 1 : return;
1463 : }
1464 :
1465 : // note that we know that mask.length() >= 2 here since
1466 : // we at least have a '[' and ']'
1467 : //
1468 94 : m = mask.substr(1, mask.length() - 2);
1469 94 : if(m.empty())
1470 : {
1471 : // an empty mask is valid, it just means keep the default
1472 : // (getaddrinfo() fails on an empty string)
1473 : //
1474 3 : return;
1475 : }
1476 : }
1477 :
1478 : // if negative, we may have a full address here, so call the
1479 : // getaddrinfo() on this other string
1480 : //
1481 177 : struct addrinfo * masklist(nullptr);
1482 177 : errno = 0;
1483 177 : int const r(getaddrinfo(m.c_str(), port_str.c_str(), &hints, &masklist));
1484 177 : if(r != 0)
1485 : {
1486 : // break on invalid addresses
1487 : //
1488 15 : int const e(errno); // if r == EAI_SYSTEM, then 'errno' is consistent here
1489 : emit_error("Invalid mask in \"/"
1490 30 : + mask
1491 30 : + "\", error "
1492 60 : + std::to_string(r)
1493 30 : + " -- "
1494 45 : + gai_strerror(r)
1495 30 : + " (errno: "
1496 60 : + std::to_string(e)
1497 30 : + " -- "
1498 45 : + strerror(e)
1499 15 : + ").");
1500 15 : return;
1501 : }
1502 317 : std::shared_ptr<struct addrinfo> mask_ai(masklist, addrinfo_deleter);
1503 :
1504 162 : if(cidr.is_ipv4())
1505 : {
1506 76 : if(masklist->ai_family != AF_INET)
1507 : {
1508 : // this one happens when the user does not put the '[...]'
1509 : // around an IPv6 address
1510 : //
1511 2 : emit_error("Incompatible address between the address and"
1512 1 : " mask address (first was an IPv4 second an IPv6).");
1513 1 : return;
1514 : }
1515 75 : if(masklist->ai_addrlen != sizeof(struct sockaddr_in))
1516 : {
1517 : emit_error("Unsupported address size (" // LCOV_EXCL_LINE
1518 : + std::to_string(masklist->ai_addrlen) // LCOV_EXCL_LINE
1519 : + ", expected" // LCOV_EXCL_LINE
1520 : + std::to_string(sizeof(struct sockaddr_in)) // LCOV_EXCL_LINE
1521 : + ")."); // LCOV_EXCL_LINE
1522 : return; // LCOV_EXCL_LINE
1523 : }
1524 75 : memcpy(mask_bits + 12, &reinterpret_cast<struct sockaddr_in *>(masklist->ai_addr)->sin_addr.s_addr, 4); // last 4 bytes are the IPv4 address, keep the rest as 1s
1525 : }
1526 : else //if(!cidr.is_ipv4())
1527 : {
1528 86 : if(masklist->ai_family != AF_INET6)
1529 : {
1530 : // this one happens if the user puts the '[...]'
1531 : // around an IPv4 address
1532 : //
1533 12 : emit_error("Incompatible address between the address"
1534 6 : " and mask address (first was an IPv6 second an IPv4).");
1535 6 : return;
1536 : }
1537 80 : if(masklist->ai_addrlen != sizeof(struct sockaddr_in6))
1538 : {
1539 : emit_error("Unsupported address size (" // LCOV_EXCL_LINE
1540 : + std::to_string(masklist->ai_addrlen) // LCOV_EXCL_LINE
1541 : + ", expected " // LCOV_EXCL_LINE
1542 : + std::to_string(sizeof(struct sockaddr_in6)) // LCOV_EXCL_LINE
1543 : + ")."); // LCOV_EXCL_LINE
1544 : return; // LCOV_EXCL_LINE
1545 : }
1546 80 : memcpy(mask_bits, &reinterpret_cast<struct sockaddr_in6 *>(masklist->ai_addr)->sin6_addr.s6_addr, 16);
1547 : }
1548 : }
1549 :
1550 415 : cidr.set_mask(mask_bits);
1551 : }
1552 :
1553 :
1554 :
1555 :
1556 :
1557 :
1558 :
1559 :
1560 6 : }
1561 : // snap_addr namespace
1562 : // vim: ts=4 sw=4 et
|