OpenVPN 3 Core Library
Loading...
Searching...
No Matches
tunio.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// Low level tun device I/O class for all platforms (Unix and Windows)
13
14#pragma once
15
16#include <utility>
17
18#include <openvpn/io/io.hpp>
19
22#include <openvpn/common/rc.hpp>
28
29namespace openvpn {
30
31template <typename ReadHandler, typename PacketFrom, typename STREAM>
32class TunIO : public RC<thread_unsafe_refcount>
33{
34 public:
36
37 TunIO(ReadHandler read_handler_arg,
38 const Frame::Ptr &frame_arg,
39 const SessionStats::Ptr &stats_arg,
40 const size_t frame_context_type = Frame::READ_TUN)
41 : read_handler(read_handler_arg),
42 frame_context((*frame_arg)[frame_context_type]),
43 stats(stats_arg)
44 {
45 }
46
47 TunIO(ReadHandler read_handler_arg,
48 const Frame::Context &frame_context_arg,
49 const SessionStats::Ptr &stats_arg)
50 : read_handler(read_handler_arg),
51 frame_context(frame_context_arg),
52 stats(stats_arg)
53 {
54 }
55
56 virtual ~TunIO()
57 {
58 // OPENVPN_LOG("**** TUNIO destruct");
59 stop();
60 delete stream;
61 }
62
63 bool write(Buffer &buf)
64 {
65 if (!halt)
66 {
67 try
68 {
69 // handle tun packet prefix, if enabled
70 if (tun_prefix)
71 {
72 if (buf.offset() >= 4 && buf.size() >= 1)
73 {
74 switch (IPCommon::version(buf[0]))
75 {
76 case 4:
77 prepend_pf_inet(buf, PF_INET);
78 break;
79 case 6:
80 prepend_pf_inet(buf, PF_INET6);
81 break;
82 default:
83 OPENVPN_LOG_TUN_ERROR("TUN write error: cannot identify IP version for prefix");
85 return false;
86 }
87 }
88 else
89 {
90 OPENVPN_LOG_TUN_ERROR("TUN write error: cannot write prefix");
92 return false;
93 }
94 }
95
96 // write data to tun device
97 const size_t wrote = stream->write_some(buf.const_buffer());
98 if (stats)
99 {
102 }
103 if (wrote == buf.size())
104 return true;
105 else
106 {
107 OPENVPN_LOG_TUN_ERROR("TUN partial write error");
109 return false;
110 }
111 }
112 catch (openvpn_io::system_error &e)
113 {
114 OPENVPN_LOG_TUN_ERROR("TUN write exception: " << e.what());
115 const openvpn_io::error_code code(e.code());
117 return false;
118 }
119 }
120 else
121 return false;
122 }
123
124 template <class BUFSEQ>
125 bool write_seq(const BUFSEQ &bs)
126 {
127 if (!halt)
128 {
129 try
130 {
131 // write data to tun device
132 const size_t wrote = stream->write_some(bs);
133 if (stats)
134 {
137 }
138 if (wrote == bs.size())
139 return true;
140 else
141 {
142 OPENVPN_LOG_TUN_ERROR("TUN partial write error");
144 return false;
145 }
146 }
147 catch (openvpn_io::system_error &e)
148 {
149 OPENVPN_LOG_TUN_ERROR("TUN write exception: " << e.what());
150 const openvpn_io::error_code code(e.code());
152 return false;
153 }
154 }
155 else
156 return false;
157 }
158
159 void start(const int n_parallel)
160 {
161 if (!halt)
162 {
163 for (int i = 0; i < n_parallel; i++)
164 queue_read(nullptr);
165 }
166 }
167
168 // must be called by derived class destructor
169 void stop()
170 {
171 if (!halt)
172 {
173 halt = true;
174 if (stream)
175 {
176 stream->cancel();
177 if (!retain_stream)
178 {
179 // OPENVPN_LOG("**** TUNIO close");
180 stream->close();
181 }
182 else
183 stream->release();
184 }
185 }
186 }
187
188 std::string name() const
189 {
190 return name_;
191 }
192
193 private:
194 void prepend_pf_inet(Buffer &buf, const std::uint32_t value)
195 {
196 const std::uint32_t net_value = htonl(value);
197 buf.prepend((unsigned char *)&net_value, sizeof(net_value));
198 }
199
200 protected:
201 void queue_read(PacketFrom *tunfrom)
202 {
203 OPENVPN_LOG_TUN_VERBOSE("TunIO::queue_read");
204 if (!tunfrom)
205 tunfrom = new PacketFrom();
206 frame_context.prepare(tunfrom->buf);
207
208 // queue read on tun device
209 stream->async_read_some(frame_context.mutable_buffer(tunfrom->buf),
210 [self = Ptr(this), tunfrom = typename PacketFrom::SPtr(tunfrom)](const openvpn_io::error_code &error, const size_t bytes_recvd) mutable
211 {
213 self->handle_read(std::move(tunfrom), error, bytes_recvd);
214 });
215 }
216
217 void handle_read(typename PacketFrom::SPtr pfp, const openvpn_io::error_code &error, const size_t bytes_recvd)
218 {
219 OPENVPN_LOG_TUN_VERBOSE("TunIO::handle_read: " << error.message());
220 if (!halt)
221 {
222 if (!error)
223 {
224 pfp->buf.set_size(bytes_recvd);
225 if (stats)
226 {
229 }
230 if (!tun_prefix)
231 {
232 read_handler->tun_read_handler(pfp);
233 }
234 else if (pfp->buf.size() >= 4)
235 {
236 // handle tun packet prefix, if enabled
237 pfp->buf.advance(4);
238 read_handler->tun_read_handler(pfp);
239 }
240 else
241 {
242 OPENVPN_LOG_TUN_ERROR("TUN Read Error: cannot read prefix");
244 }
245 }
246 else
247 {
248 OPENVPN_LOG_TUN_ERROR("TUN Read Error: " << error.message());
250 }
251 if (!halt)
252 queue_read(pfp.release()); // reuse buffer if still available
253 }
254 }
255
256 void tun_error(const Error::Type errtype, const openvpn_io::error_code *error)
257 {
258 if (stats)
259 stats->error(errtype);
260 read_handler->tun_error_handler(errtype, error);
261 }
262
263 // should be set by derived class constructor
264 std::string name_;
265 STREAM *stream = nullptr;
266 bool retain_stream = false; // don't close tun stream
267 bool tun_prefix = false;
268
269 ReadHandler read_handler;
272
273 bool halt = false;
274};
275} // namespace openvpn
#define OPENVPN_ASYNC_HANDLER
Definition bigmutex.hpp:36
openvpn_io::const_buffer const_buffer() const
Return an openvpn_io::const_buffer object used by asio write methods.
Definition buffer.hpp:1312
void prepend(const T *data, const size_t size)
Prepend data to the buffer.
Definition buffer.hpp:1575
size_t size() const
Returns the size of the buffer in T objects.
Definition buffer.hpp:1242
size_t offset() const
Returns the current offset (headroom) into the buffer.
Definition buffer.hpp:1218
size_t prepare(Buffer &buf) const
Definition frame.hpp:116
openvpn_io::mutable_buffer mutable_buffer(Buffer &buf) const
Definition frame.hpp:190
The smart pointer class.
Definition rc.hpp:119
Reference count base class for objects tracked by RCPtr. Disallows copying and assignment.
Definition rc.hpp:912
virtual void error(const size_t type, const std::string *text=nullptr)
void inc_stat(const size_t type, const count_t value)
bool tun_prefix
Definition tunio.hpp:267
const Frame::Context frame_context
Definition tunio.hpp:270
virtual ~TunIO()
Definition tunio.hpp:56
std::string name() const
Definition tunio.hpp:188
void stop()
Definition tunio.hpp:169
bool write_seq(const BUFSEQ &bs)
Definition tunio.hpp:125
std::string name_
Definition tunio.hpp:264
void handle_read(typename PacketFrom::SPtr pfp, const openvpn_io::error_code &error, const size_t bytes_recvd)
Definition tunio.hpp:217
STREAM * stream
Definition tunio.hpp:265
TunIO(ReadHandler read_handler_arg, const Frame::Context &frame_context_arg, const SessionStats::Ptr &stats_arg)
Definition tunio.hpp:47
ReadHandler read_handler
Definition tunio.hpp:269
void queue_read(PacketFrom *tunfrom)
Definition tunio.hpp:201
void prepend_pf_inet(Buffer &buf, const std::uint32_t value)
Definition tunio.hpp:194
void tun_error(const Error::Type errtype, const openvpn_io::error_code *error)
Definition tunio.hpp:256
bool retain_stream
Definition tunio.hpp:266
bool write(Buffer &buf)
Definition tunio.hpp:63
RCPtr< TunIO > Ptr
Definition tunio.hpp:35
SessionStats::Ptr stats
Definition tunio.hpp:271
TunIO(ReadHandler read_handler_arg, const Frame::Ptr &frame_arg, const SessionStats::Ptr &stats_arg, const size_t frame_context_type=Frame::READ_TUN)
Definition tunio.hpp:37
void start(const int n_parallel)
Definition tunio.hpp:159
@ TUN_FRAMING_ERROR
Definition error.hpp:39
unsigned int version(const std::uint8_t version_len_prio)
Definition ipcommon.hpp:35
#define OPENVPN_LOG_TUN_ERROR(x)
Definition tunlog.hpp:20
#define OPENVPN_LOG_TUN_VERBOSE(x)
Definition tunlog.hpp:32