OpenVPN 3 Core Library
Loading...
Searching...
No Matches
tuniproute.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#pragma once
13
14#include <sys/ioctl.h>
15#include <fcntl.h>
16#include <errno.h>
17#include <net/if.h>
18#include <linux/if_tun.h>
19
37
39
40using namespace openvpn::TunLinuxSetup;
41
42enum
43{ // add_del_route flags
44 R_IPv6 = (1 << 0),
45 R_ADD_SYS = (1 << 1),
46 R_ADD_DCO = (1 << 2),
48};
49
50inline IP::Addr cvt_pnr_ip_v4(const std::string &hexaddr)
51{
53 parse_hex(v, hexaddr);
54 if (v.size() != 4)
55 throw tun_linux_error("bad hex address");
58}
59
60inline void add_del_route(const std::string &addr_str,
61 const int prefix_len,
62 const std::string &gateway_str,
63 const std::string &dev,
64 const unsigned int flags,
65 std::vector<IP::Route> *rtvec,
66 Action::Ptr &create,
67 Action::Ptr &destroy)
68{
69 if (flags & R_IPv6)
70 {
71 const IPv6::Addr addr = IPv6::Addr::from_string(addr_str);
73 const IPv6::Addr net = addr & netmask;
74
75 if (flags & R_ADD_SYS)
76 {
77 // ip route add 2001:db8:1::/48 via 2001:db8:1::1
79 add->argv.push_back("/sbin/ip");
80 add->argv.push_back("-6");
81 add->argv.push_back("route");
82 add->argv.push_back("prepend");
83 add->argv.push_back(net.to_string() + '/' + openvpn::to_string(prefix_len));
84 add->argv.push_back("via");
85 add->argv.push_back(gateway_str);
86 if (!dev.empty())
87 {
88 add->argv.push_back("dev");
89 add->argv.push_back(dev);
90 }
91 create = add;
92
93 // for the destroy command, copy the add command but replace "add" with "delete"
94 Command::Ptr del(add->copy());
95 del->argv[3] = "del";
96 destroy = del;
97 }
98
99 if (rtvec && (flags & R_ADD_DCO))
100 rtvec->emplace_back(IP::Addr::from_ipv6(net), prefix_len);
101 }
102 else
103 {
104 const IPv4::Addr addr = IPv4::Addr::from_string(addr_str);
106 const IPv4::Addr net = addr & netmask;
107
108 if (flags & R_ADD_SYS)
109 {
110 // ip route add 192.0.2.128/25 via 192.0.2.1
112 add->argv.push_back("/sbin/ip");
113 add->argv.push_back("-4");
114 add->argv.push_back("route");
115 add->argv.push_back("prepend");
116 add->argv.push_back(net.to_string() + '/' + openvpn::to_string(prefix_len));
117 add->argv.push_back("via");
118 add->argv.push_back(gateway_str);
119 if (!dev.empty())
120 {
121 add->argv.push_back("dev");
122 add->argv.push_back(dev);
123 }
124 create = add;
125
126 // for the destroy command, copy the add command but replace "add" with "delete"
127 Command::Ptr del(add->copy());
128 del->argv[3] = "del";
129 destroy = del;
130 }
131
132 if (rtvec && (flags & R_ADD_DCO))
133 rtvec->emplace_back(IP::Addr::from_ipv4(net), prefix_len);
134 }
135}
136
137inline void add_del_route(const std::string &addr_str,
138 const int prefix_len,
139 const std::string &gateway_str,
140 const std::string &dev,
141 const unsigned int flags, // add interface route to rtvec if defined
142 std::vector<IP::Route> *rtvec,
143 ActionList &create,
144 ActionList &destroy)
145{
146 Action::Ptr c, d;
147 add_del_route(addr_str, prefix_len, gateway_str, dev, flags, rtvec, c, d);
148 create.add(c);
149 destroy.add(d);
150}
151
152inline void iface_up(const std::string &iface_name,
153 const int mtu,
154 ActionList &create,
155 ActionList &destroy)
156{
157 {
159 add->argv.push_back("/sbin/ip");
160 add->argv.push_back("link");
161 add->argv.push_back("set");
162 add->argv.push_back(iface_name);
163 add->argv.push_back("up");
164 if (mtu > 0)
165 {
166 add->argv.push_back("mtu");
167 add->argv.push_back(openvpn::to_string(mtu));
168 }
169 create.add(add);
170
171 // for the destroy command, copy the add command but replace "up" with "down"
172 Command::Ptr del(add->copy());
173 del->argv[4] = "down";
174 destroy.add(del);
175 }
176}
177
178inline void iface_config(const std::string &iface_name,
179 int unit,
180 const TunBuilderCapture &pull,
181 std::vector<IP::Route> *rtvec,
182 ActionList &create,
183 ActionList &destroy)
184{
185 // set local4 and local6 to point to IPv4/6 route configurations
186 const TunBuilderCapture::RouteAddress *local4 = pull.vpn_ipv4();
187 const TunBuilderCapture::RouteAddress *local6 = pull.vpn_ipv6();
188
189 // Set IPv4 Interface
190 if (local4)
191 {
193 add->argv.push_back("/sbin/ip");
194 add->argv.push_back("-4");
195 add->argv.push_back("addr");
196 add->argv.push_back("add");
197 add->argv.push_back(local4->address + '/' + openvpn::to_string(local4->prefix_length));
198 add->argv.push_back("broadcast");
199 add->argv.push_back((IPv4::Addr::from_string(local4->address) | ~IPv4::Addr::netmask_from_prefix_len(local4->prefix_length)).to_string());
200 add->argv.push_back("dev");
201 add->argv.push_back(iface_name);
202 if (unit >= 0)
203 {
204 add->argv.push_back("label");
205 add->argv.push_back(iface_name + ':' + openvpn::to_string(unit));
206 }
207 create.add(add);
208
209 // for the destroy command, copy the add command but replace "add" with "delete"
210 Command::Ptr del(add->copy());
211 del->argv[3] = "del";
212 destroy.add(del);
213
214 // add interface route to rtvec if defined
215 add_del_route(local4->address, local4->prefix_length, local4->address, iface_name, R_ADD_DCO, rtvec, create, destroy);
216 }
217
218 // Set IPv6 Interface
219 if (local6 && !pull.block_ipv6)
220 {
222 add->argv.push_back("/sbin/ip");
223 add->argv.push_back("-6");
224 add->argv.push_back("addr");
225 add->argv.push_back("add");
226 add->argv.push_back(local6->address + '/' + openvpn::to_string(local6->prefix_length));
227 add->argv.push_back("dev");
228 add->argv.push_back(iface_name);
229 create.add(add);
230
231 // for the destroy command, copy the add command but replace "add" with "delete"
232 Command::Ptr del(add->copy());
233 del->argv[3] = "del";
234 destroy.add(del);
235
236 // add interface route to rtvec if defined
237 add_del_route(local6->address, local6->prefix_length, local6->address, iface_name, R_ADD_DCO | R_IPv6, rtvec, create, destroy);
238 }
239}
240
242{
243 static inline void tun_config(const std::string &iface_name,
244 const TunBuilderCapture &pull,
245 std::vector<IP::Route> *rtvec,
246 ActionList &create,
247 ActionList &destroy,
248 const unsigned int flags) // TunConfigFlags
249 {
250 const LinuxGW46 gw(true);
251
252 // set local4 and local6 to point to IPv4/6 route configurations
253 const TunBuilderCapture::RouteAddress *local4 = pull.vpn_ipv4();
254 const TunBuilderCapture::RouteAddress *local6 = pull.vpn_ipv6();
255
256 // configure interface
258 iface_up(iface_name, pull.mtu, create, destroy);
259 iface_config(iface_name, -1, pull, rtvec, create, destroy);
260
261 // Process Routes
262 {
263 for (const auto &route : pull.add_routes)
264 {
265 if (route.ipv6)
266 {
267 if (local6 && !pull.block_ipv6)
268 add_del_route(route.address, route.prefix_length, local6->gateway, iface_name, R_ADD_ALL | R_IPv6, rtvec, create, destroy);
269 }
270 else
271 {
272 if (local4 && !local4->gateway.empty())
273 add_del_route(route.address, route.prefix_length, local4->gateway, iface_name, R_ADD_ALL, rtvec, create, destroy);
274 else
275 OPENVPN_LOG("ERROR: IPv4 route pushed without IPv4 ifconfig and/or route-gateway");
276 }
277 }
278 }
279
280 // Process exclude routes
281 {
282 for (const auto &route : pull.exclude_routes)
283 {
284 if (route.ipv6)
285 {
286 OPENVPN_LOG("NOTE: exclude IPv6 routes not supported yet"); // fixme
287 }
288 else
289 {
290 if (gw.v4.defined())
291 add_del_route(route.address, route.prefix_length, gw.v4.addr().to_string(), gw.v4.dev(), R_ADD_SYS, rtvec, create, destroy);
292 else
293 OPENVPN_LOG("NOTE: cannot determine gateway for exclude IPv4 routes");
294 }
295 }
296 }
297
298 // Process IPv4 redirect-gateway
300 {
301 if (pull.reroute_gw.ipv4)
302 {
303 // add bypass route
305 add_del_route(pull.remote_address.address, 32, gw.v4.addr().to_string(), gw.v4.dev(), R_ADD_SYS, rtvec, create, destroy);
306
307 add_del_route("0.0.0.0", 1, local4->gateway, iface_name, R_ADD_ALL, rtvec, create, destroy);
308 add_del_route("128.0.0.0", 1, local4->gateway, iface_name, R_ADD_ALL, rtvec, create, destroy);
309 }
310
311 // Process IPv6 redirect-gateway
312 if (pull.reroute_gw.ipv6 && !pull.block_ipv6)
313 {
314 // add bypass route
316 add_del_route(pull.remote_address.address, 128, gw.v6.addr().to_string(), gw.v6.dev(), R_ADD_SYS | R_IPv6, rtvec, create, destroy);
317
318 add_del_route("0000::", 1, local6->gateway, iface_name, R_ADD_ALL | R_IPv6, rtvec, create, destroy);
319 add_del_route("8000::", 1, local6->gateway, iface_name, R_ADD_ALL | R_IPv6, rtvec, create, destroy);
320 }
321 }
322
323 // fixme -- Process block-ipv6
324
325 // fixme -- Handle pushed DNS servers
326 }
327
328 static inline void add_bypass_route(const std::string &tun_iface_name,
329 const std::string &address,
330 bool ipv6,
331 std::vector<IP::Route> *rtvec,
332 ActionList &create,
333 ActionList &destroy)
334 {
335 LinuxGW46 gw(true);
336
337 if (!ipv6 && gw.v4.defined())
338 add_del_route(address, 32, gw.v4.addr().to_string(), gw.dev(), R_ADD_SYS, rtvec, create, destroy);
339
340 if (ipv6 && gw.v6.defined())
341 add_del_route(address, 128, gw.v6.addr().to_string(), gw.dev(), R_ADD_SYS, rtvec, create, destroy);
342 }
343};
344} // namespace openvpn::TunIPRoute
void add(Action *action)
Definition action.hpp:57
size_t size() const
Returns the size of the buffer in T objects.
Definition buffer.hpp:1242
T * data()
Get a mutable pointer to the start of the array.
Definition buffer.hpp:1450
std::string to_string() const
Definition ip.hpp:528
static Addr from_ipv6(IPv6::Addr addr)
Definition ip.hpp:268
static Addr from_ipv4(IPv4::Addr addr)
Definition ip.hpp:260
static Addr netmask_from_prefix_len(const unsigned int prefix_len)
Definition ipv4.hpp:189
static Addr from_bytes(const unsigned char *bytes)
Definition ipv4.hpp:153
std::string to_string() const
Definition ipv4.hpp:232
static Addr from_string(const std::string &ipstr, const TITLE &title)
Definition ipv4.hpp:205
static Addr netmask_from_prefix_len(const unsigned int prefix_len)
Definition ipv6.hpp:328
std::string to_string() const
Definition ipv6.hpp:131
static Addr from_string(const std::string &ipstr, const TITLE &title)
Definition ipv6.hpp:104
const IP::Addr & addr() const
Definition gw.hpp:134
const std::string & dev() const
Definition gw.hpp:129
bool defined() const
Definition gw.hpp:139
The smart pointer class.
Definition rc.hpp:119
Route address class that may use non-canonical form.
Definition capture.hpp:295
RemoteAddress remote_address
Definition capture.hpp:1082
std::vector< Route > add_routes
Definition capture.hpp:1091
const RouteAddress * vpn_ipv6() const
Gets the IPv6 tunnel address.
Definition capture.hpp:914
const RouteAddress * vpn_ipv4() const
Gets the IPv4 tunnel address.
Definition capture.hpp:902
std::vector< Route > exclude_routes
Definition capture.hpp:1092
#define OPENVPN_LOG(args)
constexpr BufferFlags CONSTRUCT_ZERO(1u<< 0)
if enabled, constructors/init will zero allocated space
void iface_config(const std::string &iface_name, int unit, const TunBuilderCapture &pull, std::vector< IP::Route > *rtvec, ActionList &create, ActionList &destroy)
void add_del_route(const std::string &addr_str, const int prefix_len, const std::string &gateway_str, const std::string &dev, const unsigned int flags, std::vector< IP::Route > *rtvec, Action::Ptr &create, Action::Ptr &destroy)
void iface_up(const std::string &iface_name, const int mtu, ActionList &create, ActionList &destroy)
IP::Addr cvt_pnr_ip_v4(const std::string &hexaddr)
void parse_hex(V &dest, const std::string &str)
Definition hexstr.hpp:352
std::string to_string(const T &t)
Convert a value to a string.
Definition to_string.hpp:45
std::string dev() const
Definition gw.hpp:188
static void add_bypass_route(const std::string &tun_iface_name, const std::string &address, bool ipv6, std::vector< IP::Route > *rtvec, ActionList &create, ActionList &destroy)
static void tun_config(const std::string &iface_name, const TunBuilderCapture &pull, std::vector< IP::Route > *rtvec, ActionList &create, ActionList &destroy, const unsigned int flags)
reroute_gw flags
remote_address ipv6
remote_address address
std::string ret
int prefix_len(const IPv4::Addr::base_type mask)
static void add(const Time &t1, const Time::Duration &d1)