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