OpenVPN 3 Core Library
Loading...
Searching...
No Matches
udplink.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 UDP transport object.
13
14#ifndef OPENVPN_TRANSPORT_UDPLINK_H
15#define OPENVPN_TRANSPORT_UDPLINK_H
16
17#include <memory>
18
19#include <openvpn/io/io.hpp>
20
22#include <openvpn/common/rc.hpp>
25
26#ifdef OPENVPN_GREMLIN
28#endif
29
30#if defined(OPENVPN_DEBUG_UDPLINK) && OPENVPN_DEBUG_UDPLINK >= 1
31#define OPENVPN_LOG_UDPLINK_ERROR(x) OPENVPN_LOG(x)
32#else
33#define OPENVPN_LOG_UDPLINK_ERROR(x)
34#endif
35
36#if defined(OPENVPN_DEBUG_UDPLINK) && OPENVPN_DEBUG_UDPLINK >= 3
37#define OPENVPN_LOG_UDPLINK_VERBOSE(x) OPENVPN_LOG(x)
38#else
39#define OPENVPN_LOG_UDPLINK_VERBOSE(x)
40#endif
41
42namespace openvpn::UDPTransport {
43
44using AsioEndpoint = openvpn_io::ip::udp::endpoint;
45
46enum
47{
50};
51
53{
54 using SPtr = std::unique_ptr<PacketFrom>;
57};
58
59template <typename ReadHandler>
60class UDPLink : public RC<thread_unsafe_refcount>
61{
62 public:
64
65 UDPLink(ReadHandler read_handler_arg,
66 openvpn_io::ip::udp::socket &socket_arg,
67 const Frame::Context &frame_context_arg,
68 const SessionStats::Ptr &stats_arg)
69 : socket(socket_arg),
70 halt(false),
71 read_handler(read_handler_arg),
72 frame_context(frame_context_arg),
73 stats(stats_arg)
74 {
75 }
76
77#ifdef OPENVPN_GREMLIN
78 void gremlin_config(openvpn_io::io_context &io_context,
80 {
81 if (config)
82 gremlin.reset(new Gremlin::SendRecvQueue(io_context, config, false));
83 }
84#endif
85
86 // Returns 0 on success, or a system error code on error.
87 // May also return SEND_PARTIAL or SEND_SOCKET_HALTED.
88 int send(const Buffer &buf, const AsioEndpoint *endpoint)
89 {
90#ifdef OPENVPN_GREMLIN
91 if (gremlin)
92 {
93 gremlin_send(buf, endpoint);
94 return 0;
95 }
96 else
97#endif
98 return do_send(buf, endpoint);
99 }
100
101 void start(const int n_parallel)
102 {
103 if (!halt)
104 {
105 for (int i = 0; i < n_parallel; i++)
106 queue_read(nullptr);
107 }
108 }
109
110 void stop()
111 {
112 halt = true;
113#ifdef OPENVPN_GREMLIN
114 if (gremlin)
115 gremlin->stop();
116#endif
117 }
118
119 void reset_align_adjust(const size_t align_adjust)
120 {
121 frame_context.reset_align_adjust(align_adjust);
122 }
123
125 {
126 stop();
127 }
128
129 private:
130 void queue_read(PacketFrom *udpfrom)
131 {
132 OPENVPN_LOG_UDPLINK_VERBOSE("UDPLink::queue_read");
133 if (!udpfrom)
134 udpfrom = new PacketFrom();
135 frame_context.prepare(udpfrom->buf);
136 socket.async_receive_from(frame_context.mutable_buffer(udpfrom->buf),
137 udpfrom->sender_endpoint,
138 [self = Ptr(this), udpfrom = PacketFrom::SPtr(udpfrom)](const openvpn_io::error_code &error, const size_t bytes_recvd) mutable
139 {
141 self->handle_read(std::move(udpfrom), error, bytes_recvd);
142 });
143 }
144
145 void handle_read(PacketFrom::SPtr pfp, const openvpn_io::error_code &error, const size_t bytes_recvd)
146 {
147 OPENVPN_LOG_UDPLINK_VERBOSE("UDPLink::handle_read: " << error.message());
148 if (!halt)
149 {
150 if (bytes_recvd)
151 {
152 if (!error)
153 {
154 OPENVPN_LOG_UDPLINK_VERBOSE("UDP[" << bytes_recvd << "] from " << pfp->sender_endpoint);
155 pfp->buf.set_size(bytes_recvd);
158#ifdef OPENVPN_GREMLIN
159 if (gremlin)
160 gremlin_recv(pfp);
161 else
162#endif
163 read_handler->udp_read_handler(pfp);
164 }
165 else
166 {
167 OPENVPN_LOG_UDPLINK_ERROR("UDP recv error: " << error.message());
169 }
170 }
171 if (!halt)
172 queue_read(pfp.release()); // reuse PacketFrom object if still available
173 }
174 }
175
176 int do_send(const Buffer &buf, const AsioEndpoint *endpoint)
177 {
178 if (!halt)
179 {
180 try
181 {
182 const size_t wrote = endpoint
183 ? socket.send_to(buf.const_buffer(), *endpoint)
184 : socket.send(buf.const_buffer());
187 if (wrote == buf.size())
188 return 0;
189
190 OPENVPN_LOG_UDPLINK_ERROR("UDP partial send error");
192 return SEND_PARTIAL;
193 }
194 catch (openvpn_io::system_error &e)
195 {
196 OPENVPN_LOG_UDPLINK_ERROR("UDP send exception: " << e.what());
198 return e.code().value();
199 }
200 }
201 else
202 return SEND_SOCKET_HALTED;
203 }
204
205#ifdef OPENVPN_GREMLIN
206 void gremlin_send(const Buffer &buf, const AsioEndpoint *endpoint)
207 {
208 std::unique_ptr<AsioEndpoint> ep;
209 if (endpoint)
210 ep.reset(new AsioEndpoint(*endpoint));
211 gremlin->send_queue([self = Ptr(this), buf = BufferAllocated(buf), ep = std::move(ep)]() mutable
212 {
213 if (!self->halt)
214 {
215 self->gremlin->maybe_corrupt_data(buf, 0);
216 self->do_send(buf, ep.get());
217 } });
218 }
219
220 void gremlin_recv(PacketFrom::SPtr &pfp)
221 {
222 gremlin->recv_queue([self = Ptr(this), pfp = std::move(pfp)]() mutable
223 {
224 if (!self->halt)
225 self->read_handler->udp_read_handler(pfp); });
226 }
227#endif
228
229 openvpn_io::ip::udp::socket &socket;
230 bool halt;
231 ReadHandler read_handler;
234
235#ifdef OPENVPN_GREMLIN
236 std::unique_ptr<Gremlin::SendRecvQueue> gremlin;
237#endif
238};
239} // namespace openvpn::UDPTransport
240
241#endif
#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
size_t size() const
Returns the size of the buffer in T objects.
Definition buffer.hpp:1241
size_t prepare(Buffer &buf) const
Definition frame.hpp:116
void reset_align_adjust(const size_t align_adjust)
Definition frame.hpp:88
openvpn_io::mutable_buffer mutable_buffer(Buffer &buf) const
Definition frame.hpp:189
The smart pointer class.
Definition rc.hpp:119
void reset() noexcept
Points this RCPtr<T> to nullptr safely.
Definition rc.hpp:290
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)
@ NETWORK_SEND_ERROR
Definition error.hpp:26
@ NETWORK_RECV_ERROR
Definition error.hpp:24
openvpn_io::ip::udp::endpoint AsioEndpoint
Definition udplink.hpp:44
BufferAllocatedType< unsigned char > BufferAllocated
Definition buffer.hpp:1894
std::unique_ptr< PacketFrom > SPtr
Definition udplink.hpp:54
static const char config[]