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