OpenVPN 3 Core Library
Loading...
Searching...
No Matches
servproto.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// OpenVPN protocol implementation for client-instance object on server
13
14#ifndef OPENVPN_SERVER_SERVPROTO_H
15#define OPENVPN_SERVER_SERVPROTO_H
16
17#include <cstdlib> // defines std::abort()
18#include <memory>
19#include <utility> // for std::move
20
23#include <openvpn/common/rc.hpp>
31#include <openvpn/ssl/proto.hpp>
35
36#ifdef OPENVPN_DEBUG_SERVPROTO
37#define OPENVPN_LOG_SERVPROTO(x) OPENVPN_LOG(x)
38#else
39#define OPENVPN_LOG_SERVPROTO(x)
40#endif
41
42namespace openvpn {
43
45{
49
50 public:
51 class Session;
52
103
104 // This is the main server-side client instance object
105 class Session : ProtoContextCallbackInterface, // Callback interface from protocol implementation
106 public TransportLink, // Transport layer
107 public TunLink, // Tun/routing layer
108 public ManLink // Management layer
109 {
110 friend class Factory; // calls constructor
111
112 public:
114
115 bool defined() const override
116 {
117 return defined_();
118 }
119
121 {
122 TunLink::send.reset(tun);
123 return this;
124 }
125
127 const PeerAddr::Ptr &addr,
128 const int local_peer_id,
129 const ProtoSessionID cookie_psid = ProtoSessionID()) override
130 {
131 TransportLink::send = parent;
132 peer_addr = addr;
133
134 // init OpenVPN protocol handshake
136 proto_context.reset(cookie_psid);
137 proto_context.set_local_peer_id(local_peer_id);
138 proto_context.start(cookie_psid);
139 proto_context.flush(true);
140
141 // coarse wakeup range
142 housekeeping_schedule.init(Time::Duration::binary_ms(512), Time::Duration::binary_ms(1024));
143 }
144
146 {
148 return TransportLink::send->stats_poll();
149 else
150 return PeerStats();
151 }
152
154 {
155 return preserve_session_id;
156 }
157
158 void stop() override
159 {
160 if (!halt)
161 {
162 halt = true;
163 housekeeping_timer.cancel();
164
165 if (ManLink::send)
166 ManLink::send->pre_stop();
167
168 // deliver final peer stats to management layer
170 {
171 if (TransportLink::send->stats_pending())
172 ManLink::send->stats_notify(TransportLink::send->stats_poll(), true);
173 }
174
178 {
179 TransportLink::send->stop();
180 TransportLink::send.reset();
181 }
182 if (TunLink::send)
183 {
184 TunLink::send->stop();
185 TunLink::send.reset();
186 }
187 if (ManLink::send)
188 {
189 ManLink::send->stop();
190 ManLink::send.reset();
191 }
192 }
193 }
194
195 // called with OpenVPN-encapsulated packets from transport layer
196 bool transport_recv(BufferAllocated &buf) override
197 {
198 bool ret = false;
200 return false;
201 try
202 {
203 OPENVPN_LOG_SERVPROTO(instance_name() << " : Transport RECV[" << buf.size() << "] " << client_endpoint_render() << ' ' << proto_context.dump_packet(buf));
204
205 // update current time
207
208 // get packet type
210
211 // process packet
212 if (pt.is_data())
213 {
214 // data packet
215 ret = proto_context.data_decrypt(pt, buf);
216 if (buf.size())
217 {
218#ifdef OPENVPN_PACKET_LOG
219 log_packet(buf, false);
220#endif
221 // make packet appear as incoming on tun interface
222 if (true) // fixme: was tun
223 {
224 OPENVPN_LOG_SERVPROTO(instance_name() << " : TUN SEND[" << buf.size() << ']');
225 // fixme -- code me
226 }
227 }
228
229 // do a lightweight flush
230 proto_context.flush(false);
231 }
232 else if (pt.is_control())
233 {
234 // control packet
235 ret = proto_context.control_net_recv(pt, std::move(buf));
236
237 // do a full flush
238 proto_context.flush(true);
239 }
240
241 // schedule housekeeping wakeup
243 }
244 catch (const std::exception &e)
245 {
246 error(e);
247 ret = false;
248 }
249
250 return ret;
251 }
252
253 // called with cleartext IP packets from routing layer
254 void tun_recv(BufferAllocated &buf) override
255 {
256 // fixme -- code me
257 }
258
259 // Return true if keepalive parameter(s) are enabled.
260 bool is_keepalive_enabled() const override
261 {
263 }
264
265 // Disable keepalive for rest of session, but fetch
266 // the keepalive parameters (in seconds).
267 // Also, allow the management layer to override parameters.
268 void disable_keepalive(unsigned int &keepalive_ping,
269 unsigned int &keepalive_timeout) override
270 {
271 proto_context.disable_keepalive(keepalive_ping, keepalive_timeout);
272 if (ManLink::send)
273 ManLink::send->keepalive_override(keepalive_ping, keepalive_timeout);
274 }
275
276 // override the data channel factory
277 void override_dc_factory(const CryptoDCFactory::Ptr &dc_factory) override
278 {
280 }
281
282 virtual ~Session()
283 {
284 // fatal error if destructor called while Session is active
285 if (defined_())
286 std::abort();
287 }
288
289 private:
290 Session(openvpn_io::io_context &io_context_arg,
291 const Factory &factory,
292 ManClientInstance::Factory::Ptr man_factory_arg,
293 TunClientInstance::Factory::Ptr tun_factory_arg)
294 : proto_context(this, factory.clone_proto_config(), factory.stats),
295 housekeeping_timer(io_context_arg),
296 disconnect_at(Time::infinite()),
297 stats(factory.stats),
298 man_factory(std::move(man_factory_arg)),
299 tun_factory(std::move(tun_factory_arg))
300 {
301 }
302
303 bool supports_epoch_data() override
304 {
305 /* TODO: currently all server implementations do not implement this feature in their data channel */
306 return false;
307 }
308
309 bool defined_() const
310 {
311 return !halt && TransportLink::send;
312 }
313
314 // proto base class calls here for control channel network sends
315 void control_net_send(const Buffer &net_buf) override
316 {
317 OPENVPN_LOG_SERVPROTO(instance_name() << " : Transport SEND[" << net_buf.size() << "] " << client_endpoint_render() << ' ' << proto_context.dump_packet(net_buf));
319 {
320 if (TransportLink::send->transport_send_const(net_buf))
322 }
323 }
324
325 // Called on server with credentials and peer info provided by client.
326 // Should be overriden by derived class if credentials are required.
327 void server_auth(const std::string &username,
328 const SafeString &password,
329 const std::string &peer_info,
330 const AuthCert::Ptr &auth_cert) override
331 {
332 constexpr size_t MAX_USERNAME_SIZE = 256;
333 constexpr size_t MAX_PASSWORD_SIZE = 16384;
334
335 if (get_management())
336 {
337 AuthCreds::Ptr auth_creds(new AuthCreds(Unicode::utf8_printable(username, MAX_USERNAME_SIZE | Unicode::UTF8_FILTER),
341 ManLink::send->auth_request(auth_creds, auth_cert, peer_addr);
342 }
343 }
344
345 // proto base class calls here for app-level control-channel messages received
346 void control_recv(BufferPtr &&app_bp) override
347 {
348 const std::string msg = ProtoContext::template read_control_string<std::string>(*app_bp);
350 {
351 /* if we received invalid data from a client on the control channel terminate the connection */
352 const auto reason = "Control channel message with invalid characters received";
353 auth_failed(reason, reason);
354 return;
355 }
356
357 if (msg == "PUSH_REQUEST")
358 {
359 if (get_management())
360 ManLink::send->push_request(proto_context.conf_ptr());
361 else
362 auth_failed("no management provider", "");
363 }
364 else if (msg == "EXIT")
365 {
366 OPENVPN_LOG("Client disconnecting from server, EXIT received");
368 disconnect_in(Time::Duration::seconds(1));
369 }
370 else if (string::starts_with(msg, "ACC,"))
371 {
372 if (get_management())
373 ManLink::send->app_control(msg);
374 }
375 else
376 {
377 OPENVPN_LOG(instance_name() << " : Unrecognized client request: " << msg);
378 }
379 }
380
381 void active(bool primary) override
382 {
384 ManLink::send->push_request(proto_context.conf_ptr());
385 }
386
387 void auth_failed(const std::string &reason,
388 const std::string &client_reason) override
389 {
390 push_halt_restart_msg(HaltRestart::AUTH_FAILED, reason, client_reason);
391 }
392
393 void relay(const IP::Addr &target, const int port) override
394 {
396 return;
397
399
401 {
403 TunLink::send->relay(target, port);
404 disconnect_in(Time::Duration::seconds(10)); // not a real disconnect, just complete transition to relay
405 }
406
408 {
409 auto buf = BufferAllocatedRc::Create(64);
410 buf_append_string(*buf, "RELAY");
411 buf->null_terminate();
412 proto_context.control_send(std::move(buf));
413 proto_context.flush(true);
414 }
415
417 }
418
419 void push_reply(std::vector<BufferPtr> &&push_msgs) override
420 {
422 return;
423
425 {
428 }
429
431
432 if (get_tun())
433 {
435 for (auto &msg : push_msgs)
436 {
437 msg->null_terminate();
438 proto_context.control_send(std::move(msg));
439 }
440 proto_context.flush(true);
442 }
443 else
444 {
445 auth_failed("no tun provider", "");
446 }
447 }
448
450 {
451 if (get_tun())
452 return TunLink::send->tun_native_handle();
453 else
455 }
456
458 const std::string &reason,
459 const std::string &client_reason) override
460 {
462 return;
463
465
467 BufferStreamOut os(*buf);
468
469 std::string ts;
470
471 switch (type)
472 {
474 ts = "HALT";
475 os << "HALT,";
476 if (!client_reason.empty())
477 os << client_reason;
478 else
479 os << "client was disconnected from server";
481 disconnect_in(Time::Duration::seconds(1));
482 preserve_session_id = false;
483 break;
485 ts = "RESTART";
486 os << "RESTART,";
487 if (!client_reason.empty())
488 os << client_reason;
489 else
490 os << "server requested a client reconnect";
492 disconnect_in(Time::Duration::seconds(1));
493 preserve_session_id = false;
494 break;
496 ts = "RESTART_PASSIVE";
497 os << "RESTART,[P]:";
498 if (!client_reason.empty())
499 os << client_reason;
500 else
501 os << "server requested a client reconnect";
502 break;
504 ts = "RESTART_PSID";
505 os << "RESTART,[P]:";
506 if (!client_reason.empty())
507 os << client_reason;
508 else
509 os << "server requested a client reconnect";
511 disconnect_in(Time::Duration::seconds(1));
512 break;
514 ts = "AUTH_FAILED";
515 os << ts;
516 if (!client_reason.empty())
517 os << ',' << client_reason;
519 disconnect_in(Time::Duration::seconds(1));
520 preserve_session_id = false;
521 break;
522 case HaltRestart::RAW:
523 {
524 const size_t pos = reason.find_first_of(',');
525 if (pos != std::string::npos)
526 ts = reason.substr(0, pos);
527 else
528 ts = reason;
529 os << reason;
531 disconnect_in(Time::Duration::seconds(1));
532 preserve_session_id = false;
533 break;
534 }
535 }
536
537 OPENVPN_LOG(instance_name() << " : Disconnect: " << ts << ' ' << reason);
538
540 {
541 buf->null_terminate();
542 proto_context.control_send(std::move(buf));
543 proto_context.flush(true);
544 }
545
547 }
548
549 void schedule_disconnect(const unsigned int seconds) override
550 {
552 return;
554 disconnect_in(Time::Duration::seconds(seconds));
556 }
557
558 void schedule_auth_pending_timeout(const unsigned int seconds) override
559 {
560 if (halt || (disconnect_type >= DT_RELAY_TRANSITION) || !seconds)
561 return;
564 disconnect_in(Time::Duration::seconds(seconds));
566 }
567
568 void post_cc_msg(BufferPtr &&msg) override
569 {
571 return;
572
574 msg->null_terminate();
575 proto_context.control_send(std::move(msg));
576 proto_context.flush(true);
578 }
579
580 void stats_notify(const PeerStats &ps, const bool final) override
581 {
582 if (ManLink::send)
583 ManLink::send->stats_notify(ps, final);
584 }
585
586 void float_notify(const PeerAddr::Ptr &addr) override
587 {
588 if (ManLink::send)
589 ManLink::send->float_notify(addr);
590 }
591
592 void ipma_notify(const struct ovpn_tun_head_ipma &ipma) override
593 {
594 if (ManLink::send)
595 ManLink::send->ipma_notify(ipma);
596 }
597
598 void data_limit_notify(const int key_id,
599 const DataLimit::Mode cdl_mode,
600 const DataLimit::State cdl_status) override
601 {
603 proto_context.data_limit_notify(key_id, cdl_mode, cdl_status);
604 proto_context.flush(true);
606 }
607
609 {
610 if (halt)
611 OPENVPN_LOG("Debug: ServerProto: get_management() called with halt=true ManLink::send=" << bool(ManLink::send) << " man_factory=" << bool(man_factory));
612 if (!ManLink::send)
613 {
614 if (man_factory && !halt)
615 ManLink::send = man_factory->new_man_obj(this);
616 }
617 return bool(ManLink::send);
618 }
619
620 bool get_tun()
621 {
622 if (halt)
623 OPENVPN_LOG("Debug: ServerProto: get_tun() called with halt=true TunLink::send=" << bool(TunLink::send) << " tun_factory=" << bool(tun_factory));
624 if (!TunLink::send)
625 {
626 if (tun_factory && !halt)
627 TunLink::send = tun_factory->new_tun_obj(this);
628 }
629 return bool(TunLink::send);
630 }
631
632 // caller must ensure that update_now() was called before
633 // and set_housekeeping_timer() called after this method
634 void disconnect_in(const Time::Duration &dur)
635 {
637 }
638
640 {
642 }
643
644 void housekeeping_callback(const openvpn_io::error_code &e)
645 {
646 try
647 {
648 if (!e && !halt)
649 {
650 // update current time
652
657 else if (proto_context.now() >= disconnect_at)
658 {
659 switch (disconnect_type)
660 {
661 case DT_HALT_RESTART:
662 error("disconnect triggered");
663 break;
666 break;
667 case DT_AUTH_PENDING:
668 auth_failed("Auth Pending Timeout", "Auth Pending Timeout");
669 break;
670 default:
671 error("unknown disconnect");
672 break;
673 }
674 }
675 else
677 }
678 }
679 catch (const std::exception &exc)
680 {
681 error(exc);
682 }
683 }
684
686 {
688 next.min(disconnect_at);
690 {
691 if (!next.is_infinite())
692 {
693 next.max(proto_context.now());
696 housekeeping_timer.async_wait([self = Ptr(this)](const openvpn_io::error_code &error)
697 { self->housekeeping_callback(error); });
698 }
699 else
700 {
701 housekeeping_timer.cancel();
703 }
704 }
705 }
706
708 {
710 return TransportLink::send->transport_info();
711 else
712 return "";
713 }
714
715 void error(const std::string &error)
716 {
717 OPENVPN_LOG(instance_name() << " : ServerProto: " << error);
718 stop();
719 }
720
721 void error(const std::exception &e)
722 {
723 error(e.what());
724 }
725
726 void error()
727 {
728 stop();
729 }
730
732 {
733 switch (err)
734 {
737 error();
738 break;
739 default:
740 error(std::string("Session invalidated: ") + Error::name(err));
741 break;
742 }
743 }
744
745 std::string instance_name() const
746 {
747 if (ManLink::send)
748 return ManLink::send->instance_name();
749 else
750 return "UNNAMED_CLIENT";
751 }
752
753 // higher values are higher priority
761
765
766 bool halt = false;
767
769
772
774
776
779
780 bool proto_request_push = false;
781 };
782};
783
788} // namespace openvpn
789
790#endif
std::size_t expires_at(const Time &t)
Definition asiotimer.hpp:64
bool similar(const Time &t) const
void init(const Time::Duration &pre, const Time::Duration &post)
void reset(const Time &t)
size_t size() const
Returns the size of the buffer in T objects.
Definition buffer.hpp:1242
void set_factory(const CryptoDCFactory::Ptr &factory)
Definition cryptodc.hpp:200
void data_limit_notify(const unsigned int key_id, const DataLimit::Mode cdl_mode, const DataLimit::State cdl_status)
Definition proto.hpp:4401
void set_local_peer_id(const int local_peer_id)
Definition proto.hpp:4424
const Time & now() const
Definition proto.hpp:4430
CryptoDCSettings & dc_settings()
Definition proto.hpp:4412
void flush(const bool control_channel)
Definition proto.hpp:4149
void control_send(BufferPtr &&app_bp)
Definition proto.hpp:4206
PacketType packet_type(const Buffer &buf)
Definition proto.hpp:4110
bool is_keepalive_enabled() const
Definition proto.hpp:4377
ProtoConfig::Ptr conf_ptr() const
Definition proto.hpp:4482
std::string dump_packet(const Buffer &buf)
Definition proto.hpp:1419
bool data_decrypt(const PacketType &type, BufferAllocated &in_out)
Definition proto.hpp:4254
void disable_keepalive(unsigned int &keepalive_ping, unsigned int &keepalive_timeout)
Definition proto.hpp:4385
Error::Type invalidation_reason() const
Definition proto.hpp:4341
Time next_housekeeping() const
Definition proto.hpp:4187
bool control_net_recv(const PacketType &type, BufferAllocated &&net_buf)
Definition proto.hpp:4224
bool invalidated() const
Definition proto.hpp:4335
void reset(const ProtoSessionID cookie_psid=ProtoSessionID())
Resets ProtoContext *this to it's initial state.
Definition proto.hpp:3993
void start(const ProtoSessionID cookie_psid=ProtoSessionID())
Initialize the state machine and start protocol negotiation.
Definition proto.hpp:4123
The smart pointer class.
Definition rc.hpp:119
void reset() noexcept
Points this RCPtr<T> to nullptr safely.
Definition rc.hpp:290
static Ptr Create(ArgsT &&...args)
Creates a new instance of RcEnable with the given arguments.
Definition make_rc.hpp:43
A string-like type that clears the buffer contents on delete.
Definition safestr.hpp:27
ProtoContext::ProtoConfig ProtoConfig
Definition servproto.hpp:57
ProtoContext::TLSWrapPreValidate::Ptr tls_crypt_preval
Factory(openvpn_io::io_context &io_context_arg, const ProtoConfig &c)
Definition servproto.hpp:59
TransportClientInstance::Recv::Ptr new_client_instance() override
ProtoConfig::Ptr proto_context_config
Definition servproto.hpp:92
TunClientInstance::Factory::Ptr tun_factory
Definition servproto.hpp:95
ProtoConfig::Ptr clone_proto_config() const
Definition servproto.hpp:86
ProtoContext::TLSWrapPreValidate::Ptr tls_auth_preval
bool validate_initial_packet(const BufferAllocated &net_buf) override
Definition servproto.hpp:72
openvpn_io::io_context & io_context
Definition servproto.hpp:91
ManClientInstance::Factory::Ptr man_factory
Definition servproto.hpp:94
void disable_keepalive(unsigned int &keepalive_ping, unsigned int &keepalive_timeout) override
void disconnect_in(const Time::Duration &dur)
void housekeeping_callback(const openvpn_io::error_code &e)
void override_dc_factory(const CryptoDCFactory::Ptr &dc_factory) override
void error(const std::exception &e)
void tun_recv(BufferAllocated &buf) override
void control_net_send(const Buffer &net_buf) override
void push_halt_restart_msg(const HaltRestart::Type type, const std::string &reason, const std::string &client_reason) override
TunClientInstance::Recv * override_tun(TunClientInstance::Send *tun) override
void schedule_disconnect(const unsigned int seconds) override
ManClientInstance::Factory::Ptr man_factory
void active(bool primary) override
Called when KeyContext transitions to ACTIVE state.
bool supports_epoch_data() override
void data_limit_notify(const int key_id, const DataLimit::Mode cdl_mode, const DataLimit::State cdl_status) override
void control_recv(BufferPtr &&app_bp) override
TunClientInstance::Factory::Ptr tun_factory
bool should_preserve_session_id() override
bool defined() const override
void error(const std::string &error)
void relay(const IP::Addr &target, const int port) override
TunClientInstance::NativeHandle tun_native_handle() override
bool transport_recv(BufferAllocated &buf) override
std::string instance_name() const
void server_auth(const std::string &username, const SafeString &password, const std::string &peer_info, const AuthCert::Ptr &auth_cert) override
void stats_notify(const PeerStats &ps, const bool final) override
void schedule_auth_pending_timeout(const unsigned int seconds) override
void push_reply(std::vector< BufferPtr > &&push_msgs) override
Session(openvpn_io::io_context &io_context_arg, const Factory &factory, ManClientInstance::Factory::Ptr man_factory_arg, TunClientInstance::Factory::Ptr tun_factory_arg)
void start(const TransportClientInstance::Send::Ptr &parent, const PeerAddr::Ptr &addr, const int local_peer_id, const ProtoSessionID cookie_psid=ProtoSessionID()) override
bool is_keepalive_enabled() const override
void auth_failed(const std::string &reason, const std::string &client_reason) override
void ipma_notify(const struct ovpn_tun_head_ipma &ipma) override
void invalidation_error(const Error::Type err)
std::string client_endpoint_render()
void float_notify(const PeerAddr::Ptr &addr) override
PeerStats stats_poll() override
void post_cc_msg(BufferPtr &&msg) override
Link< TunClientInstance::Send, TunClientInstance::Recv > TunLink
Definition servproto.hpp:47
Link< ManClientInstance::Send, ManClientInstance::Recv > ManLink
Definition servproto.hpp:48
Link< TransportClientInstance::Send, TransportClientInstance::Recv > TransportLink
Definition servproto.hpp:46
virtual void error(const size_t type, const std::string *text=nullptr)
static TimeType infinite()
Definition time.hpp:256
void max(const TimeType &t)
Definition time.hpp:348
void min(const TimeType &t)
Definition time.hpp:342
bool is_infinite() const
Definition time.hpp:269
#define OPENVPN_LOG(args)
constexpr BufferFlags GROW(1u<< 2)
if enabled, buffer will grow (otherwise buffer_full exception will be thrown)
const char * name(const size_t type)
Definition error.hpp:117
@ KEV_NEGOTIATE_ERROR
Definition error.hpp:99
@ KEEPALIVE_TIMEOUT
Definition error.hpp:61
STRING utf8_printable(const STRING &str, size_t max_len_flags)
Definition unicode.hpp:129
bool is_valid_utf8(const STRING &str, const size_t max_len_flags=0)
Definition unicode.hpp:75
bool starts_with(const STRING &str, const std::string &prefix)
Definition string.hpp:79
void buf_append_string(Buffer &buf, const std::string &str)
Definition bufstr.hpp:82
#define OPENVPN_LOG_SERVPROTO(x)
Definition servproto.hpp:39
proxy_host_port port
std::string ret
std::ostringstream os
#define msg(flags,...)