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 IP address parser.
27 : *
28 : * This function is used to parse IP addresses from a string to a
29 : * vector of ranges.
30 : */
31 :
32 : // self
33 : //
34 : #include "libaddr/addr_parser.h"
35 : #include "libaddr/addr_exception.h"
36 :
37 :
38 : // advgetopt library
39 : //
40 : #include <advgetopt/validator_integer.h>
41 :
42 :
43 : // C++ library
44 : //
45 : #include <algorithm>
46 : #include <iostream>
47 :
48 :
49 : // C library
50 : //
51 : #include <ifaddrs.h>
52 : #include <netdb.h>
53 :
54 :
55 : // last include
56 : //
57 : #include <snapdev/poison.h>
58 :
59 :
60 :
61 : namespace addr
62 : {
63 :
64 :
65 : namespace
66 : {
67 :
68 :
69 : /** \brief Delete an addrinfo structure.
70 : *
71 : * This deleter is used to make sure all the addinfo get released when
72 : * an exception occurs or the function using such exists.
73 : *
74 : * \param[in] ai The addrinfo structure to free.
75 : */
76 131992 : void addrinfo_deleter(addrinfo * ai)
77 : {
78 131992 : freeaddrinfo(ai);
79 131992 : }
80 :
81 :
82 : }
83 :
84 :
85 :
86 :
87 :
88 : /** \brief Initialize an addr_parser object.
89 : *
90 : * This function initializes the addr_parser object.
91 : *
92 : * Especially, it calls the set_allow() functions a few times to set
93 : * flags which are expected to be true on initialization.
94 : */
95 131953 : addr_parser::addr_parser()
96 : {
97 : // allow addresses & DNS lookups by default
98 : //
99 131953 : set_allow(allow_t::ALLOW_ADDRESS, true);
100 131953 : set_allow(allow_t::ALLOW_ADDRESS_LOOKUP, true);
101 :
102 : // allow port after address
103 : //
104 131953 : set_allow(allow_t::ALLOW_PORT, true);
105 131953 : }
106 :
107 :
108 : /** \brief Set the default IP addresses.
109 : *
110 : * This function sets the default IP addresses to be used by the parser
111 : * when the input string of the parse() function does not include an IP
112 : * address.
113 : *
114 : * The \p address parameter cannot include a port. See
115 : * set_default_port() as a way to change the default port.
116 : *
117 : * The function expects either an IPv4 or an IPv6 address. It can be
118 : * called twice if you need to define both types of addresses (which
119 : * is often a good idea.)
120 : *
121 : * For example, the following input is considered valid when a default
122 : * address is defined:
123 : *
124 : * \code
125 : * parser.parse(":123");
126 : * \endcode
127 : *
128 : * It returns the default address and port 123. Note that by default
129 : * an address is mandatory unless a default address is defined.
130 : *
131 : * To prevent the parser from working when no default and no address
132 : * are specified, then make sure to set the REQUIRED_ADDRESS allow
133 : * flag to true:
134 : *
135 : * \code
136 : * parser.set_allow(parser.allow_t::ALLOW_REQUIRED_ADDRESS, true);
137 : * // now address is mandatory
138 : * \endcode
139 : *
140 : * To completely prevent the use of an address in an input string, set
141 : * the `ADDRESS` and `REQUIRED_ADDRESS` values to false:
142 : *
143 : * \code
144 : * parser.set_allow(parser.allow_t::ALLOW_ADDRESS, false);
145 : * parser.set_allow(parser.allow_t::ALLOW_REQUIRED_ADDRESS, false);
146 : * \endcode
147 : *
148 : * To remove both default IP addresses, call this function with an empty
149 : * string:
150 : *
151 : * \code
152 : * parser.set_default_address(std::string());
153 : * \endcode
154 : *
155 : * \todo
156 : * Consider saving the default IPs as addr structures and allow such
157 : * as input (keep in mind that the default could also represent multiple
158 : * addresses).
159 : *
160 : * \param[in] addr The new address.
161 : */
162 227 : void addr_parser::set_default_address(std::string const & address)
163 : {
164 227 : if(address.empty())
165 : {
166 3 : f_default_address4.clear();
167 3 : f_default_address6.clear();
168 : }
169 224 : else if(address[0] == '[')
170 : {
171 : // remove the '[' and ']'
172 : //
173 5 : if(address.back() != ']')
174 : {
175 3 : throw addr_invalid_argument("an IPv6 address starting with '[' must end with ']'.");
176 : }
177 2 : f_default_address6 = address.substr(1, address.length() - 2);
178 : }
179 219 : else if(address.find(':') != std::string::npos)
180 : {
181 103 : f_default_address6 = address;
182 : }
183 : else
184 : {
185 116 : f_default_address4 = address;
186 : }
187 224 : }
188 :
189 :
190 : /** \brief Retrieve the default IP address for IPv4 parsing.
191 : *
192 : * This function returns a copy of the default IP address used by
193 : * the parser when the input string does not include an IP address.
194 : *
195 : * If the function returns an empty string, then no default address
196 : * is defined.
197 : *
198 : * \return The default IPv4 address.
199 : *
200 : * \sa get_default_address6()
201 : * \sa set_default_address()
202 : */
203 115 : std::string const & addr_parser::get_default_address4() const
204 : {
205 115 : return f_default_address4;
206 : }
207 :
208 :
209 : /** \brief Retrieve the default IP address for IPv4 parsing.
210 : *
211 : * This function returns a copy of the default IP address used by
212 : * the parser when the input string does not include an IP address.
213 : *
214 : * If the function returns an empty string, then no default address
215 : * is defined.
216 : *
217 : * \return The default IPv6 address, without square brackets.
218 : *
219 : * \sa get_default_address4()
220 : * \sa set_default_address()
221 : */
222 115 : std::string const & addr_parser::get_default_address6() const
223 : {
224 115 : return f_default_address6;
225 : }
226 :
227 :
228 : /** \brief Define the default port.
229 : *
230 : * This function is used to define the default port to use in the address
231 : * parser object. By default this is set to -1 meaning: no default port.
232 : *
233 : * This function accepts any port number from 0 to 65535. It also accepts
234 : * -1 to reset the port back to "no default".
235 : *
236 : * To prevent the parser from working when no default and no port
237 : * are specified, then make sure to set the REQUIRED_PORT allow
238 : * flag to true:
239 : *
240 : * \code
241 : * parser.set_allow(parser.allow_t::ALLOW_REQUIRED_PORT, true);
242 : * // now port is mandatory
243 : * \endcode
244 : *
245 : * To completely prevent the use of a port in an input string, set
246 : * the `PORT` and `REQUIRED_PORT` values to false:
247 : *
248 : * \code
249 : * parser.set_allow(parser.allow_t::ALLOW_PORT, false);
250 : * parser.set_allow(parser.allow_t::ALLOW_REQUIRED_PORT, false);
251 : * \endcode
252 : *
253 : * \exception addr_invalid_argument_exception
254 : * If the port number is out of range, then this expcetion is raised.
255 : * The allowed range for a port is 0 to 65535. This function also
256 : * accepts -1 meaning that no default port is specified.
257 : *
258 : * \param[in] port The new default port.
259 : */
260 84 : void addr_parser::set_default_port(int const port)
261 : {
262 84 : if(port < -1
263 70 : || port > 65535)
264 : {
265 25 : throw addr_invalid_argument("addr_parser::set_default_port(): port must be in range [-1..65535].");
266 : }
267 :
268 59 : f_default_port = port;
269 59 : }
270 :
271 :
272 : /** \brief Retrieve the default port.
273 : *
274 : * This function retrieves the default port as defined by the
275 : * set_default_port() function.
276 : */
277 76 : int addr_parser::get_default_port() const
278 : {
279 76 : return f_default_port;
280 : }
281 :
282 :
283 : /** \brief Define the default mask.
284 : *
285 : * This function is used to define the default mask. Note that the
286 : * default mask will not be used at all if the allow_t::ALLOW_MASK allow
287 : * flag is not set to true:
288 : *
289 : * \code
290 : * parser.set_allow(parser.allow_t::ALLOW_MASK, true);
291 : * parser.set_default_mask("255.255.0.0");
292 : * parser.set_default_mask("[ffff:ffff:ffff::]");
293 : * \endcode
294 : *
295 : * The IPv6 mask does not require the square brackets (`'['` and `']'`).
296 : *
297 : * To remove the default mask, call this function with an empty
298 : * string:
299 : *
300 : * \code
301 : * parser.set_default_mask(std::string());
302 : * \endcode
303 : *
304 : * \note
305 : * As you can see, here we expect the mask to be a string. This is because
306 : * it gets parsed as if it came from the input string of the parser. This
307 : * also means that if the mask is invalid, it will not be detected until
308 : * you attempt to parse an input string that does not include a mask and
309 : * the default gets used.
310 : *
311 : * \todo
312 : * Add a check of the default mask when it gets set so we can throw on
313 : * errors and that way it is much more likely that programmers can fix
314 : * their errors early. (Actually by pre-parsing we could save it as
315 : * an addr and allow a `set_default_mask(addr ...)`!)
316 : *
317 : * \param[in] mask The mask to use by default.
318 : */
319 111 : void addr_parser::set_default_mask(std::string const & mask)
320 : {
321 111 : if(mask.empty())
322 : {
323 3 : f_default_mask4.clear();
324 3 : f_default_mask6.clear();
325 : }
326 108 : else if(mask[0] == '[')
327 : {
328 : // remove the '[' and ']'
329 : //
330 30 : if(mask.back() != ']')
331 : {
332 3 : throw addr_invalid_argument("an IPv6 mask starting with '[' must end with ']'.");
333 : }
334 27 : f_default_mask6 = mask.substr(1, mask.length() - 2);
335 : }
336 78 : else if(mask.find(':') != std::string::npos)
337 : {
338 25 : f_default_mask6 = mask;
339 : }
340 : else
341 : {
342 53 : f_default_mask4 = mask;
343 : }
344 108 : }
345 :
346 :
347 : /** \brief Retrieve the default mask.
348 : *
349 : * This function returns a reference to the mask as set by the
350 : * set_default_mask() function. The value is an empty string by
351 : * default.
352 : *
353 : * The default mask will be used if no mask is specified in the
354 : * input string to the parse() function. When no default mask
355 : * is defined, the mask is set to all 1s.
356 : *
357 : * \note
358 : * The default mask is a string, not a binary mask. It gets
359 : * converted by the parser at the time it is required.
360 : *
361 : * \return The default mask.
362 : *
363 : * \sa get_default_mask6()
364 : * \sa set_default_mask()
365 : */
366 12 : std::string const & addr_parser::get_default_mask4() const
367 : {
368 12 : return f_default_mask4;
369 : }
370 :
371 :
372 : /** \brief Retrieve the default mask.
373 : *
374 : * This function returns a reference to the mask as set by the
375 : * set_default_mask() function. The value is an empty string by
376 : * default.
377 : *
378 : * The default mask will be used if no mask is specified in the
379 : * input string to the parse() function. When no default mask
380 : * is defined, the mask is set to all 1s.
381 : *
382 : * \note
383 : * The default mask is a string, not a binary mask. It gets
384 : * converted by the parser at the time it is required.
385 : *
386 : * \return The default mask.
387 : *
388 : * \sa get_default_mask4()
389 : * \sa set_default_mask()
390 : */
391 12 : std::string const & addr_parser::get_default_mask6() const
392 : {
393 12 : return f_default_mask6;
394 : }
395 :
396 :
397 : /** \brief Set the protocol to use to filter addresses.
398 : *
399 : * This function sets the protocol as one of the following:
400 : *
401 : * \li "ip" -- only return IP address supporting the IP protocol
402 : * (this is offered because getaddrinfo() may return such IP addresses.)
403 : * \li "tcp" -- only return IP address supporting TCP
404 : * \li "udp" -- only return IP address supporting UDP
405 : *
406 : * Any other value is refused. To reset the protocol to the default,
407 : * which is "do not filter by protocol", call the clear_protocol().
408 : *
409 : * \exception addr_invalid_argument_exception
410 : * If the string passed to this function is not one of the acceptable
411 : * protocols (ip, tcp, udp), then this exception is raised.
412 : *
413 : * \param[in] protocol The default protocol for this parser.
414 : *
415 : * \sa clear_protocol()
416 : * \sa get_protocol()
417 : */
418 118 : void addr_parser::set_protocol(std::string const & protocol)
419 : {
420 118 : if(protocol == "ip")
421 : {
422 2 : f_protocol = IPPROTO_IP;
423 : }
424 116 : else if(protocol == "tcp")
425 : {
426 107 : f_protocol = IPPROTO_TCP;
427 : }
428 9 : else if(protocol == "udp")
429 : {
430 6 : f_protocol = IPPROTO_UDP;
431 : }
432 : else
433 : {
434 : // not a protocol we support
435 : //
436 : throw addr_invalid_argument(
437 6 : std::string("unknown protocol \"")
438 9 : + protocol
439 9 : + "\", expected \"tcp\" or \"udp\".");
440 : }
441 115 : }
442 :
443 :
444 : /** \brief Set the protocol to use to filter addresses.
445 : *
446 : * This function sets the protocol as one of the following:
447 : *
448 : * \li IPPROTO_IP -- only return IP address supporting the IP protocol
449 : * (this is offered because getaddrinfo() may return such IP addresses.)
450 : * \li IPPROTO_TCP -- only return IP address supporting TCP
451 : * \li IPPROTO_UDP -- only return IP address supporting UDP
452 : *
453 : * Any other value is refused. To reset the protocol to the default,
454 : * which is "do not filter by protocol", call the clear_protocol().
455 : *
456 : * \exception addr_invalid_argument_exception
457 : * If the string passed to this function is not one of the acceptable
458 : * protocols (ip, tcp, udp), then this exception is raised.
459 : *
460 : * \param[in] protocol The default protocol for this parser.
461 : *
462 : * \sa clear_protocol()
463 : * \sa get_protocol()
464 : */
465 132021 : void addr_parser::set_protocol(int const protocol)
466 : {
467 : // make sure that's a protocol we support
468 : //
469 132021 : switch(protocol)
470 : {
471 131821 : case IPPROTO_IP:
472 : case IPPROTO_TCP:
473 : case IPPROTO_UDP:
474 131821 : break;
475 :
476 200 : default:
477 : throw addr_invalid_argument(
478 400 : std::string("unknown protocol \"")
479 800 : + std::to_string(protocol)
480 600 : + "\", expected \"tcp\" or \"udp\".");
481 :
482 : }
483 :
484 131821 : f_protocol = protocol;
485 131821 : }
486 :
487 :
488 : /** \brief Use this function to reset the protocol back to "no default."
489 : *
490 : * This function sets the protocol to -1 (which is something you cannot
491 : * do by calling the set_protocol() functions above.)
492 : *
493 : * The -1 special value means that the protocol is not defined, that
494 : * there is no default. In most cases this means all the addresses
495 : * that match, ignoring the protocol, will be returned by the parse()
496 : * function.
497 : *
498 : * \sa set_protocol()
499 : * \sa get_protocol()
500 : */
501 3 : void addr_parser::clear_protocol()
502 : {
503 3 : f_protocol = -1;
504 3 : }
505 :
506 :
507 : /** \brief Retrieve the protocol as defined by the set_protocol().
508 : *
509 : * This function returns the protocol number as defined by the
510 : * set_protocol.
511 : *
512 : * When defined, the protocol is used whenever we call the
513 : * getaddrinfo() function. In general, this means the IP addresses
514 : * returned will have to match that protocol.
515 : *
516 : * This function may return -1. The value -1 is used as "do not
517 : * filter by protocol". The protocol can be set to -1 by calling
518 : * the clear_protocol() function.
519 : *
520 : * \return The parser default protocol.
521 : *
522 : * \sa set_protocol()
523 : * \sa clear_protocol()
524 : */
525 216 : int addr_parser::get_protocol() const
526 : {
527 216 : return f_protocol;
528 : }
529 :
530 :
531 : /** \brief Change the set of flags defining the sorting order.
532 : *
533 : * The parser, once done parsing all the input, will sort the addresses
534 : * according to these flags.
535 : *
536 : * By default, it does not re-arrange the order in which the addresses
537 : * were defined.
538 : *
539 : * The parser is capable of sorting by IP type (IPv6 or IPv4 first),
540 : * and simply by IP addresses. It can also merge adjacent or overlapping
541 : * ranges into a single range.
542 : *
543 : * \exception addr_invalid_argument
544 : * This exception is raised you set SORT_IPV6_FIRST and SORT_IPV4_FIRST
545 : * at the same time because these flags are mutually exclusive.
546 : *
547 : * \param[in] sort The sort parameters.
548 : *
549 : * \sa get_sort_order()
550 : */
551 0 : void addr_parser::set_sort_order(sort_t const sort)
552 : {
553 0 : if((sort & (SORT_IPV6_FIRST | SORT_IPV4_FIRST)) == (SORT_IPV6_FIRST | SORT_IPV4_FIRST))
554 : {
555 0 : throw addr_invalid_argument("addr_parser::set_sort_order(): flags SORT_IPV6_FIRST and SORT_IPV4_FIRST are mutually exclusive.");
556 : }
557 :
558 0 : f_sort = sort;
559 0 : }
560 :
561 :
562 : /** \brief Get the flags defining the sort order of the parser.
563 : *
564 : * This function returns the sort order of the parser as a set of flags.
565 : *
566 : * By default this value is set to NO_SORT meaning that the input is
567 : * kept as is.
568 : *
569 : * \return The sort order flags.
570 : *
571 : * \sa set_sort_order()
572 : */
573 0 : sort_t addr_parser::get_sort_order() const
574 : {
575 0 : return f_sort;
576 : }
577 :
578 :
579 : /** \brief Set or clear allow flags in the parser.
580 : *
581 : * This parser has a set of flags it uses to know whether the input
582 : * string can include certain things such as a port or a mask.
583 : *
584 : * This function is used to allow or require certain parameters and
585 : * to disallow others.
586 : *
587 : * By default, the ADDRESS and PORT flags are set, meaning that an
588 : * address and a port can appear, but either or both are optinal.
589 : * If unspecified, then the default will be used. If not default
590 : * is defined, then the parser may fail in this situation.
591 : *
592 : * One problem is that we include contradictory syntatical features.
593 : * The parser supports lists of addresses separated by commas and
594 : * lists of ports separated by commas. Both are not supported
595 : * simultaneously. This means you want to allow multiple addresses
596 : * separated by commas, the function makes sure that the multiple
597 : * port separated by commas support is turned off.
598 : *
599 : * \li `ADDRESS` -- the IP address is allowed, but optional
600 : * \li `REQUIRED_ADDRESS` -- the IP address is mandatory
601 : * \li `PORT` -- the port is allowed, but optional
602 : * \li `REQUIRED_PORT` -- the port is mandatory
603 : * \li `MASK` -- the mask is allowed, but optional
604 : * \li `MULTI_ADDRESSES_COMMAS` -- the input can have multiple addresses
605 : * separated by commas (prevents MULTI_PORTS_COMMAS)
606 : * \li `MULTI_ADDRESSES_SPACES` -- the input can have multiple addresses
607 : * separated by spaces
608 : * \li `MULTI_PORTS_SEMICOLONS` -- the input can have multiple ports
609 : * separated by semicolons _NOT IMPLEMENTED YET_
610 : * \li `MULTI_PORTS_COMMAS` -- the input can have multiple ports separated
611 : * by commas (prevents MULTI_ADDRESSES_COMMAS) _NOT IMPLEMENTED YET_
612 : * \li `PORT_RANGE` -- the input supports port ranges (p1-p2) _NOT
613 : * IMPLEMENTED YET_
614 : * \li `ADDRESS_RANGE` -- the input supports address ranges (addr-addr) _NOT
615 : * IMPLEMENTED YET_
616 : *
617 : * The `MULTI_ADDRESSES_COMMAS` and `MULTI_ADDRESSES_SPACES` can be used
618 : * together in which case any number of both characters are accepted
619 : * between addresses.
620 : *
621 : * Note that the `MULTI_ADDRESSES_COMMAS` and `MULTI_PORTS_COMMAS` are
622 : * mutually exclusive. The last set_allow() counts as the one you are
623 : * interested in.
624 : *
625 : * \param[in] flag The flag to set or clear.
626 : * \param[in] allow Whether to allow (true) or disallow (false).
627 : *
628 : * \sa get_allow()
629 : */
630 396412 : void addr_parser::set_allow(allow_t const flag, bool const allow)
631 : {
632 396412 : if(flag < static_cast<allow_t>(0)
633 396392 : || flag >= allow_t::ALLOW_max)
634 : {
635 40 : throw addr_invalid_argument("addr_parser::set_allow(): flag has to be one of the valid flags.");
636 : }
637 :
638 396372 : f_flags[static_cast<int>(flag)] = allow;
639 :
640 : // if we just set a certain flag, others may need to go to false
641 : //
642 396372 : if(allow)
643 : {
644 : // we can only support one type of commas
645 : //
646 396347 : switch(flag)
647 : {
648 5 : case allow_t::ALLOW_MULTI_ADDRESSES_COMMAS:
649 5 : f_flags[static_cast<int>(allow_t::ALLOW_MULTI_PORTS_COMMAS)] = false;
650 5 : break;
651 :
652 2 : case allow_t::ALLOW_MULTI_PORTS_COMMAS:
653 2 : f_flags[static_cast<int>(allow_t::ALLOW_MULTI_ADDRESSES_COMMAS)] = false;
654 2 : break;
655 :
656 396340 : default:
657 396340 : break;
658 :
659 : }
660 : }
661 396372 : }
662 :
663 :
664 : /** \brief Retrieve the current statius of an allow flag.
665 : *
666 : * This function returns the current status of the allow flags.
667 : *
668 : * By default, the `ADDRESS` and `PORT` flags are set to true.
669 : * All the other flags are set to false.
670 : *
671 : * You may change the value of an allow flag by calling the
672 : * set_allow() function.
673 : *
674 : * \param[in] flag Which flag is to be checked.
675 : *
676 : * \return The value of the flag: true or false.
677 : *
678 : * \sa set_allow()
679 : */
680 857275 : bool addr_parser::get_allow(allow_t const flag) const
681 : {
682 857275 : if(flag < static_cast<allow_t>(0)
683 857265 : || flag >= allow_t::ALLOW_max)
684 : {
685 20 : throw addr_invalid_argument("addr_parser::get_allow(): flag has to be one of the valid flags.");
686 : }
687 :
688 857255 : return f_flags[static_cast<int>(flag)];
689 : }
690 :
691 :
692 : /** \brief Check whether errors were registered so far.
693 : *
694 : * This function returns true if the system detected errors in one
695 : * of the previous calls to parse(). The flag can be cleared using
696 : * the clear_errors() function.
697 : *
698 : * On construction and after a call to clear_error(), this flag is
699 : * always false. If you are to call parser() multiple times with
700 : * the same addr_parser object, then you want to make sure to call
701 : * the clear_errors() function before calling the parse() function.
702 : * Otherwise you won't know whether errors occurred in a earlier
703 : * or later call.
704 : *
705 : * \code
706 : * // first time, not required
707 : * parser.parse(...);
708 : * ...
709 : *
710 : * // next time, required
711 : * parser.clear_errors();
712 : * parser.parse(...);
713 : * ...
714 : * \endcode
715 : *
716 : * \return true if errors were generated.
717 : */
718 131832 : bool addr_parser::has_errors() const
719 : {
720 131832 : return !f_error.empty();
721 : }
722 :
723 :
724 : /** \brief Emit an error and save it in this class.
725 : *
726 : * This function adds the message to the error string part of this
727 : * object. A newline is also added at the end of the message.
728 : *
729 : * Next the function increments the error counter.
730 : *
731 : * \note
732 : * You are expected to emit one error at a time. If you want to
733 : * emit several messages in a row, that will work and properly
734 : * count each message.
735 : *
736 : * \param[in] msg The message to add to the parser error messages.
737 : *
738 : * \sa error_messages()
739 : */
740 65 : void addr_parser::emit_error(std::string const & msg)
741 : {
742 65 : f_error += msg;
743 65 : f_error += "\n";
744 65 : ++f_error_count;
745 65 : }
746 :
747 :
748 : /** \brief Return the current error messages.
749 : *
750 : * The error messages are added to the addr_parser using the
751 : * emit_error() function.
752 : *
753 : * This function does not clear the list of error messages.
754 : * To do that, call the clear_errors() function.
755 : *
756 : * The number of messages can be determined by counting the
757 : * number of "\n" characters in the string. The error_count()
758 : * will return that same number (assuming no message included
759 : * a '\n' character when emit_error() was called.)
760 : *
761 : * \return A string with the list of messages.
762 : *
763 : * \sa emit_error()
764 : * \sa clear_errors()
765 : */
766 65 : std::string const & addr_parser::error_messages() const
767 : {
768 65 : return f_error;
769 : }
770 :
771 :
772 : /** \brief Return the number of error messages that were emitted.
773 : *
774 : * Each time the emit_error() function is called, the error
775 : * counter is incremented by 1. This function returns that
776 : * error counter.
777 : *
778 : * The clear_errors() function can be used to clear the
779 : * counter back to zero.
780 : *
781 : * \return The number of errors that were emitted so far.
782 : *
783 : * \sa emit_error()
784 : */
785 65 : int addr_parser::error_count() const
786 : {
787 65 : return f_error_count;
788 : }
789 :
790 :
791 : /** \brief Clear the error message and error counter.
792 : *
793 : * This function clears all the error messages and reset the
794 : * counter back to zero. In order words, it will be possible
795 : * to tell how many times the emit_error() was called since
796 : * the start or the last clear_errors() call.
797 : *
798 : * To retrieve a copy of the error counter, use the error_count()
799 : * function.
800 : *
801 : * \sa error_count()
802 : */
803 5 : void addr_parser::clear_errors()
804 : {
805 5 : f_error.clear();
806 5 : f_error_count = 0;
807 5 : }
808 :
809 :
810 : /** \brief Parse a string of addresses, ports, and masks.
811 : *
812 : * This function is used to parse the list of addresses defined
813 : * in the \p in parameter.
814 : *
815 : * One address is composed of one to three elements:
816 : *
817 : * \code
818 : * [ address ] [ ':' port ] [ '/' mask ]
819 : * \endcode
820 : *
821 : * Although all three elements are optional (at least by default),
822 : * a valid address is expected to include at least one of the
823 : * three elements. (i.e. an empty string is just skipped silently.)
824 : *
825 : * ### Multiple Addresses
826 : *
827 : * Multiple addresses can be defined if at least one of the
828 : * `MULTI_ADDRESSES_COMMAS` or `MULTI_ADDRESSES_SPACES` allow
829 : * flags is set to true.
830 : *
831 : * Next comes `MULTI_ADDRESSES_COMMAS`: if set to true, addresses
832 : * must be separated by commas and spaces are not allowed.
833 : *
834 : * Finally we have `MULTI_ADDRESSES_SPACES`. If that one is true, then
835 : * addresses must be separated by spaces and commas are not allowed.
836 : *
837 : * ### Make Address Field Required
838 : *
839 : * To make the address field a required field, set the
840 : * `REQUIRED_ADDRESS` flag (see set_allow()) to true and do not define a
841 : * default address (see set_default_address()).
842 : *
843 : * ### Make Port Field Required
844 : *
845 : * To make the port field a required fiel, set the `REQUIRED_PORT`
846 : * flag (see set_allow()) to true and do not define a default port
847 : * (see set_default_port()).
848 : *
849 : * ### Allow Mask
850 : *
851 : * The mask cannot be made mandatory. However, you have to set
852 : * the `MASK` flag to true to allow it. By default it is not
853 : * allowed.
854 : *
855 : * ### Ranges
856 : *
857 : * Ranges are not yet implemented.
858 : *
859 : * ### Sort
860 : *
861 : * After the function parsed all the input, it sorts the results in
862 : * the vector of ranges. Ranges are sorted using the addr_range::compare()
863 : * function. Sorting can also be used to merge ranges. So if two ranges
864 : * have an overlap or are adjacent, the union of those two ranges will
865 : * be kept and the two ranges are otherwise removed from the result.
866 : *
867 : * The sort is particularly useful if you first want to connect with
868 : * IPv6 addresses instead of IPv4 (which is the current expected behavior
869 : * of your services and tools).
870 : *
871 : * \param[in] in The input string to be parsed.
872 : *
873 : * \return A vector of address ranges, see has_errors() to determine whether
874 : * errors occurred while parsing the input.
875 : *
876 : * \sa has_errors()
877 : */
878 131841 : addr_range::vector_t addr_parser::parse(std::string const & in)
879 : {
880 131841 : addr_range::vector_t result;
881 :
882 263682 : if(get_allow(allow_t::ALLOW_MULTI_ADDRESSES_COMMAS)
883 131841 : && get_allow(allow_t::ALLOW_MULTI_ADDRESSES_SPACES))
884 : {
885 2 : std::string const comma_space(", ");
886 1 : std::string::size_type s(0);
887 17 : while(s < in.length())
888 : {
889 8 : auto const it(std::find_first_of(in.begin() + s, in.end(), comma_space.begin(), comma_space.end()));
890 8 : std::string::size_type const e(it == in.end() ? in.length() : it - in.begin());
891 8 : if(e > s)
892 : {
893 3 : parse_cidr(in.substr(s, e - s), result);
894 : }
895 8 : s = e + 1;
896 : }
897 : }
898 263680 : else if(get_allow(allow_t::ALLOW_MULTI_ADDRESSES_COMMAS)
899 131840 : || get_allow(allow_t::ALLOW_MULTI_ADDRESSES_SPACES))
900 : {
901 2 : char const sep(get_allow(allow_t::ALLOW_MULTI_ADDRESSES_COMMAS) ? ',' : ' ');
902 2 : std::string::size_type s(0);
903 24 : while(s < in.length())
904 : {
905 11 : std::string::size_type e(in.find(sep, s));
906 11 : if(e == std::string::npos)
907 : {
908 2 : e = in.length();
909 : }
910 11 : if(e > s)
911 : {
912 6 : parse_cidr(in.substr(s, e - s), result);
913 : }
914 11 : s = e + 1;
915 : }
916 : }
917 : else
918 : {
919 131838 : parse_cidr(in, result);
920 : }
921 :
922 131841 : if((f_sort & SORT_FULL) != 0)
923 : {
924 0 : std::sort(
925 : result.begin()
926 : , result.end()
927 0 : , [](auto const & a, auto const & b)
928 : {
929 0 : switch(a.compare(b))
930 : {
931 0 : case compare_t::COMPARE_SMALLER:
932 : case compare_t::COMPARE_OVERLAP_SMALL_VS_LARGE:
933 : case compare_t::COMPARE_INCLUDED:
934 : case compare_t::COMPARE_IPV6_VS_IPV4:
935 : case compare_t::COMPARE_SMALL_VS_LARGE:
936 : case compare_t::COMPARE_FOLLOWS:
937 : case compare_t::COMPARE_FIRST:
938 0 : return true;
939 :
940 0 : default:
941 0 : return false;
942 :
943 : }
944 : });
945 : }
946 :
947 131841 : if((f_sort & SORT_MERGE) != 0)
948 : {
949 0 : std::size_t max(result.size());
950 0 : for(std::size_t idx(0); idx < max - 1; ++idx)
951 : {
952 0 : addr_range const r(result[idx].union_if_possible(result[idx + 1]));
953 0 : if(!r.is_empty())
954 : {
955 : // merge worked
956 : //
957 0 : result[idx] = r;
958 0 : result.erase(result.begin() + idx + 1);
959 0 : --max;
960 : }
961 : }
962 : }
963 :
964 131841 : if((f_sort & SORT_IPV4_FIRST) != 0)
965 : {
966 0 : std::sort(
967 : result.begin()
968 : , result.end()
969 0 : , [](auto const & a, auto const & b)
970 : {
971 0 : return a.compare(b) == compare_t::COMPARE_IPV4_VS_IPV6;
972 0 : });
973 : }
974 131841 : else if((f_sort & SORT_IPV6_FIRST) != 0)
975 : {
976 0 : std::sort(
977 : result.begin()
978 : , result.end()
979 0 : , [](auto const & a, auto const & b)
980 : {
981 0 : return a.compare(b) == compare_t::COMPARE_IPV6_VS_IPV4;
982 0 : });
983 : }
984 :
985 131841 : return result;
986 : }
987 :
988 :
989 : /** \brief Check one address.
990 : *
991 : * This function checks one address, although if it is a name, it could
992 : * represent multiple IP addresses.
993 : *
994 : * This function separate the address:port from the mask if the mask is
995 : * allowed. Then it parses the address:port part and the mask separately.
996 : *
997 : * \param[in] in The address to parse.
998 : * \param[in,out] result The list of resulting addresses.
999 : */
1000 131847 : void addr_parser::parse_cidr(std::string const & in, addr_range::vector_t & result)
1001 : {
1002 131847 : if(get_allow(allow_t::ALLOW_MASK))
1003 : {
1004 : // check whether there is a mask
1005 : //
1006 948 : std::string mask;
1007 :
1008 948 : std::string address;
1009 474 : std::string::size_type const p(in.find('/'));
1010 474 : if(p != std::string::npos)
1011 : {
1012 420 : address = in.substr(0, p);
1013 420 : mask = in.substr(p + 1);
1014 : }
1015 : else
1016 : {
1017 54 : address = in;
1018 : }
1019 :
1020 474 : int const errcnt(f_error_count);
1021 :
1022 : // handle the address first
1023 : //
1024 948 : addr_range::vector_t addr_mask;
1025 474 : parse_address(address, mask, addr_mask);
1026 :
1027 : // now check for the mask
1028 : //
1029 948 : for(auto & am : addr_mask)
1030 : {
1031 948 : std::string m(mask);
1032 474 : if(m.empty())
1033 : {
1034 : // the mask was not defined in the input, then adapt it to
1035 : // the type of address we got in 'am'
1036 : //
1037 56 : if(am.get_from().is_ipv4())
1038 : {
1039 29 : m = f_default_mask4;
1040 : }
1041 : else
1042 : {
1043 : // parse_mask() expects '[...]' around IPv6 addresses
1044 : //
1045 27 : m = "[" + f_default_mask6 + "]";
1046 : }
1047 : }
1048 :
1049 474 : parse_mask(m, am.get_from());
1050 : }
1051 :
1052 : // now append the list to the result if no errors occurred
1053 : //
1054 474 : if(errcnt == f_error_count)
1055 : {
1056 : // note: no need to test the SORT_NO_EMPTY since that was already
1057 : // done when adding addresses to addr_mask
1058 : //
1059 424 : result.insert(result.end(), addr_mask.begin(), addr_mask.end());
1060 : }
1061 : }
1062 : else
1063 : {
1064 : // no mask allowed, if there is one, this call will fail
1065 : //
1066 131373 : parse_address(in, std::string(), result);
1067 : }
1068 131847 : }
1069 :
1070 :
1071 : /** \brief Parse one address.
1072 : *
1073 : * This function is called with one address. It determines whether we
1074 : * are dealing with an IPv4 or an IPv6 address and call the
1075 : * corresponding sub-function.
1076 : *
1077 : * An address is considered an IPv6 address if it starts with a '['
1078 : * character.
1079 : *
1080 : * \note
1081 : * The input cannot include a mask. It has to already have been
1082 : * removed.
1083 : *
1084 : * \note
1085 : * The mask parameter is only used to determine whether this function
1086 : * is being called with an IPv6 or not. It is otherwise ignored.
1087 : *
1088 : * \param[in] in The input address eventually including a port.
1089 : * \param[in] mask The mask used to determine whether we are dealing with
1090 : * an IPv6 or not.
1091 : * \param[in,out] result The list of resulting addresses.
1092 : */
1093 131847 : void addr_parser::parse_address(std::string const & in, std::string const & mask, addr_range::vector_t & result)
1094 : {
1095 : // With our only supported format, ipv6 addresses must be between square
1096 : // brackets. The address may just be a mask in which case the '[' may
1097 : // not be at the very start (i.e. "/[ffff:ffff::]")
1098 : //
1099 263694 : if(in.empty()
1100 131847 : || in[0] == ':') // if it start with ':' then there is no address
1101 : {
1102 : // if the address is empty, then use the mask to determine the
1103 : // type of IP address (note: if the address starts with ':'
1104 : // it is considered empty since an IPv6 would have a '[' at
1105 : // the start)
1106 : //
1107 318 : if(!mask.empty())
1108 : {
1109 111 : if(mask[0] == '[')
1110 : {
1111 : // IPv6 parsing
1112 : //
1113 5 : parse_address6(in, result);
1114 : }
1115 : else
1116 : {
1117 : // if the number is 33 or more, it has to be IPv6, otherwise
1118 : // we cannot know...
1119 : //
1120 106 : int mask_count(0);
1121 356 : for(char const * s(mask.c_str()); *s != '\0'; ++s)
1122 : {
1123 260 : if(*s >= '0' && *s <= '9')
1124 : {
1125 255 : mask_count = mask_count * 10 + *s - '0';
1126 505 : if(mask_count > 1000)
1127 : {
1128 : // not valid
1129 : //
1130 5 : mask_count = -1;
1131 5 : break;;
1132 : }
1133 : }
1134 : else
1135 : {
1136 : // not a valid decimal number
1137 : //
1138 5 : mask_count = -1;
1139 5 : break;
1140 : }
1141 : }
1142 106 : if(mask_count > 32)
1143 : {
1144 96 : parse_address6(in, result);
1145 : }
1146 : else
1147 : {
1148 10 : parse_address4(in, result);
1149 : }
1150 : }
1151 : }
1152 : else
1153 : {
1154 414 : if(f_default_address4.empty()
1155 207 : && !f_default_address6.empty())
1156 : {
1157 102 : parse_address6(in, result);
1158 : }
1159 : else
1160 : {
1161 105 : parse_address4(in, result);
1162 : }
1163 : }
1164 : }
1165 : else
1166 : {
1167 : // if an address has a ']' then it is IPv6 even if the '['
1168 : // is missing, that being said, it is still considered
1169 : // invalid as per our processes
1170 : //
1171 263058 : if(in[0] == '['
1172 131529 : || in.find(']') != std::string::npos)
1173 : {
1174 65778 : parse_address6(in, result);
1175 : }
1176 : else
1177 : {
1178 : // if there is no port, then a ':' can be viewed as an IPv6
1179 : // address because there is no other ':', but if there are
1180 : // '.' before the ':' then we assume that it is IPv4 still
1181 : //
1182 131502 : if(!get_allow(allow_t::ALLOW_PORT)
1183 65751 : && !get_allow(allow_t::ALLOW_REQUIRED_PORT))
1184 : {
1185 3 : std::string::size_type const p(in.find(':'));
1186 3 : if(p != std::string::npos
1187 3 : && in.find('.') > p)
1188 : {
1189 1 : parse_address6(in, result);
1190 : }
1191 : else
1192 : {
1193 2 : parse_address4(in, result);
1194 : }
1195 : }
1196 : else
1197 : {
1198 65748 : parse_address4(in, result);
1199 : }
1200 : }
1201 : }
1202 131847 : }
1203 :
1204 :
1205 : /** \brief Parse one IPv4 address.
1206 : *
1207 : * This function checks the input parameter \p in and extracts the
1208 : * address and port. There is a port if the input strings includes
1209 : * a `':'` character.
1210 : *
1211 : * If this function detects that a port is not allowed and yet
1212 : * a `':'` character is found, then it generates an error and
1213 : * returns without adding anything to `result`.
1214 : *
1215 : * \param[in] in The input string with the address and optional port.
1216 : * \param[in,out] result The list of resulting addresses.
1217 : */
1218 65865 : void addr_parser::parse_address4(std::string const & in, addr_range::vector_t & result)
1219 : {
1220 131729 : std::string address;
1221 131729 : std::string port_str;
1222 :
1223 65865 : std::string::size_type const p(in.find(':'));
1224 :
1225 131730 : if(get_allow(allow_t::ALLOW_PORT)
1226 65865 : || get_allow(allow_t::ALLOW_REQUIRED_PORT))
1227 : {
1228 : // the address can include a port
1229 : //
1230 65862 : if(p != std::string::npos)
1231 : {
1232 : // get the address only if not empty (otherwise we want to
1233 : // keep the default)
1234 : //
1235 65820 : if(p > 0)
1236 : {
1237 65710 : address = in.substr(0, p);
1238 : }
1239 :
1240 : // get the port only if not empty (otherwise we want to
1241 : // keep the default)
1242 : //
1243 65820 : if(p + 1 < in.length())
1244 : {
1245 65795 : port_str = in.substr(p + 1);
1246 : }
1247 : }
1248 42 : else if(!in.empty())
1249 : {
1250 38 : address = in;
1251 : }
1252 : }
1253 : else
1254 : {
1255 3 : if(p != std::string::npos
1256 1 : && !get_allow(allow_t::ALLOW_PORT)
1257 4 : && !get_allow(allow_t::ALLOW_REQUIRED_PORT))
1258 : {
1259 1 : emit_error("Port not allowed (" + in + ").");
1260 1 : return;
1261 : }
1262 :
1263 2 : if(!in.empty())
1264 : {
1265 1 : address = in;
1266 : }
1267 : }
1268 :
1269 65864 : parse_address_port(address, port_str, result, false);
1270 : }
1271 :
1272 :
1273 : /** \brief Parse one IPv6 address.
1274 : *
1275 : * This function checks the input parameter \p in and extracts the
1276 : * address and port. There is a port if the input strings includes
1277 : * a `':'` character after the closing square bracket (`']'`).
1278 : *
1279 : * If this function detects that a port is not allowed and yet
1280 : * a `':'` character is found, then it generates an error and
1281 : * returns without adding anything to `result`.
1282 : *
1283 : * \note
1284 : * This function can be called with an IPv6
1285 : *
1286 : * \param[in] in The input string with the address and optional port.
1287 : * \param[in,out] result The list of resulting addresses.
1288 : */
1289 65982 : void addr_parser::parse_address6(std::string const & in, addr_range::vector_t & result)
1290 : {
1291 65982 : std::string::size_type p(0);
1292 :
1293 131961 : std::string address;
1294 131961 : std::string port_str;
1295 :
1296 : // remove the square brackets if present
1297 : //
1298 131964 : if(!in.empty()
1299 65982 : && in[0] == '[')
1300 : {
1301 65778 : p = in.find(']');
1302 :
1303 65778 : if(p == std::string::npos)
1304 : {
1305 1 : emit_error("IPv6 is missing the ']' (" + in + ").");
1306 1 : return;
1307 : }
1308 :
1309 65777 : if(p != 1)
1310 : {
1311 : // get the address only if not empty (otherwise we want to
1312 : // keep the default) -- so we actually support "[]" to
1313 : // represent "use the default address if defined".
1314 : //
1315 65776 : address = in.substr(1, p - 1);
1316 : }
1317 : }
1318 :
1319 : // on entry 'p' is either 0 or the position of the ']' character
1320 : //
1321 65981 : p = in.find(':', p);
1322 :
1323 65981 : if(p != std::string::npos)
1324 : {
1325 131946 : if(get_allow(allow_t::ALLOW_PORT)
1326 65973 : || get_allow(allow_t::ALLOW_REQUIRED_PORT))
1327 : {
1328 : // there is also a port, extract it
1329 : //
1330 65971 : port_str = in.substr(p + 1);
1331 : }
1332 4 : else if(!get_allow(allow_t::ALLOW_PORT)
1333 2 : && !get_allow(allow_t::ALLOW_REQUIRED_PORT))
1334 : {
1335 2 : emit_error("Port not allowed (" + in + ").");
1336 2 : return;
1337 : }
1338 : }
1339 :
1340 65979 : parse_address_port(address, port_str, result, true);
1341 : }
1342 :
1343 :
1344 : /** \brief Parse the address and port.
1345 : *
1346 : * This function receives an address and a port string and
1347 : * convert them in an addr object which gets saved in
1348 : * the specified result range vector.
1349 : *
1350 : * The address can be an IPv4 or an IPv6 address.
1351 : *
1352 : * The port may be numeric or a name such as `"http"`.
1353 : *
1354 : * \note
1355 : * This function is not responsible for handling the default address
1356 : * and default port. This is expected to be dealt with by the caller
1357 : * if required.
1358 : *
1359 : * \param[in] address The address to convert to binary.
1360 : * \param[in] port_str The port as a string.
1361 : * \param[out] result The range where we save the results.
1362 : * \param[in] ipv6 Use the default IPv6 address if the address is empty.
1363 : */
1364 131843 : void addr_parser::parse_address_port(std::string address, std::string port_str, addr_range::vector_t & result, bool ipv6)
1365 : {
1366 : // make sure the port is good
1367 : //
1368 131843 : if(port_str.empty())
1369 : {
1370 77 : if(get_allow(allow_t::ALLOW_REQUIRED_PORT))
1371 : {
1372 4 : emit_error("Required port is missing.");
1373 4 : return;
1374 : }
1375 73 : if(f_default_port != -1)
1376 : {
1377 52 : port_str = std::to_string(f_default_port);
1378 : }
1379 : }
1380 :
1381 : // make sure the address is good
1382 : //
1383 131839 : if(address.empty())
1384 : {
1385 319 : if(get_allow(allow_t::ALLOW_REQUIRED_ADDRESS))
1386 : {
1387 2 : emit_error("Required address is missing.");
1388 2 : return;
1389 : }
1390 : // internal default if no address was defined
1391 : // (TBD: should it be an IPv6 instead?)
1392 : //
1393 317 : if(ipv6)
1394 : {
1395 203 : if(f_default_address6.empty())
1396 : {
1397 101 : address = "::";
1398 : }
1399 : else
1400 : {
1401 102 : address = f_default_address6;
1402 : }
1403 : }
1404 : else
1405 : {
1406 114 : if(f_default_address4.empty())
1407 : {
1408 11 : address = "0.0.0.0";
1409 : }
1410 : else
1411 : {
1412 103 : address = f_default_address4;
1413 : }
1414 : }
1415 : }
1416 :
1417 : // prepare hints for the the getaddrinfo() function
1418 : //
1419 131837 : addrinfo hints;
1420 131837 : memset(&hints, 0, sizeof(hints));
1421 131837 : hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG | AI_V4MAPPED;
1422 131837 : hints.ai_family = AF_UNSPEC;
1423 :
1424 131837 : switch(f_protocol)
1425 : {
1426 66371 : case IPPROTO_TCP:
1427 66371 : hints.ai_socktype = SOCK_STREAM;
1428 66371 : hints.ai_protocol = IPPROTO_TCP;
1429 66371 : break;
1430 :
1431 65452 : case IPPROTO_UDP:
1432 65452 : hints.ai_socktype = SOCK_DGRAM;
1433 65452 : hints.ai_protocol = IPPROTO_UDP;
1434 65452 : break;
1435 :
1436 : }
1437 :
1438 : // convert address to binary
1439 : //
1440 131837 : if(get_allow(allow_t::ALLOW_ADDRESS_LOOKUP))
1441 : {
1442 131832 : addrinfo * addrlist(nullptr);
1443 : {
1444 131832 : errno = 0;
1445 131832 : char const * service(port_str.c_str());
1446 131832 : if(port_str.empty())
1447 : {
1448 19 : service = "0"; // fallback to port 0 when unspecified
1449 : }
1450 131832 : int const r(getaddrinfo(address.c_str(), service, &hints, &addrlist));
1451 131832 : if(r != 0)
1452 : {
1453 : // break on invalid addresses
1454 : //
1455 2 : int const e(errno); // if r == EAI_SYSTEM, then 'errno' is consistent here
1456 6 : emit_error(
1457 : "Invalid address in \""
1458 4 : + address
1459 6 : + (port_str.empty() ? "" : ":")
1460 6 : + port_str
1461 6 : + "\" error "
1462 8 : + std::to_string(r)
1463 6 : + " -- "
1464 6 : + gai_strerror(r)
1465 8 : + (e == 0
1466 8 : ? ""
1467 : : " (errno: "
1468 4 : + std::to_string(e)
1469 6 : + " -- "
1470 6 : + strerror(e)
1471 : + ")."));
1472 2 : return;
1473 : }
1474 : }
1475 263660 : std::shared_ptr<addrinfo> ai(addrlist, addrinfo_deleter);
1476 :
1477 131830 : bool first(true);
1478 395538 : while(addrlist != nullptr)
1479 : {
1480 : // go through the addresses and create ranges and save that in the result
1481 : //
1482 131854 : if(addrlist->ai_family == AF_INET)
1483 : {
1484 65876 : if(addrlist->ai_addrlen != sizeof(sockaddr_in))
1485 : {
1486 : emit_error("Unsupported address size (" // LCOV_EXCL_LINE
1487 : + std::to_string(addrlist->ai_addrlen) // LCOV_EXCL_LINE
1488 : + ", expected" // LCOV_EXCL_LINE
1489 : + std::to_string(sizeof(sockaddr_in)) // LCOV_EXCL_LINE
1490 : + ")."); // LCOV_EXCL_LINE
1491 : }
1492 : else
1493 : {
1494 131752 : addr a(*reinterpret_cast<sockaddr_in *>(addrlist->ai_addr));
1495 : // in most cases we do not get a protocol from
1496 : // the getaddrinfo() function...
1497 65876 : a.set_protocol(addrlist->ai_protocol);
1498 65876 : a.set_hostname(address);
1499 131752 : addr_range r;
1500 65876 : r.set_from(a);
1501 131752 : if((f_sort & SORT_NO_EMPTY) == 0
1502 65876 : || !r.is_empty())
1503 : {
1504 65876 : result.push_back(r);
1505 : }
1506 : }
1507 : }
1508 65978 : else if(addrlist->ai_family == AF_INET6)
1509 : {
1510 65978 : if(addrlist->ai_addrlen != sizeof(sockaddr_in6))
1511 : {
1512 : emit_error("Unsupported address size (" // LCOV_EXCL_LINE
1513 : + std::to_string(addrlist->ai_addrlen) // LCOV_EXCL_LINE
1514 : + ", expected " // LCOV_EXCL_LINE
1515 : + std::to_string(sizeof(sockaddr_in6)) // LCOV_EXCL_LINE
1516 : + ")."); // LCOV_EXCL_LINE
1517 : }
1518 : else
1519 : {
1520 131956 : addr a(*reinterpret_cast<sockaddr_in6 *>(addrlist->ai_addr));
1521 65978 : a.set_hostname(address);
1522 65978 : a.set_protocol(addrlist->ai_protocol);
1523 131956 : addr_range r;
1524 65978 : r.set_from(a);
1525 131956 : if((f_sort & SORT_NO_EMPTY) == 0
1526 65978 : || !r.is_empty())
1527 : {
1528 65978 : result.push_back(r);
1529 : }
1530 : }
1531 : }
1532 : else if(first) // LCOV_EXCL_LINE
1533 : {
1534 : // ignore errors from further addresses
1535 : //
1536 : emit_error("Unsupported address family " // LCOV_EXCL_LINE
1537 : + std::to_string(addrlist->ai_family) // LCOV_EXCL_LINE
1538 : + "."); // LCOV_EXCL_LINE
1539 : }
1540 :
1541 131854 : first = false;
1542 :
1543 131854 : addrlist = addrlist->ai_next;
1544 : }
1545 : }
1546 : else
1547 : {
1548 5 : std::int64_t port(0);
1549 10 : if(get_allow(allow_t::ALLOW_REQUIRED_PORT)
1550 5 : || !port_str.empty())
1551 : {
1552 5 : bool const valid_port(advgetopt::validator_integer::convert_string(port_str, port));
1553 5 : if(!valid_port
1554 4 : || port < 0
1555 4 : || port > 65535)
1556 : {
1557 2 : emit_error("Invalid port in \""
1558 2 : + port_str
1559 3 : + "\" (no service name lookup allowed).");
1560 1 : return;
1561 : }
1562 :
1563 8 : if(!get_allow(allow_t::ALLOW_PORT)
1564 4 : && !get_allow(allow_t::ALLOW_REQUIRED_PORT))
1565 : {
1566 0 : emit_error("Found a port (\""
1567 0 : + port_str
1568 0 : + "\") when it is not allowed.");
1569 0 : return;
1570 : }
1571 : }
1572 4 : sockaddr_in in;
1573 4 : if(inet_pton(AF_INET, address.c_str(), &in.sin_addr) == 1)
1574 : {
1575 1 : in.sin_family = AF_INET;
1576 1 : in.sin_port = htons(port);
1577 1 : memset(in.sin_zero, 0, sizeof(in.sin_zero)); // probably useless
1578 :
1579 2 : addr a(in);
1580 1 : a.set_hostname(address);
1581 1 : a.set_protocol(f_protocol);
1582 2 : addr_range r;
1583 1 : r.set_from(a);
1584 2 : if((f_sort & SORT_NO_EMPTY) == 0
1585 1 : || !r.is_empty())
1586 : {
1587 1 : result.push_back(r);
1588 : }
1589 : }
1590 : else
1591 : {
1592 3 : sockaddr_in6 in6;
1593 3 : if(inet_pton(AF_INET6, address.c_str(), &in6.sin6_addr) == 1)
1594 : {
1595 1 : in6.sin6_family = AF_INET6;
1596 1 : in6.sin6_port = htons(port);
1597 1 : in6.sin6_flowinfo = 0;
1598 1 : in6.sin6_scope_id = 0;
1599 :
1600 2 : addr a(in6);
1601 1 : a.set_hostname(address);
1602 1 : a.set_protocol(f_protocol);
1603 2 : addr_range r;
1604 1 : r.set_from(a);
1605 2 : if((f_sort & SORT_NO_EMPTY) == 0
1606 1 : || !r.is_empty())
1607 : {
1608 1 : result.push_back(r);
1609 : }
1610 : }
1611 : else
1612 : {
1613 4 : emit_error("Unknown address in \""
1614 4 : + address
1615 6 : + "\" (no DNS lookup was allowed).");
1616 : }
1617 : }
1618 : }
1619 : }
1620 :
1621 :
1622 : /** \brief Parse a mask.
1623 : *
1624 : * If the input string is a decimal number, then use that as the
1625 : * number of bits to clear.
1626 : *
1627 : * If the mask is not just one decimal number, try to convert it
1628 : * as an address.
1629 : *
1630 : * If the string is neither a decimal number nor a valid IP address
1631 : * then the parser adds an error string to the f_error variable.
1632 : *
1633 : * \param[in] mask The mask to transform to binary.
1634 : * \param[in,out] cidr The address to which the mask will be added.
1635 : */
1636 474 : void addr_parser::parse_mask(std::string const & mask, addr & cidr)
1637 : {
1638 : // no mask?
1639 : //
1640 474 : if(mask.empty())
1641 : {
1642 : // in the current implementation this cannot happen since we
1643 : // do not call this function when mask is empty
1644 : //
1645 : // hwoever, the algorithm below expect that 'mask' is not
1646 : // empty (otherwise we get the case of 0 even though it
1647 : // may not be correct.)
1648 : //
1649 : return; // LCOV_EXCL_LINE
1650 : }
1651 :
1652 : // the mask may be a decimal number or an address, if just one number
1653 : // then it's not an address, so test that first
1654 : //
1655 470 : uint8_t mask_bits[16] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
1656 :
1657 : // convert the mask to an integer, if possible
1658 : //
1659 470 : int mask_count(0);
1660 : {
1661 1304 : for(char const * s(mask.c_str()); *s != '\0'; ++s)
1662 : {
1663 1032 : if(*s >= '0' && *s <= '9')
1664 : {
1665 849 : mask_count = mask_count * 10 + *s - '0';
1666 1683 : if(mask_count > 1000)
1667 : {
1668 30 : emit_error("Mask number too large ("
1669 30 : + mask
1670 45 : + ", expected a maximum of 128).");
1671 15 : return;
1672 : }
1673 : }
1674 : else
1675 : {
1676 183 : mask_count = -1;
1677 183 : break;
1678 : }
1679 : }
1680 : }
1681 :
1682 : // the conversion to an integer worked if mask_count != -1
1683 : //
1684 455 : if(mask_count != -1)
1685 : {
1686 272 : if(cidr.is_ipv4())
1687 : {
1688 42 : if(mask_count > 32)
1689 : {
1690 10 : emit_error("Unsupported mask size ("
1691 10 : + std::to_string(mask_count)
1692 15 : + ", expected 32 at the most for an IPv4).");
1693 5 : return;
1694 : }
1695 37 : mask_count = 32 - mask_count;
1696 : }
1697 : else
1698 : {
1699 230 : if(mask_count > 128)
1700 : {
1701 10 : emit_error("Unsupported mask size ("
1702 10 : + std::to_string(mask_count)
1703 15 : + ", expected 128 at the most for an IPv6).");
1704 5 : return;
1705 : }
1706 225 : mask_count = 128 - mask_count;
1707 : }
1708 :
1709 : // clear a few bits at the bottom of mask_bits
1710 : //
1711 262 : int idx(15);
1712 3322 : for(; mask_count > 8; mask_count -= 8, --idx)
1713 : {
1714 1530 : mask_bits[idx] = 0;
1715 : }
1716 262 : mask_bits[idx] = 255 << mask_count;
1717 : }
1718 : else //if(mask_count < 0)
1719 : {
1720 : // prepare hints for the the getaddrinfo() function
1721 : //
1722 183 : addrinfo hints;
1723 183 : memset(&hints, 0, sizeof(hints));
1724 183 : hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV | AI_ADDRCONFIG | AI_V4MAPPED;
1725 183 : hints.ai_family = AF_UNSPEC;
1726 :
1727 183 : switch(cidr.get_protocol())
1728 : {
1729 98 : case IPPROTO_TCP:
1730 98 : hints.ai_socktype = SOCK_STREAM;
1731 98 : hints.ai_protocol = IPPROTO_TCP;
1732 98 : break;
1733 :
1734 85 : case IPPROTO_UDP:
1735 85 : hints.ai_socktype = SOCK_DGRAM;
1736 85 : hints.ai_protocol = IPPROTO_UDP;
1737 85 : break;
1738 :
1739 : }
1740 :
1741 338 : std::string const port_str(std::to_string(cidr.get_port()));
1742 :
1743 : // if the mask is an IPv6, then it has to have the '[...]'
1744 338 : std::string m(mask);
1745 183 : if(cidr.is_ipv4())
1746 : {
1747 87 : if(mask[0] == '[')
1748 : {
1749 1 : emit_error("The address uses the IPv4 syntax, the mask cannot use IPv6.");
1750 1 : return;
1751 : }
1752 : }
1753 : else //if(!cidr.is_ipv4())
1754 : {
1755 96 : if(mask[0] != '[')
1756 : {
1757 1 : emit_error("The address uses the IPv6 syntax, the mask cannot use IPv4.");
1758 1 : return;
1759 : }
1760 95 : if(mask.back() != ']')
1761 : {
1762 1 : emit_error("The IPv6 mask is missing the ']' (" + mask + ").");
1763 1 : return;
1764 : }
1765 :
1766 : // note that we know that mask.length() >= 2 here since
1767 : // we at least have a '[' and ']'
1768 : //
1769 94 : m = mask.substr(1, mask.length() - 2);
1770 94 : if(m.empty())
1771 : {
1772 : // an empty mask is valid, it just means keep the default
1773 : // (getaddrinfo() fails on an empty string)
1774 : //
1775 3 : return;
1776 : }
1777 : }
1778 :
1779 : // if negative, we may have a full address here, so call the
1780 : // getaddrinfo() on this other string
1781 : //
1782 177 : addrinfo * masklist(nullptr);
1783 177 : errno = 0;
1784 177 : int const r(getaddrinfo(m.c_str(), port_str.c_str(), &hints, &masklist));
1785 177 : if(r != 0)
1786 : {
1787 : // break on invalid addresses
1788 : //
1789 15 : int const e(errno); // if r == EAI_SYSTEM, then 'errno' is consistent here
1790 30 : emit_error("Invalid mask in \"/"
1791 30 : + mask
1792 45 : + "\", error "
1793 60 : + std::to_string(r)
1794 45 : + " -- "
1795 45 : + gai_strerror(r)
1796 45 : + " (errno: "
1797 60 : + std::to_string(e)
1798 45 : + " -- "
1799 45 : + strerror(e)
1800 45 : + ").");
1801 15 : return;
1802 : }
1803 317 : std::shared_ptr<addrinfo> mask_ai(masklist, addrinfo_deleter);
1804 :
1805 162 : if(cidr.is_ipv4())
1806 : {
1807 76 : if(masklist->ai_family != AF_INET)
1808 : {
1809 : // this one happens when the user does not put the '[...]'
1810 : // around an IPv6 address
1811 : //
1812 1 : emit_error("Incompatible address between the address and"
1813 : " mask address (first was an IPv4 second an IPv6).");
1814 1 : return;
1815 : }
1816 75 : if(masklist->ai_addrlen != sizeof(sockaddr_in))
1817 : {
1818 : emit_error("Unsupported address size (" // LCOV_EXCL_LINE
1819 : + std::to_string(masklist->ai_addrlen) // LCOV_EXCL_LINE
1820 : + ", expected" // LCOV_EXCL_LINE
1821 : + std::to_string(sizeof(sockaddr_in)) // LCOV_EXCL_LINE
1822 : + ")."); // LCOV_EXCL_LINE
1823 : return; // LCOV_EXCL_LINE
1824 : }
1825 75 : memcpy(mask_bits + 12, &reinterpret_cast<sockaddr_in *>(masklist->ai_addr)->sin_addr.s_addr, 4); // last 4 bytes are the IPv4 address, keep the rest as 1s
1826 : }
1827 : else //if(!cidr.is_ipv4())
1828 : {
1829 86 : if(masklist->ai_family != AF_INET6)
1830 : {
1831 : // this one happens if the user puts the '[...]'
1832 : // around an IPv4 address
1833 : //
1834 6 : emit_error("Incompatible address between the address"
1835 : " and mask address (first was an IPv6 second an IPv4).");
1836 6 : return;
1837 : }
1838 80 : if(masklist->ai_addrlen != sizeof(sockaddr_in6))
1839 : {
1840 : emit_error("Unsupported address size (" // LCOV_EXCL_LINE
1841 : + std::to_string(masklist->ai_addrlen) // LCOV_EXCL_LINE
1842 : + ", expected " // LCOV_EXCL_LINE
1843 : + std::to_string(sizeof(sockaddr_in6)) // LCOV_EXCL_LINE
1844 : + ")."); // LCOV_EXCL_LINE
1845 : return; // LCOV_EXCL_LINE
1846 : }
1847 80 : memcpy(mask_bits, &reinterpret_cast<sockaddr_in6 *>(masklist->ai_addr)->sin6_addr.s6_addr, 16);
1848 : }
1849 : }
1850 :
1851 417 : cidr.set_mask(mask_bits);
1852 : }
1853 :
1854 :
1855 : /** \brief Transform a string into an `addr` object.
1856 : *
1857 : * This function converts the string \p a in an IP address saved in
1858 : * the returned addr object or throws an error if the conversion
1859 : * fails.
1860 : *
1861 : * The \p default_address parameter string can be set to an address
1862 : * which is returned if the input in \p a does not include an
1863 : * address such as in ":123".
1864 : *
1865 : * The \p port parameter can be specified or set to -1. If -1, then
1866 : * there is no default port. Either way, the port can be defined in
1867 : * \p a.
1868 : *
1869 : * The protocol can be specified, as a string. For example, you can
1870 : * use "tcp". The default is no specific protocol which means any
1871 : * type of IP address can be returned. Note that if more than one
1872 : * result is returned when the protocol was not specified, the
1873 : * results will be filtered to only keep the address that uses the
1874 : * TCP protocol. If as a result we have a single address, then that
1875 : * result gets returned.
1876 : *
1877 : * \note
1878 : * This function does not allow for address or port ranges. It is
1879 : * expected to return exactly one address. You can allow a \p mask
1880 : * by setting that parameter to true.
1881 : *
1882 : * \exception addr_invalid_argument
1883 : * If the parsed address is not returning a valid `addr` object, then
1884 : * this function fails by throwing an error. If you would prefer to
1885 : * handle the error mechanism, you want to create your own addr_parser
1886 : * and then call the addr_parser::parse() function. This will allow
1887 : * you to get error messages instead of an exception.
1888 : *
1889 : * \param[in] a The address string to be converted.
1890 : * \param[in] default_addrress The default address or an empty string.
1891 : * \param[in] default_port The default port or -1
1892 : * \param[in] protocol The protocol the address has to be of, or the
1893 : * empty string to allow any protocol.
1894 : * \param[in] m Whether to allow a mask (true) or not (false).
1895 : *
1896 : * \return The address converted in an `addr` object.
1897 : *
1898 : * \sa addr_parser::parse()
1899 : */
1900 14 : addr string_to_addr(
1901 : std::string const & a
1902 : , std::string const & default_address
1903 : , int default_port
1904 : , std::string const & protocol
1905 : , bool mask)
1906 : {
1907 28 : addr_parser p;
1908 :
1909 14 : if(!default_address.empty())
1910 : {
1911 10 : p.set_default_address(default_address);
1912 : }
1913 :
1914 14 : if(default_port != -1)
1915 : {
1916 8 : p.set_default_port(default_port);
1917 : }
1918 :
1919 14 : if(!protocol.empty())
1920 : {
1921 7 : p.set_protocol(protocol);
1922 : }
1923 :
1924 13 : p.set_allow(allow_t::ALLOW_MASK, mask);
1925 :
1926 26 : addr_range::vector_t result(p.parse(a));
1927 :
1928 13 : if(result.size() != 1)
1929 : {
1930 : // when the protocol is not specified, this happens like all the
1931 : // time, we search for an entry with protocol TCP by default
1932 : // because in most cases that's what people want
1933 : //
1934 7 : if(protocol.empty())
1935 : {
1936 21 : result.erase(
1937 14 : std::remove_if(
1938 : result.begin()
1939 : , result.end()
1940 21 : , [](auto const it)
1941 : {
1942 21 : return it.has_from() && it.get_from().get_protocol() != IPPROTO_TCP;
1943 28 : })
1944 35 : , result.end());
1945 : }
1946 7 : if(result.size() != 1)
1947 : {
1948 : // an invalid protocol is caught by the set_protocol()
1949 : // function so we should never be able to reach here
1950 : //
1951 : throw addr_invalid_argument( // LCOV_EXCL_LINE
1952 : "the address \"" // LCOV_EXCL_LINE
1953 : + a // LCOV_EXCL_LINE
1954 : + "\" could not be converted to a single address in string_to_addr(), found " // LCOV_EXCL_LINE
1955 : + std::to_string(result.size()) // LCOV_EXCL_LINE
1956 : + " entries instead."); // LCOV_EXCL_LINE
1957 : }
1958 : }
1959 :
1960 : // at the movement we only can get a "to" so the following exceptions
1961 : // can't happen which is why we have an LCOV_EXCL_LINE
1962 : //
1963 26 : if(result[0].has_to()
1964 13 : || result[0].is_range())
1965 : {
1966 : throw addr_invalid_argument("string_to_addr() does not support ranges."); // LCOV_EXCL_LINE
1967 : }
1968 :
1969 13 : if(!result[0].has_from())
1970 : {
1971 : throw addr_invalid_argument("string_to_addr() has no 'from' address."); // LCOV_EXCL_LINE
1972 : }
1973 :
1974 26 : return result[0].get_from();
1975 : }
1976 :
1977 :
1978 :
1979 6 : }
1980 : // namespace addr
1981 : // vim: ts=4 sw=4 et
|