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 {
32 Netblock() = default;
33
35 {
36 if (!route.is_canonical())
37 throw vpn_serv_netblock("not canonical");
38 if (route.host_bits() < 2)
39 throw vpn_serv_netblock("need at least 4 addresses in netblock");
40 net = route.addr;
41 server_gw = net + 1;
43 }
44
45 // The Netblock constructor already sets the server
46 // gateway to the .1 address of the subnet, but call
47 // here to override that selection.
49 {
50 if (!contains(gw))
51 throw vpn_serv_netblock("override_server_gw: server gateway address is not contained by netblock");
52 server_gw = gw;
53 }
54
55 bool defined() const
56 {
57 return net.defined();
58 }
59
64
65 bool contains(const IP::Addr &a) const
66 {
67 if (net.defined() && net.version() == a.version())
68 return (a & netmask()) == net;
69 else
70 return false;
71 }
72
74 {
76 }
77
78 std::string to_string() const
79 {
80 return '[' + net.to_string() + '/' + std::to_string(prefix_len) + ',' + server_gw.to_string() + ']';
81 }
82
85 unsigned int prefix_len = 0;
86 };
87
88 struct ClientNetblock : public Netblock
89 {
90 ClientNetblock() = default;
91
94 {
95 const size_t extent = route.extent();
96 bcast = net + (extent - 1);
97 clients = IP::Range(net + 2, extent - 3);
98 }
99
100 std::string to_string() const
101 {
102 return '[' + Netblock::to_string() + ','
103 + clients.to_string() + ','
104 + bcast.to_string() + ']';
105 }
106
109 };
110
112 {
113 friend class VPNServerNetblock;
114
115 public:
116 const IP::Range &range4() const
117 {
118 return range4_;
119 }
120
121 bool range6_defined() const
122 {
123 return range6_.defined();
124 }
125 const IP::Range &range6() const
126 {
127 return range6_;
128 }
129
130 private:
133 };
134
135 VPNServerNetblock() = default;
136
138 const std::string &opt_name,
139 const bool ipv4_optional,
140 const unsigned int n_threads)
141 {
142 // ifconfig
143 if (!ipv4_optional || opt.exists(opt_name))
144 {
145 const Option &o = opt.get(opt_name);
146 const IP::Addr gw(o.get(1, 64), opt_name + " gateway");
147 const IP::Addr nm(o.get(2, 64), opt_name + " netmask");
148 IP::Route rt(gw, nm.prefix_len());
149 if (rt.version() != IP::Addr::V4)
150 throw vpn_serv_netblock(opt_name + " address is not IPv4");
151 rt.force_canonical();
152 snb4 = ClientNetblock(rt);
153 if (snb4.server_gw != gw)
154 throw vpn_serv_netblock(opt_name + " local gateway must be first usable address of subnet");
155 }
156
157 // ifconfig-ipv6
158 {
159 const Option *o = opt.get_ptr(opt_name + "-ipv6");
160 if (o)
161 {
162 IP::Route rt(o->get(1, 64), opt_name + "-ipv6 network");
163 if (rt.version() != IP::Addr::V6)
164 throw vpn_serv_netblock(opt_name + "-ipv6 network is not IPv6");
165 if (!rt.is_canonical())
166 throw vpn_serv_netblock(opt_name + "-ipv6 network is not canonical");
167 snb6 = ClientNetblock(rt);
168 }
169 }
170
171 if (n_threads)
172 {
173 // IPv4 per-thread partition
174 {
175 IP::RangePartition rp(snb4.clients, n_threads);
176 IP::Range crange;
177 for (unsigned int i = 0; i < n_threads; ++i)
178 {
179 if (!rp.next(crange))
180 throw vpn_serv_netblock(opt_name + " : unexpected ServerNetblock4 partition fail");
181 PerThread pt;
182 pt.range4_ = crange;
183 thr.push_back(pt);
184 }
185 }
186
187 // IPv6 per-thread partition
188 if (snb6.defined())
189 {
190 IP::RangePartition rp(snb6.clients, n_threads);
191 IP::Range crange;
192 for (unsigned int i = 0; i < n_threads; ++i)
193 {
194 if (!rp.next(crange))
195 throw vpn_serv_netblock(opt_name + " : unexpected ServerNetblock6 partition fail");
196 thr[i].range6_ = crange;
197 }
198 }
199 }
200 }
201
203 {
204 return snb4;
205 }
207 {
208 return snb6;
209 }
210
211 bool netblock_contains(const IP::Addr &a) const
212 {
213 return snb4.contains(a) || snb6.contains(a);
214 }
215
216 size_t size() const
217 {
218 return thr.size();
219 }
220
221 const PerThread &per_thread(const size_t index) const
222 {
223 return thr[index];
224 }
225
226 std::string to_string() const
227 {
228 std::ostringstream os;
229 os << "IPv4: " << snb4.to_string() << "\n";
230 if (snb6.defined())
231 os << "IPv6: " << snb6.to_string() << "\n";
232 for (size_t i = 0; i < thr.size(); ++i)
233 {
234 const PerThread &pt = thr[i];
235 os << '[' << i << ']';
236 os << " v4=" << pt.range4().to_string();
237 if (pt.range6_defined())
238 os << " v6=" << pt.range6().to_string();
239 os << "\n";
240 }
241 return os.str();
242 }
243
244 private:
247 std::vector<PerThread> thr;
248};
249} // namespace openvpn
250
251#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:1240
const Option * get_ptr(const std::string &name) const
Definition options.hpp:1174
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
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:354
bool contains(const IP::Addr &a) const
void override_server_gw(const IP::Addr &gw)
std::ostringstream os