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
106 OPENVPN_LOG_TUN_ERROR("TUN partial write error");
108 return false;
109 }
110 catch (openvpn_io::system_error &e)
111 {
112 OPENVPN_LOG_TUN_ERROR("TUN write exception: " << e.what());
113 const openvpn_io::error_code code(e.code());
115 return false;
116 }
117 }
118 else
119 return false;
120 }
121
122 template <class BUFSEQ>
123 bool write_seq(const BUFSEQ &bs)
124 {
125 if (!halt)
126 {
127 try
128 {
129 // write data to tun device
130 const size_t wrote = stream->write_some(bs);
131 if (stats)
132 {
135 }
136 if (wrote == bs.size())
137 return true;
138
139 OPENVPN_LOG_TUN_ERROR("TUN partial write error");
141 return false;
142 }
143 catch (openvpn_io::system_error &e)
144 {
145 OPENVPN_LOG_TUN_ERROR("TUN write exception: " << e.what());
146 const openvpn_io::error_code code(e.code());
148 return false;
149 }
150 }
151 else
152 return false;
153 }
154
155 void start(const int n_parallel)
156 {
157 if (!halt)
158 {
159 for (int i = 0; i < n_parallel; i++)
160 queue_read(nullptr);
161 }
162 }
163
164 // must be called by derived class destructor
165 void stop()
166 {
167 if (!halt)
168 {
169 halt = true;
170 if (stream)
171 {
172 stream->cancel();
173 if (!retain_stream)
174 {
175 // OPENVPN_LOG("**** TUNIO close");
176 stream->close();
177 }
178 else
179 stream->release();
180 }
181 }
182 }
183
184 std::string name() const
185 {
186 return name_;
187 }
188
189 private:
190 void prepend_pf_inet(Buffer &buf, const std::uint32_t value)
191 {
192 const std::uint32_t net_value = htonl(value);
193 buf.prepend((unsigned char *)&net_value, sizeof(net_value));
194 }
195
196 protected:
197 void queue_read(PacketFrom *tunfrom)
198 {
199 OPENVPN_LOG_TUN_VERBOSE("TunIO::queue_read");
200 if (!tunfrom)
201 tunfrom = new PacketFrom();
202 frame_context.prepare(tunfrom->buf);
203
204 // queue read on tun device
205 stream->async_read_some(frame_context.mutable_buffer(tunfrom->buf),
206 [self = Ptr(this), tunfrom = typename PacketFrom::SPtr(tunfrom)](const openvpn_io::error_code &error, const size_t bytes_recvd) mutable
207 {
209 self->handle_read(std::move(tunfrom), error, bytes_recvd);
210 });
211 }
212
213 void handle_read(typename PacketFrom::SPtr pfp, const openvpn_io::error_code &error, const size_t bytes_recvd)
214 {
215 OPENVPN_LOG_TUN_VERBOSE("TunIO::handle_read: " << error.message());
216 if (!halt)
217 {
218 if (!error)
219 {
220 pfp->buf.set_size(bytes_recvd);
221 if (stats)
222 {
225 }
226 if (!tun_prefix)
227 {
228 read_handler->tun_read_handler(pfp);
229 }
230 else if (pfp->buf.size() >= 4)
231 {
232 // handle tun packet prefix, if enabled
233 pfp->buf.advance(4);
234 read_handler->tun_read_handler(pfp);
235 }
236 else
237 {
238 OPENVPN_LOG_TUN_ERROR("TUN Read Error: cannot read prefix");
240 }
241 }
242 else
243 {
244 OPENVPN_LOG_TUN_ERROR("TUN Read Error: " << error.message());
246 }
247 if (!halt)
248 queue_read(pfp.release()); // reuse buffer if still available
249 }
250 }
251
252 void tun_error(const Error::Type errtype, const openvpn_io::error_code *error)
253 {
254 if (stats)
255 stats->error(errtype);
256 read_handler->tun_error_handler(errtype, error);
257 }
258
259 // should be set by derived class constructor
260 std::string name_;
261 STREAM *stream = nullptr;
262 bool retain_stream = false; // don't close tun stream
263 bool tun_prefix = false;
264
265 ReadHandler read_handler;
268
269 bool halt = false;
270};
271} // 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:1311
void prepend(const T *data, const size_t size)
Prepend data to the buffer.
Definition buffer.hpp:1572
size_t size() const
Returns the size of the buffer in T objects.
Definition buffer.hpp:1241
size_t offset() const
Returns the current offset (headroom) into the buffer.
Definition buffer.hpp:1217
size_t prepare(Buffer &buf) const
Definition frame.hpp:116
openvpn_io::mutable_buffer mutable_buffer(Buffer &buf) const
Definition frame.hpp:189
The smart pointer class.
Definition rc.hpp:119
Reference count base class for objects tracked by RCPtr. Disallows copying and assignment.
Definition rc.hpp:908
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:263
const Frame::Context frame_context
Definition tunio.hpp:266
virtual ~TunIO()
Definition tunio.hpp:56
std::string name() const
Definition tunio.hpp:184
void stop()
Definition tunio.hpp:165
bool write_seq(const BUFSEQ &bs)
Definition tunio.hpp:123
std::string name_
Definition tunio.hpp:260
void handle_read(typename PacketFrom::SPtr pfp, const openvpn_io::error_code &error, const size_t bytes_recvd)
Definition tunio.hpp:213
STREAM * stream
Definition tunio.hpp:261
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:265
void queue_read(PacketFrom *tunfrom)
Definition tunio.hpp:197
void prepend_pf_inet(Buffer &buf, const std::uint32_t value)
Definition tunio.hpp:190
void tun_error(const Error::Type errtype, const openvpn_io::error_code *error)
Definition tunio.hpp:252
bool retain_stream
Definition tunio.hpp:262
bool write(Buffer &buf)
Definition tunio.hpp:63
SessionStats::Ptr stats
Definition tunio.hpp:267
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:155
@ 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