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>
30#include <openvpn/ssl/proto.hpp>
34
35#ifdef OPENVPN_DEBUG_SERVPROTO
36#define OPENVPN_LOG_SERVPROTO(x) OPENVPN_LOG(x)
37#else
38#define OPENVPN_LOG_SERVPROTO(x)
39#endif
40
41namespace openvpn {
42
44{
48
49 public:
50 class Session;
51
102
103 // This is the main server-side client instance object
104 class Session : ProtoContextCallbackInterface, // Callback interface from protocol implementation
105 public TransportLink, // Transport layer
106 public TunLink, // Tun/routing layer
107 public ManLink // Management layer
108 {
109 friend class Factory; // calls constructor
110
111 public:
113
114 bool defined() const override
115 {
116 return defined_();
117 }
118
120 {
121 TunLink::send.reset(tun);
122 return this;
123 }
124
126 const PeerAddr::Ptr &addr,
127 const int local_peer_id,
128 const ProtoSessionID cookie_psid = ProtoSessionID()) override
129 {
130 TransportLink::send = parent;
131 peer_addr = addr;
132
133 // init OpenVPN protocol handshake
135 proto_context.reset(cookie_psid);
136 proto_context.set_local_peer_id(local_peer_id);
137 proto_context.start(cookie_psid);
138 proto_context.flush(true);
139
140 // coarse wakeup range
141 housekeeping_schedule.init(Time::Duration::binary_ms(512), Time::Duration::binary_ms(1024));
142 }
143
145 {
147 return TransportLink::send->stats_poll();
148 return PeerStats();
149 }
150
152 {
153 return preserve_session_id;
154 }
155
156 void stop() override
157 {
158 if (!halt)
159 {
160 halt = true;
161 housekeeping_timer.cancel();
162
163 if (ManLink::send)
164 ManLink::send->pre_stop();
165
166 // deliver final peer stats to management layer
168 {
169 if (TransportLink::send->stats_pending())
170 ManLink::send->stats_notify(TransportLink::send->stats_poll(), true);
171 }
172
176 {
177 TransportLink::send->stop();
178 TransportLink::send.reset();
179 }
180 if (TunLink::send)
181 {
182 TunLink::send->stop();
183 TunLink::send.reset();
184 }
185 if (ManLink::send)
186 {
187 ManLink::send->stop();
188 ManLink::send.reset();
189 }
190 }
191 }
192
193 // called with OpenVPN-encapsulated packets from transport layer
194 bool transport_recv(BufferAllocated &buf) override
195 {
196 bool ret = false;
198 return false;
199 try
200 {
201 OPENVPN_LOG_SERVPROTO(instance_name() << " : Transport RECV[" << buf.size() << "] " << client_endpoint_render() << ' ' << proto_context.dump_packet(buf));
202
203 // update current time
205
206 // get packet type
208
209 // process packet
210 if (pt.is_data())
211 {
212 // data packet
213 ret = proto_context.data_decrypt(pt, buf);
214 if (!buf.empty())
215 {
216#ifdef OPENVPN_PACKET_LOG
217 log_packet(buf, false);
218#endif
219 // make packet appear as incoming on tun interface
220 if (true) // fixme: was tun
221 {
222 OPENVPN_LOG_SERVPROTO(instance_name() << " : TUN SEND[" << buf.size() << ']');
223 // fixme -- code me
224 }
225 }
226
227 // do a lightweight flush
228 proto_context.flush(false);
229 }
230 else if (pt.is_control())
231 {
232 // control packet
233 ret = proto_context.control_net_recv(pt, std::move(buf));
234
235 // do a full flush
236 proto_context.flush(true);
237 }
238
239 // schedule housekeeping wakeup
241 }
242 catch (const std::exception &e)
243 {
244 error(e);
245 ret = false;
246 }
247
248 return ret;
249 }
250
251 // called with cleartext IP packets from routing layer
252 void tun_recv(BufferAllocated &buf) override
253 {
254 // fixme -- code me
255 }
256
257 // Return true if keepalive parameter(s) are enabled.
258 bool is_keepalive_enabled() const override
259 {
261 }
262
263 // Disable keepalive for rest of session, but fetch
264 // the keepalive parameters (in seconds).
265 // Also, allow the management layer to override parameters.
266 void disable_keepalive(unsigned int &keepalive_ping,
267 unsigned int &keepalive_timeout) override
268 {
269 proto_context.disable_keepalive(keepalive_ping, keepalive_timeout);
270 if (ManLink::send)
271 ManLink::send->keepalive_override(keepalive_ping, keepalive_timeout);
272 }
273
274 // override the data channel factory
275 void override_dc_factory(const CryptoDCFactory::Ptr &dc_factory) override
276 {
278 }
279
280 virtual ~Session()
281 {
282 // fatal error if destructor called while Session is active
283 if (defined_())
284 std::abort();
285 }
286
287 private:
288 Session(openvpn_io::io_context &io_context_arg,
289 const Factory &factory,
290 ManClientInstance::Factory::Ptr man_factory_arg,
291 TunClientInstance::Factory::Ptr tun_factory_arg)
292 : proto_context(this, factory.clone_proto_config(), factory.stats),
293 housekeeping_timer(io_context_arg),
294 disconnect_at(Time::infinite()),
295 stats(factory.stats),
296 man_factory(std::move(man_factory_arg)),
297 tun_factory(std::move(tun_factory_arg))
298 {
299 }
300
301 bool supports_epoch_data() override
302 {
303 /* TODO: currently all server implementations do not implement this feature in their data channel */
304 return false;
305 }
306
307 bool defined_() const
308 {
309 return !halt && TransportLink::send;
310 }
311
312 // proto base class calls here for control channel network sends
313 void control_net_send(const Buffer &net_buf) override
314 {
315 OPENVPN_LOG_SERVPROTO(instance_name() << " : Transport SEND[" << net_buf.size() << "] " << client_endpoint_render() << ' ' << proto_context.dump_packet(net_buf));
317 {
318 if (TransportLink::send->transport_send_const(net_buf))
320 }
321 }
322
323 // Called on server with credentials and peer info provided by client.
324 // Should be overriden by derived class if credentials are required.
325 void server_auth(const std::string &username,
326 const SafeString &password,
327 const std::string &peer_info,
328 const AuthCert::Ptr &auth_cert) override
329 {
330 constexpr size_t MAX_USERNAME_SIZE = 256;
331 constexpr size_t MAX_PASSWORD_SIZE = 16384;
332
333 if (get_management())
334 {
335 AuthCreds::Ptr auth_creds(new AuthCreds(Unicode::utf8_printable(username, MAX_USERNAME_SIZE | Unicode::UTF8_FILTER),
339 ManLink::send->auth_request(auth_creds, auth_cert, peer_addr);
340 }
341 }
342
343 // proto base class calls here for app-level control-channel messages received
344 void control_recv(BufferPtr &&app_bp) override
345 {
346 const std::string msg = ProtoContext::template read_control_string<std::string>(*app_bp);
348 {
349 /* if we received invalid data from a client on the control channel terminate the connection */
350 const std::string reason("Control channel message with invalid characters received");
351 auth_failed(reason, reason);
352 return;
353 }
354
355 if (msg == "PUSH_REQUEST")
356 {
357 if (get_management())
358 ManLink::send->push_request(proto_context.conf_ptr());
359 else
360 auth_failed("no management provider", "");
361 }
362 else if (msg == "EXIT")
363 {
364 OPENVPN_LOG("Client disconnecting from server, EXIT received");
366 disconnect_in(Time::Duration::seconds(1));
367 }
368 else if (msg.starts_with("ACC,"))
369 {
370 if (get_management())
371 ManLink::send->app_control(msg);
372 }
373 else
374 {
375 OPENVPN_LOG(instance_name() << " : Unrecognized client request: " << msg);
376 }
377 }
378
379 void active(bool primary) override
380 {
382 ManLink::send->push_request(proto_context.conf_ptr());
383 }
384
385 void auth_failed(const std::string &reason,
386 const std::string &client_reason) override
387 {
388 push_halt_restart_msg(HaltRestart::AUTH_FAILED, reason, client_reason);
389 }
390
391 void relay(const IP::Addr &target, const int port) override
392 {
394 return;
395
397
399 {
401 TunLink::send->relay(target, port);
402 disconnect_in(Time::Duration::seconds(10)); // not a real disconnect, just complete transition to relay
403 }
404
406 {
407 auto buf = BufferAllocatedRc::Create(64);
408 buf_append_string(*buf, "RELAY");
409 buf->null_terminate();
410 proto_context.control_send(std::move(buf));
411 proto_context.flush(true);
412 }
413
415 }
416
417 void push_reply(std::vector<BufferPtr> &&push_msgs) override
418 {
420 return;
421
423 {
426 }
427
429
430 if (get_tun())
431 {
433 for (auto &msg : push_msgs)
434 {
435 msg->null_terminate();
436 proto_context.control_send(std::move(msg));
437 }
438 proto_context.flush(true);
440 }
441 else
442 {
443 auth_failed("no tun provider", "");
444 }
445 }
446
448 {
449 if (get_tun())
450 return TunLink::send->tun_native_handle();
452 }
453
455 const std::string &reason,
456 const std::string &client_reason) override
457 {
459 return;
460
462
464 BufferStreamOut os(*buf);
465
466 std::string ts;
467
468 switch (type)
469 {
471 ts = "HALT";
472 os << "HALT,";
473 if (!client_reason.empty())
474 os << client_reason;
475 else
476 os << "client was disconnected from server";
478 disconnect_in(Time::Duration::seconds(1));
479 preserve_session_id = false;
480 break;
482 ts = "RESTART";
483 os << "RESTART,";
484 if (!client_reason.empty())
485 os << client_reason;
486 else
487 os << "server requested a client reconnect";
489 disconnect_in(Time::Duration::seconds(1));
490 preserve_session_id = false;
491 break;
493 ts = "RESTART_PASSIVE";
494 os << "RESTART,[P]:";
495 if (!client_reason.empty())
496 os << client_reason;
497 else
498 os << "server requested a client reconnect";
499 break;
501 ts = "RESTART_PSID";
502 os << "RESTART,[P]:";
503 if (!client_reason.empty())
504 os << client_reason;
505 else
506 os << "server requested a client reconnect";
508 disconnect_in(Time::Duration::seconds(1));
509 break;
511 ts = "AUTH_FAILED";
512 os << ts;
513 if (!client_reason.empty())
514 os << ',' << client_reason;
516 disconnect_in(Time::Duration::seconds(1));
517 preserve_session_id = false;
518 break;
519 case HaltRestart::RAW:
520 {
521 const size_t pos = reason.find_first_of(',');
522 if (pos != std::string::npos)
523 ts = reason.substr(0, pos);
524 else
525 ts = reason;
526 os << reason;
528 disconnect_in(Time::Duration::seconds(1));
529 preserve_session_id = false;
530 break;
531 }
532 }
533
534 OPENVPN_LOG(instance_name() << " : Disconnect: " << ts << ' ' << reason);
535
537 {
538 buf->null_terminate();
539 proto_context.control_send(std::move(buf));
540 proto_context.flush(true);
541 }
542
544 }
545
546 void schedule_disconnect(const unsigned int seconds) override
547 {
549 return;
551 disconnect_in(Time::Duration::seconds(seconds));
553 }
554
555 void schedule_auth_pending_timeout(const unsigned int seconds) override
556 {
557 if (halt || (disconnect_type >= DT_RELAY_TRANSITION) || !seconds)
558 return;
561 disconnect_in(Time::Duration::seconds(seconds));
563 }
564
565 void post_cc_msg(BufferPtr &&msg) override
566 {
568 return;
569
571 msg->null_terminate();
572 proto_context.control_send(std::move(msg));
573 proto_context.flush(true);
575 }
576
577 void stats_notify(const PeerStats &ps, const bool final) override
578 {
579 if (ManLink::send)
580 ManLink::send->stats_notify(ps, final);
581 }
582
583 void float_notify(const PeerAddr::Ptr &addr) override
584 {
585 if (ManLink::send)
586 ManLink::send->float_notify(addr);
587 }
588
589 void ipma_notify(const struct ovpn_tun_head_ipma &ipma) override
590 {
591 if (ManLink::send)
592 ManLink::send->ipma_notify(ipma);
593 }
594
595 void data_limit_notify(const int key_id,
596 const DataLimit::Mode cdl_mode,
597 const DataLimit::State cdl_status) override
598 {
600 proto_context.data_limit_notify(key_id, cdl_mode, cdl_status);
601 proto_context.flush(true);
603 }
604
606 {
607 if (halt)
608 OPENVPN_LOG("Debug: ServerProto: get_management() called with halt=true ManLink::send=" << bool(ManLink::send) << " man_factory=" << bool(man_factory));
609 if (!ManLink::send)
610 {
611 if (man_factory && !halt)
612 ManLink::send = man_factory->new_man_obj(this);
613 }
614 return bool(ManLink::send);
615 }
616
617 bool get_tun()
618 {
619 if (halt)
620 OPENVPN_LOG("Debug: ServerProto: get_tun() called with halt=true TunLink::send=" << bool(TunLink::send) << " tun_factory=" << bool(tun_factory));
621 if (!TunLink::send)
622 {
623 if (tun_factory && !halt)
624 TunLink::send = tun_factory->new_tun_obj(this);
625 }
626 return bool(TunLink::send);
627 }
628
629 // caller must ensure that update_now() was called before
630 // and set_housekeeping_timer() called after this method
631 void disconnect_in(const Time::Duration &dur)
632 {
634 }
635
637 {
639 }
640
641 void housekeeping_callback(const openvpn_io::error_code &e)
642 {
643 try
644 {
645 if (!e && !halt)
646 {
647 // update current time
649
654 else if (proto_context.now() >= disconnect_at)
655 {
656 switch (disconnect_type)
657 {
658 case DT_HALT_RESTART:
659 error("disconnect triggered");
660 break;
663 break;
664 case DT_AUTH_PENDING:
665 auth_failed("Auth Pending Timeout", "Auth Pending Timeout");
666 break;
667 default:
668 error("unknown disconnect");
669 break;
670 }
671 }
672 else
674 }
675 }
676 catch (const std::exception &exc)
677 {
678 error(exc);
679 }
680 }
681
683 {
685 next.min(disconnect_at);
687 {
688 if (!next.is_infinite())
689 {
690 next.max(proto_context.now());
693 housekeeping_timer.async_wait([self = Ptr(this)](const openvpn_io::error_code &error)
694 { self->housekeeping_callback(error); });
695 }
696 else
697 {
698 housekeeping_timer.cancel();
700 }
701 }
702 }
703
705 {
707 return TransportLink::send->transport_info();
708 return "";
709 }
710
711 void error(const std::string &error)
712 {
713 OPENVPN_LOG(instance_name() << " : ServerProto: " << error);
714 stop();
715 }
716
717 void error(const std::exception &e)
718 {
719 error(e.what());
720 }
721
722 void error()
723 {
724 stop();
725 }
726
728 {
729 switch (err)
730 {
733 error();
734 break;
735 default:
736 error(std::string("Session invalidated: ") + Error::name(err));
737 break;
738 }
739 }
740
741 std::string instance_name() const
742 {
743 if (ManLink::send)
744 return ManLink::send->instance_name();
745 return "UNNAMED_CLIENT";
746 }
747
748 // higher values are higher priority
756
760
761 bool halt = false;
762
764
767
769
771
774
775 bool proto_request_push = false;
776 };
777};
778
783} // namespace openvpn
784
785#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:1241
bool empty() const
Returns true if the buffer is empty.
Definition buffer.hpp:1235
void set_factory(const CryptoDCFactory::Ptr &factory)
Definition cryptodc.hpp:196
void data_limit_notify(const unsigned int key_id, const DataLimit::Mode cdl_mode, const DataLimit::State cdl_status)
Definition proto.hpp:4448
bool control_net_recv(const PacketType &type, BufferPtr &&net_bp)
Definition proto.hpp:4270
void set_local_peer_id(const int local_peer_id)
Definition proto.hpp:4471
const Time & now() const
Definition proto.hpp:4477
CryptoDCSettings & dc_settings()
Definition proto.hpp:4459
void flush(const bool control_channel)
Definition proto.hpp:4197
void control_send(BufferPtr &&app_bp)
Definition proto.hpp:4253
PacketType packet_type(const Buffer &buf)
Definition proto.hpp:4158
bool is_keepalive_enabled() const
Definition proto.hpp:4424
ProtoConfig::Ptr conf_ptr() const
Definition proto.hpp:4529
std::string dump_packet(const Buffer &buf)
Definition proto.hpp:1426
bool data_decrypt(const PacketType &type, BufferAllocated &in_out)
Definition proto.hpp:4301
void disable_keepalive(unsigned int &keepalive_ping, unsigned int &keepalive_timeout)
Definition proto.hpp:4432
Error::Type invalidation_reason() const
Definition proto.hpp:4388
Time next_housekeeping() const
Definition proto.hpp:4235
bool invalidated() const
Definition proto.hpp:4382
void reset(const ProtoSessionID cookie_psid=ProtoSessionID())
Resets ProtoContext *this to it's initial state.
Definition proto.hpp:4042
void start(const ProtoSessionID cookie_psid=ProtoSessionID())
Initialize the state machine and start protocol negotiation.
Definition proto.hpp:4171
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::TLSWrapPreValidate::Ptr tls_crypt_preval
Factory(openvpn_io::io_context &io_context_arg, const ProtoConfig &c)
Definition servproto.hpp:58
TransportClientInstance::Recv::Ptr new_client_instance() override
ProtoConfig::Ptr proto_context_config
Definition servproto.hpp:91
TunClientInstance::Factory::Ptr tun_factory
Definition servproto.hpp:94
ProtoContext::ProtoConfig ProtoConfig
Definition servproto.hpp:56
ProtoConfig::Ptr clone_proto_config() const
Definition servproto.hpp:85
ProtoContext::TLSWrapPreValidate::Ptr tls_auth_preval
Definition servproto.hpp:99
bool validate_initial_packet(const BufferAllocated &net_buf) override
Definition servproto.hpp:71
openvpn_io::io_context & io_context
Definition servproto.hpp:90
ManClientInstance::Factory::Ptr man_factory
Definition servproto.hpp:93
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
virtual void error(const size_t type, const std::string *text=nullptr)
static TimeType infinite()
Definition time.hpp:254
void max(const TimeType &t)
Definition time.hpp:343
void min(const TimeType &t)
Definition time.hpp:337
bool is_infinite() const
Definition time.hpp:266
#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
void buf_append_string(Buffer &buf, const std::string &str)
Definition bufstr.hpp:82
#define OPENVPN_LOG_SERVPROTO(x)
Definition servproto.hpp:38
proxy_host_port port
std::string ret
std::ostringstream os
#define msg(flags,...)