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
102 {
103 }
104
105 List(const Item &item)
106 {
107 push_back(item);
108 }
109
110 List(Item &&item)
111 {
112 push_back(std::move(item));
113 }
114
115 List(const OptionList &opt,
116 const std::string &directive,
117 const LoadMode load_mode,
118 const unsigned int n_cores)
119 {
120 const auto *opt_list = opt.get_index_ptr(directive);
121 if (opt_list)
122 {
123 reserve(opt_list->size());
124 for (auto i : *opt_list)
125 {
126 const Option &o = opt[i];
127 o.touch();
128
129 unsigned int mult = 1;
130 unsigned int local = 0;
131
132 Item e;
133
134 // directive
135 e.directive = o.get(0, 64);
136
137 // IP address
138 e.addr = o.get(1, 128);
139
140 // port number
141 e.port = o.get(2, 16);
143 {
144 local = 1;
145 e.port = "";
146 }
147 else
149
150 // protocol
151 {
152 const std::string title = e.directive + " protocol";
153 e.proto = Protocol::parse(o.get(3 - local, 16), Protocol::NO_SUFFIX, title.c_str());
154 }
155
156 // Modify protocol based on IP version of given address.
157 // AllowVPNBindingProfile tells us to support
158 // special address case for WS::ViaVPN, where address
159 // begins with '@' followed by a client connection
160 // profile filename.
161 if (!local && !is_vpn_binding_profile(load_mode, e))
162 {
163 const std::string title = e.directive + " addr";
164 const IP::Addr addr = IP::Addr(e.addr, title.c_str());
166 }
167
168 // number of threads
169 int n_threads_exists = 0;
170 {
171 const std::string ntstr = o.get_optional(4 - local, 16);
172 if (ntstr.length() > 0 && string::is_digit(ntstr[0]))
173 n_threads_exists = 1;
174 }
175 if (n_threads_exists)
176 {
177 std::string n_threads = o.get(4 - local, 16);
178 if (string::ends_with(n_threads, "*N"))
179 {
180 mult = n_cores;
181 n_threads = n_threads.substr(0, n_threads.length() - 2);
182 }
183 if (!parse_number_validate<unsigned int>(n_threads, 3, 1, 100, &e.n_threads))
184 OPENVPN_THROW(option_error, e.directive << ": bad num threads: " << n_threads);
185#ifndef OPENVPN_PLATFORM_WIN
186 if (local && e.n_threads != 1)
187 OPENVPN_THROW(option_error, e.directive << ": local socket only supports one thread per pathname (not " << n_threads << ')');
188#endif
189 e.n_threads *= mult;
190 }
191 else
192 e.n_threads = 1;
193
194 // SSL
195 if (o.size() >= 5 - local + n_threads_exists)
196 {
197 const std::string &ssl_qualifier = o.get(4 - local + n_threads_exists, 16);
198 if (ssl_qualifier == "ssl")
199 {
200 if (local)
201 OPENVPN_THROW(option_error, e.directive << ": SSL not supported on local sockets");
202 e.ssl = Item::SSLOn;
203 }
204 else if (ssl_qualifier == "!ssl")
205 e.ssl = Item::SSLOff;
206#ifdef OPENVPN_POLYSOCK_SUPPORTS_ALT_ROUTING
207 else if (ssl_qualifier == "alt")
208 e.ssl = Item::AltRouting;
209#endif
210 else
211 OPENVPN_THROW(option_error, e.directive << ": unrecognized SSL qualifier");
212 }
213
214 push_back(std::move(e));
215 }
216 }
217 else if (load_mode == AllowDefault)
218 {
219 Item e;
220
221 // parse "proto" option if present
222 {
223 const Option *o = opt.get_ptr("proto");
224 if (o)
226 else
228 }
229
230 // parse "port" option if present
231 {
232 const Option *o = opt.get_ptr("lport");
233 if (!o)
234 o = opt.get_ptr("port");
235 if (o)
236 {
237 e.port = o->get(1, 16);
238 HostPort::validate_port(e.port, "listen");
239 }
240 else
241 e.port = "1194";
242 }
243
244 // parse "local" option if present
245 {
246 const Option *o = opt.get_ptr("local");
247 if (o)
248 {
249 e.addr = o->get(1, 128);
250 const IP::Addr addr = IP::Addr(e.addr, "local addr");
252 }
253 else if (e.proto.is_ipv6())
254 e.addr = "::0";
255 else
256 e.addr = "0.0.0.0";
257 }
258
259 // n_threads defaults to one unless "listen" directive is used
260 e.n_threads = 1;
261
262 push_back(std::move(e));
263 }
264 else if (load_mode != AllowEmpty)
265 OPENVPN_THROW(option_error, "no " << directive << " directives found");
266 }
267
268 unsigned int total_threads() const
269 {
270 unsigned int ret = 0;
271 for (auto &i : *this)
272 ret += i.n_threads;
273 return ret;
274 }
275
276 std::string to_string() const
277 {
278 std::string ret;
279 for (auto &i : *this)
280 {
281 ret += i.to_string();
282 ret += '\n';
283 }
284 return ret;
285 }
286
287 std::string local_addr() const
288 {
289 for (auto &i : *this)
290 if (i.proto.is_local())
291 return i.addr;
292 return std::string();
293 }
294
295 List expand_ports_by_n_threads(const size_t max_size) const
296 {
297 List ret;
298 for (const auto &e : *this)
299 {
300 unsigned int offset = 0;
301 do
302 {
303 if (ret.size() >= max_size)
304 OPENVPN_THROW(option_error, e.directive << ": max_size=" << max_size << " exceeded");
305 ret.emplace_back(e.port_offset(offset));
306 } while (++offset < e.n_threads);
307 }
308 return ret;
309 }
310
311 List expand_ports_by_unit(const unsigned int unit) const
312 {
313 List ret;
314 for (const auto &e : *this)
315 ret.emplace_back(e.port_offset(unit));
316 return ret;
317 }
318
319 private:
320 static bool is_vpn_binding_profile(const LoadMode load_mode,
321 const Item &e)
322 {
323#ifdef VPN_BINDING_PROFILES
324 return load_mode == AllowVPNBindingProfile
325 && !e.addr.empty()
326 && e.addr[0] == '@';
327#else
328 return false;
329#endif
330 }
331};
332} // namespace openvpn::Listen
333
334#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:1276
const Option * get_ptr(const std::string &name) const
Definition options.hpp:1186
std::string get_optional(const size_t index, const size_t max_len) const
Definition options.hpp:194
void touch(bool lightly=false) const
Definition options.hpp:385
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
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:284
bool ends_with(const STRING &str, const std::string &suffix)
Definition string.hpp:111
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:314
Item port_offset(const unsigned int offset) const
std::string to_string() const
unsigned int n_threads
server addresses push_back({address, port})
std::string ret