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