OpenVPN 3 Core Library
Loading...
Searching...
No Matches
options.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12// General-purpose options parser, used to parse the OpenVPN configuration
13// file as well as the server-pushed options list. Note that these classes
14// don't get into the interpretation or typing of options -- they only care
15// about parsing the options into lists of strings, and then presenting the
16// complete configuration file as a list of options.
17//
18// The parser understands the general grammar of OpenVPN configuration
19// files including:
20//
21// 1. option/argument parsing, quoting, escaping, and comments,
22// 2. inline directives such as
23// <ca>
24// ...
25// </ca>
26// 3. and meta-directives such as those used by OpenVPN Access Server such as:
27// # OVPN_ACCESS_SERVER_USERNAME=test
28//
29// The basic organization of the parser is as follows:
30//
31// Option -- a list of strings, where the first string is the
32// option/directive name, and subsequent strings are arguments.
33//
34// OptionList -- a list of Options that also contains a map for
35// optimal lookup of specific options
36
37#ifndef OPENVPN_COMMON_OPTIONS_H
38#define OPENVPN_COMMON_OPTIONS_H
39
40#include <string>
41#include <sstream>
42#include <vector>
43#include <algorithm> // for std::sort, std::min
44#include <utility> // for std::move
45#include <type_traits> // for std::is_nothrow_move_constructible
46#include <unordered_map>
47#include <cstdint> // for std::uint64_t
48
49#include <openvpn/common/rc.hpp>
58
59namespace openvpn {
60
61class Option
62{
63 public:
64 OPENVPN_UNTAGGED_EXCEPTION(RejectedException);
65 enum
66 {
67 MULTILINE = 0x8000000,
68 };
69
70 // Validate string by size and multiline status.
71 // OR max_len with MULTILINE to allow multiline string.
72 // Return values:
79
80 // Options for render methods
82 {
83 RENDER_TRUNC_64 = (1 << 0), // truncate option after 64 chars
84 RENDER_PASS_FMT = (1 << 1), // pass \r\n\t
85 RENDER_NUMBER = (1 << 2), // number lines
86 RENDER_BRACKET = (1 << 3), // quote options using []
87 RENDER_UNUSED = (1 << 4), // only show unused options
88 };
89
91 {
92 static_assert(std::is_nothrow_move_constructible<Option>::value, "class Option not noexcept move constructable");
93 }
94
95 template <typename T, typename... Args>
96 explicit Option(T first, Args... args)
97 {
98 reserve(1 + sizeof...(args));
99 from_list(std::move(first), std::forward<Args>(args)...);
100 }
101
102 static validate_status validate(const std::string &str, const size_t max_len)
103 {
104 const size_t pos = str.find_first_of("\r\n");
105 const size_t len = max_len & ((size_t)MULTILINE - 1); // NOTE -- use smallest flag value here
106 if (pos != std::string::npos && !(max_len & MULTILINE))
107 return STATUS_MULTILINE;
108 else if (len > 0 && Unicode::utf8_length(str) > len)
109 return STATUS_LENGTH;
110 else
111 return STATUS_GOOD;
112 }
113
114 static const char *validate_status_description(const validate_status status)
115 {
116 switch (status)
117 {
118 case STATUS_GOOD:
119 return "good";
120 case STATUS_MULTILINE:
121 return "multiline";
122 case STATUS_LENGTH:
123 return "too long";
124 default:
125 return "unknown";
126 }
127 }
128
129 void min_args(const size_t n) const
130 {
131 const size_t s = data.size();
132 if (s < n)
133 OPENVPN_THROW_ARG1(option_error, ERR_INVALID_OPTION_VAL, err_ref() << " must have at least " << (n - 1) << " arguments");
134 }
135
136 void exact_args(const size_t n) const
137 {
138 const size_t s = data.size();
139 if (s != n)
140 OPENVPN_THROW_ARG1(option_error, ERR_INVALID_OPTION_VAL, err_ref() << " must have exactly " << n << " arguments");
141 }
142
143 void validate_arg(const size_t index, const size_t max_len) const
144 {
145 if (max_len > 0 && index < data.size())
146 {
147 const validate_status status = validate(data[index], max_len);
148 if (status != STATUS_GOOD)
149 OPENVPN_THROW_ARG1(option_error, ERR_INVALID_OPTION_VAL, err_ref() << " is " << validate_status_description(status));
150 }
151 }
152
153 bool is_multiline() const
154 {
155 if (data.size() == 2)
156 {
157 const std::string &str = data[1];
158 const size_t pos = str.find_first_of("\r\n");
159 return pos != std::string::npos;
160 }
161 else
162 return false;
163 }
164
165 static void validate_string(const std::string &name, const std::string &str, const size_t max_len)
166 {
167 const validate_status status = validate(str, max_len);
168 if (status != STATUS_GOOD)
169 OPENVPN_THROW_ARG1(option_error, ERR_INVALID_OPTION_VAL, name << " is " << validate_status_description(status));
170 }
171
172 std::string printable_directive() const
173 {
174 try
175 {
176 if (data.size() > 0)
177 return Unicode::utf8_printable(data[0], 32);
178 else
179 return "";
180 }
181 catch (const std::exception &)
182 {
183 return "[DIRECTIVE]";
184 }
185 }
186
187 const std::string &get(const size_t index, const size_t max_len) const
188 {
189 min_args(index + 1);
190 validate_arg(index, max_len);
191 return data[index];
192 }
193
194 std::string get_optional(const size_t index, const size_t max_len) const
195 {
196 validate_arg(index, max_len);
197 if (index < data.size())
198 return data[index];
199 else
200 return "";
201 }
202
203 std::string get_default(const size_t index, const size_t max_len, const std::string &default_value) const
204 {
205 validate_arg(index, max_len);
206 if (index < data.size())
207 return data[index];
208 else
209 return default_value;
210 }
211
212 const std::string *get_ptr(const size_t index, const size_t max_len) const
213 {
214 validate_arg(index, max_len);
215 if (index < data.size())
216 return &data[index];
217 else
218 return nullptr;
219 }
220
221 template <typename T>
222 T get_num(const size_t idx) const
223 {
224 typedef typename std::remove_const<T>::type T_nonconst;
225 T_nonconst n(0); // we shouldn't need to initialize here, but some compilers complain "may be used uninitialized in this function"
226 const std::string &numstr = get(idx, 64);
227 if (numstr.length() >= 2 && numstr[0] == '0' && numstr[1] == 'x')
228 {
229 if (!parse_hex_number(numstr.substr(2), n))
230 OPENVPN_THROW_ARG1(option_error, ERR_INVALID_OPTION_VAL, err_ref() << '[' << idx << "] expecting a hex number");
231 }
232 else if (!parse_number<T_nonconst>(numstr, n))
233 OPENVPN_THROW_ARG1(option_error, ERR_INVALID_OPTION_VAL, err_ref() << '[' << idx << "] must be a number");
234 return n;
235 }
236
237 template <typename T>
238 T get_num(const size_t idx, const T default_value) const
239 {
240 if (size() > idx)
241 return get_num<T>(idx);
242 else
243 return default_value;
244 }
245
246 template <typename T>
247 T get_num(const size_t idx, const T default_value, const T min_value, const T max_value) const
248 {
249 const T ret = get_num<T>(idx, default_value);
250 if (ret != default_value && (ret < min_value || ret > max_value))
251 range_error(idx, min_value, max_value);
252 return ret;
253 }
254
255 template <typename T>
256 T get_num(const size_t idx, const T min_value, const T max_value) const
257 {
258 const T ret = get_num<T>(idx);
259 if (ret < min_value || ret > max_value)
260 range_error(idx, min_value, max_value);
261 return ret;
262 }
263
264 std::string render(const unsigned int flags) const
265 {
266 std::ostringstream out;
267 size_t max_len_flags = (flags & RENDER_TRUNC_64) ? 64 : 0;
269 max_len_flags |= Unicode::UTF8_PASS_FMT;
270 bool first = true;
271 for (std::vector<std::string>::const_iterator i = data.begin(); i != data.end(); ++i)
272 {
273 if (!first)
274 out << ' ';
275 if (flags & RENDER_BRACKET)
276 out << '[';
277 out << Unicode::utf8_printable(*i, max_len_flags);
278 if (flags & RENDER_BRACKET)
279 out << ']';
280 first = false;
281 }
282 return out.str();
283 }
284
285 static void escape_string(std::ostream &out, const std::string &term, const bool must_quote)
286 {
287 if (must_quote)
288 out << '\"';
289 for (std::string::const_iterator j = term.begin(); j != term.end(); ++j)
290 {
291 const char c = *j;
292 if (c == '\"' || c == '\\')
293 out << '\\';
294 out << c;
295 }
296 if (must_quote)
297 out << '\"';
298 }
299
300 // Render the option args into a string format such that it could be parsed back to
301 // the equivalent option args.
302 std::string escape(const bool csv) const
303 {
304 std::ostringstream out;
305 bool more = false;
306 for (std::vector<std::string>::const_iterator i = data.begin(); i != data.end(); ++i)
307 {
308 const std::string &term = *i;
309 const bool must_quote = must_quote_string(term, csv);
310 if (more)
311 out << ' ';
312 escape_string(out, term, must_quote);
313 more = true;
314 }
315 return out.str();
316 }
317
318 void clear()
319 {
320 data.clear();
322 warn_only_if_unknown_ = false;
323 meta_ = false;
324 }
325
326 // delegate to data
327 size_t size() const
328 {
329 return data.size();
330 }
331 bool empty() const
332 {
333 return data.empty();
334 }
335 void push_back(const std::string &item)
336 {
337 data.push_back(item);
338 }
339 void push_back(std::string &&item)
340 {
341 data.push_back(std::move(item));
342 }
343 void reserve(const size_t n)
344 {
345 data.reserve(n);
346 }
347 void resize(const size_t n)
348 {
349 data.resize(n);
350 }
351
352 // raw references to data
353 const std::string &ref(const size_t i) const
354 {
355 return data[i];
356 }
357 std::string &ref(const size_t i)
358 {
359 return data[i];
360 }
361
362 // equality
363 bool operator==(const Option &other) const
364 {
365 return data == other.data;
366 }
367 bool operator!=(const Option &other) const
368 {
369 return data != other.data;
370 }
371
372 // remove first n elements
373 void remove_first(const size_t n_elements)
374 {
375 const size_t n = std::min(data.size(), n_elements);
376 if (n)
377 data.erase(data.begin(), data.begin() + n);
378 }
379
385 void touch(bool lightly = false) const
386 {
387 // Note that we violate constness here, which is done
388 // because the touched bit is considered to be option metadata.
389 if (lightly)
390 {
393 }
394 else
395 {
397 }
398 }
399
401 {
403 }
404
405 bool warnonlyunknown() const
406 {
408 }
409
410 // was this option processed?
411 bool touched() const
412 {
414 }
415
416 // was an option of the same name (or this option see \c touched)
417 // touched
422
423
424 // refer to the option when constructing an error message
425 std::string err_ref() const
426 {
427 std::string ret = "option";
428 if (data.size())
429 {
430 ret += " '";
432 ret += '\'';
433 }
434 return ret;
435 }
436
441 void set_meta(bool value = true)
442 {
443 meta_ = value;
444 }
445
451 bool meta() const
452 {
453 return meta_;
454 }
455
456 private:
457 void from_list(std::string arg)
458 {
459 push_back(std::move(arg));
460 }
461
462 void from_list(const char *arg)
463 {
464 push_back(std::string(arg));
465 }
466
467 void from_list(std::vector<std::string> arg)
468 {
469 data.insert(data.end(), arg.begin(), arg.end());
470 }
471
472 template <typename T, typename... Args>
473 void from_list(T first, Args... args)
474 {
475 from_list(std::move(first));
476 from_list(std::forward<Args>(args)...);
477 }
478
479 template <typename T>
480 void range_error(const size_t idx, const T min_value, const T max_value) const
481 {
482 OPENVPN_THROW_ARG1(option_error, ERR_INVALID_OPTION_VAL, err_ref() << '[' << idx << "] must be in the range [" << min_value << ',' << max_value << ']');
483 }
484
485 bool must_quote_string(const std::string &str, const bool csv) const
486 {
487 for (const auto c : str)
488 {
489 if (string::is_space(c))
490 return true;
491 if (csv && c == ',')
492 return true;
493 }
494 return false;
495 }
496
498 enum class touchedState
499 {
500 /* Option was never used */
507 TOUCHED
508 };
510
512 bool meta_ = false;
513 std::vector<std::string> data;
514};
515
516class OptionList : public std::vector<Option>, public RCCopyable<thread_unsafe_refcount>
517{
518 public:
520 typedef std::vector<unsigned int> IndexList;
521 typedef std::unordered_map<std::string, IndexList> IndexMap;
522 typedef std::pair<std::string, IndexList> IndexPair;
523
524 static bool is_comment(const char c)
525 {
526 return c == '#' || c == ';';
527 }
528
529 // standard lex filter that doesn't understand end-of-line comments
531
532 // special lex filter that recognizes end-of-line comments
534 {
535 public:
536 LexComment() = default;
537
538 void put(char c)
539 {
540 if (in_comment)
541 {
542 ch = -1;
543 }
544 else if (backslash)
545 {
546 ch = c;
547 backslash = false;
548 }
549 else if (c == '\\')
550 {
551 backslash = true;
552 ch = -1;
553 }
554 else if (handle_quote(c))
555 {
556 ch = -1;
557 }
558 else if (is_comment(c) && !in_quote())
559 {
560 in_comment = true;
561 ch = -1;
562 }
563 else
564 {
565 ch = c;
566 }
567 }
568
569 bool available() const
570 {
571 return ch != -1;
572 }
573 int get() const
574 {
575 return ch;
576 }
577 void reset()
578 {
579 ch = -1;
580 }
581
582 private:
583 bool in_comment = false;
584 bool backslash = false;
585 int ch = -1;
586 };
587
588 class Limits
589 {
590 public:
591 Limits(const std::string &error_message,
592 const std::uint64_t max_bytes_arg,
593 const size_t extra_bytes_per_opt_arg,
594 const size_t extra_bytes_per_term_arg,
595 const size_t max_line_len_arg,
596 const size_t max_directive_len_arg)
597 : bytes(0),
598 max_bytes(max_bytes_arg),
599 extra_bytes_per_opt(extra_bytes_per_opt_arg),
600 extra_bytes_per_term(extra_bytes_per_term_arg),
601 max_line_len(max_line_len_arg),
602 max_directive_len(max_directive_len_arg),
603 err(error_message)
604 {
605 }
606
607 void add_bytes(const size_t n)
608 {
609 bytes += n;
611 }
612
613 void add_string(const std::string &str)
614 {
615 bytes += str.length();
617 }
618
619 void add_term()
620 {
623 }
624
625 void add_opt()
626 {
629 }
630
631 size_t get_max_line_len() const
632 {
633 return max_line_len;
634 }
635
636 std::uint64_t get_bytes() const
637 {
638 return bytes;
639 }
640
641 void validate_directive(const Option &opt)
642 {
644 }
645
646 private:
648 {
649 if (bytes >= max_bytes)
650 error();
651 }
652
653 void error()
654 {
655 throw option_error(ERR_INVALID_CONFIG, err);
656 }
657
658 std::uint64_t bytes;
659 const std::uint64_t max_bytes;
662 const size_t max_line_len;
663 const size_t max_directive_len;
664 const std::string err;
665 };
666
667 // Used by extend() to optionally control which options are copied.
668 struct FilterBase : public RC<thread_unsafe_refcount>
669 {
671 virtual bool filter(const Option &opt) = 0;
672 };
673
674 class KeyValue : public RC<thread_unsafe_refcount>
675 {
676 public:
678
680 : key_priority(0)
681 {
682 }
683 KeyValue(const std::string &key_arg, const std::string &value_arg, const int key_priority_arg = 0)
684 : key(key_arg), value(value_arg), key_priority(key_priority_arg)
685 {
686 }
687
688 size_t combined_length() const
689 {
690 return key.length() + value.length();
691 }
692
693 Option convert_to_option(Limits *lim, const std::string &meta_prefix) const
694 {
695 bool newline_present = false;
696 Option opt;
697 const std::string unesc_value = unescape(value, newline_present);
698
699 if (string::starts_with(key, meta_prefix))
700 {
701 opt.push_back(std::string(key, meta_prefix.length()));
702 opt.set_meta();
703 }
704 else
705 {
706 opt.push_back(key);
707 }
708
709 if (newline_present || singular_arg(key))
710 opt.push_back(unesc_value);
711 else if (unesc_value != "NOARGS")
712 Split::by_space_void<Option, Lex, SpaceMatch, Limits>(opt, unesc_value, lim);
713 return opt;
714 }
715
717 {
718 // look for usage such as: remote.7
719 const size_t dp = key.find_last_of(".");
720 if (dp != std::string::npos)
721 {
722 const size_t tp = dp + 1;
723 if (tp < key.length())
724 {
725 const char *tail = key.c_str() + tp;
726 try
727 {
728 key_priority = parse_number_throw<int>(tail, "option priority");
729 key = key.substr(0, dp);
730 }
731 catch (const number_parse_exception &)
732 {
733 ;
734 }
735 }
736 }
737 }
738
739 static bool compare(const Ptr &a, const Ptr &b)
740 {
741 const int cmp = a->key.compare(b->key);
742 if (cmp < 0)
743 return true;
744 else if (cmp > 0)
745 return false;
746 else
747 return a->key_priority < b->key_priority;
748 }
749
750 std::string key;
751 std::string value;
753
754 private:
755 static std::string unescape(const std::string &value, bool &newline_present)
756 {
757 std::string ret;
758 ret.reserve(value.length());
759
760 bool bs = false;
761 for (size_t i = 0; i < value.length(); ++i)
762 {
763 const char c = value[i];
764 if (bs)
765 {
766 if (c == 'n')
767 {
768 ret += '\n';
769 newline_present = true;
770 }
771 else if (c == '\\')
772 ret += '\\';
773 else
774 {
775 ret += '\\';
776 ret += c;
777 }
778 bs = false;
779 }
780 else
781 {
782 if (c == '\\')
783 bs = true;
784 else
785 ret += c;
786 }
787 }
788 if (bs)
789 ret += '\\';
790 return ret;
791 }
792
793 static bool singular_arg(const std::string &key)
794 {
795 bool upper = false;
796 bool lower = false;
797 for (size_t i = 0; i < key.length(); ++i)
798 {
799 const char c = key[i];
800 if (c >= 'a' && c <= 'z')
801 lower = true;
802 else if (c >= 'A' && c <= 'Z')
803 upper = true;
804 }
805 return upper && !lower;
806 }
807 };
808
809 struct KeyValueList : public std::vector<KeyValue::Ptr>
810 {
812 {
814 sort();
815 }
816
818 {
819 for (iterator i = begin(); i != end(); ++i)
820 {
821 KeyValue &kv = **i;
822 kv.split_priority();
823 }
824 }
825
826 void sort()
827 {
828 std::sort(begin(), end(), KeyValue::compare);
829 }
830 };
831
833 {
834 }
835
836 template <typename T, typename... Args>
837 explicit OptionList(T first, Args... args)
838 {
839 reserve(1 + sizeof...(args));
840 from_list(std::move(first), std::forward<Args>(args)...);
841 update_map();
842 }
843
844 static OptionList parse_from_csv_static(const std::string &str, Limits *lim)
845 {
847 ret.parse_from_csv(str, lim);
848 ret.update_map();
849 return ret;
850 }
851
852 static OptionList parse_from_csv_static_nomap(const std::string &str, Limits *lim)
853 {
855 ret.parse_from_csv(str, lim);
856 return ret;
857 }
858
859 static OptionList parse_from_config_static(const std::string &str, Limits *lim)
860 {
862 ret.parse_from_config(str, lim);
863 ret.update_map();
864 return ret;
865 }
866
867 static OptionList::Ptr parse_from_config_static_ptr(const std::string &str, Limits *lim)
868 {
870 ret->parse_from_config(str, lim);
871 ret->update_map();
872 return ret;
873 }
874
875 static OptionList parse_from_argv_static(const std::vector<std::string> &argv)
876 {
878 ret.parse_from_argv(argv);
879 ret.update_map();
880 return ret;
881 }
882
883 void clear()
884 {
885 std::vector<Option>::clear();
886 map_.clear();
887 }
888
889 // caller should call update_map() after this function
890 void parse_from_csv(const std::string &str, Limits *lim)
891 {
892 if (lim)
893 lim->add_string(str);
894 std::vector<std::string> list = Split::by_char<std::vector<std::string>, Lex, Limits>(str, ',', 0, ~0, lim);
895 for (std::vector<std::string>::const_iterator i = list.begin(); i != list.end(); ++i)
896 {
897 const Option opt = Split::by_space<Option, Lex, SpaceMatch, Limits>(*i, lim);
898 if (opt.size())
899 {
900 if (lim)
901 {
902 lim->add_opt();
903 lim->validate_directive(opt);
904 }
905 push_back(std::move(opt));
906 }
907 }
908 }
909
910 // caller should call update_map() after this function
911 void parse_from_argv(const std::vector<std::string> &argv)
912 {
913 Option opt;
914 for (auto &arg : argv)
915 {
916 std::string a = arg;
917 if (string::starts_with(a, "--"))
918 {
919 if (!opt.empty())
920 {
921 push_back(std::move(opt));
922 opt.clear();
923 }
924 a = a.substr(2);
925 }
926 if (!a.empty())
927 opt.push_back(a);
928 }
929 if (!opt.empty())
930 push_back(std::move(opt));
931 }
932
933 // caller should call update_map() after this function
934 void parse_from_peer_info(const std::string &str, Limits *lim)
935 {
936 if (lim)
937 lim->add_string(str);
938 SplitLines in(str, 0);
939 while (in(true))
940 {
941 const std::string &line = in.line_ref();
942 Option opt;
943 opt.reserve(2);
944 Split::by_char_void<Option, NullLex, Limits>(opt, line, '=', 0, 1, lim);
945 if (opt.size())
946 {
947 if (lim)
948 {
949 lim->add_opt();
950 lim->validate_directive(opt);
951 }
952 push_back(std::move(opt));
953 }
954 }
955 }
956
957 // caller may want to call list.preprocess() before this function
958 // caller should call update_map() after this function
959 void parse_from_key_value_list(const KeyValueList &list, const std::string &meta_tag, Limits *lim)
960 {
961 const std::string meta_prefix = meta_tag + "_";
962
963 for (KeyValueList::const_iterator i = list.begin(); i != list.end(); ++i)
964 {
965 const KeyValue &kv = **i;
966 if (lim)
967 lim->add_bytes(kv.combined_length());
968
969 Option opt = kv.convert_to_option(lim, meta_prefix);
970 if (lim)
971 {
972 lim->add_opt();
973 lim->validate_directive(opt);
974 }
975 push_back(std::move(opt));
976 }
977 }
978
979 static Option parse_option_from_line(const std::string &line, Limits *lim)
980 {
981 return Split::by_space<Option, LexComment, SpaceMatch, Limits>(line, lim);
982 }
983
984 // caller should call update_map() after this function
985 void parse_from_config(const std::string &str, Limits *lim)
986 {
987 if (lim)
988 lim->add_string(str);
989
990 SplitLines in(str, lim ? lim->get_max_line_len() : 0);
991 int line_num = 0;
992 bool in_multiline = false;
993 Option multiline;
994 while (in(true))
995 {
996 ++line_num;
997 if (in.line_overflow())
998 line_too_long(line_num);
999 const std::string &line = in.line_ref();
1000 if (in_multiline)
1001 {
1002 if (is_close_tag(line, multiline.ref(0)))
1003 {
1004 if (lim)
1005 {
1006 lim->add_opt();
1007 lim->validate_directive(multiline);
1008 }
1009 multiline.set_meta(true);
1010 push_back(std::move(multiline));
1011 multiline.clear();
1012 in_multiline = false;
1013 }
1014 else
1015 {
1016 std::string &mref = multiline.ref(1);
1017 mref += line;
1018 mref += '\n';
1019 }
1020 }
1021 else if (!ignore_line(line))
1022 {
1023 Option opt = parse_option_from_line(line, lim);
1024 if (opt.size())
1025 {
1026 if (is_open_tag(opt.ref(0)))
1027 {
1028 if (opt.size() > 1)
1029 extraneous_err(line_num, "option", opt);
1030 untag_open_tag(opt.ref(0));
1031 opt.push_back("");
1032 multiline = std::move(opt);
1033 in_multiline = true;
1034 }
1035 else
1036 {
1037 if (lim)
1038 {
1039 lim->add_opt();
1040 lim->validate_directive(opt);
1041 }
1042 push_back(std::move(opt));
1043 }
1044 }
1045 }
1046 }
1047 if (in_multiline)
1048 not_closed_out_err("option", multiline);
1049 }
1050
1051 // caller should call update_map() after this function
1052 void parse_meta_from_config(const std::string &str, const std::string &tag, Limits *lim)
1053 {
1054 SplitLines in(str, lim ? lim->get_max_line_len() : 0);
1055 int line_num = 0;
1056 bool in_multiline = false;
1057 Option multiline;
1058 const std::string prefix = tag + "_";
1059 while (in(true))
1060 {
1061 ++line_num;
1062 if (in.line_overflow())
1063 line_too_long(line_num);
1064 std::string &line = in.line_ref();
1065 if (string::starts_with(line, "# "))
1066 {
1067 line = std::string(line, 2);
1068 if (in_multiline)
1069 {
1070 if (is_close_meta_tag(line, prefix, multiline.ref(0)))
1071 {
1072 if (lim)
1073 {
1074 lim->add_opt();
1075 lim->validate_directive(multiline);
1076 }
1077 multiline.set_meta(true);
1078 push_back(std::move(multiline));
1079 multiline.clear();
1080 in_multiline = false;
1081 }
1082 else
1083 {
1084 std::string &mref = multiline.ref(1);
1085 mref += line;
1086 mref += '\n';
1087 }
1088 }
1089 else if (string::starts_with(line, prefix))
1090 {
1091 Option opt = Split::by_char<Option, NullLex, Limits>(std::string(line, prefix.length()), '=', 0, 1, lim);
1092 if (opt.size())
1093 {
1094 if (is_open_meta_tag(opt.ref(0)))
1095 {
1096 if (opt.size() > 1)
1097 extraneous_err(line_num, "meta option", opt);
1098 untag_open_meta_tag(opt.ref(0));
1099 opt.push_back("");
1100 multiline = std::move(opt);
1101 in_multiline = true;
1102 }
1103 else
1104 {
1105 if (lim)
1106 {
1107 lim->add_opt();
1108 lim->validate_directive(opt);
1109 }
1110 opt.set_meta(true);
1111 push_back(std::move(opt));
1112 }
1113 }
1114 }
1115 }
1116 }
1117 if (in_multiline)
1118 not_closed_out_err("meta option", multiline);
1119 }
1120
1121 // Append elements in other to self,
1122 // caller should call update_map() after this function.
1123 void extend(const OptionList &other, FilterBase *filt = nullptr)
1124 {
1125 reserve(size() + other.size());
1126 for (const auto &opt : other)
1127 {
1128 if (!filt || filt->filter(opt))
1129 {
1130 push_back(opt);
1131 opt.touch();
1132 }
1133 }
1134 }
1135
1136 // Append elements in other to self,
1137 // consumes other,
1138 // caller should call update_map() after this function.
1139 void extend(OptionList &&other, FilterBase *filt = nullptr)
1140 {
1141 reserve(size() + other.size());
1142 for (auto &opt : other)
1143 {
1144 if (!filt || filt->filter(opt))
1145 push_back(std::move(opt));
1146 }
1147 }
1148
1149 // Append elements in other having given name to self,
1150 // caller should call update_map() after this function.
1151 // Return the number of elements processed.
1152 unsigned int extend(const OptionList &other, const std::string &name)
1153 {
1154 IndexMap::const_iterator oi = other.map().find(name);
1155 unsigned int count = 0;
1156 if (oi != other.map().end())
1157 for (IndexList::const_iterator i = oi->second.begin(); i != oi->second.end(); ++i)
1158 {
1159 const Option &opt = other[*i];
1160 push_back(opt);
1161 opt.touch();
1162 ++count;
1163 }
1164 return count;
1165 }
1166
1167 // Append to self only those elements in other that do not exist
1168 // in self, caller should call update_map() after this function.
1169 // Caller should also consider calling update_map() before this function,
1170 // to ensure that lookups on this->map will see up-to-date data.
1172 {
1173 for (std::vector<Option>::const_iterator i = other.begin(); i != other.end(); ++i)
1174 {
1175 const Option &opt = *i;
1176 if (!opt.empty() && map().find(opt.ref(0)) == map().end())
1177 {
1178 push_back(opt);
1179 opt.touch();
1180 }
1181 }
1182 }
1183
1184 // Get the last instance of an option, or return nullptr if option
1185 // doesn't exist.
1186 const Option *get_ptr(const std::string &name) const
1187 {
1188 IndexMap::const_iterator e = map_.find(name);
1189 if (e != map_.end())
1190 {
1191 const size_t size = e->second.size();
1192 if (size)
1193 {
1194 for (const auto &optidx : e->second)
1195 {
1196 (*this)[optidx].touch(true);
1197 }
1198 const Option *ret = &((*this)[e->second[size - 1]]);
1199 ret->touch();
1200 return ret;
1201 }
1202 }
1203 return nullptr;
1204 }
1205
1206 // Get an option, return nullptr if option doesn't exist, or
1207 // throw an error if more than one instance exists.
1208 const Option *get_unique_ptr(const std::string &name) const
1209 {
1210 IndexMap::const_iterator e = map_.find(name);
1211 if (e != map_.end() && !e->second.empty())
1212 {
1213 if (e->second.size() == 1)
1214 {
1215 const Option *ret = &((*this)[e->second[0]]);
1216 ret->touch();
1217 return ret;
1218 }
1219 else
1220 OPENVPN_THROW_ARG1(option_error, ERR_INVALID_CONFIG, "more than one instance of option '" << name << '\'');
1221 }
1222 else
1223 return nullptr;
1224 }
1225
1226 // Get an option, throw an error if more than one instance exists and the instances
1227 // are not exact duplicates of one other.
1228 const Option *get_consistent(const std::string &name) const
1229 {
1230 IndexMap::const_iterator e = map_.find(name);
1231 if (e != map_.end() && !e->second.empty())
1232 {
1233 const Option *first = &((*this)[e->second[0]]);
1234 first->touch();
1235 if (e->second.size() >= 2)
1236 {
1237 for (size_t i = 1; i < e->second.size(); ++i)
1238 {
1239 const Option *other = &(*this)[e->second[i]];
1240 other->touch();
1241 if (*other != *first)
1242 OPENVPN_THROW_ARG1(option_error, ERR_INVALID_OPTION_VAL, "more than one instance of option '" << name << "' with inconsistent argument(s)");
1243 }
1244 }
1245 return first;
1246 }
1247 else
1248 return nullptr;
1249 }
1250
1251 // Get option, throw error if not found
1252 // If multiple options of the same name exist, return
1253 // the last one.
1254 const Option &get(const std::string &name) const
1255 {
1256 const Option *o = get_ptr(name);
1257 if (o)
1258 return *o;
1259 else
1260 OPENVPN_THROW_ARG1(option_error, ERR_INVALID_CONFIG, "option '" << name << "' not found");
1261 }
1262
1263 // Get the list of options having the same name (by index),
1264 // throw an exception if option is not found.
1265 const IndexList &get_index(const std::string &name) const
1266 {
1267 IndexMap::const_iterator e = map_.find(name);
1268 if (e != map_.end() && !e->second.empty())
1269 return e->second;
1270 else
1271 OPENVPN_THROW_ARG1(option_error, ERR_INVALID_CONFIG, "option '" << name << "' not found");
1272 }
1273
1274 // Get the list of options having the same name (by index),
1275 // return nullptr is option is not found.
1276 const IndexList *get_index_ptr(const std::string &name) const
1277 {
1278 IndexMap::const_iterator e = map_.find(name);
1279 if (e != map_.end() && !e->second.empty())
1280 return &e->second;
1281 else
1282 return nullptr;
1283 }
1284
1285 // Concatenate all one-arg directives of a given name, in index order.
1286 std::string cat(const std::string &name) const
1287 {
1288 std::string ret;
1289 const OptionList::IndexList *il = get_index_ptr(name);
1290 if (il)
1291 {
1292 size_t size = 0;
1293 OptionList::IndexList::const_iterator i;
1294 for (i = il->begin(); i != il->end(); ++i)
1295 {
1296 const Option &o = (*this)[*i];
1297 if (o.size() == 2)
1298 size += o.ref(1).length() + 1;
1299 else
1300 OPENVPN_THROW_ARG1(option_error, ERR_INVALID_OPTION_VAL, "option '" << name << "' (" << o.size() << ") must have exactly one parameter");
1301 }
1302 ret.reserve(size);
1303 for (i = il->begin(); i != il->end(); ++i)
1304 {
1305 const Option &o = (*this)[*i];
1306 if (o.size() >= 2)
1307 {
1308 o.touch();
1309 ret += o.ref(1);
1311 }
1312 }
1313 }
1314 return ret;
1315 }
1316
1317 // Return true if option exists, but raise an exception if multiple
1318 // instances of the option exist.
1319 bool exists_unique(const std::string &name) const
1320 {
1321 return get_unique_ptr(name) != nullptr;
1322 }
1323
1324 // Return true if one or more instances of a given option exist.
1325 bool exists(const std::string &name) const
1326 {
1327 return get_ptr(name) != nullptr;
1328 }
1329
1330 // Convenience method that gets a particular argument index within an option,
1331 // while raising an exception if option doesn't exist or if argument index
1332 // is out-of-bounds.
1333 const std::string &get(const std::string &name, size_t index, const size_t max_len) const
1334 {
1335 const Option &o = get(name);
1336 return o.get(index, max_len);
1337 }
1338
1339 // Convenience method that gets a particular argument index within an option,
1340 // while returning the empty string if option doesn't exist, and raising an
1341 // exception if argument index is out-of-bounds.
1342 std::string get_optional(const std::string &name, size_t index, const size_t max_len) const
1343 {
1344 const Option *o = get_ptr(name);
1345 if (o)
1346 return o->get(index, max_len);
1347 else
1348 return "";
1349 }
1350
1351 // Like get_optional(), but return "" if argument index is out-of-bounds.
1352 std::string get_optional_relaxed(const std::string &name, size_t index, const size_t max_len) const
1353 {
1354 const Option *o = get_ptr(name);
1355 if (o)
1356 return o->get_optional(index, max_len);
1357 else
1358 return "";
1359 }
1360
1361 // Like get_optional(), but return "" if exception is thrown.
1362 std::string get_optional_noexcept(const std::string &name, size_t index, const size_t max_len) const
1363 {
1364 try
1365 {
1366 return get_optional(name, index, max_len);
1367 }
1368 catch (const std::exception &)
1369 {
1370 return "";
1371 }
1372 }
1373
1374 // Return raw C string to option data or nullptr if option doesn't exist.
1375 const char *get_c_str(const std::string &name, size_t index, const size_t max_len) const
1376 {
1377 const Option *o = get_ptr(name);
1378 if (o)
1379 return o->get(index, max_len).c_str();
1380 else
1381 return nullptr;
1382 }
1383
1384 // Convenience method that gets a particular argument index within an option,
1385 // while returning a default string if option doesn't exist, and raising an
1386 // exception if argument index is out-of-bounds.
1387 std::string get_default(const std::string &name,
1388 size_t index,
1389 const size_t max_len,
1390 const std::string &default_value) const
1391 {
1392 const Option *o = get_ptr(name);
1393 if (o)
1394 return o->get(index, max_len);
1395 else
1396 return default_value;
1397 }
1398
1399 // Like get_default(), but return default_value if argument index is out-of-bounds.
1400 std::string get_default_relaxed(const std::string &name,
1401 size_t index,
1402 const size_t max_len,
1403 const std::string &default_value) const
1404 {
1405 const Option *o = get_ptr(name);
1406 if (o)
1407 {
1408 const std::string *s = o->get_ptr(index, max_len);
1409 if (s)
1410 return *s;
1411 }
1412 return default_value;
1413 }
1414
1415 template <typename T>
1416 T get_num(const std::string &name, const size_t idx, const T default_value) const
1417 {
1418 typedef typename std::remove_const<T>::type T_nonconst;
1419 T_nonconst n = default_value;
1420 const Option *o = get_ptr(name);
1421 if (o)
1422 n = o->get_num<T>(idx, default_value);
1423 return n;
1424 }
1425
1426 template <typename T>
1427 T get_num(const std::string &name,
1428 const size_t idx,
1429 const T default_value,
1430 const T min_value,
1431 const T max_value) const
1432 {
1433 typedef typename std::remove_const<T>::type T_nonconst;
1434 T_nonconst n = default_value;
1435 const Option *o = get_ptr(name);
1436 if (o)
1437 n = o->get_num<T>(idx, default_value, min_value, max_value);
1438 return n;
1439 }
1440
1441 template <typename T>
1442 T get_num(const std::string &name, const size_t idx, const T min_value, const T max_value) const
1443 {
1444 const Option &o = get(name);
1445 return o.get_num<T>(idx, min_value, max_value);
1446 }
1447
1448 template <typename T>
1449 T get_num(const std::string &name, const size_t idx) const
1450 {
1451 const Option &o = get(name);
1452 return o.get_num<T>(idx);
1453 }
1454
1455 // Touch an option, if it exists.
1456 void touch(const std::string &name) const
1457 {
1458 const Option *o = get_ptr(name);
1459 if (o)
1460 o->touch();
1461 }
1462
1463 // Render object as a string.
1464 // flags should be given as Option::render_flags.
1465 std::string render(const unsigned int flags) const
1466 {
1467 std::ostringstream out;
1468 for (size_t i = 0; i < size(); ++i)
1469 {
1470 const Option &o = (*this)[i];
1471 if (!(flags & Option::RENDER_UNUSED) || !o.touched())
1472 {
1474 out << i << ' ';
1475 out << o.render(flags) << std::endl;
1476 }
1477 }
1478 return out.str();
1479 }
1480
1481 std::string render_csv() const
1482 {
1483 std::string ret;
1484 bool first = true;
1485 for (auto &e : *this)
1486 {
1487 if (!first)
1488 ret += ',';
1489 ret += e.escape(true);
1490 first = false;
1491 }
1492 return ret;
1493 }
1494
1495 // Render contents of hash map used to locate options after underlying option list
1496 // has been modified.
1497 std::string render_map() const
1498 {
1499 std::ostringstream out;
1500 for (IndexMap::const_iterator i = map_.begin(); i != map_.end(); ++i)
1501 {
1502 out << i->first << " [";
1503 for (IndexList::const_iterator j = i->second.begin(); j != i->second.end(); ++j)
1504 out << ' ' << *j;
1505 out << " ]" << std::endl;
1506 }
1507 return out.str();
1508 }
1509
1510 // Return number of unused options based on the notion that
1511 // all used options have been touched.
1512 size_t n_unused(bool ignore_meta = false) const
1513 {
1514 size_t n = 0;
1515 for (std::vector<Option>::const_iterator i = begin(); i != end(); ++i)
1516 {
1517 const Option &opt = *i;
1518 if (!opt.touched() && !(opt.meta() && ignore_meta))
1519 ++n;
1520 }
1521 return n;
1522 }
1523
1524 // Return number of unused meta options based on the notion that
1525 // all used options have been touched.
1526 size_t meta_unused() const
1527 {
1528 size_t n = 0;
1529 for (std::vector<Option>::const_iterator i = begin(); i != end(); ++i)
1530 {
1531 const Option &opt = *i;
1532 if (opt.meta() && !opt.touched())
1533 ++n;
1534 }
1535 return n;
1536 }
1537
1538 void show_unused_options(const char *title = nullptr) const
1539 {
1540 // show unused options
1541 if (n_unused())
1542 {
1543 if (!title)
1544 title = "NOTE: Unused Options";
1545 OPENVPN_LOG_NTNL(title << std::endl
1547 }
1548 }
1549
1550 // Add item to underlying option list while updating map as well.
1551 void add_item(const Option &opt)
1552 {
1553 if (!opt.empty())
1554 {
1555 const size_t i = size();
1556 push_back(opt);
1557 map_[opt.ref(0)].push_back((unsigned int)i);
1558 }
1559 }
1560
1561 // Return hash map used to locate options.
1562 const IndexMap &map() const
1563 {
1564 return map_;
1565 }
1566
1567 // Rebuild hash map used to locate options after underlying option list
1568 // has been modified.
1570 {
1571 map_.clear();
1572 for (size_t i = 0; i < size(); ++i)
1573 {
1574 const Option &opt = (*this)[i];
1575 if (!opt.empty())
1576 map_[opt.ref(0)].push_back((unsigned int)i);
1577 }
1578 }
1579
1580 // return true if line is blank or a comment
1581 static bool ignore_line(const std::string &line)
1582 {
1583 for (std::string::const_iterator i = line.begin(); i != line.end(); ++i)
1584 {
1585 const char c = *i;
1586 if (!SpaceMatch::is_space(c))
1587 return is_comment(c);
1588 }
1589 return true;
1590 }
1591
1592 // multiline tagging
1593
1594 // return true if string is a tag, e.g. "<ca>"
1595 static bool is_open_tag(const std::string &str)
1596 {
1597 const size_t n = str.length();
1598 return n >= 3 && str[0] == '<' && str[1] != '/' && str[n - 1] == '>';
1599 }
1600
1601 // return true if string is a close tag, e.g. "</ca>"
1602 static bool is_close_tag(const std::string &str, const std::string &tag)
1603 {
1604 const size_t n = str.length();
1605 return n >= 4 && str[0] == '<' && str[1] == '/' && str.substr(2, n - 3) == tag && str[n - 1] == '>';
1606 }
1607
1608 // remove <> chars from open tag
1609 static void untag_open_tag(std::string &str)
1610 {
1611 const size_t n = str.length();
1612 if (n >= 3)
1613 str = str.substr(1, n - 2);
1614 }
1615
1616 // detect multiline breakout attempt (return true)
1617 static bool detect_multiline_breakout_nothrow(const std::string &opt, const std::string &tag)
1618 {
1619 std::string line;
1620 for (auto &c : opt)
1621 {
1622 if (c == '\n' || c == '\r')
1623 line.clear();
1624 else
1625 {
1626 line += c;
1627 if (tag.empty())
1628 {
1629 if (line.length() >= 2
1630 && line[0] == '<'
1631 && line[1] == '/')
1632 return true;
1633 }
1634 else if (is_close_tag(line, tag))
1635 return true;
1636 }
1637 }
1638 return false;
1639 }
1640
1641 // detect multiline breakout attempt
1642 static void detect_multiline_breakout(const std::string &opt, const std::string &tag)
1643 {
1645 throw option_error(ERR_INVALID_CONFIG, "multiline breakout detected");
1646 }
1647
1648 private:
1649 // multiline tagging (meta)
1650
1651 // return true if string is a meta tag, e.g. WEB_CA_BUNDLE_START
1652 static bool is_open_meta_tag(const std::string &str)
1653 {
1654 return string::ends_with(str, "_START");
1655 }
1656
1657 // return true if string is a tag, e.g. WEB_CA_BUNDLE_STOP
1658 static bool is_close_meta_tag(const std::string &str, const std::string &prefix, const std::string &tag)
1659 {
1660 return prefix + tag + "_STOP" == str;
1661 }
1662
1663 // remove trailing "_START" from open tag
1664 static void untag_open_meta_tag(std::string &str)
1665 {
1666 const size_t n = str.length();
1667 if (n >= 6)
1668 str = std::string(str, 0, n - 6);
1669 }
1670
1671 static void extraneous_err(const int line_num, const char *type, const Option &opt)
1672 {
1673 OPENVPN_THROW_ARG1(option_error, ERR_INVALID_OPTION_VAL, "line " << line_num << ": " << type << " <" << opt.printable_directive() << "> is followed by extraneous text");
1674 }
1675
1676 static void not_closed_out_err(const char *type, const Option &opt)
1677 {
1678 OPENVPN_THROW_ARG1(option_error, ERR_INVALID_OPTION_VAL, type << " <" << opt.printable_directive() << "> was not properly closed out");
1679 }
1680
1681 static void line_too_long(const int line_num)
1682 {
1683 OPENVPN_THROW_ARG1(option_error, ERR_INVALID_OPTION_VAL, "line " << line_num << " is too long");
1684 }
1685
1687 {
1688 push_back(std::move(opt));
1689 }
1690
1691 template <typename T, typename... Args>
1692 void from_list(T first, Args... args)
1693 {
1694 from_list(std::move(first));
1695 from_list(std::forward<Args>(args)...);
1696 }
1697
1699};
1700
1701} // namespace openvpn
1702
1703#endif // OPENVPN_COMMON_OPTIONS_H
Helper class to handle quote processing.
Definition lex.hpp:39
bool in_quote() const
Check if currently inside a quote.
Definition lex.hpp:45
bool handle_quote(char c)
Handle a character as a potential quote.
Definition lex.hpp:60
Option convert_to_option(Limits *lim, const std::string &meta_prefix) const
Definition options.hpp:693
KeyValue(const std::string &key_arg, const std::string &value_arg, const int key_priority_arg=0)
Definition options.hpp:683
size_t combined_length() const
Definition options.hpp:688
static std::string unescape(const std::string &value, bool &newline_present)
Definition options.hpp:755
static bool compare(const Ptr &a, const Ptr &b)
Definition options.hpp:739
static bool singular_arg(const std::string &key)
Definition options.hpp:793
Limits(const std::string &error_message, const std::uint64_t max_bytes_arg, const size_t extra_bytes_per_opt_arg, const size_t extra_bytes_per_term_arg, const size_t max_line_len_arg, const size_t max_directive_len_arg)
Definition options.hpp:591
void validate_directive(const Option &opt)
Definition options.hpp:641
void add_string(const std::string &str)
Definition options.hpp:613
void add_bytes(const size_t n)
Definition options.hpp:607
size_t get_max_line_len() const
Definition options.hpp:631
const size_t extra_bytes_per_term
Definition options.hpp:661
const size_t extra_bytes_per_opt
Definition options.hpp:660
const std::uint64_t max_bytes
Definition options.hpp:659
std::uint64_t get_bytes() const
Definition options.hpp:636
const std::string err
Definition options.hpp:664
const size_t max_directive_len
Definition options.hpp:663
static OptionList parse_from_argv_static(const std::vector< std::string > &argv)
Definition options.hpp:875
static void detect_multiline_breakout(const std::string &opt, const std::string &tag)
Definition options.hpp:1642
std::string get_optional(const std::string &name, size_t index, const size_t max_len) const
Definition options.hpp:1342
void show_unused_options(const char *title=nullptr) const
Definition options.hpp:1538
static void untag_open_tag(std::string &str)
Definition options.hpp:1609
void parse_from_peer_info(const std::string &str, Limits *lim)
Definition options.hpp:934
static void not_closed_out_err(const char *type, const Option &opt)
Definition options.hpp:1676
void from_list(Option opt)
Definition options.hpp:1686
void extend_nonexistent(const OptionList &other)
Definition options.hpp:1171
OptionList(T first, Args... args)
Definition options.hpp:837
void parse_from_config(const std::string &str, Limits *lim)
Definition options.hpp:985
const IndexMap & map() const
Definition options.hpp:1562
std::string cat(const std::string &name) const
Definition options.hpp:1286
static bool is_close_tag(const std::string &str, const std::string &tag)
Definition options.hpp:1602
const Option * get_consistent(const std::string &name) const
Definition options.hpp:1228
void extend(const OptionList &other, FilterBase *filt=nullptr)
Definition options.hpp:1123
const char * get_c_str(const std::string &name, size_t index, const size_t max_len) const
Definition options.hpp:1375
std::string get_optional_noexcept(const std::string &name, size_t index, const size_t max_len) const
Definition options.hpp:1362
void parse_from_argv(const std::vector< std::string > &argv)
Definition options.hpp:911
const IndexList & get_index(const std::string &name) const
Definition options.hpp:1265
std::unordered_map< std::string, IndexList > IndexMap
Definition options.hpp:521
T get_num(const std::string &name, const size_t idx, const T default_value, const T min_value, const T max_value) const
Definition options.hpp:1427
void parse_from_key_value_list(const KeyValueList &list, const std::string &meta_tag, Limits *lim)
Definition options.hpp:959
T get_num(const std::string &name, const size_t idx, const T default_value) const
Definition options.hpp:1416
T get_num(const std::string &name, const size_t idx) const
Definition options.hpp:1449
T get_num(const std::string &name, const size_t idx, const T min_value, const T max_value) const
Definition options.hpp:1442
std::string render_map() const
Definition options.hpp:1497
const IndexList * get_index_ptr(const std::string &name) const
Definition options.hpp:1276
void touch(const std::string &name) const
Definition options.hpp:1456
bool exists_unique(const std::string &name) const
Definition options.hpp:1319
static OptionList parse_from_csv_static(const std::string &str, Limits *lim)
Definition options.hpp:844
static OptionList::Ptr parse_from_config_static_ptr(const std::string &str, Limits *lim)
Definition options.hpp:867
static void line_too_long(const int line_num)
Definition options.hpp:1681
static void extraneous_err(const int line_num, const char *type, const Option &opt)
Definition options.hpp:1671
RCPtr< OptionList > Ptr
Definition options.hpp:519
static bool ignore_line(const std::string &line)
Definition options.hpp:1581
std::string get_optional_relaxed(const std::string &name, size_t index, const size_t max_len) const
Definition options.hpp:1352
void parse_from_csv(const std::string &str, Limits *lim)
Definition options.hpp:890
const std::string & get(const std::string &name, size_t index, const size_t max_len) const
Definition options.hpp:1333
void add_item(const Option &opt)
Definition options.hpp:1551
void from_list(T first, Args... args)
Definition options.hpp:1692
static Option parse_option_from_line(const std::string &line, Limits *lim)
Definition options.hpp:979
const Option * get_unique_ptr(const std::string &name) const
Definition options.hpp:1208
std::string get_default_relaxed(const std::string &name, size_t index, const size_t max_len, const std::string &default_value) const
Definition options.hpp:1400
static OptionList parse_from_csv_static_nomap(const std::string &str, Limits *lim)
Definition options.hpp:852
const Option & get(const std::string &name) const
Definition options.hpp:1254
static OptionList parse_from_config_static(const std::string &str, Limits *lim)
Definition options.hpp:859
void extend(OptionList &&other, FilterBase *filt=nullptr)
Definition options.hpp:1139
size_t n_unused(bool ignore_meta=false) const
Definition options.hpp:1512
const Option * get_ptr(const std::string &name) const
Definition options.hpp:1186
std::vector< unsigned int > IndexList
Definition options.hpp:520
unsigned int extend(const OptionList &other, const std::string &name)
Definition options.hpp:1152
std::pair< std::string, IndexList > IndexPair
Definition options.hpp:522
static bool is_close_meta_tag(const std::string &str, const std::string &prefix, const std::string &tag)
Definition options.hpp:1658
std::string render_csv() const
Definition options.hpp:1481
std::string render(const unsigned int flags) const
Definition options.hpp:1465
static bool detect_multiline_breakout_nothrow(const std::string &opt, const std::string &tag)
Definition options.hpp:1617
StandardLex Lex
Definition options.hpp:530
size_t meta_unused() const
Definition options.hpp:1526
static bool is_comment(const char c)
Definition options.hpp:524
std::string get_default(const std::string &name, size_t index, const size_t max_len, const std::string &default_value) const
Definition options.hpp:1387
static bool is_open_tag(const std::string &str)
Definition options.hpp:1595
static bool is_open_meta_tag(const std::string &str)
Definition options.hpp:1652
static void untag_open_meta_tag(std::string &str)
Definition options.hpp:1664
void parse_meta_from_config(const std::string &str, const std::string &tag, Limits *lim)
Definition options.hpp:1052
bool exists(const std::string &name) const
Definition options.hpp:1325
bool touched_lightly() const
Definition options.hpp:418
bool is_multiline() const
Definition options.hpp:153
Option(T first, Args... args)
Definition options.hpp:96
std::string get_default(const size_t index, const size_t max_len, const std::string &default_value) const
Definition options.hpp:203
void exact_args(const size_t n) const
Definition options.hpp:136
std::string get_optional(const size_t index, const size_t max_len) const
Definition options.hpp:194
void push_back(const std::string &item)
Definition options.hpp:335
void touch(bool lightly=false) const
Definition options.hpp:385
void from_list(std::vector< std::string > arg)
Definition options.hpp:467
void from_list(std::string arg)
Definition options.hpp:457
std::string err_ref() const
Definition options.hpp:425
const std::string & get(const size_t index, const size_t max_len) const
Definition options.hpp:187
volatile touchedState touched_
Definition options.hpp:509
static const char * validate_status_description(const validate_status status)
Definition options.hpp:114
T get_num(const size_t idx, const T default_value) const
Definition options.hpp:238
bool must_quote_string(const std::string &str, const bool csv) const
Definition options.hpp:485
static void escape_string(std::ostream &out, const std::string &term, const bool must_quote)
Definition options.hpp:285
static void validate_string(const std::string &name, const std::string &str, const size_t max_len)
Definition options.hpp:165
void push_back(std::string &&item)
Definition options.hpp:339
OPENVPN_UNTAGGED_EXCEPTION(RejectedException)
std::vector< std::string > data
Definition options.hpp:513
T get_num(const size_t idx) const
Definition options.hpp:222
void set_meta(bool value=true)
Definition options.hpp:441
size_t size() const
Definition options.hpp:327
void min_args(const size_t n) const
Definition options.hpp:129
void resize(const size_t n)
Definition options.hpp:347
std::string & ref(const size_t i)
Definition options.hpp:357
T get_num(const size_t idx, const T min_value, const T max_value) const
Definition options.hpp:256
void validate_arg(const size_t index, const size_t max_len) const
Definition options.hpp:143
void reserve(const size_t n)
Definition options.hpp:343
std::string printable_directive() const
Definition options.hpp:172
void enableWarnOnly()
Definition options.hpp:400
bool warn_only_if_unknown_
Definition options.hpp:511
T get_num(const size_t idx, const T default_value, const T min_value, const T max_value) const
Definition options.hpp:247
void remove_first(const size_t n_elements)
Definition options.hpp:373
bool operator!=(const Option &other) const
Definition options.hpp:367
bool empty() const
Definition options.hpp:331
void from_list(T first, Args... args)
Definition options.hpp:473
void from_list(const char *arg)
Definition options.hpp:462
std::string escape(const bool csv) const
Definition options.hpp:302
void range_error(const size_t idx, const T min_value, const T max_value) const
Definition options.hpp:480
const std::string & ref(const size_t i) const
Definition options.hpp:353
const std::string * get_ptr(const size_t index, const size_t max_len) const
Definition options.hpp:212
bool operator==(const Option &other) const
Definition options.hpp:363
bool warnonlyunknown() const
Definition options.hpp:405
static validate_status validate(const std::string &str, const size_t max_len)
Definition options.hpp:102
std::string render(const unsigned int flags) const
Definition options.hpp:264
bool touched() const
Definition options.hpp:411
bool meta() const
Definition options.hpp:451
Reference count base class for objects tracked by RCPtr. Allows copying and assignment.
Definition rc.hpp:979
The smart pointer class.
Definition rc.hpp:119
Reference count base class for objects tracked by RCPtr. Disallows copying and assignment.
Definition rc.hpp:912
std::string & line_ref()
#define OPENVPN_THROW_ARG1(exc, arg, stuff)
#define OPENVPN_LOG_NTNL(args)
STRING utf8_printable(const STRING &str, size_t max_len_flags)
Definition unicode.hpp:129
size_t utf8_length(const STRING &str)
Definition unicode.hpp:179
bool starts_with(const STRING &str, const std::string &prefix)
Definition string.hpp:79
void add_trailing(std::string &str, const char c)
Definition string.hpp:184
bool is_space(const char c)
Definition string.hpp:279
bool ends_with(const STRING &str, const std::string &suffix)
Definition string.hpp:111
Support deferred server-side state creation when client connects.
Definition ovpncli.cpp:95
bool parse_hex_number(const char *str, T &retval)
Definition hexstr.hpp:383
RCPtr< FilterBase > Ptr
Definition options.hpp:670
virtual bool filter(const Option &opt)=0
static bool is_space(char c)
Definition lex.hpp:25
reroute_gw flags
std::string ret
static std::stringstream out
Definition test_path.cpp:10