OpenVPN 3 Core Library
Loading...
Searching...
No Matches
tuncli.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// Client tun interface for Windows
13
14#ifndef OPENVPN_TUN_WIN_CLIENT_TUNCLI_H
15#define OPENVPN_TUN_WIN_CLIENT_TUNCLI_H
16
17#include <string>
18#include <sstream>
19#include <memory>
20
30#include <openvpn/tun/tunio.hpp>
35
36namespace openvpn::TunWin {
37
38OPENVPN_EXCEPTION(tun_win_error);
39
40// struct used to pass received tun packets
42{
43 typedef std::unique_ptr<PacketFrom> SPtr;
45};
46
47// tun interface wrapper for Windows
48template <typename ReadHandler, typename TunPersist>
49class Tun : public TunIO<ReadHandler, PacketFrom, TunWrapAsioStream<TunPersist>>
50{
52
53 public:
54 typedef RCPtr<Tun> Ptr;
55
56 Tun(const typename TunPersist::Ptr &tun_persist,
57 const std::string &name,
58 const bool retain_stream,
59 ReadHandler read_handler,
60 const Frame::Ptr &frame,
62 : Base(read_handler, frame, stats, Frame::READ_TUN)
63 {
67 }
68};
69
70class Client : public TunClient
71{
72 friend class ClientConfig; // calls constructor
73 friend class TunIO<Client *, PacketFrom, TunWrapAsioStream<TunPersist>>; // calls tun_read_handler
74
76
77 public:
79
80 void apply_push_update(const OptionList &opt, TransportClient &transcli) override
81 {
82 stop_();
83 if (impl)
84 {
85 impl.reset();
86 }
87
88 // this has to be done in post, because we need to wait
89 // for all async tun read requests to complete
90 openvpn_io::post(io_context, [self = Ptr(this), opt, &transcli]
91 {
94 self->tun_start(opt, transcli, c); });
95 }
96
97 void tun_start(const OptionList &opt, TransportClient &transcli, CryptoDCSettings &) override
98 {
99 if (!impl)
100 {
101 halt = false;
102 if (config->tun_persist)
103 tun_persist = config->tun_persist; // long-term persistent
104 else
105 tun_persist.reset(new TunPersist(false, TunWrapObjRetain::NO_RETAIN, nullptr)); // short-term
106
107 try
108 {
109 const IP::Addr server_addr = transcli.server_endpoint_addr();
110
111 // Check if persisted tun session matches properties of to-be-created session
112 if (tun_persist->use_persisted_tun(server_addr, config->tun_prop, opt))
113 {
114 state = tun_persist->state().state;
115 OPENVPN_LOG("TunPersist: reused tun context");
116 }
117 else
118 {
119 // notify parent
121
122 // close old TAP handle if persisted
123 tun_persist->close();
124
125 // parse pushed options
128 state.get(),
129 config->stats.get(),
130 server_addr,
131 config->tun_prop,
132 opt,
133 nullptr,
134 false);
135 OPENVPN_LOG("CAPTURED OPTIONS:" << std::endl
136 << po->to_string());
137
138 // create new tun setup object
139 tun_setup = config->new_setup_obj(io_context);
140
141 // open/config TAP
142 HANDLE th;
143 {
144 std::ostringstream os;
145 auto os_print = Cleanup([&os]()
146 { OPENVPN_LOG_STRING(os.str()); });
147 th = tun_setup->establish(*po, Win::module_name(), config->stop, os, NULL);
148 }
149
150 // create ASIO wrapper for HANDLE
151 TAPStream *ts = new TAPStream(io_context, th);
152
153 state->vpn_interface_index = tun_setup->vpn_interface_index();
154
155 // persist tun settings state
156 if (tun_persist->persist_tun_state(ts, {state, nullptr}))
157 OPENVPN_LOG("TunPersist: saving tun context:" << std::endl
158 << tun_persist->options());
159
160 // setup handler for external tun close
161 tun_setup->set_service_fail_handler([self = Ptr(this)]()
162 {
163 if (!self->halt)
164 self->parent.tun_error(Error::TUN_IFACE_DISABLED, "service failure"); });
165
166 // enable tun_setup destructor
167 tun_persist->add_destructor(tun_setup);
168
169 // assert ownership over TAP device handle
170 tun_setup->confirm();
171
172 // if layer 2, set up to capture DHCP messages over the tunnel
173 if (config->tun_prop.layer() == Layer::OSI_LAYER_2)
175 }
176
177 // configure tun interface packet forwarding
179 "TUN_WIN",
180 true,
181 this,
182 config->frame,
183 config->stats));
184 impl->start(config->n_parallel);
185
186 if (!dhcp_capture)
187 parent.tun_connected(); // signal that we are connected
188 }
189 catch (const std::exception &e)
190 {
191 if (tun_persist)
192 tun_persist->close();
193 stop();
195 const ExceptionCode *ec = dynamic_cast<const ExceptionCode *>(&e);
196 if (ec && ec->code_defined())
197 err = ec->code();
198 parent.tun_error(err, e.what());
199 }
200 }
201 }
202
203 bool tun_send(BufferAllocated &buf) override
204 {
205 return send(buf);
206 }
207
208 std::string tun_name() const override
209 {
210 if (impl)
211 return impl->name();
212 else
213 return "UNDEF_TUN";
214 }
215
216 std::string vpn_ip4() const override
217 {
218 if (state->vpn_ip4_addr.specified())
219 return state->vpn_ip4_addr.to_string();
220 else
221 return "";
222 }
223
224 std::string vpn_ip6() const override
225 {
226 if (state->vpn_ip6_addr.specified())
227 return state->vpn_ip6_addr.to_string();
228 else
229 return "";
230 }
231
232 std::string vpn_gw4() const override
233 {
234 if (state->vpn_ip4_gw.specified())
235 return state->vpn_ip4_gw.to_string();
236 else
237 return "";
238 }
239
240 std::string vpn_gw6() const override
241 {
242 if (state->vpn_ip6_gw.specified())
243 return state->vpn_ip6_gw.to_string();
244 else
245 return "";
246 }
247
248 int vpn_mtu() const override
249 {
250 return state->mtu;
251 }
252
253 std::uint32_t vpn_interface_index() const override
254 {
255 if (tun_setup)
256 return tun_setup->vpn_interface_index();
257
258 if (tun_persist && tun_persist->state().state)
259 return tun_persist->state().state->vpn_interface_index;
260
262 }
263
264 void set_disconnect() override
265 {
266 }
267
268 void stop() override
269 {
270 stop_();
271 }
272 virtual ~Client()
273 {
274 stop_();
275 }
276
277 private:
278 Client(openvpn_io::io_context &io_context_arg,
279 ClientConfig *config_arg,
280 TunClientParent &parent_arg)
281 : io_context(io_context_arg),
282 config(config_arg),
283 parent(parent_arg),
284 state(new TunProp::State()),
285 l2_timer(io_context_arg),
286 frame_context((*config_arg->frame)[Frame::READ_TUN]),
287 halt(false)
288 {
289 }
290
291 bool send(Buffer &buf)
292 {
293 if (impl)
294 {
295 if (dhcp_capture)
296 dhcp_inspect(buf);
297
298 return impl->write(buf);
299 }
300 else
301 return false;
302#ifdef OPENVPN_DEBUG_TAPWIN
304#endif
305 }
306
307 void tun_read_handler(PacketFrom::SPtr &pfp) // called by TunImpl
308 {
309 parent.tun_recv(pfp->buf);
310
311#ifdef OPENVPN_DEBUG_TAPWIN
313#endif
314 }
315
316 void tun_error_handler(const Error::Type errtype, // called by TunImpl
317 const openvpn_io::error_code *error)
318 {
319 if (errtype == Error::TUN_READ_ERROR && error && error->value() == 995)
320 parent.tun_error(Error::TUN_IFACE_DISABLED, "TAP adapter is disabled");
321 else
322 parent.tun_error(Error::TUN_ERROR, "TUN I/O error");
323 }
324
325 void stop_()
326 {
327 if (!halt)
328 {
329 halt = true;
330
331 l2_timer.cancel();
332
333 // stop tun
334 if (impl)
335 impl->stop();
337 }
338 }
339
340 HANDLE tap_handle()
341 {
342 if (tun_persist)
343 {
344 TAPStream *stream = tun_persist->obj();
345 if (stream)
346 return stream->native_handle();
347 }
348 return Win::Handle::undefined();
349 }
350
352 {
353 HANDLE h = tap_handle();
356 }
357
359 {
360 try
361 {
362 if (dhcp_capture->mod_reply(buf))
363 {
364 OPENVPN_LOG("DHCP PROPS:" << std::endl
365 << dhcp_capture->get_props().to_string());
367 }
368 }
369 catch (const std::exception &e)
370 {
371 stop();
372 parent.tun_error(Error::TUN_SETUP_FAILED, std::string("L2 exception: ") + e.what());
373 }
374 }
375
376 void layer_2_schedule_timer(const unsigned int seconds)
377 {
378 l2_timer.expires_after(Time::Duration::seconds(seconds));
379 l2_timer.async_wait([self = Ptr(this)](const openvpn_io::error_code &error)
380 {
382 if (!error && !self->halt)
383 self->layer_2_timer_callback(); });
384 }
385
386 // Normally called once per second by l2_timer while we are waiting
387 // for layer 2 DHCP handshake to complete.
389 {
390 try
391 {
392 if (dhcp_capture && tun_setup)
393 {
394 if (tun_setup->l2_ready(dhcp_capture->get_props()))
395 {
396 std::ostringstream os;
397 tun_setup->l2_finish(dhcp_capture->get_props(), config->stop, os);
398 OPENVPN_LOG_STRING(os.str());
400 dhcp_capture.reset();
401 }
402 else
403 {
404 OPENVPN_LOG("L2: Waiting for DHCP handshake...");
406 }
407 }
408 }
409 catch (const std::exception &e)
410 {
411 stop();
412 parent.tun_error(Error::TUN_SETUP_FAILED, std::string("L2 exception: ") + e.what());
413 }
414 }
415
416 openvpn_io::io_context &io_context;
417 TunPersist::Ptr tun_persist; // contains the TAP device HANDLE
423
424 // Layer 2 DHCP stuff
425 std::unique_ptr<DHCPCapture> dhcp_capture;
427
429
430 bool halt;
431};
432
433inline TunClient::Ptr ClientConfig::new_tun_client_obj(openvpn_io::io_context &io_context,
434 TunClientParent &parent,
435 TransportClient *transcli)
436{
438 return TunClient::Ptr(new WintunClient(io_context, this, parent));
439 else if (tun_type == TunWin::TapWindows6)
440 return TunClient::Ptr(new Client(io_context, this, parent));
441 else
442 throw tun_win_error("unsupported tun driver");
443}
444
445} // namespace openvpn::TunWin
446
447#endif
#define OPENVPN_ASYNC_HANDLER
Definition bigmutex.hpp:36
std::size_t expires_after(const Time::Duration &d)
Definition asiotimer.hpp:69
Error::Type code() const
Definition excode.hpp:47
bool code_defined() const
Definition excode.hpp:56
The smart pointer class.
Definition rc.hpp:119
void reset() noexcept
Points this RCPtr<T> to nullptr safely.
Definition rc.hpp:290
T * get() const noexcept
Returns the raw pointer to the object T, or nullptr.
Definition rc.hpp:321
std::string to_string() const
Converts the tunnel configuration to a human-readable string representation.
Definition capture.hpp:968
static void configure_builder(TunBuilderBase *tb, State *state, SessionStats *stats, const IP::Addr &server_addr, const Config &config, const OptionList &opt, const EmulateExcludeRouteFactory *eer_factory, const bool quiet)
Definition tunprop.hpp:92
TunClient::Ptr new_tun_client_obj(openvpn_io::io_context &io_context, TunClientParent &parent, TransportClient *transcli) override
Definition tuncli.hpp:433
TunWin::SetupBase::Ptr tun_setup
Definition tuncli.hpp:422
std::uint32_t vpn_interface_index() const override
Definition tuncli.hpp:253
Frame::Context & frame_context
Definition tuncli.hpp:428
std::string tun_name() const override
Definition tuncli.hpp:208
void stop() override
Definition tuncli.hpp:268
TunProp::State::Ptr state
Definition tuncli.hpp:421
bool send(Buffer &buf)
Definition tuncli.hpp:291
std::string vpn_ip6() const override
Definition tuncli.hpp:224
std::string vpn_ip4() const override
Definition tuncli.hpp:216
TunPersist::Ptr tun_persist
Definition tuncli.hpp:417
TunClientParent & parent
Definition tuncli.hpp:419
std::string vpn_gw6() const override
Definition tuncli.hpp:240
void apply_push_update(const OptionList &opt, TransportClient &transcli) override
Notifies tun client about received PUSH_UPDATE control channel message.
Definition tuncli.hpp:80
std::string vpn_gw4() const override
Definition tuncli.hpp:232
void tun_read_handler(PacketFrom::SPtr &pfp)
Definition tuncli.hpp:307
std::unique_ptr< DHCPCapture > dhcp_capture
Definition tuncli.hpp:425
Client(openvpn_io::io_context &io_context_arg, ClientConfig *config_arg, TunClientParent &parent_arg)
Definition tuncli.hpp:278
Tun< Client *, TunPersist > TunImpl
Definition tuncli.hpp:75
void dhcp_inspect(Buffer &buf)
Definition tuncli.hpp:358
int vpn_mtu() const override
Definition tuncli.hpp:248
RCPtr< Client > Ptr
Definition tuncli.hpp:78
void layer_2_schedule_timer(const unsigned int seconds)
Definition tuncli.hpp:376
void tun_start(const OptionList &opt, TransportClient &transcli, CryptoDCSettings &) override
Definition tuncli.hpp:97
bool tun_send(BufferAllocated &buf) override
Definition tuncli.hpp:203
void set_disconnect() override
Definition tuncli.hpp:264
openvpn_io::io_context & io_context
Definition tuncli.hpp:416
ClientConfig::Ptr config
Definition tuncli.hpp:418
void tun_error_handler(const Error::Type errtype, const openvpn_io::error_code *error)
Definition tuncli.hpp:316
TunIO< ReadHandler, PacketFrom, TunWrapAsioStream< TunPersist > > Base
Definition tuncli.hpp:51
RCPtr< Tun > Ptr
Definition tuncli.hpp:54
Tun(const typename TunPersist::Ptr &tun_persist, const std::string &name, const bool retain_stream, ReadHandler read_handler, const Frame::Ptr &frame, const SessionStats::Ptr &stats)
Definition tuncli.hpp:56
#define OPENVPN_EXCEPTION(C)
#define OPENVPN_LOG(args)
#define OPENVPN_LOG_STRING(str)
@ TUN_IFACE_DISABLED
Definition error.hpp:42
void tap_process_logging(HANDLE th)
Definition tunutil.hpp:657
DNS utilities for Windows.
openvpn_io::windows::stream_handle TAPStream
TunPersistTemplate< ScopedTAPStream, TunPersistState< RingBuffer::Ptr > > TunPersist
bool defined(HANDLE handle)
Definition handle.hpp:25
std::wstring module_name()
Definition modname.hpp:29
CleanupType< F > Cleanup(F method) noexcept
Definition cleanup.hpp:43
constexpr std::uint32_t INVALID_ADAPTER_INDEX
Definition tunbase.hpp:29
virtual IP::Addr server_endpoint_addr() const =0
virtual void tun_error(const Error::Type fatal_err, const std::string &err_text)=0
virtual void tun_connected()=0
virtual void tun_pre_tun_config()=0
virtual void tun_recv(BufferAllocated &buf)=0
RCPtr< TunClient > Ptr
Definition tunbase.hpp:34
BufferAllocated buf
Definition tuncli.hpp:44
std::unique_ptr< PacketFrom > SPtr
Definition tuncli.hpp:43
std::ostringstream os