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(flag_t::ADDRESS, true);
100 131953 : set_allow(flag_t::ADDRESS_LOOKUP, true);
101 :
102 : // allow port after address
103 : //
104 131953 : set_allow(flag_t::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.flag_t::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.flag_t::ADDRESS, false);
145 : * parser.set_allow(parser.flag_t::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.flag_t::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.flag_t::PORT, false);
250 : * parser.set_allow(parser.flag_t::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 71 : || 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 flag_t::MASK allow
287 : * flag is not set to true:
288 : *
289 : * \code
290 : * parser.set_allow(parser.flag_t::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 Set or clear allow flags in the parser.
532 : *
533 : * This parser has a set of flags it uses to know whether the input
534 : * string can include certain things such as a port or a mask.
535 : *
536 : * This function is used to allow or require certain parameters and
537 : * to disallow others.
538 : *
539 : * By default, the ADDRESS and PORT flags are set, meaning that an
540 : * address and a port can appear, but either or both are optinal.
541 : * If unspecified, then the default will be used. If not default
542 : * is defined, then the parser may fail in this situation.
543 : *
544 : * One problem is that we include contradictory syntatical features.
545 : * The parser supports lists of addresses separated by commas and
546 : * lists of ports separated by commas. Both are not supported
547 : * simultaneously. This means you want to allow multiple addresses
548 : * separated by commas, the function makes sure that the multiple
549 : * port separated by commas support is turned off.
550 : *
551 : * \li `ADDRESS` -- the IP address is allowed, but optional
552 : * \li `REQUIRED_ADDRESS` -- the IP address is mandatory
553 : * \li `PORT` -- the port is allowed, but optional
554 : * \li `REQUIRED_PORT` -- the port is mandatory
555 : * \li `MASK` -- the mask is allowed, but optional
556 : * \li `MULTI_ADDRESSES_COMMAS` -- the input can have multiple addresses
557 : * separated by commas (prevents MULTI_PORTS_COMMAS)
558 : * \li `MULTI_ADDRESSES_SPACES` -- the input can have multiple addresses
559 : * separated by spaces
560 : * \li `MULTI_PORTS_SEMICOLONS` -- the input can have multiple ports
561 : * separated by semicolons _NOT IMPLEMENTED YET_
562 : * \li `MULTI_PORTS_COMMAS` -- the input can have multiple ports separated
563 : * by commas (prevents MULTI_ADDRESSES_COMMAS) _NOT IMPLEMENTED YET_
564 : * \li `PORT_RANGE` -- the input supports port ranges (p1-p2) _NOT
565 : * IMPLEMENTED YET_
566 : * \li `ADDRESS_RANGE` -- the input supports address ranges (addr-addr) _NOT
567 : * IMPLEMENTED YET_
568 : *
569 : * The `MULTI_ADDRESSES_COMMAS` and `MULTI_ADDRESSES_SPACES` can be used
570 : * together in which case any number of both characters are accepted
571 : * between addresses.
572 : *
573 : * Note that the `MULTI_ADDRESSES_COMMAS` and `MULTI_PORTS_COMMAS` are
574 : * mutually exclusive. The last set_allow() counts as the one you are
575 : * interested in.
576 : *
577 : * \param[in] flag The flag to set or clear.
578 : * \param[in] allow Whether to allow (true) or disallow (false).
579 : *
580 : * \sa get_allow()
581 : */
582 396412 : void addr_parser::set_allow(flag_t const flag, bool const allow)
583 : {
584 396412 : if(flag < static_cast<flag_t>(0)
585 396392 : || flag >= flag_t::FLAG_max)
586 : {
587 40 : throw addr_invalid_argument("addr_parser::set_allow(): flag has to be one of the valid flags.");
588 : }
589 :
590 396372 : f_flags[static_cast<int>(flag)] = allow;
591 :
592 : // if we just set a certain flag, others may need to go to false
593 : //
594 396372 : if(allow)
595 : {
596 : // we can only support one type of commas
597 : //
598 396347 : switch(flag)
599 : {
600 5 : case flag_t::MULTI_ADDRESSES_COMMAS:
601 5 : f_flags[static_cast<int>(flag_t::MULTI_PORTS_COMMAS)] = false;
602 5 : break;
603 :
604 2 : case flag_t::MULTI_PORTS_COMMAS:
605 2 : f_flags[static_cast<int>(flag_t::MULTI_ADDRESSES_COMMAS)] = false;
606 2 : break;
607 :
608 396340 : default:
609 396340 : break;
610 :
611 : }
612 : }
613 396372 : }
614 :
615 :
616 : /** \brief Retrieve the current statius of an allow flag.
617 : *
618 : * This function returns the current status of the allow flags.
619 : *
620 : * By default, the `ADDRESS` and `PORT` flags are set to true.
621 : * All the other flags are set to false.
622 : *
623 : * You may change the value of an allow flag by calling the
624 : * set_allow() function.
625 : *
626 : * \param[in] flag Which flag is to be checked.
627 : *
628 : * \return The value of the flag: true or false.
629 : *
630 : * \sa set_allow()
631 : */
632 857275 : bool addr_parser::get_allow(flag_t const flag) const
633 : {
634 857275 : if(flag < static_cast<flag_t>(0)
635 857265 : || flag >= flag_t::FLAG_max)
636 : {
637 20 : throw addr_invalid_argument("addr_parser::get_allow(): flag has to be one of the valid flags.");
638 : }
639 :
640 857255 : return f_flags[static_cast<int>(flag)];
641 : }
642 :
643 :
644 : /** \brief Check whether errors were registered so far.
645 : *
646 : * This function returns true if the system detected errors in one
647 : * of the previous calls to parse(). The flag can be cleared using
648 : * the clear_errors() function.
649 : *
650 : * On construction and after a call to clear_error(), this flag is
651 : * always false. If you are to call parser() multiple times with
652 : * the same addr_parser object, then you want to make sure to call
653 : * the clear_errors() function before calling the parse() function.
654 : * Otherwise you won't know whether errors occurred in a earlier
655 : * or later call.
656 : *
657 : * \code
658 : * // first time, not required
659 : * parser.parse(...);
660 : * ...
661 : *
662 : * // next time, required
663 : * parser.clear_errors();
664 : * parser.parse(...);
665 : * ...
666 : * \endcode
667 : *
668 : * \return true if errors were generated.
669 : */
670 131832 : bool addr_parser::has_errors() const
671 : {
672 131832 : return !f_error.empty();
673 : }
674 :
675 :
676 : /** \brief Emit an error and save it in this class.
677 : *
678 : * This function adds the message to the error string part of this
679 : * object. A newline is also added at the end of the message.
680 : *
681 : * Next the function increments the error counter.
682 : *
683 : * \note
684 : * You are expected to emit one error at a time. If you want to
685 : * emit several messages in a row, that will work and properly
686 : * count each message.
687 : *
688 : * \param[in] msg The message to add to the parser error messages.
689 : *
690 : * \sa error_messages()
691 : */
692 65 : void addr_parser::emit_error(std::string const & msg)
693 : {
694 65 : f_error += msg;
695 65 : f_error += "\n";
696 65 : ++f_error_count;
697 65 : }
698 :
699 :
700 : /** \brief Return the current error messages.
701 : *
702 : * The error messages are added to the addr_parser using the
703 : * emit_error() function.
704 : *
705 : * This function does not clear the list of error messages.
706 : * To do that, call the clear_errors() function.
707 : *
708 : * The number of messages can be determined by counting the
709 : * number of "\n" characters in the string. The error_count()
710 : * will return that same number (assuming no message included
711 : * a '\n' character when emit_error() was called.)
712 : *
713 : * \return A string with the list of messages.
714 : *
715 : * \sa emit_error()
716 : * \sa clear_errors()
717 : */
718 65 : std::string const & addr_parser::error_messages() const
719 : {
720 65 : return f_error;
721 : }
722 :
723 :
724 : /** \brief Return the number of error messages that were emitted.
725 : *
726 : * Each time the emit_error() function is called, the error
727 : * counter is incremented by 1. This function returns that
728 : * error counter.
729 : *
730 : * The clear_errors() function can be used to clear the
731 : * counter back to zero.
732 : *
733 : * \return The number of errors that were emitted so far.
734 : *
735 : * \sa emit_error()
736 : */
737 65 : int addr_parser::error_count() const
738 : {
739 65 : return f_error_count;
740 : }
741 :
742 :
743 : /** \brief Clear the error message and error counter.
744 : *
745 : * This function clears all the error messages and reset the
746 : * counter back to zero. In order words, it will be possible
747 : * to tell how many times the emit_error() was called since
748 : * the start or the last clear_errors() call.
749 : *
750 : * To retrieve a copy of the error counter, use the error_count()
751 : * function.
752 : *
753 : * \sa error_count()
754 : */
755 5 : void addr_parser::clear_errors()
756 : {
757 5 : f_error.clear();
758 5 : f_error_count = 0;
759 5 : }
760 :
761 :
762 : /** \brief Parse a string of addresses, ports, and masks.
763 : *
764 : * This function is used to parse the list of addresses defined
765 : * in the \p in parameter.
766 : *
767 : * One address is composed of one to three elements:
768 : *
769 : * \code
770 : * [ address ] [ ':' port ] [ '/' mask ]
771 : * \endcode
772 : *
773 : * Although all three elements are optional (at least by default),
774 : * a valid address is expected to include at least one of the
775 : * three elements. (i.e. an empty string is just skipped silently.)
776 : *
777 : * ### Multiple Addresses
778 : *
779 : * Multiple addresses can be defined if at least one of the
780 : * `MULTI_ADDRESSES_COMMAS` or `MULTI_ADDRESSES_SPACES` allow
781 : * flags is set to true.
782 : *
783 : * Next comes `MULTI_ADDRESSES_COMMAS`: if set to true, addresses
784 : * must be separated by commas and spaces are not allowed.
785 : *
786 : * Finally we have `MULTI_ADDRESSES_SPACES`. If that one is true, then
787 : * addresses must be separated by spaces and commas are not allowed.
788 : *
789 : * ### Make Address Field Required
790 : *
791 : * To make the address field a required field, set the
792 : * `REQUIRED_ADDRESS` flag (see set_allow()) to true and do not define a
793 : * default address (see set_default_address()).
794 : *
795 : * ### Make Port Field Required
796 : *
797 : * To make the port field a required fiel, set the `REQUIRED_PORT`
798 : * flag (see set_allow()) to true and do not define a default port
799 : * (see set_default_port()).
800 : *
801 : * ### Allow Mask
802 : *
803 : * The mask cannot be made mandatory. However, you have to set
804 : * the `MASK` flag to true to allow it. By default it is not
805 : * allowed.
806 : *
807 : * ### Ranges
808 : *
809 : * Ranges are not yet implemented.
810 : *
811 : * \param[in] in The input string to be parsed.
812 : *
813 : * \return A vector of address ranges, see has_errors() to determine whether
814 : * errors occurred while parsing the input.
815 : *
816 : * \sa has_errors()
817 : */
818 131841 : addr_range::vector_t addr_parser::parse(std::string const & in)
819 : {
820 131841 : addr_range::vector_t result;
821 :
822 263682 : if(get_allow(flag_t::MULTI_ADDRESSES_COMMAS)
823 131841 : && get_allow(flag_t::MULTI_ADDRESSES_SPACES))
824 : {
825 2 : std::string const comma_space(", ");
826 1 : std::string::size_type s(0);
827 17 : while(s < in.length())
828 : {
829 8 : auto const it(std::find_first_of(in.begin() + s, in.end(), comma_space.begin(), comma_space.end()));
830 8 : std::string::size_type const e(it == in.end() ? in.length() : it - in.begin());
831 8 : if(e > s)
832 : {
833 3 : parse_cidr(in.substr(s, e - s), result);
834 : }
835 8 : s = e + 1;
836 : }
837 : }
838 263680 : else if(get_allow(flag_t::MULTI_ADDRESSES_COMMAS)
839 131840 : || get_allow(flag_t::MULTI_ADDRESSES_SPACES))
840 : {
841 2 : char const sep(get_allow(flag_t::MULTI_ADDRESSES_COMMAS) ? ',' : ' ');
842 2 : std::string::size_type s(0);
843 24 : while(s < in.length())
844 : {
845 11 : std::string::size_type e(in.find(sep, s));
846 11 : if(e == std::string::npos)
847 : {
848 2 : e = in.length();
849 : }
850 11 : if(e > s)
851 : {
852 6 : parse_cidr(in.substr(s, e - s), result);
853 : }
854 11 : s = e + 1;
855 : }
856 : }
857 : else
858 : {
859 131838 : parse_cidr(in, result);
860 : }
861 :
862 131841 : return result;
863 : }
864 :
865 :
866 : /** \brief Check one address.
867 : *
868 : * This function checks one address, although if it is a name, it could
869 : * represent multiple IP addresses.
870 : *
871 : * This function separate the address:port from the mask if the mask is
872 : * allowed. Then it parses the address:port part and the mask separately.
873 : *
874 : * \param[in] in The address to parse.
875 : * \param[in,out] result The list of resulting addresses.
876 : */
877 131847 : void addr_parser::parse_cidr(std::string const & in, addr_range::vector_t & result)
878 : {
879 131847 : if(get_allow(flag_t::MASK))
880 : {
881 : // check whether there is a mask
882 : //
883 948 : std::string mask;
884 :
885 948 : std::string address;
886 474 : std::string::size_type const p(in.find('/'));
887 474 : if(p != std::string::npos)
888 : {
889 420 : address = in.substr(0, p);
890 420 : mask = in.substr(p + 1);
891 : }
892 : else
893 : {
894 54 : address = in;
895 : }
896 :
897 474 : int const errcnt(f_error_count);
898 :
899 : // handle the address first
900 : //
901 948 : addr_range::vector_t addr_mask;
902 474 : parse_address(address, mask, addr_mask);
903 :
904 : // now check for the mask
905 : //
906 948 : for(auto & am : addr_mask)
907 : {
908 948 : std::string m(mask);
909 474 : if(m.empty())
910 : {
911 : // the mask was not defined in the input, then adapt it to
912 : // the type of address we got in 'am'
913 : //
914 56 : if(am.get_from().is_ipv4())
915 : {
916 29 : m = f_default_mask4;
917 : }
918 : else
919 : {
920 : // parse_mask() expects '[...]' around IPv6 addresses
921 : //
922 27 : m = "[" + f_default_mask6 + "]";
923 : }
924 : }
925 :
926 474 : parse_mask(m, am.get_from());
927 : }
928 :
929 : // now append the list to the result if no errors occurred
930 : //
931 474 : if(errcnt == f_error_count)
932 : {
933 424 : result.insert(result.end(), addr_mask.begin(), addr_mask.end());
934 : }
935 : }
936 : else
937 : {
938 : // no mask allowed, if there is one, this call will fail
939 : //
940 131373 : parse_address(in, std::string(), result);
941 : }
942 131847 : }
943 :
944 :
945 : /** \brief Parse one address.
946 : *
947 : * This function is called with one address. It determines whether we
948 : * are dealing with an IPv4 or an IPv6 address and call the
949 : * corresponding sub-function.
950 : *
951 : * An address is considered an IPv6 address if it starts with a '['
952 : * character.
953 : *
954 : * \note
955 : * The input cannot include a mask. It has to already have been
956 : * removed.
957 : *
958 : * \note
959 : * The mask parameter is only used to determine whether this function
960 : * is being called with an IPv6 or not. It is otherwise ignored.
961 : *
962 : * \param[in] in The input address eventually including a port.
963 : * \param[in] mask The mask used to determine whether we are dealing with
964 : * an IPv6 or not.
965 : * \param[in,out] result The list of resulting addresses.
966 : */
967 131847 : void addr_parser::parse_address(std::string const & in, std::string const & mask, addr_range::vector_t & result)
968 : {
969 : // With our only supported format, ipv6 addresses must be between square
970 : // brackets. The address may just be a mask in which case the '[' may
971 : // not be at the very start (i.e. "/[ffff:ffff::]")
972 : //
973 263694 : if(in.empty()
974 131847 : || in[0] == ':') // if it start with ':' then there is no address
975 : {
976 : // if the address is empty, then use the mask to determine the
977 : // type of IP address (note: if the address starts with ':'
978 : // it is considered empty since an IPv6 would have a '[' at
979 : // the start)
980 : //
981 318 : if(!mask.empty())
982 : {
983 111 : if(mask[0] == '[')
984 : {
985 : // IPv6 parsing
986 : //
987 5 : parse_address6(in, result);
988 : }
989 : else
990 : {
991 : // if the number is 33 or more, it has to be IPv6, otherwise
992 : // we cannot know...
993 : //
994 106 : int mask_count(0);
995 353 : for(char const * s(mask.c_str()); *s != '\0'; ++s)
996 : {
997 257 : if(*s >= '0' && *s <= '9')
998 : {
999 252 : mask_count = mask_count * 10 + *s - '0';
1000 499 : if(mask_count > 1000)
1001 : {
1002 : // not valid
1003 : //
1004 5 : mask_count = -1;
1005 5 : break;;
1006 : }
1007 : }
1008 : else
1009 : {
1010 : // not a valid decimal number
1011 : //
1012 5 : mask_count = -1;
1013 5 : break;
1014 : }
1015 : }
1016 106 : if(mask_count > 32)
1017 : {
1018 96 : parse_address6(in, result);
1019 : }
1020 : else
1021 : {
1022 10 : parse_address4(in, result);
1023 : }
1024 : }
1025 : }
1026 : else
1027 : {
1028 414 : if(f_default_address4.empty()
1029 207 : && !f_default_address6.empty())
1030 : {
1031 102 : parse_address6(in, result);
1032 : }
1033 : else
1034 : {
1035 105 : parse_address4(in, result);
1036 : }
1037 : }
1038 : }
1039 : else
1040 : {
1041 : // if an address has a ']' then it is IPv6 even if the '['
1042 : // is missing, that being said, it is still considered
1043 : // invalid as per our processes
1044 : //
1045 263058 : if(in[0] == '['
1046 131529 : || in.find(']') != std::string::npos)
1047 : {
1048 65778 : parse_address6(in, result);
1049 : }
1050 : else
1051 : {
1052 : // if there is no port, then a ':' can be viewed as an IPv6
1053 : // address because there is no other ':', but if there are
1054 : // '.' before the ':' then we assume that it is IPv4 still
1055 : //
1056 131502 : if(!get_allow(flag_t::PORT)
1057 65751 : && !get_allow(flag_t::REQUIRED_PORT))
1058 : {
1059 3 : std::string::size_type const p(in.find(':'));
1060 3 : if(p != std::string::npos
1061 3 : && in.find('.') > p)
1062 : {
1063 1 : parse_address6(in, result);
1064 : }
1065 : else
1066 : {
1067 2 : parse_address4(in, result);
1068 : }
1069 : }
1070 : else
1071 : {
1072 65748 : parse_address4(in, result);
1073 : }
1074 : }
1075 : }
1076 131847 : }
1077 :
1078 :
1079 : /** \brief Parse one IPv4 address.
1080 : *
1081 : * This function checks the input parameter \p in and extracts the
1082 : * address and port. There is a port if the input strings includes
1083 : * a `':'` character.
1084 : *
1085 : * If this function detects that a port is not allowed and yet
1086 : * a `':'` character is found, then it generates an error and
1087 : * returns without adding anything to `result`.
1088 : *
1089 : * \param[in] in The input string with the address and optional port.
1090 : * \param[in,out] result The list of resulting addresses.
1091 : */
1092 65865 : void addr_parser::parse_address4(std::string const & in, addr_range::vector_t & result)
1093 : {
1094 131729 : std::string address;
1095 131729 : std::string port_str;
1096 :
1097 65865 : std::string::size_type const p(in.find(':'));
1098 :
1099 131730 : if(get_allow(flag_t::PORT)
1100 65865 : || get_allow(flag_t::REQUIRED_PORT))
1101 : {
1102 : // the address can include a port
1103 : //
1104 65862 : if(p != std::string::npos)
1105 : {
1106 : // get the address only if not empty (otherwise we want to
1107 : // keep the default)
1108 : //
1109 65820 : if(p > 0)
1110 : {
1111 65710 : address = in.substr(0, p);
1112 : }
1113 :
1114 : // get the port only if not empty (otherwise we want to
1115 : // keep the default)
1116 : //
1117 65820 : if(p + 1 < in.length())
1118 : {
1119 65795 : port_str = in.substr(p + 1);
1120 : }
1121 : }
1122 42 : else if(!in.empty())
1123 : {
1124 38 : address = in;
1125 : }
1126 : }
1127 : else
1128 : {
1129 3 : if(p != std::string::npos
1130 1 : && !get_allow(flag_t::PORT)
1131 4 : && !get_allow(flag_t::REQUIRED_PORT))
1132 : {
1133 1 : emit_error("Port not allowed (" + in + ").");
1134 1 : return;
1135 : }
1136 :
1137 2 : if(!in.empty())
1138 : {
1139 1 : address = in;
1140 : }
1141 : }
1142 :
1143 65864 : parse_address_port(address, port_str, result, false);
1144 : }
1145 :
1146 :
1147 : /** \brief Parse one IPv6 address.
1148 : *
1149 : * This function checks the input parameter \p in and extracts the
1150 : * address and port. There is a port if the input strings includes
1151 : * a `':'` character after the closing square bracket (`']'`).
1152 : *
1153 : * If this function detects that a port is not allowed and yet
1154 : * a `':'` character is found, then it generates an error and
1155 : * returns without adding anything to `result`.
1156 : *
1157 : * \note
1158 : * This function can be called with an IPv6
1159 : *
1160 : * \param[in] in The input string with the address and optional port.
1161 : * \param[in,out] result The list of resulting addresses.
1162 : */
1163 65982 : void addr_parser::parse_address6(std::string const & in, addr_range::vector_t & result)
1164 : {
1165 65982 : std::string::size_type p(0);
1166 :
1167 131961 : std::string address;
1168 131961 : std::string port_str;
1169 :
1170 : // if there is an address extract it otherwise put the default
1171 : //
1172 131964 : if(!in.empty()
1173 65982 : && in[0] == '[')
1174 : {
1175 65778 : p = in.find(']');
1176 :
1177 65778 : if(p == std::string::npos)
1178 : {
1179 1 : emit_error("IPv6 is missing the ']' (" + in + ").");
1180 1 : return;
1181 : }
1182 :
1183 65777 : if(p != 1)
1184 : {
1185 : // get the address only if not empty (otherwise we want to
1186 : // keep the default) -- so we actually support "[]" to
1187 : // represent "use the default address if defined".
1188 : //
1189 65776 : address = in.substr(1, p - 1);
1190 : }
1191 : }
1192 :
1193 : // on entry 'p' is either 0 or the position of the ']' character
1194 : //
1195 65981 : p = in.find(':', p);
1196 :
1197 65981 : if(p != std::string::npos)
1198 : {
1199 131946 : if(get_allow(flag_t::PORT)
1200 65973 : || get_allow(flag_t::REQUIRED_PORT))
1201 : {
1202 : // there is also a port, extract it
1203 : //
1204 65971 : port_str = in.substr(p + 1);
1205 : }
1206 4 : else if(!get_allow(flag_t::PORT)
1207 2 : && !get_allow(flag_t::REQUIRED_PORT))
1208 : {
1209 2 : emit_error("Port not allowed (" + in + ").");
1210 2 : return;
1211 : }
1212 : }
1213 :
1214 65979 : parse_address_port(address, port_str, result, true);
1215 : }
1216 :
1217 :
1218 : /** \brief Parse the address and port.
1219 : *
1220 : * This function receives an address and a port string and
1221 : * convert them in an addr object which gets saved in
1222 : * the specified result range vector.
1223 : *
1224 : * The address can be an IPv4 or an IPv6 address.
1225 : *
1226 : * The port may be numeric or a name such as `"http"`.
1227 : *
1228 : * \note
1229 : * This function is not responsible for handling the default address
1230 : * and default port. This is expected to be dealt with by the caller
1231 : * if required.
1232 : *
1233 : * \param[in] address The address to convert to binary.
1234 : * \param[in] port_str The port as a string.
1235 : * \param[out] result The range where we save the results.
1236 : * \param[in] ipv6 Use the default IPv6 address if the address is empty.
1237 : */
1238 131843 : void addr_parser::parse_address_port(std::string address, std::string port_str, addr_range::vector_t & result, bool ipv6)
1239 : {
1240 : // make sure the port is good
1241 : //
1242 131843 : if(port_str.empty())
1243 : {
1244 77 : if(get_allow(flag_t::REQUIRED_PORT))
1245 : {
1246 4 : emit_error("Required port is missing.");
1247 4 : return;
1248 : }
1249 73 : if(f_default_port != -1)
1250 : {
1251 52 : port_str = std::to_string(f_default_port);
1252 : }
1253 : }
1254 :
1255 : // make sure the address is good
1256 : //
1257 131839 : if(address.empty())
1258 : {
1259 319 : if(get_allow(flag_t::REQUIRED_ADDRESS))
1260 : {
1261 2 : emit_error("Required address is missing.");
1262 2 : return;
1263 : }
1264 : // internal default if no address was defined
1265 : // (TBD: should it be an IPv6 instead?)
1266 : //
1267 317 : if(ipv6)
1268 : {
1269 203 : if(f_default_address6.empty())
1270 : {
1271 101 : address = "::";
1272 : }
1273 : else
1274 : {
1275 102 : address = f_default_address6;
1276 : }
1277 : }
1278 : else
1279 : {
1280 114 : if(f_default_address4.empty())
1281 : {
1282 11 : address = "0.0.0.0";
1283 : }
1284 : else
1285 : {
1286 103 : address = f_default_address4;
1287 : }
1288 : }
1289 : }
1290 :
1291 : // prepare hints for the the getaddrinfo() function
1292 : //
1293 131837 : addrinfo hints;
1294 131837 : memset(&hints, 0, sizeof(hints));
1295 131837 : hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG | AI_V4MAPPED;
1296 131837 : hints.ai_family = AF_UNSPEC;
1297 :
1298 131837 : switch(f_protocol)
1299 : {
1300 65998 : case IPPROTO_TCP:
1301 65998 : hints.ai_socktype = SOCK_STREAM;
1302 65998 : hints.ai_protocol = IPPROTO_TCP;
1303 65998 : break;
1304 :
1305 65825 : case IPPROTO_UDP:
1306 65825 : hints.ai_socktype = SOCK_DGRAM;
1307 65825 : hints.ai_protocol = IPPROTO_UDP;
1308 65825 : break;
1309 :
1310 : }
1311 :
1312 : // convert address to binary
1313 : //
1314 131837 : if(get_allow(flag_t::ADDRESS_LOOKUP))
1315 : {
1316 131832 : addrinfo * addrlist(nullptr);
1317 : {
1318 131832 : errno = 0;
1319 131832 : char const * service(port_str.c_str());
1320 131832 : if(port_str.empty())
1321 : {
1322 19 : service = "0"; // fallback to port 0 when unspecified
1323 : }
1324 131832 : int const r(getaddrinfo(address.c_str(), service, &hints, &addrlist));
1325 131832 : if(r != 0)
1326 : {
1327 : // break on invalid addresses
1328 : //
1329 2 : int const e(errno); // if r == EAI_SYSTEM, then 'errno' is consistent here
1330 6 : emit_error(
1331 : "Invalid address in \""
1332 4 : + address
1333 6 : + (port_str.empty() ? "" : ":")
1334 6 : + port_str
1335 6 : + "\" error "
1336 8 : + std::to_string(r)
1337 6 : + " -- "
1338 6 : + gai_strerror(r)
1339 8 : + (e == 0
1340 8 : ? ""
1341 : : " (errno: "
1342 4 : + std::to_string(e)
1343 6 : + " -- "
1344 6 : + strerror(e)
1345 : + ")."));
1346 2 : return;
1347 : }
1348 : }
1349 263660 : std::shared_ptr<addrinfo> ai(addrlist, addrinfo_deleter);
1350 :
1351 131830 : bool first(true);
1352 395538 : while(addrlist != nullptr)
1353 : {
1354 : // go through the addresses and create ranges and save that in the result
1355 : //
1356 131854 : if(addrlist->ai_family == AF_INET)
1357 : {
1358 65876 : if(addrlist->ai_addrlen != sizeof(sockaddr_in))
1359 : {
1360 : emit_error("Unsupported address size (" // LCOV_EXCL_LINE
1361 : + std::to_string(addrlist->ai_addrlen) // LCOV_EXCL_LINE
1362 : + ", expected" // LCOV_EXCL_LINE
1363 : + std::to_string(sizeof(sockaddr_in)) // LCOV_EXCL_LINE
1364 : + ")."); // LCOV_EXCL_LINE
1365 : }
1366 : else
1367 : {
1368 65876 : addr a(*reinterpret_cast<sockaddr_in *>(addrlist->ai_addr));
1369 : // in most cases we do not get a protocol from
1370 : // the getaddrinfo() function...
1371 65876 : a.set_protocol(addrlist->ai_protocol);
1372 65876 : addr_range r;
1373 65876 : r.set_from(a);
1374 65876 : result.push_back(r);
1375 : }
1376 : }
1377 65978 : else if(addrlist->ai_family == AF_INET6)
1378 : {
1379 65978 : if(addrlist->ai_addrlen != sizeof(sockaddr_in6))
1380 : {
1381 : emit_error("Unsupported address size (" // LCOV_EXCL_LINE
1382 : + std::to_string(addrlist->ai_addrlen) // LCOV_EXCL_LINE
1383 : + ", expected " // LCOV_EXCL_LINE
1384 : + std::to_string(sizeof(sockaddr_in6)) // LCOV_EXCL_LINE
1385 : + ")."); // LCOV_EXCL_LINE
1386 : }
1387 : else
1388 : {
1389 65978 : addr a(*reinterpret_cast<sockaddr_in6 *>(addrlist->ai_addr));
1390 65978 : a.set_protocol(addrlist->ai_protocol);
1391 65978 : addr_range r;
1392 65978 : r.set_from(a);
1393 65978 : result.push_back(r);
1394 : }
1395 : }
1396 : else if(first) // LCOV_EXCL_LINE
1397 : {
1398 : // ignore errors from further addresses
1399 : //
1400 : emit_error("Unsupported address family " // LCOV_EXCL_LINE
1401 : + std::to_string(addrlist->ai_family) // LCOV_EXCL_LINE
1402 : + "."); // LCOV_EXCL_LINE
1403 : }
1404 :
1405 131854 : first = false;
1406 :
1407 131854 : addrlist = addrlist->ai_next;
1408 : }
1409 : }
1410 : else
1411 : {
1412 5 : std::int64_t port(0);
1413 10 : if(get_allow(flag_t::REQUIRED_PORT)
1414 5 : || !port_str.empty())
1415 : {
1416 5 : bool const valid_port(advgetopt::validator_integer::convert_string(port_str, port));
1417 5 : if(!valid_port
1418 4 : || port < 0
1419 4 : || port > 65535)
1420 : {
1421 2 : emit_error("Invalid port in \""
1422 2 : + port_str
1423 3 : + "\" (no service name lookup allowed).");
1424 1 : return;
1425 : }
1426 :
1427 8 : if(!get_allow(flag_t::PORT)
1428 4 : && !get_allow(flag_t::REQUIRED_PORT))
1429 : {
1430 0 : emit_error("Found a port (\""
1431 0 : + port_str
1432 0 : + "\") when it is not allowed.");
1433 0 : return;
1434 : }
1435 : }
1436 4 : sockaddr_in in;
1437 4 : if(inet_pton(AF_INET, address.c_str(), &in.sin_addr) == 1)
1438 : {
1439 1 : in.sin_family = AF_INET;
1440 1 : in.sin_port = htons(port);
1441 1 : memset(in.sin_zero, 0, sizeof(in.sin_zero)); // probably useless
1442 :
1443 1 : addr a(in);
1444 1 : addr_range r;
1445 1 : r.set_from(a);
1446 1 : result.push_back(r);
1447 : }
1448 : else
1449 : {
1450 3 : sockaddr_in6 in6;
1451 3 : if(inet_pton(AF_INET6, address.c_str(), &in6.sin6_addr) == 1)
1452 : {
1453 1 : in6.sin6_family = AF_INET6;
1454 1 : in6.sin6_port = htons(port);
1455 1 : in6.sin6_flowinfo = 0;
1456 1 : in6.sin6_scope_id = 0;
1457 :
1458 1 : addr a(in6);
1459 1 : addr_range r;
1460 1 : r.set_from(a);
1461 1 : result.push_back(r);
1462 : }
1463 : else
1464 : {
1465 4 : emit_error("Unknown address in \""
1466 4 : + address
1467 6 : + "\" (no DNS lookup was allowed).");
1468 : }
1469 : }
1470 : }
1471 : }
1472 :
1473 :
1474 : /** \brief Parse a mask.
1475 : *
1476 : * If the input string is a decimal number, then use that as the
1477 : * number of bits to clear.
1478 : *
1479 : * If the mask is not just one decimal number, try to convert it
1480 : * as an address.
1481 : *
1482 : * If the string is neither a decimal number nor a valid IP address
1483 : * then the parser adds an error string to the f_error variable.
1484 : *
1485 : * \param[in] mask The mask to transform to binary.
1486 : * \param[in,out] cidr The address to which the mask will be added.
1487 : */
1488 474 : void addr_parser::parse_mask(std::string const & mask, addr & cidr)
1489 : {
1490 : // no mask?
1491 : //
1492 474 : if(mask.empty())
1493 : {
1494 : // in the current implementation this cannot happen since we
1495 : // do not call this function when mask is empty
1496 : //
1497 : // hwoever, the algorithm below expect that 'mask' is not
1498 : // empty (otherwise we get the case of 0 even though it
1499 : // may not be correct.)
1500 : //
1501 : return; // LCOV_EXCL_LINE
1502 : }
1503 :
1504 : // the mask may be a decimal number or an address, if just one number
1505 : // then it's not an address, so test that first
1506 : //
1507 470 : uint8_t mask_bits[16] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 };
1508 :
1509 : // convert the mask to an integer, if possible
1510 : //
1511 470 : int mask_count(0);
1512 : {
1513 1300 : for(char const * s(mask.c_str()); *s != '\0'; ++s)
1514 : {
1515 1028 : if(*s >= '0' && *s <= '9')
1516 : {
1517 845 : mask_count = mask_count * 10 + *s - '0';
1518 1675 : if(mask_count > 1000)
1519 : {
1520 30 : emit_error("Mask number too large ("
1521 30 : + mask
1522 45 : + ", expected a maximum of 128).");
1523 15 : return;
1524 : }
1525 : }
1526 : else
1527 : {
1528 183 : mask_count = -1;
1529 183 : break;
1530 : }
1531 : }
1532 : }
1533 :
1534 : // the conversion to an integer worked if mask_count != -1
1535 : //
1536 455 : if(mask_count != -1)
1537 : {
1538 272 : if(cidr.is_ipv4())
1539 : {
1540 42 : if(mask_count > 32)
1541 : {
1542 10 : emit_error("Unsupported mask size ("
1543 10 : + std::to_string(mask_count)
1544 15 : + ", expected 32 at the most for an IPv4).");
1545 5 : return;
1546 : }
1547 37 : mask_count = 32 - mask_count;
1548 : }
1549 : else
1550 : {
1551 230 : if(mask_count > 128)
1552 : {
1553 10 : emit_error("Unsupported mask size ("
1554 10 : + std::to_string(mask_count)
1555 15 : + ", expected 128 at the most for an IPv6).");
1556 5 : return;
1557 : }
1558 225 : mask_count = 128 - mask_count;
1559 : }
1560 :
1561 : // clear a few bits at the bottom of mask_bits
1562 : //
1563 262 : int idx(15);
1564 3322 : for(; mask_count > 8; mask_count -= 8, --idx)
1565 : {
1566 1530 : mask_bits[idx] = 0;
1567 : }
1568 262 : mask_bits[idx] = 255 << mask_count;
1569 : }
1570 : else //if(mask_count < 0)
1571 : {
1572 : // prepare hints for the the getaddrinfo() function
1573 : //
1574 183 : addrinfo hints;
1575 183 : memset(&hints, 0, sizeof(hints));
1576 183 : hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV | AI_ADDRCONFIG | AI_V4MAPPED;
1577 183 : hints.ai_family = AF_UNSPEC;
1578 :
1579 183 : switch(cidr.get_protocol())
1580 : {
1581 116 : case IPPROTO_TCP:
1582 116 : hints.ai_socktype = SOCK_STREAM;
1583 116 : hints.ai_protocol = IPPROTO_TCP;
1584 116 : break;
1585 :
1586 67 : case IPPROTO_UDP:
1587 67 : hints.ai_socktype = SOCK_DGRAM;
1588 67 : hints.ai_protocol = IPPROTO_UDP;
1589 67 : break;
1590 :
1591 : }
1592 :
1593 338 : std::string const port_str(std::to_string(cidr.get_port()));
1594 :
1595 : // if the mask is an IPv6, then it has to have the '[...]'
1596 338 : std::string m(mask);
1597 183 : if(cidr.is_ipv4())
1598 : {
1599 87 : if(mask[0] == '[')
1600 : {
1601 1 : emit_error("The address uses the IPv4 syntax, the mask cannot use IPv6.");
1602 1 : return;
1603 : }
1604 : }
1605 : else //if(!cidr.is_ipv4())
1606 : {
1607 96 : if(mask[0] != '[')
1608 : {
1609 1 : emit_error("The address uses the IPv6 syntax, the mask cannot use IPv4.");
1610 1 : return;
1611 : }
1612 95 : if(mask.back() != ']')
1613 : {
1614 1 : emit_error("The IPv6 mask is missing the ']' (" + mask + ").");
1615 1 : return;
1616 : }
1617 :
1618 : // note that we know that mask.length() >= 2 here since
1619 : // we at least have a '[' and ']'
1620 : //
1621 94 : m = mask.substr(1, mask.length() - 2);
1622 94 : if(m.empty())
1623 : {
1624 : // an empty mask is valid, it just means keep the default
1625 : // (getaddrinfo() fails on an empty string)
1626 : //
1627 3 : return;
1628 : }
1629 : }
1630 :
1631 : // if negative, we may have a full address here, so call the
1632 : // getaddrinfo() on this other string
1633 : //
1634 177 : addrinfo * masklist(nullptr);
1635 177 : errno = 0;
1636 177 : int const r(getaddrinfo(m.c_str(), port_str.c_str(), &hints, &masklist));
1637 177 : if(r != 0)
1638 : {
1639 : // break on invalid addresses
1640 : //
1641 15 : int const e(errno); // if r == EAI_SYSTEM, then 'errno' is consistent here
1642 30 : emit_error("Invalid mask in \"/"
1643 30 : + mask
1644 45 : + "\", error "
1645 60 : + std::to_string(r)
1646 45 : + " -- "
1647 45 : + gai_strerror(r)
1648 45 : + " (errno: "
1649 60 : + std::to_string(e)
1650 45 : + " -- "
1651 45 : + strerror(e)
1652 45 : + ").");
1653 15 : return;
1654 : }
1655 317 : std::shared_ptr<addrinfo> mask_ai(masklist, addrinfo_deleter);
1656 :
1657 162 : if(cidr.is_ipv4())
1658 : {
1659 76 : if(masklist->ai_family != AF_INET)
1660 : {
1661 : // this one happens when the user does not put the '[...]'
1662 : // around an IPv6 address
1663 : //
1664 1 : emit_error("Incompatible address between the address and"
1665 : " mask address (first was an IPv4 second an IPv6).");
1666 1 : return;
1667 : }
1668 75 : if(masklist->ai_addrlen != sizeof(sockaddr_in))
1669 : {
1670 : emit_error("Unsupported address size (" // LCOV_EXCL_LINE
1671 : + std::to_string(masklist->ai_addrlen) // LCOV_EXCL_LINE
1672 : + ", expected" // LCOV_EXCL_LINE
1673 : + std::to_string(sizeof(sockaddr_in)) // LCOV_EXCL_LINE
1674 : + ")."); // LCOV_EXCL_LINE
1675 : return; // LCOV_EXCL_LINE
1676 : }
1677 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
1678 : }
1679 : else //if(!cidr.is_ipv4())
1680 : {
1681 86 : if(masklist->ai_family != AF_INET6)
1682 : {
1683 : // this one happens if the user puts the '[...]'
1684 : // around an IPv4 address
1685 : //
1686 6 : emit_error("Incompatible address between the address"
1687 : " and mask address (first was an IPv6 second an IPv4).");
1688 6 : return;
1689 : }
1690 80 : if(masklist->ai_addrlen != sizeof(sockaddr_in6))
1691 : {
1692 : emit_error("Unsupported address size (" // LCOV_EXCL_LINE
1693 : + std::to_string(masklist->ai_addrlen) // LCOV_EXCL_LINE
1694 : + ", expected " // LCOV_EXCL_LINE
1695 : + std::to_string(sizeof(sockaddr_in6)) // LCOV_EXCL_LINE
1696 : + ")."); // LCOV_EXCL_LINE
1697 : return; // LCOV_EXCL_LINE
1698 : }
1699 80 : memcpy(mask_bits, &reinterpret_cast<sockaddr_in6 *>(masklist->ai_addr)->sin6_addr.s6_addr, 16);
1700 : }
1701 : }
1702 :
1703 417 : cidr.set_mask(mask_bits);
1704 : }
1705 :
1706 :
1707 : /** \brief Transform a string into an `addr` object.
1708 : *
1709 : * This function converts the string \p a in an IP address saved in
1710 : * the returned addr object or throws an error if the conversion
1711 : * fails.
1712 : *
1713 : * The \p default_address parameter string can be set to an address
1714 : * which is returned if the input in \p a does not include an
1715 : * address such as in ":123".
1716 : *
1717 : * The \p port parameter can be specified or set to -1. If -1, then
1718 : * there is no default port. Either way, the port can be defined in
1719 : * \p a.
1720 : *
1721 : * The protocol can be specified, as a string. For example, you can
1722 : * use "tcp". The default is no specific protocol which means any
1723 : * type of IP address can be returned. Note that if more than one
1724 : * result is returned when the protocol was not specified, the
1725 : * results will be filtered to only keep the address that uses the
1726 : * TCP protocol. If as a result we have a single address, then that
1727 : * result gets returned.
1728 : *
1729 : * \note
1730 : * This function does not allow for address or port ranges. It is
1731 : * expected to return exactly one address. You can allow a \p mask
1732 : * by setting that parameter to true.
1733 : *
1734 : * \exception addr_invalid_argument
1735 : * If the parsed address is not returning a valid `addr` object, then
1736 : * this function fails by throwing an error. If you would prefer to
1737 : * handle the error mechanism, you want to create your own addr_parser
1738 : * and then call the addr_parser::parse() function. This will allow
1739 : * you to get error messages instead of an exception.
1740 : *
1741 : * \param[in] a The address string to be converted.
1742 : * \param[in] default_addrress The default address or an empty string.
1743 : * \param[in] default_port The default port or -1
1744 : * \param[in] protocol The protocol the address has to be of, or the
1745 : * empty string to allow any protocol.
1746 : * \param[in] m Whether to allow a mask (true) or not (false).
1747 : *
1748 : * \return The address converted in an `addr` object.
1749 : *
1750 : * \sa addr_parser::parse()
1751 : */
1752 14 : addr string_to_addr(
1753 : std::string const & a
1754 : , std::string const & default_address
1755 : , int default_port
1756 : , std::string const & protocol
1757 : , bool mask)
1758 : {
1759 28 : addr_parser p;
1760 :
1761 14 : if(!default_address.empty())
1762 : {
1763 10 : p.set_default_address(default_address);
1764 : }
1765 :
1766 14 : if(default_port != -1)
1767 : {
1768 8 : p.set_default_port(default_port);
1769 : }
1770 :
1771 14 : if(!protocol.empty())
1772 : {
1773 7 : p.set_protocol(protocol);
1774 : }
1775 :
1776 13 : p.set_allow(addr_parser::flag_t::MASK, mask);
1777 :
1778 26 : addr_range::vector_t result(p.parse(a));
1779 :
1780 13 : if(result.size() != 1)
1781 : {
1782 : // when the protocol is not specified, this happens like all the
1783 : // time, we search for an entry with protocol TCP by default
1784 : // because in most cases that's what people want
1785 : //
1786 7 : if(protocol.empty())
1787 : {
1788 21 : result.erase(
1789 14 : std::remove_if(
1790 : result.begin()
1791 : , result.end()
1792 21 : , [](auto const it)
1793 : {
1794 21 : return it.has_from() && it.get_from().get_protocol() != IPPROTO_TCP;
1795 28 : })
1796 35 : , result.end());
1797 : }
1798 7 : if(result.size() != 1)
1799 : {
1800 : // an invalid protocol is caught by the set_protocol()
1801 : // function so we should never be able to reach here
1802 : //
1803 : throw addr_invalid_argument( // LCOV_EXCL_LINE
1804 : "the address \"" // LCOV_EXCL_LINE
1805 : + a // LCOV_EXCL_LINE
1806 : + "\" could not be converted to a single address in string_to_addr(), found " // LCOV_EXCL_LINE
1807 : + std::to_string(result.size()) // LCOV_EXCL_LINE
1808 : + " entries instead."); // LCOV_EXCL_LINE
1809 : }
1810 : }
1811 :
1812 : // at the movement we only can get a "to" so the following exceptions
1813 : // can't happen which is why we have an LCOV_EXCL_LINE
1814 : //
1815 26 : if(result[0].has_to()
1816 13 : || result[0].is_range())
1817 : {
1818 : throw addr_invalid_argument("string_to_addr() does not support ranges."); // LCOV_EXCL_LINE
1819 : }
1820 :
1821 13 : if(!result[0].has_from())
1822 : {
1823 : throw addr_invalid_argument("string_to_addr() has no 'from' address."); // LCOV_EXCL_LINE
1824 : }
1825 :
1826 26 : return result[0].get_from();
1827 : }
1828 :
1829 :
1830 :
1831 6 : }
1832 : // namespace addr
1833 : // vim: ts=4 sw=4 et
|