OpenVPN 3 Core Library
Loading...
Searching...
No Matches
listenlist.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_SERVER_LISTENLIST_H
13#define OPENVPN_SERVER_LISTENLIST_H
14
15#include <string>
16#include <vector>
17#include <utility> // for std::move
18
27#include <openvpn/addr/ip.hpp>
29
30namespace openvpn::Listen {
31struct Item
32{
34 {
38#ifdef OPENVPN_POLYSOCK_SUPPORTS_ALT_ROUTING
39 AltRouting,
40#endif
41 };
42
43 std::string directive;
44 std::string addr;
45 std::string port;
48 unsigned int n_threads = 0;
49
50 std::string to_string() const
51 {
52 std::string ret;
53 ret += directive + ' ' + addr;
54 if (!proto.is_local())
55 ret += ' ' + port;
56 ret += ' ' + std::string(proto.str()) + ' ' + openvpn::to_string(n_threads);
57 switch (ssl)
58 {
59 case SSLUnspecified:
60 break;
61 case SSLOn:
62 ret += " ssl";
63 break;
64 case SSLOff:
65 ret += " !ssl";
66 break;
67#ifdef OPENVPN_POLYSOCK_SUPPORTS_ALT_ROUTING
68 case AltRouting:
69 ret += " alt";
70 break;
71#endif
72 }
73 return ret;
74 }
75
76 Item port_offset(const unsigned int offset) const
77 {
78 Item ret(*this);
79 if (ret.proto.is_unix()) // unix socket filenames should contain %s for "port" substitution
80 ret.addr = printfmt(ret.addr, offset);
81 else
82 ret.port = openvpn::to_string(HostPort::parse_port(ret.port, "offset") + offset);
83 ret.n_threads = 0;
84 return ret;
85 }
86};
87
88class List : public std::vector<Item>
89{
90 public:
92 {
96#ifdef VPN_BINDING_PROFILES
97 AllowVPNBindingProfile,
98#endif
99 };
100
101 List() = default;
102
103 List(const Item &item)
104 {
105 push_back(item);
106 }
107
108 List(Item &&item)
109 {
110 push_back(std::move(item));
111 }
112
113 List(const OptionList &opt,
114 const std::string &directive,
115 const LoadMode load_mode,
116 const unsigned int n_cores)
117 {
118 const auto *opt_list = opt.get_index_ptr(directive);
119 if (opt_list)
120 {
121 reserve(opt_list->size());
122 for (auto i : *opt_list)
123 {
124 const Option &o = opt[i];
125 o.touch();
126
127 unsigned int mult = 1;
128 unsigned int local = 0;
129
130 Item e;
131
132 // directive
133 e.directive = o.get(0, 64);
134
135 // IP address
136 e.addr = o.get(1, 128);
137
138 // port number
139 e.port = o.get(2, 16);
141 {
142 local = 1;
143 e.port = "";
144 }
145 else
147
148 // protocol
149 {
150 const std::string title = e.directive + " protocol";
151 e.proto = Protocol::parse(o.get(3 - local, 16), Protocol::NO_SUFFIX, title.c_str());
152 }
153
154 // Modify protocol based on IP version of given address.
155 // AllowVPNBindingProfile tells us to support
156 // special address case for WS::ViaVPN, where address
157 // begins with '@' followed by a client connection
158 // profile filename.
159 if (!local && !is_vpn_binding_profile(load_mode, e))
160 {
161 const std::string title = e.directive + " addr";
162 const IP::Addr addr = IP::Addr(e.addr, title.c_str());
164 }
165
166 // number of threads
167 int n_threads_exists = 0;
168 {
169 const std::string ntstr = o.get_optional(4 - local, 16);
170 if (!ntstr.empty() && string::is_digit(ntstr[0]))
171 n_threads_exists = 1;
172 }
173 if (n_threads_exists)
174 {
175 std::string n_threads = o.get(4 - local, 16);
176 if (n_threads.ends_with("*N"))
177 {
178 mult = n_cores;
179 n_threads = n_threads.substr(0, n_threads.length() - 2);
180 }
181 if (!parse_number_validate<unsigned int>(n_threads, 3, 1, 100, &e.n_threads))
182 OPENVPN_THROW(option_error, e.directive << ": bad num threads: " << n_threads);
183#ifndef OPENVPN_PLATFORM_WIN
184 if (local && e.n_threads != 1)
185 OPENVPN_THROW(option_error, e.directive << ": local socket only supports one thread per pathname (not " << n_threads << ')');
186#endif
187 e.n_threads *= mult;
188 }
189 else
190 e.n_threads = 1;
191
192 // SSL
193 if (o.size() >= 5 - local + n_threads_exists)
194 {
195 const std::string &ssl_qualifier = o.get(4 - local + n_threads_exists, 16);
196 if (ssl_qualifier == "ssl")
197 {
198 if (local)
199 OPENVPN_THROW(option_error, e.directive << ": SSL not supported on local sockets");
200 e.ssl = Item::SSLOn;
201 }
202 else if (ssl_qualifier == "!ssl")
203 e.ssl = Item::SSLOff;
204#ifdef OPENVPN_POLYSOCK_SUPPORTS_ALT_ROUTING
205 else if (ssl_qualifier == "alt")
206 e.ssl = Item::AltRouting;
207#endif
208 else
209 OPENVPN_THROW(option_error, e.directive << ": unrecognized SSL qualifier");
210 }
211
212 push_back(std::move(e));
213 }
214 }
215 else if (load_mode == AllowDefault)
216 {
217 Item e;
218
219 // parse "proto" option if present
220 {
221 const Option *o = opt.get_ptr("proto");
222 if (o)
224 else
226 }
227
228 // parse "port" option if present
229 {
230 const Option *o = opt.get_ptr("lport");
231 if (!o)
232 o = opt.get_ptr("port");
233 if (o)
234 {
235 e.port = o->get(1, 16);
236 HostPort::validate_port(e.port, "listen");
237 }
238 else
239 e.port = "1194";
240 }
241
242 // parse "local" option if present
243 {
244 const Option *o = opt.get_ptr("local");
245 if (o)
246 {
247 e.addr = o->get(1, 128);
248 const IP::Addr addr = IP::Addr(e.addr, "local addr");
250 }
251 else if (e.proto.is_ipv6())
252 e.addr = "::0";
253 else
254 e.addr = "0.0.0.0";
255 }
256
257 // n_threads defaults to one unless "listen" directive is used
258 e.n_threads = 1;
259
260 push_back(std::move(e));
261 }
262 else if (load_mode != AllowEmpty)
263 OPENVPN_THROW(option_error, "no " << directive << " directives found");
264 }
265
266 unsigned int total_threads() const
267 {
268 unsigned int ret = 0;
269 for (auto &i : *this)
270 ret += i.n_threads;
271 return ret;
272 }
273
274 std::string to_string() const
275 {
276 std::string ret;
277 for (auto &i : *this)
278 {
279 ret += i.to_string();
280 ret += '\n';
281 }
282 return ret;
283 }
284
285 std::string local_addr() const
286 {
287 for (auto &i : *this)
288 if (i.proto.is_local())
289 return i.addr;
290 return std::string();
291 }
292
293 List expand_ports_by_n_threads(const size_t max_size) const
294 {
295 List ret;
296 for (const auto &e : *this)
297 {
298 unsigned int offset = 0;
299 do
300 {
301 if (ret.size() >= max_size)
302 OPENVPN_THROW(option_error, e.directive << ": max_size=" << max_size << " exceeded");
303 ret.emplace_back(e.port_offset(offset));
304 } while (++offset < e.n_threads);
305 }
306 return ret;
307 }
308
309 List expand_ports_by_unit(const unsigned int unit) const
310 {
311 List ret;
312 for (const auto &e : *this)
313 ret.emplace_back(e.port_offset(unit));
314 return ret;
315 }
316
317 private:
318 static bool is_vpn_binding_profile(const LoadMode load_mode,
319 const Item &e)
320 {
321#ifdef VPN_BINDING_PROFILES
322 return load_mode == AllowVPNBindingProfile
323 && !e.addr.empty()
324 && e.addr[0] == '@';
325#else
326 return false;
327#endif
328 }
329};
330} // namespace openvpn::Listen
331
332#endif
Version version() const
Definition ip.hpp:895
std::string local_addr() const
List expand_ports_by_n_threads(const size_t max_size) const
unsigned int total_threads() const
std::string to_string() const
List expand_ports_by_unit(const unsigned int unit) const
List(const OptionList &opt, const std::string &directive, const LoadMode load_mode, const unsigned int n_cores)
List(const Item &item)
static bool is_vpn_binding_profile(const LoadMode load_mode, const Item &e)
const IndexList * get_index_ptr(const std::string &name) const
Definition options.hpp:1260
const Option * get_ptr(const std::string &name) const
Definition options.hpp:1174
std::string get_optional(const size_t index, const size_t max_len) const
Definition options.hpp:191
void touch(bool lightly=false) const
Definition options.hpp:378
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
const char * str() const
Definition protocol.hpp:212
static bool is_local_type(const std::string &str)
Definition protocol.hpp:174
bool is_local() const
Definition protocol.hpp:107
void mod_addr_version(const IP::Addr::Version ip_version)
Definition protocol.hpp:132
static Protocol parse(const std::string &str, const AllowSuffix allow_suffix, const char *title=nullptr)
Definition protocol.hpp:157
bool is_ipv6() const
Definition protocol.hpp:95
#define OPENVPN_THROW(exc, stuff)
void validate_port(const std::string &port, const std::string &title, unsigned int *value=nullptr)
Definition hostport.hpp:34
unsigned short parse_port(const std::string &port, const std::string &title)
Definition hostport.hpp:46
bool is_digit(const char c)
Definition string.hpp:232
int n_cores()
Definition core.hpp:32
std::string to_string(const T &t)
Convert a value to a string.
Definition to_string.hpp:45
std::string printfmt(const std::string &fmt, Args... args)
Definition format.hpp:313
Item port_offset(const unsigned int offset) const
std::string to_string() const
unsigned int n_threads
server addresses push_back(address)
std::string ret