OpenVPN 3 Core Library
Loading...
Searching...
No Matches
optfilt.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#ifndef OPENVPN_CLIENT_OPTFILT_H
13#define OPENVPN_CLIENT_OPTFILT_H
14
15#include <vector>
16
21
22// Options filters, consumes the route-nopull and pull-filter client options
23
24namespace openvpn {
25
27{
28 public:
30 : route_nopull_(opt.exists("route-nopull"))
31 {
32 if (!opt.exists("pull-filter"))
33 return;
34
35 for (auto i : opt.get_index("pull-filter"))
36 {
37 FilterAction action = None;
38 auto &o = opt[i];
39 o.exact_args(3);
40 o.touch();
41
42 const auto &action_str = o.get(1, -1);
43 if (action_str == "accept")
44 action = Accept;
45 else if (action_str == "ignore")
46 action = Ignore;
47 else if (action_str == "reject")
48 action = Reject;
49 else
50 throw option_error(ERR_INVALID_OPTION_VAL, "invalid pull-filter action: " + action_str);
51
52 Option match = OptionList::parse_option_from_line(o.get(2, -1), nullptr);
53 pull_filter_list_.push_back({action, match});
54 }
55 }
56
57 bool filter(const Option &opt) override
58 {
59 return filter_(opt) == Accept ? true : false;
60 }
61
62 private:
70
76
78 {
79 static_filter_(opt);
80
81 FilterAction action = pull_filter_(opt);
82 if (action == None)
83 {
84 if (route_nopull_)
85 action = route_nopull_filter_(opt);
86 else
87 action = Accept;
88 }
89 return action;
90 }
91
92 void static_filter_(const Option &o)
93 {
94 // Reject pushed DNS servers with priority < 0
95 if (o.size() >= 3
96 && o.ref(0) == "dns"
97 && o.ref(1) == "server"
99 {
100 throw option_error(ERR_INVALID_CONFIG, o.escape(false));
101 }
102 }
103
104 // Return an action if a pull-filter directive matches the pushed option
106 {
107 for (const auto &pull_filter : pull_filter_list_)
108 {
109 if (!pull_filter_matches_(pushed, pull_filter.match))
110 continue;
111
112 if (pull_filter.action != Accept)
113 {
114 OPENVPN_LOG((pull_filter.action == Ignore ? "Ignored" : "Rejected")
115 << " due to pull-filter: "
117 if (pull_filter.action == Reject)
118 throw Option::RejectedException(pushed.escape(false));
119 }
120 return pull_filter.action;
121 }
122 return None;
123 }
124
125 bool pull_filter_matches_(const Option &pushed, const Option &match)
126 {
127 if (pushed.size() < match.size())
128 return false;
129 if (!is_safe_conversion<int>(match.size() - 1))
130 return false;
131 int i = static_cast<int>(match.size() - 1);
132 if (!string::starts_with(pushed.get(i, -1), match.get(i, -1)))
133 return false;
134
135 while (--i >= 0)
136 {
137 if (pushed.get(i, -1) != match.get(i, -1))
138 return false;
139 }
140
141 return true;
142 }
143
144 // return action if pushed option should be ignored due to route-nopull directive.
146 {
147 FilterAction action = Accept;
148 if (opt.size() >= 1)
149 {
150 const std::string &directive = opt.ref(0);
151 if (directive.length() >= 1)
152 {
153 switch (directive[0])
154 {
155 case 'b':
156 if (directive == "block-ipv6")
157 {
158 action = Ignore;
159 }
160 break;
161 case 'c':
162 if (directive == "client-nat")
163 {
164 action = Ignore;
165 }
166 break;
167 case 'd':
168 if (directive == "dhcp-option"
169 || directive == "dhcp-renew"
170 || directive == "dhcp-pre-release" || directive == "dhcp-release")
171 {
172 action = Ignore;
173 }
174 break;
175 case 'i':
176 if (directive == "ip-win32")
177 {
178 action = Ignore;
179 }
180 break;
181 case 'r':
182 if (directive == "route"
183 || directive == "route-ipv6"
184 || directive == "route-metric"
185 || directive == "redirect-gateway"
186 || directive == "redirect-private"
187 || directive == "register-dns"
188 || directive == "route-delay"
189 || directive == "route-method")
190 {
191 action = Ignore;
192 }
193 break;
194 case 't':
195 if (directive == "tap-sleep")
196 {
197 action = Ignore;
198 }
199 break;
200 }
201 if (action == Ignore)
202 {
203 OPENVPN_LOG("Ignored due to route-nopull: "
205 }
206 }
207 }
208 return action;
209 }
210
212 std::vector<PullFilter> pull_filter_list_;
213};
214
215} // namespace openvpn
216
217#endif
const IndexList & get_index(const std::string &name) const
Definition options.hpp:1265
void touch(const std::string &name) const
Definition options.hpp:1456
static Option parse_option_from_line(const std::string &line, Limits *lim)
Definition options.hpp:979
bool exists(const std::string &name) const
Definition options.hpp:1325
const std::string & get(const size_t index, const size_t max_len) const
Definition options.hpp:187
size_t size() const
Definition options.hpp:327
std::string escape(const bool csv) const
Definition options.hpp:302
const std::string & ref(const size_t i) const
Definition options.hpp:353
std::string render(const unsigned int flags) const
Definition options.hpp:264
bool filter(const Option &opt) override
Definition optfilt.hpp:57
std::vector< PullFilter > pull_filter_list_
Definition optfilt.hpp:212
FilterAction route_nopull_filter_(const Option &opt)
Definition optfilt.hpp:145
void static_filter_(const Option &o)
Definition optfilt.hpp:92
FilterAction pull_filter_(const Option &pushed)
Definition optfilt.hpp:105
bool pull_filter_matches_(const Option &pushed, const Option &match)
Definition optfilt.hpp:125
PushedOptionsFilter(const OptionList &opt)
Definition optfilt.hpp:29
FilterAction filter_(const Option &opt)
Definition optfilt.hpp:77
#define OPENVPN_LOG(args)
bool starts_with(const STRING &str, const std::string &prefix)
Definition string.hpp:79
static int parse_priority(const std::string &prio_str)
Definition dns.hpp:45