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 // persist tun settings state
154 if (tun_persist->persist_tun_state(ts, {state, nullptr}))
155 OPENVPN_LOG("TunPersist: saving tun context:" << std::endl
156 << tun_persist->options());
157
158 // setup handler for external tun close
159 tun_setup->set_service_fail_handler([self = Ptr(this)]()
160 {
161 if (!self->halt)
162 self->parent.tun_error(Error::TUN_IFACE_DISABLED, "service failure"); });
163
164 // enable tun_setup destructor
165 tun_persist->add_destructor(tun_setup);
166
167 // assert ownership over TAP device handle
168 tun_setup->confirm();
169
170 // if layer 2, set up to capture DHCP messages over the tunnel
171 if (config->tun_prop.layer() == Layer::OSI_LAYER_2)
173 }
174
175 // configure tun interface packet forwarding
177 "TUN_WIN",
178 true,
179 this,
180 config->frame,
181 config->stats));
182 impl->start(config->n_parallel);
183
184 if (!dhcp_capture)
185 parent.tun_connected(); // signal that we are connected
186 }
187 catch (const std::exception &e)
188 {
189 if (tun_persist)
190 tun_persist->close();
191 stop();
193 const ExceptionCode *ec = dynamic_cast<const ExceptionCode *>(&e);
194 if (ec && ec->code_defined())
195 err = ec->code();
196 parent.tun_error(err, e.what());
197 }
198 }
199 }
200
201 bool tun_send(BufferAllocated &buf) override
202 {
203 return send(buf);
204 }
205
206 std::string tun_name() const override
207 {
208 if (impl)
209 return impl->name();
210 else
211 return "UNDEF_TUN";
212 }
213
214 std::string vpn_ip4() const override
215 {
216 if (state->vpn_ip4_addr.specified())
217 return state->vpn_ip4_addr.to_string();
218 else
219 return "";
220 }
221
222 std::string vpn_ip6() const override
223 {
224 if (state->vpn_ip6_addr.specified())
225 return state->vpn_ip6_addr.to_string();
226 else
227 return "";
228 }
229
230 std::string vpn_gw4() const override
231 {
232 if (state->vpn_ip4_gw.specified())
233 return state->vpn_ip4_gw.to_string();
234 else
235 return "";
236 }
237
238 std::string vpn_gw6() const override
239 {
240 if (state->vpn_ip6_gw.specified())
241 return state->vpn_ip6_gw.to_string();
242 else
243 return "";
244 }
245
246 int vpn_mtu() const override
247 {
248 return state->mtu;
249 }
250
251 void set_disconnect() override
252 {
253 }
254
255 void stop() override
256 {
257 stop_();
258 }
259 virtual ~Client()
260 {
261 stop_();
262 }
263
264 private:
265 Client(openvpn_io::io_context &io_context_arg,
266 ClientConfig *config_arg,
267 TunClientParent &parent_arg)
268 : io_context(io_context_arg),
269 config(config_arg),
270 parent(parent_arg),
271 state(new TunProp::State()),
272 l2_timer(io_context_arg),
273 frame_context((*config_arg->frame)[Frame::READ_TUN]),
274 halt(false)
275 {
276 }
277
278 bool send(Buffer &buf)
279 {
280 if (impl)
281 {
282 if (dhcp_capture)
283 dhcp_inspect(buf);
284
285 return impl->write(buf);
286 }
287 else
288 return false;
289#ifdef OPENVPN_DEBUG_TAPWIN
291#endif
292 }
293
294 void tun_read_handler(PacketFrom::SPtr &pfp) // called by TunImpl
295 {
296 parent.tun_recv(pfp->buf);
297
298#ifdef OPENVPN_DEBUG_TAPWIN
300#endif
301 }
302
303 void tun_error_handler(const Error::Type errtype, // called by TunImpl
304 const openvpn_io::error_code *error)
305 {
306 if (errtype == Error::TUN_READ_ERROR && error && error->value() == 995)
307 parent.tun_error(Error::TUN_IFACE_DISABLED, "TAP adapter is disabled");
308 else
309 parent.tun_error(Error::TUN_ERROR, "TUN I/O error");
310 }
311
312 void stop_()
313 {
314 if (!halt)
315 {
316 halt = true;
317
318 l2_timer.cancel();
319
320 // stop tun
321 if (impl)
322 impl->stop();
324 }
325 }
326
327 HANDLE tap_handle()
328 {
329 if (tun_persist)
330 {
331 TAPStream *stream = tun_persist->obj();
332 if (stream)
333 return stream->native_handle();
334 }
335 return Win::Handle::undefined();
336 }
337
339 {
340 HANDLE h = tap_handle();
343 }
344
346 {
347 try
348 {
349 if (dhcp_capture->mod_reply(buf))
350 {
351 OPENVPN_LOG("DHCP PROPS:" << std::endl
352 << dhcp_capture->get_props().to_string());
354 }
355 }
356 catch (const std::exception &e)
357 {
358 stop();
359 parent.tun_error(Error::TUN_SETUP_FAILED, std::string("L2 exception: ") + e.what());
360 }
361 }
362
363 void layer_2_schedule_timer(const unsigned int seconds)
364 {
365 l2_timer.expires_after(Time::Duration::seconds(seconds));
366 l2_timer.async_wait([self = Ptr(this)](const openvpn_io::error_code &error)
367 {
369 if (!error && !self->halt)
370 self->layer_2_timer_callback(); });
371 }
372
373 // Normally called once per second by l2_timer while we are waiting
374 // for layer 2 DHCP handshake to complete.
376 {
377 try
378 {
379 if (dhcp_capture && tun_setup)
380 {
381 if (tun_setup->l2_ready(dhcp_capture->get_props()))
382 {
383 std::ostringstream os;
384 tun_setup->l2_finish(dhcp_capture->get_props(), config->stop, os);
385 OPENVPN_LOG_STRING(os.str());
387 dhcp_capture.reset();
388 }
389 else
390 {
391 OPENVPN_LOG("L2: Waiting for DHCP handshake...");
393 }
394 }
395 }
396 catch (const std::exception &e)
397 {
398 stop();
399 parent.tun_error(Error::TUN_SETUP_FAILED, std::string("L2 exception: ") + e.what());
400 }
401 }
402
403 openvpn_io::io_context &io_context;
404 TunPersist::Ptr tun_persist; // contains the TAP device HANDLE
410
411 // Layer 2 DHCP stuff
412 std::unique_ptr<DHCPCapture> dhcp_capture;
414
416
417 bool halt;
418};
419
420inline TunClient::Ptr ClientConfig::new_tun_client_obj(openvpn_io::io_context &io_context,
421 TunClientParent &parent,
422 TransportClient *transcli)
423{
425 return TunClient::Ptr(new WintunClient(io_context, this, parent));
426 else if (tun_type == TunWin::TapWindows6)
427 return TunClient::Ptr(new Client(io_context, this, parent));
428 else
429 throw tun_win_error("unsupported tun driver");
430}
431
432} // namespace openvpn::TunWin
433
434#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:54
bool code_defined() const
Definition excode.hpp:63
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
Definition capture.hpp:567
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:90
TunClient::Ptr new_tun_client_obj(openvpn_io::io_context &io_context, TunClientParent &parent, TransportClient *transcli) override
Definition tuncli.hpp:420
TunWin::SetupBase::Ptr tun_setup
Definition tuncli.hpp:409
Frame::Context & frame_context
Definition tuncli.hpp:415
std::string tun_name() const override
Definition tuncli.hpp:206
void stop() override
Definition tuncli.hpp:255
TunProp::State::Ptr state
Definition tuncli.hpp:408
bool send(Buffer &buf)
Definition tuncli.hpp:278
std::string vpn_ip6() const override
Definition tuncli.hpp:222
std::string vpn_ip4() const override
Definition tuncli.hpp:214
TunPersist::Ptr tun_persist
Definition tuncli.hpp:404
TunClientParent & parent
Definition tuncli.hpp:406
std::string vpn_gw6() const override
Definition tuncli.hpp:238
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:230
void tun_read_handler(PacketFrom::SPtr &pfp)
Definition tuncli.hpp:294
std::unique_ptr< DHCPCapture > dhcp_capture
Definition tuncli.hpp:412
Client(openvpn_io::io_context &io_context_arg, ClientConfig *config_arg, TunClientParent &parent_arg)
Definition tuncli.hpp:265
Tun< Client *, TunPersist > TunImpl
Definition tuncli.hpp:75
void dhcp_inspect(Buffer &buf)
Definition tuncli.hpp:345
int vpn_mtu() const override
Definition tuncli.hpp:246
RCPtr< Client > Ptr
Definition tuncli.hpp:78
void layer_2_schedule_timer(const unsigned int seconds)
Definition tuncli.hpp:363
void tun_start(const OptionList &opt, TransportClient &transcli, CryptoDCSettings &) override
Definition tuncli.hpp:97
bool tun_send(BufferAllocated &buf) override
Definition tuncli.hpp:201
void set_disconnect() override
Definition tuncli.hpp:251
openvpn_io::io_context & io_context
Definition tuncli.hpp:403
ClientConfig::Ptr config
Definition tuncli.hpp:405
void tun_error_handler(const Error::Type errtype, const openvpn_io::error_code *error)
Definition tuncli.hpp:303
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
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:32
BufferAllocated buf
Definition tuncli.hpp:44
std::unique_ptr< PacketFrom > SPtr
Definition tuncli.hpp:43