OpenVPN 3 Core Library
Loading...
Searching...
No Matches
vpnservnetblock.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_VPNSERVNETBLOCK_H
13#define OPENVPN_SERVER_VPNSERVNETBLOCK_H
14
15#include <sstream>
16
22
23namespace openvpn {
24
26{
27 public:
28 OPENVPN_EXCEPTION(vpn_serv_netblock);
29
30 struct Netblock
31 {
33 {
34 }
35
37 {
38 if (!route.is_canonical())
39 throw vpn_serv_netblock("not canonical");
40 if (route.host_bits() < 2)
41 throw vpn_serv_netblock("need at least 4 addresses in netblock");
42 net = route.addr;
43 server_gw = net + 1;
45 }
46
47 // The Netblock constructor already sets the server
48 // gateway to the .1 address of the subnet, but call
49 // here to override that selection.
51 {
52 if (!contains(gw))
53 throw vpn_serv_netblock("override_server_gw: server gateway address is not contained by netblock");
54 server_gw = gw;
55 }
56
57 bool defined() const
58 {
59 return net.defined();
60 }
61
66
67 bool contains(const IP::Addr &a) const
68 {
69 if (net.defined() && net.version() == a.version())
70 return (a & netmask()) == net;
71 else
72 return false;
73 }
74
76 {
78 }
79
80 std::string to_string() const
81 {
82 return '[' + net.to_string() + '/' + std::to_string(prefix_len) + ',' + server_gw.to_string() + ']';
83 }
84
87 unsigned int prefix_len = 0;
88 };
89
90 struct ClientNetblock : public Netblock
91 {
93 {
94 }
95
98 {
99 const size_t extent = route.extent();
100 bcast = net + (extent - 1);
101 clients = IP::Range(net + 2, extent - 3);
102 }
103
104 std::string to_string() const
105 {
106 return '[' + Netblock::to_string() + ','
107 + clients.to_string() + ','
108 + bcast.to_string() + ']';
109 }
110
113 };
114
116 {
117 friend class VPNServerNetblock;
118
119 public:
120 const IP::Range &range4() const
121 {
122 return range4_;
123 }
124
125 bool range6_defined() const
126 {
127 return range6_.defined();
128 }
129 const IP::Range &range6() const
130 {
131 return range6_;
132 }
133
134 private:
137 };
138
140 {
141 }
142
144 const std::string &opt_name,
145 const bool ipv4_optional,
146 const unsigned int n_threads)
147 {
148 // ifconfig
149 if (!ipv4_optional || opt.exists(opt_name))
150 {
151 const Option &o = opt.get(opt_name);
152 const IP::Addr gw(o.get(1, 64), opt_name + " gateway");
153 const IP::Addr nm(o.get(2, 64), opt_name + " netmask");
154 IP::Route rt(gw, nm.prefix_len());
155 if (rt.version() != IP::Addr::V4)
156 throw vpn_serv_netblock(opt_name + " address is not IPv4");
157 rt.force_canonical();
158 snb4 = ClientNetblock(rt);
159 if (snb4.server_gw != gw)
160 throw vpn_serv_netblock(opt_name + " local gateway must be first usable address of subnet");
161 }
162
163 // ifconfig-ipv6
164 {
165 const Option *o = opt.get_ptr(opt_name + "-ipv6");
166 if (o)
167 {
168 IP::Route rt(o->get(1, 64), opt_name + "-ipv6 network");
169 if (rt.version() != IP::Addr::V6)
170 throw vpn_serv_netblock(opt_name + "-ipv6 network is not IPv6");
171 if (!rt.is_canonical())
172 throw vpn_serv_netblock(opt_name + "-ipv6 network is not canonical");
173 snb6 = ClientNetblock(rt);
174 }
175 }
176
177 if (n_threads)
178 {
179 // IPv4 per-thread partition
180 {
181 IP::RangePartition rp(snb4.clients, n_threads);
182 IP::Range crange;
183 for (unsigned int i = 0; i < n_threads; ++i)
184 {
185 if (!rp.next(crange))
186 throw vpn_serv_netblock(opt_name + " : unexpected ServerNetblock4 partition fail");
187 PerThread pt;
188 pt.range4_ = crange;
189 thr.push_back(pt);
190 }
191 }
192
193 // IPv6 per-thread partition
194 if (snb6.defined())
195 {
196 IP::RangePartition rp(snb6.clients, n_threads);
197 IP::Range crange;
198 for (unsigned int i = 0; i < n_threads; ++i)
199 {
200 if (!rp.next(crange))
201 throw vpn_serv_netblock(opt_name + " : unexpected ServerNetblock6 partition fail");
202 thr[i].range6_ = crange;
203 }
204 }
205 }
206 }
207
209 {
210 return snb4;
211 }
213 {
214 return snb6;
215 }
216
217 bool netblock_contains(const IP::Addr &a) const
218 {
219 return snb4.contains(a) || snb6.contains(a);
220 }
221
222 size_t size() const
223 {
224 return thr.size();
225 }
226
227 const PerThread &per_thread(const size_t index) const
228 {
229 return thr[index];
230 }
231
232 std::string to_string() const
233 {
234 std::ostringstream os;
235 os << "IPv4: " << snb4.to_string() << std::endl;
236 if (snb6.defined())
237 os << "IPv6: " << snb6.to_string() << std::endl;
238 for (size_t i = 0; i < thr.size(); ++i)
239 {
240 const PerThread &pt = thr[i];
241 os << '[' << i << ']';
242 os << " v4=" << pt.range4().to_string();
243 if (pt.range6_defined())
244 os << " v6=" << pt.range6().to_string();
245 os << std::endl;
246 }
247 return os.str();
248 }
249
250 private:
253 std::vector<PerThread> thr;
254};
255} // namespace openvpn
256
257#endif
Version version() const
Definition ip.hpp:895
std::string to_string() const
Definition ip.hpp:528
bool defined() const
Definition ip.hpp:872
static Addr netmask_from_prefix_len(Version v, const unsigned int prefix_len)
Definition ip.hpp:502
unsigned int prefix_len() const
Definition ip.hpp:968
divide a range of IP addresses into smaller, equal-sized partitions
Definition range.hpp:226
bool next(RangeType< ADDR > &r)
Retrieves the next partition in the range.
Definition range.hpp:372
designed to represent and manage a range of IP addresses.
Definition range.hpp:65
bool defined() const
Check if the range is defined (non-empty).
Definition range.hpp:328
std::string to_string() const
Convert the range to a string representation.
Definition range.hpp:357
IP::Addr::Version version() const
Definition route.hpp:139
size_t extent() const
Definition route.hpp:164
unsigned int host_bits() const
Definition route.hpp:200
bool is_canonical() const
Definition route.hpp:169
unsigned int prefix_len
Definition route.hpp:38
const Option & get(const std::string &name) const
Definition options.hpp:1254
const Option * get_ptr(const std::string &name) const
Definition options.hpp:1186
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
std::vector< PerThread > thr
bool netblock_contains(const IP::Addr &a) const
OPENVPN_EXCEPTION(vpn_serv_netblock)
const ClientNetblock & netblock6() const
VPNServerNetblock(const OptionList &opt, const std::string &opt_name, const bool ipv4_optional, const unsigned int n_threads)
const PerThread & per_thread(const size_t index) const
std::string to_string() const
const ClientNetblock & netblock4() const
RangeType< IP::Addr > Range
Definition range.hpp:215
RouteType< IP::Addr > Route
Definition route.hpp:357
bool contains(const IP::Addr &a) const
void override_server_gw(const IP::Addr &gw)
std::ostringstream os