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