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 using 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 return 0;
205 }
206
207 bool contains(const ADDR &a) const // assumes canonical address/routes
208 {
209 if (addr.defined() && version_eq(addr, a))
210 return (a & netmask()) == addr;
211 return false;
212 }
213
214 bool contains(const RouteType &r) const // assumes canonical routes
215 {
216 return contains(r.addr) && r.prefix_len >= prefix_len;
217 }
218
219 bool split(RouteType &r1, RouteType &r2) const // assumes we are canonical
220 {
221 if (!is_host())
222 {
223 const unsigned int newpl = prefix_len + 1;
224 r1.addr = addr;
225 r1.prefix_len = newpl;
226
227 r2.addr = addr + netmask_(addr, newpl).extent_from_netmask();
228 r2.prefix_len = newpl;
229
230 return true;
231 }
232 return false;
233 }
234
235 std::string to_string() const
236 {
237 return addr.to_string() + '/' + openvpn::to_string(prefix_len);
238 }
239
240 std::string to_string_by_netmask() const
241 {
242 return addr.to_string() + ' ' + netmask().to_string();
243 }
244
246 {
247 if (prefix_len == addr.size())
248 return addr.to_string();
249 return addr.to_string() + '/' + openvpn::to_string(prefix_len);
250 }
251
252 bool operator==(const RouteType &other) const
253 {
254 return std::tie(prefix_len, addr) == std::tie(other.prefix_len, other.addr);
255 }
256
257 bool operator!=(const RouteType &other) const
258 {
259 return std::tie(prefix_len, addr) != std::tie(other.prefix_len, other.addr);
260 }
261
262 bool operator<(const RouteType &other) const
263 {
264 return std::tie(prefix_len, addr) < std::tie(other.prefix_len, other.addr);
265 }
266
267 template <typename HASH>
268 void hash(HASH &h) const
269 {
270 addr.hash(h);
271 h(prefix_len);
272 }
273
274#ifdef USE_OPENVPN_HASH
275 std::uint64_t hash_value() const
276 {
277 Hash64 h;
278 hash(h);
279 return h.value();
280 }
281#endif
282
283 private:
284 static IPv4::Addr netmask_(const IPv4::Addr &, unsigned int prefix_len)
285 {
287 }
288
289 static IPv6::Addr netmask_(const IPv6::Addr &, unsigned int prefix_len)
290 {
292 }
293
294 static IP::Addr netmask_(const IP::Addr &addr, unsigned int prefix_len)
295 {
297 }
298
299 static bool version_eq(const IPv4::Addr &, const IPv4::Addr &)
300 {
301 return true;
302 }
303
304 static bool version_eq(const IPv6::Addr &, const IPv6::Addr &)
305 {
306 return true;
307 }
308
309 static bool version_eq(const IP::Addr &a1, const IP::Addr &a2)
310 {
311 return a1.version() == a2.version();
312 }
313};
314
315template <typename ADDR>
316struct RouteTypeList : public std::vector<RouteType<ADDR>>
317{
318 using Base = std::vector<RouteType<ADDR>>;
319
320 OPENVPN_EXCEPTION(route_list_error);
321
322 std::string to_string() const
323 {
324 std::ostringstream os;
325 for (auto &r : *this)
326 os << r.to_string() << "\n";
327 return os.str();
328 }
329
331 {
332 IP::Addr::VersionMask mask = 0;
333 for (auto &r : *this)
334 mask |= r.version_mask();
335 return mask;
336 }
337
338 void verify_canonical() const
339 {
340 for (auto &r : *this)
341 r.verify_canonical();
342 }
343
344 template <typename R>
345 bool contains(const R &c) const
346 {
347 for (auto &r : *this)
348 if (r.contains(c))
349 return true;
350 return false;
351 }
352};
353
357
361
363OPENVPN_OSTREAM(Route4, to_string);
364OPENVPN_OSTREAM(Route6, to_string);
365
367OPENVPN_OSTREAM(Route4List, to_string);
368OPENVPN_OSTREAM(Route6List, to_string);
369
370#ifndef OPENVPN_LEGACY_TITLE_ABSTRACTION
371
372template <typename TITLE>
373inline Route route_from_string_prefix(const std::string &addrstr,
374 const unsigned int prefix_len,
375 const TITLE &title,
376 const IP::Addr::Version required_version = IP::Addr::UNSPEC)
377{
378 Route r;
379 r.addr = IP::Addr(addrstr, title, required_version);
381 if (r.prefix_len > r.addr.size())
382 OPENVPN_THROW(Route::route_error, title << " : bad prefix length : " << addrstr);
383 return r;
384}
385
386template <typename TITLE>
387inline Route route_from_string(const std::string &rtstr,
388 const TITLE &title,
389 const IP::Addr::Version required_version = IP::Addr::UNSPEC)
390{
391 Route r(rtstr, title);
392 r.addr.validate_version(title, required_version);
393 return r;
394}
395
396#else
397
398inline Route route_from_string_prefix(const std::string &addrstr,
399 const unsigned int prefix_len,
400 const std::string &title,
401 const IP::Addr::Version required_version = IP::Addr::UNSPEC)
402{
403 Route r;
404 r.addr = IP::Addr(addrstr, title, required_version);
405 r.prefix_len = prefix_len;
406 if (r.prefix_len > r.addr.size())
407 OPENVPN_THROW(Route::route_error, title << " : bad prefix length : " << addrstr);
408 return r;
409}
410
411inline Route route_from_string(const std::string &rtstr,
412 const std::string &title,
413 const IP::Addr::Version required_version = IP::Addr::UNSPEC)
414{
415 Route r(rtstr, title);
416 r.addr.validate_version(title, required_version);
417 return r;
418}
419
420#endif
421
422} // namespace openvpn::IP
423
424#ifdef USE_OPENVPN_HASH
428#endif
429
430#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:240
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:235
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:299
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:252
static IPv6::Addr netmask_(const IPv6::Addr &, unsigned int prefix_len)
Definition route.hpp:289
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:294
static IPv4::Addr netmask_(const IPv4::Addr &, unsigned int prefix_len)
Definition route.hpp:284
void hash(HASH &h) const
Definition route.hpp:268
bool operator!=(const RouteType &other) const
Definition route.hpp:257
std::string to_string_optional_prefix_len() const
Definition route.hpp:245
void verify_canonical() const
Definition route.hpp:189
bool split(RouteType &r1, RouteType &r2) const
Definition route.hpp:219
RouteType(const std::string &rtstr)
Definition route.hpp:62
static bool version_eq(const IPv6::Addr &, const IPv6::Addr &)
Definition route.hpp:304
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:214
static bool version_eq(const IP::Addr &a1, const IP::Addr &a2)
Definition route.hpp:309
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:262
bool contains(const ADDR &a) const
Definition route.hpp:207
static Addr netmask_from_prefix_len(const unsigned int prefix_len)
Definition ipv4.hpp:186
unsigned int prefix_len() const
Definition ipv4.hpp:453
Addr extent_from_netmask() const
Definition ipv4.hpp:473
static Addr netmask_from_prefix_len(const unsigned int prefix_len)
Definition ipv6.hpp:325
#define OPENVPN_THROW(exc, stuff)
#define OPENVPN_HASH_METHOD(T, meth)
Definition hash.hpp:30
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:373
RouteType< IP::Addr > Route
Definition route.hpp:354
Route route_from_string(const std::string &rtstr, const TITLE &title, const IP::Addr::Version required_version=IP::Addr::UNSPEC)
Definition route.hpp:387
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:330
OPENVPN_EXCEPTION(route_list_error)
std::vector< RouteType< ADDR > > Base
Definition route.hpp:318
bool contains(const R &c) const
Definition route.hpp:345
std::string to_string() const
Definition route.hpp:322
void verify_canonical() const
Definition route.hpp:338
std::ostringstream os
int prefix_len(const IPv4::Addr::base_type mask)