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