OpenVPN 3 Core Library
Loading...
Searching...
No Matches
route.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_ADDR_ROUTE_H
13#define OPENVPN_ADDR_ROUTE_H
14
15#include <string>
16#include <sstream>
17#include <vector>
18#include <cstdint> // for std::uint32_t
19#include <tuple>
20
27#include <openvpn/addr/ip.hpp>
28
29namespace openvpn::IP {
30// Basic route object
31template <typename ADDR>
33{
34 public:
35 typedef ADDR Addr;
36
37 ADDR addr;
38 unsigned int prefix_len;
39
40 OPENVPN_EXCEPTION(route_error);
41
43 : prefix_len(0)
44 {
45 }
46
47 RouteType(const ADDR &addr_arg,
48 const unsigned int prefix_len_arg)
49 : addr(addr_arg),
50 prefix_len(prefix_len_arg)
51 {
52 }
53
54#ifndef OPENVPN_LEGACY_TITLE_ABSTRACTION
55
56 template <typename TITLE>
57 RouteType(const std::string &rtstr, const TITLE &title)
58 : RouteType(RouteType::from_string(rtstr, title))
59 {
60 }
61
62 RouteType(const std::string &rtstr)
63 : RouteType(RouteType::from_string(rtstr, nullptr))
64 {
65 }
66
67 template <typename TITLE>
68 static RouteType from_string(const std::string &rtstr, const TITLE &title)
69 {
70 RouteType r;
71 std::vector<std::string> pair;
72 pair.reserve(2);
73 Split::by_char_void<std::vector<std::string>, NullLex, Split::NullLimit>(pair, rtstr, '/', 0, 1);
74 r.addr = ADDR::from_string(pair[0], title);
75 if (pair.size() >= 2)
76 {
77 r.prefix_len = parse_number_throw<unsigned int>(pair[1], "prefix length");
79 }
80 else
81 r.prefix_len = r.addr.size();
82 return r;
83 }
84
85 static RouteType from_string(const std::string &rtstr)
86 {
87 return from_string(rtstr, nullptr);
88 }
89
90 template <typename TITLE>
91 void validate_prefix_length(const TITLE &title)
92 {
93 if (!is_valid())
94 OPENVPN_THROW(route_error, (!StringTempl::empty(title) ? title : "route") << ' ' << addr.to_string() << " : bad prefix length : " << prefix_len);
95 }
96
97#else
98
99 RouteType(const std::string &rtstr, const char *title = nullptr)
100 : RouteType(RouteType::from_string(rtstr, title))
101 {
102 }
103
104 RouteType(const std::string &rtstr, const std::string &title)
105 : RouteType(RouteType::from_string(rtstr, title.c_str()))
106 {
107 }
108
109 static RouteType from_string(const std::string &rtstr, const char *title = nullptr)
110 {
111 RouteType r;
112 std::vector<std::string> pair;
113 pair.reserve(2);
114 Split::by_char_void<std::vector<std::string>, NullLex, Split::NullLimit>(pair, rtstr, '/', 0, 1);
115 r.addr = ADDR::from_string(pair[0], title);
116 if (pair.size() >= 2)
117 {
118 r.prefix_len = parse_number_throw<unsigned int>(pair[1], "prefix length");
119 r.validate_prefix_length(title);
120 }
121 else
122 r.prefix_len = r.addr.size();
123 return r;
124 }
125
126 void validate_prefix_length(const char *title = nullptr)
127 {
128 if (!is_valid())
129 OPENVPN_THROW(route_error, (title ? title : "route") << ' ' << addr.to_string() << " : bad prefix length : " << prefix_len);
130 }
131
132#endif
133
134 bool defined() const
135 {
136 return addr.defined();
137 }
138
140 {
141 return addr.version();
142 }
143
145 {
146 return addr.version_mask();
147 }
148
150 {
151 return RouteType<IPv4::Addr>(addr.to_ipv4(), prefix_len);
152 }
153
155 {
156 return RouteType<IPv6::Addr>(addr.to_ipv6(), prefix_len);
157 }
158
159 ADDR netmask() const
160 {
161 return netmask_(addr, prefix_len);
162 }
163
164 size_t extent() const
165 {
166 return netmask().extent_from_netmask().to_ulong();
167 }
168
169 bool is_canonical() const
170 {
171 return canonical_addr() == addr;
172 }
173
174 bool is_valid() const
175 {
176 return prefix_len <= addr.size();
177 }
178
179 ADDR canonical_addr() const
180 {
181 return addr & netmask();
182 }
183
185 {
187 }
188
189 void verify_canonical() const
190 {
191 if (!is_canonical())
192 throw route_error("route not canonical: " + to_string());
193 }
194
195 bool is_host() const
196 {
197 return addr.defined() && prefix_len == addr.size();
198 }
199
200 unsigned int host_bits() const
201 {
202 if (prefix_len < addr.size())
203 return addr.size() - prefix_len;
204 else
205 return 0;
206 }
207
208 bool contains(const ADDR &a) const // assumes canonical address/routes
209 {
210 if (addr.defined() && version_eq(addr, a))
211 return (a & netmask()) == addr;
212 else
213 return false;
214 }
215
216 bool contains(const RouteType &r) const // assumes canonical routes
217 {
218 return contains(r.addr) && r.prefix_len >= prefix_len;
219 }
220
221 bool split(RouteType &r1, RouteType &r2) const // assumes we are canonical
222 {
223 if (!is_host())
224 {
225 const unsigned int newpl = prefix_len + 1;
226 r1.addr = addr;
227 r1.prefix_len = newpl;
228
229 r2.addr = addr + netmask_(addr, newpl).extent_from_netmask();
230 r2.prefix_len = newpl;
231
232 return true;
233 }
234 return false;
235 }
236
237 std::string to_string() const
238 {
239 return addr.to_string() + '/' + openvpn::to_string(prefix_len);
240 }
241
242 std::string to_string_by_netmask() const
243 {
244 return addr.to_string() + ' ' + netmask().to_string();
245 }
246
248 {
249 if (prefix_len == addr.size())
250 return addr.to_string();
251 else
252 return addr.to_string() + '/' + openvpn::to_string(prefix_len);
253 }
254
255 bool operator==(const RouteType &other) const
256 {
257 return std::tie(prefix_len, addr) == std::tie(other.prefix_len, other.addr);
258 }
259
260 bool operator!=(const RouteType &other) const
261 {
262 return std::tie(prefix_len, addr) != std::tie(other.prefix_len, other.addr);
263 }
264
265 bool operator<(const RouteType &other) const
266 {
267 return std::tie(prefix_len, addr) < std::tie(other.prefix_len, other.addr);
268 }
269
270 template <typename HASH>
271 void hash(HASH &h) const
272 {
273 addr.hash(h);
274 h(prefix_len);
275 }
276
277#ifdef USE_OPENVPN_HASH
278 std::uint64_t hash_value() const
279 {
280 Hash64 h;
281 hash(h);
282 return h.value();
283 }
284#endif
285
286 private:
287 static IPv4::Addr netmask_(const IPv4::Addr &, unsigned int prefix_len)
288 {
290 }
291
292 static IPv6::Addr netmask_(const IPv6::Addr &, unsigned int prefix_len)
293 {
295 }
296
297 static IP::Addr netmask_(const IP::Addr &addr, unsigned int prefix_len)
298 {
300 }
301
302 static bool version_eq(const IPv4::Addr &, const IPv4::Addr &)
303 {
304 return true;
305 }
306
307 static bool version_eq(const IPv6::Addr &, const IPv6::Addr &)
308 {
309 return true;
310 }
311
312 static bool version_eq(const IP::Addr &a1, const IP::Addr &a2)
313 {
314 return a1.version() == a2.version();
315 }
316};
317
318template <typename ADDR>
319struct RouteTypeList : public std::vector<RouteType<ADDR>>
320{
321 typedef std::vector<RouteType<ADDR>> Base;
322
323 OPENVPN_EXCEPTION(route_list_error);
324
325 std::string to_string() const
326 {
327 std::ostringstream os;
328 for (auto &r : *this)
329 os << r.to_string() << std::endl;
330 return os.str();
331 }
332
334 {
335 IP::Addr::VersionMask mask = 0;
336 for (auto &r : *this)
337 mask |= r.version_mask();
338 return mask;
339 }
340
341 void verify_canonical() const
342 {
343 for (auto &r : *this)
344 r.verify_canonical();
345 }
346
347 template <typename R>
348 bool contains(const R &c) const
349 {
350 for (auto &r : *this)
351 if (r.contains(c))
352 return true;
353 return false;
354 }
355};
356
360
364
366OPENVPN_OSTREAM(Route4, to_string);
367OPENVPN_OSTREAM(Route6, to_string);
368
370OPENVPN_OSTREAM(Route4List, to_string);
371OPENVPN_OSTREAM(Route6List, to_string);
372
373#ifndef OPENVPN_LEGACY_TITLE_ABSTRACTION
374
375template <typename TITLE>
376inline Route route_from_string_prefix(const std::string &addrstr,
377 const unsigned int prefix_len,
378 const TITLE &title,
379 const IP::Addr::Version required_version = IP::Addr::UNSPEC)
380{
381 Route r;
382 r.addr = IP::Addr(addrstr, title, required_version);
384 if (r.prefix_len > r.addr.size())
385 OPENVPN_THROW(Route::route_error, title << " : bad prefix length : " << addrstr);
386 return r;
387}
388
389template <typename TITLE>
390inline Route route_from_string(const std::string &rtstr,
391 const TITLE &title,
392 const IP::Addr::Version required_version = IP::Addr::UNSPEC)
393{
394 Route r(rtstr, title);
395 r.addr.validate_version(title, required_version);
396 return r;
397}
398
399#else
400
401inline Route route_from_string_prefix(const std::string &addrstr,
402 const unsigned int prefix_len,
403 const std::string &title,
404 const IP::Addr::Version required_version = IP::Addr::UNSPEC)
405{
406 Route r;
407 r.addr = IP::Addr(addrstr, title, required_version);
408 r.prefix_len = prefix_len;
409 if (r.prefix_len > r.addr.size())
410 OPENVPN_THROW(Route::route_error, title << " : bad prefix length : " << addrstr);
411 return r;
412}
413
414inline Route route_from_string(const std::string &rtstr,
415 const std::string &title,
416 const IP::Addr::Version required_version = IP::Addr::UNSPEC)
417{
418 Route r(rtstr, title);
419 r.addr.validate_version(title, required_version);
420 return r;
421}
422
423#endif
424
425} // namespace openvpn::IP
426
427#ifdef USE_OPENVPN_HASH
431#endif
432
433#endif
Version version() const
Definition ip.hpp:895
unsigned int VersionMask
Definition ip.hpp:53
static Addr netmask_from_prefix_len(Version v, const unsigned int prefix_len)
Definition ip.hpp:502
RouteType(const std::string &rtstr, const TITLE &title)
Definition route.hpp:57
bool is_host() const
Definition route.hpp:195
std::string to_string_by_netmask() const
Definition route.hpp:242
RouteType(const ADDR &addr_arg, const unsigned int prefix_len_arg)
Definition route.hpp:47
static RouteType from_string(const std::string &rtstr)
Definition route.hpp:85
IP::Addr::Version version() const
Definition route.hpp:139
void validate_prefix_length(const TITLE &title)
Definition route.hpp:91
std::string to_string() const
Definition route.hpp:237
bool is_valid() const
Definition route.hpp:174
ADDR netmask() const
Definition route.hpp:159
static bool version_eq(const IPv4::Addr &, const IPv4::Addr &)
Definition route.hpp:302
RouteType< IPv4::Addr > to_ipv4() const
Definition route.hpp:149
size_t extent() const
Definition route.hpp:164
bool operator==(const RouteType &other) const
Definition route.hpp:255
static IPv6::Addr netmask_(const IPv6::Addr &, unsigned int prefix_len)
Definition route.hpp:292
unsigned int host_bits() const
Definition route.hpp:200
IP::Addr::VersionMask version_mask() const
Definition route.hpp:144
static IP::Addr netmask_(const IP::Addr &addr, unsigned int prefix_len)
Definition route.hpp:297
static IPv4::Addr netmask_(const IPv4::Addr &, unsigned int prefix_len)
Definition route.hpp:287
void hash(HASH &h) const
Definition route.hpp:271
bool operator!=(const RouteType &other) const
Definition route.hpp:260
std::string to_string_optional_prefix_len() const
Definition route.hpp:247
void verify_canonical() const
Definition route.hpp:189
bool split(RouteType &r1, RouteType &r2) const
Definition route.hpp:221
RouteType(const std::string &rtstr)
Definition route.hpp:62
static bool version_eq(const IPv6::Addr &, const IPv6::Addr &)
Definition route.hpp:307
static RouteType from_string(const std::string &rtstr, const TITLE &title)
Definition route.hpp:68
ADDR canonical_addr() const
Definition route.hpp:179
bool contains(const RouteType &r) const
Definition route.hpp:216
static bool version_eq(const IP::Addr &a1, const IP::Addr &a2)
Definition route.hpp:312
bool is_canonical() const
Definition route.hpp:169
RouteType< IPv6::Addr > to_ipv6() const
Definition route.hpp:154
unsigned int prefix_len
Definition route.hpp:38
bool defined() const
Definition route.hpp:134
OPENVPN_EXCEPTION(route_error)
bool operator<(const RouteType &other) const
Definition route.hpp:265
bool contains(const ADDR &a) const
Definition route.hpp:208
static Addr netmask_from_prefix_len(const unsigned int prefix_len)
Definition ipv4.hpp:189
unsigned int prefix_len() const
Definition ipv4.hpp:456
Addr extent_from_netmask() const
Definition ipv4.hpp:476
static Addr netmask_from_prefix_len(const unsigned int prefix_len)
Definition ipv6.hpp:328
#define OPENVPN_THROW(exc, stuff)
#define OPENVPN_HASH_METHOD(T, meth)
Definition hash.hpp:30
RouteTypeList< IP::Addr > RouteList
Definition route.hpp:361
RouteTypeList< IPv6::Addr > Route6List
Definition route.hpp:363
RouteType< IPv6::Addr > Route6
Definition route.hpp:359
RouteTypeList< IPv4::Addr > Route4List
Definition route.hpp:362
RouteType< IP::Addr > Route
Definition route.hpp:357
Route route_from_string_prefix(const std::string &addrstr, const unsigned int prefix_len, const TITLE &title, const IP::Addr::Version required_version=IP::Addr::UNSPEC)
Definition route.hpp:376
RouteType< IPv4::Addr > Route4
Definition route.hpp:358
Route route_from_string(const std::string &rtstr, const TITLE &title, const IP::Addr::Version required_version=IP::Addr::UNSPEC)
Definition route.hpp:390
bool empty(std::nullptr_t)
std::string to_string(const T &t)
Convert a value to a string.
Definition to_string.hpp:45
#define OPENVPN_OSTREAM(TYPE, METH)
Definition ostream.hpp:21
IP::Addr::VersionMask version_mask() const
Definition route.hpp:333
OPENVPN_EXCEPTION(route_list_error)
bool contains(const R &c) const
Definition route.hpp:348
std::vector< RouteType< ADDR > > Base
Definition route.hpp:321
std::string to_string() const
Definition route.hpp:325
void verify_canonical() const
Definition route.hpp:341
std::ostringstream os
int prefix_len(const IPv4::Addr::base_type mask)