OpenVPN 3 Core Library
Loading...
Searching...
No Matches
ovpncli.cpp
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// Implementation file for OpenVPNClient API defined in ovpncli.hpp.
13
14#include <iostream>
15#include <string>
16#include <memory>
17#include <utility>
18#include <atomic>
19
20#include <openvpn/io/io.hpp>
21
22// Set up export of our public interface unless
23// OPENVPN_CORE_API_VISIBILITY_HIDDEN is defined
24#if defined(__GNUC__)
25#define OPENVPN_CLIENT_EXPORT
26#ifndef OPENVPN_CORE_API_VISIBILITY_HIDDEN
27#pragma GCC visibility push(default)
28#endif
29#include "ovpncli.hpp" // public interface
30#ifndef OPENVPN_CORE_API_VISIBILITY_HIDDEN
31#pragma GCC visibility pop
32#endif
33#else
34// no public interface export defined for this compiler
35#define OPENVPN_CLIENT_EXPORT
36#include "ovpncli.hpp" // public interface
37#endif
38
39// debug settings (production setting in parentheses)
40
41// #define OPENVPN_DUMP_CONFIG // dump parsed configuration (comment out)
42// #define OPENVPN_DEBUG_CLIPROTO // shows packets in/out (comment out)
43#define OPENVPN_DEBUG_PROTO 1 // increases low-level protocol verbosity (1)
44// #define OPENVPN_DEBUG_PROTO_DUMP // dump hex of transport-layer packets, requires OPENVPN_DEBUG_CLIPROTO (comment out)
45// #define OPENVPN_DEBUG_VERBOSE_ERRORS // verbosely log Error::Type errors (comment out)
46#define OPENVPN_DEBUG_TUN 2 // debug level for tun object (2)
47#define OPENVPN_DEBUG_UDPLINK 2 // debug level for UDP link object (2)
48#define OPENVPN_DEBUG_TCPLINK 2 // debug level for TCP link object (2)
49#define OPENVPN_DEBUG_COMPRESS 1 // debug level for compression objects (1)
50#define OPENVPN_DEBUG_REMOTELIST 0 // debug level for RemoteList object (0)
51#define OPENVPN_DEBUG_TUN_BUILDER 0 // debug level for tun/builder/client.hpp (0)
52// #define OPENVPN_SHOW_SESSION_TOKEN // show server-pushed auth-token (comment out)
53// #define OPENVPN_DEBUG_TAPWIN // shows Windows TAP driver debug logging (comment out)
54
55// enable assertion checks (can safely be disabled in production)
56// #define OPENVPN_ENABLE_ASSERT
57
58// force null tun device (useful for testing)
59// #define OPENVPN_FORCE_TUN_NULL
60
61// log cleartext tunnel packets to file for debugging/analysis
62// #define OPENVPN_PACKET_LOG "pkt.log"
63
64#ifndef OPENVPN_LOG
65// log thread settings
66#define OPENVPN_LOG_CLASS openvpn::ClientAPI::LogReceiver
67#define OPENVPN_LOG_INFO openvpn::ClientAPI::LogInfo
68#include <openvpn/log/logthread.hpp> // should be included early
69#endif
70
71
72// on Android and iOS, use TunBuilderBase abstraction
74#if (defined(OPENVPN_PLATFORM_ANDROID) || defined(OPENVPN_PLATFORM_IPHONE)) && !defined(OPENVPN_FORCE_TUN_NULL) && !defined(OPENVPN_EXTERNAL_TUN_FACTORY)
75#define USE_TUN_BUILDER
76#endif
77
91
92// copyright
94
95namespace openvpn {
96namespace ClientAPI {
97
99
101{
102 public:
104
106 : parent(parent_arg)
107 {
108 std::memset(errors, 0, sizeof(errors));
109#ifdef OPENVPN_DEBUG_VERBOSE_ERRORS
111#endif
112 }
113
114 static size_t combined_n()
115 {
116 return N_STATS + Error::N_ERRORS;
117 }
118
119 static std::string combined_name(const size_t index)
120 {
121 if (index < N_STATS + Error::N_ERRORS)
122 {
123 if (index < N_STATS)
124 return stat_name(index);
125 else
126 return Error::name(index - N_STATS);
127 }
128 else
129 return "";
130 }
131
132 count_t combined_value(const size_t index) const
133 {
134 if (index < N_STATS + Error::N_ERRORS)
135 {
136 if (index < N_STATS)
137 return get_stat(index);
138 else
139 return errors[index - N_STATS];
140 }
141 else
142 return 0;
143 }
144
145 count_t stat_count(const size_t index) const
146 {
147 return get_stat_fast(index);
148 }
149
150 count_t error_count(const size_t index) const
151 {
152 return errors[index];
153 }
154
156 {
157 parent = nullptr;
158 }
159
160 void error(const size_t err, const std::string *text = nullptr) override
161 {
162 if (err < Error::N_ERRORS)
163 {
164#ifdef OPENVPN_DEBUG_VERBOSE_ERRORS
165 if (text)
166 OPENVPN_LOG("ERROR: " << Error::name(err) << " : " << *text);
167 else
168 OPENVPN_LOG("ERROR: " << Error::name(err));
169#endif
170 ++errors[err];
171 }
172 }
173
174 private:
177};
178
180{
181 public:
183
185 : parent(parent_arg)
186 {
187 }
188
190 {
191 if (parent)
192 {
193 if (event->id() == ClientEvent::CUSTOM_CONTROL)
194 {
197 ev.protocol = accm->protocol;
198 ev.payload = accm->custommessage;
199 parent->acc_event(ev);
200 }
201 else
202 {
203 Event ev;
204 ev.name = event->name();
205 ev.info = event->render();
206 ev.error = event->is_error();
207 ev.fatal = event->is_fatal();
208
209 // save connected event
210 if (event->id() == ClientEvent::CONNECTED)
211 last_connected = std::move(event);
212 else if (event->id() == ClientEvent::DISCONNECTED)
214
215 parent->event(ev);
216 }
217 }
218 }
219
221 {
223 if (connected)
224 {
225 const ClientEvent::Connected *c = connected->connected_cast();
226 if (c)
227 {
228 ci.user = c->user;
229 ci.serverHost = c->server_host;
230 ci.serverPort = c->server_port;
232 ci.serverIp = c->server_ip;
233 ci.vpnIp4 = c->vpn_ip4;
234 ci.vpnIp6 = c->vpn_ip6;
235 ci.gw4 = c->vpn_gw4;
236 ci.gw6 = c->vpn_gw6;
237 ci.clientIp = c->client_ip;
238 ci.tunName = c->tun_name;
239 ci.defined = true;
240 ci.vpnMtu = c->vpn_mtu;
241 return;
242 }
243 }
244 ci.defined = false;
245 }
246
248 {
249 parent = nullptr;
250 }
251
252 private:
255};
256
258{
259 public:
261 : parent(nullptr)
262 {
263 }
264
265 void set_parent(OpenVPNClient *parent_arg)
266 {
267 parent = parent_arg;
268 }
269
270 void set_rg_local(bool rg_local_arg)
271 {
272 rg_local = rg_local_arg;
273 }
274
275 bool socket_protect(openvpn_io::detail::socket_type socket, IP::Addr endpoint) override
276 {
277 if (parent)
278 {
279#if defined(OPENVPN_COMMAND_AGENT) && defined(OPENVPN_PLATFORM_WIN)
280 return rg_local ? true : WinCommandAgent::add_bypass_route(endpoint);
281#elif defined(OPENVPN_COMMAND_AGENT) && defined(OPENVPN_PLATFORM_MAC)
282 return rg_local ? true : UnixCommandAgent::add_bypass_route(endpoint);
283#else
284 return parent->socket_protect(socket, endpoint.to_string(), endpoint.is_ipv6());
285#endif
286 }
287 else
288 return true;
289 }
290
292 {
293 parent = nullptr;
294 }
295
296 private:
298 bool rg_local = false; // do not add bypass route if true
299};
300
302{
303 public:
305 : parent(nullptr)
306 {
307 }
308
309 void set_parent(OpenVPNClient *parent_arg)
310 {
311 parent = parent_arg;
312 }
313
315 {
316 parent = nullptr;
317 }
318
320 {
321 if (parent)
323 else
324 return false;
325 }
326
327 private:
329};
330
332{
333 public:
334 void set_parent(OpenVPNClient *parent_arg)
335 {
336 parent = parent_arg;
337 }
338
340 {
341 parent = nullptr;
342 }
343
345 {
346 if (parent)
347 {
348 const std::string title = "remote-override";
350 try
351 {
353 }
354 catch (const std::exception &e)
355 {
356 ro.error = e.what();
357 }
359 if (ro.error.empty())
360 {
361 if (!ro.ip.empty())
362 ri->set_ip_addr(IP::Addr(ro.ip, title));
363 if (ro.host.empty())
364 ro.host = ro.ip;
365 HostPort::validate_host(ro.host, title);
366 HostPort::validate_port(ro.port, title);
367 ri->server_host = std::move(ro.host);
368 ri->server_port = std::move(ro.port);
369 ri->transport_protocol = Protocol::parse(ro.proto, Protocol::CLIENT_SUFFIX, title.c_str());
370 }
371 else
372 throw Exception("remote override exception: " + ro.error);
373 return ri;
374 }
375 else
376 return RemoteList::Item::Ptr();
377 }
378
379 private:
381};
382
384{
385 public:
386 MyClockTick(openvpn_io::io_context &io_context,
387 OpenVPNClient *parent_arg,
388 const unsigned int ms)
389 : timer(io_context),
390 parent(parent_arg),
391 period(Time::Duration::milliseconds(ms))
392 {
393 }
394
395 void cancel()
396 {
397 timer.cancel();
398 }
399
401 {
402 parent = nullptr;
403 }
404
405 void schedule()
406 {
408 timer.async_wait([this](const openvpn_io::error_code &error)
409 {
410 if (!parent || error)
411 return;
412 try {
414 }
415 catch (...)
416 {
417 }
418 schedule(); });
419 }
420
421 private:
424 const Time::Duration period;
425};
426
427namespace Private {
429{
430 public:
431 // state objects
441 std::unique_ptr<MyClockTick> clock_tick;
442
443 // extra settings submitted by API client
445
449
450#ifdef OPENVPN_GREMLIN
451 Gremlin::Config::Ptr gremlin_config;
452#endif
453 // Ensure that init is called
455
456 template <typename SESSION_STATS, typename CLIENT_EVENTS>
457 void attach(OpenVPNClient *parent,
458 openvpn_io::io_context *io_context,
460 {
461 // only one attachment per instantiation allowed
462 if (attach_called)
463 throw Exception("ClientState::attach() can only be called once per ClientState instantiation");
464 attach_called = true;
465
466 // async stop
468
469 // io_context
470 if (io_context)
472 else
473 {
474 io_context_ = new openvpn_io::io_context(1); // concurrency hint=1
475 io_context_owned = true;
476 }
477
478 // client stats
479 stats.reset(new SESSION_STATS(parent));
480
481 // client events
482 events.reset(new CLIENT_EVENTS(parent));
483
484 // socket protect
487 socket_protect.set_rg_local(rg_flags.redirect_gateway_local());
488
489 // reconnect notifications
491
492 // remote override
494 }
495
497 {
498 }
499
501 {
502 stop_scope_local.reset();
503 stop_scope_global.reset();
507 if (clock_tick)
508 clock_tick->detach_from_parent();
509 if (stats)
510 stats->detach_from_parent();
511 if (events)
512 events->detach_from_parent();
513 session.reset();
515 delete io_context_;
516 }
517
518 // foreign thread access
519
521 {
522 foreign_thread_ready.store(true, std::memory_order_release);
523 }
524
526 {
527 return foreign_thread_ready.load(std::memory_order_acquire);
528 }
529
530 // io_context
531
532 openvpn_io::io_context *io_context()
533 {
534 return io_context_;
535 }
536
537 // async stop
538
540 {
541 return &async_stop_local_;
542 }
543
545 {
546 return async_stop_global_;
547 }
548
553
554 // disconnect
556 {
557 if (clock_tick)
558 clock_tick->cancel();
559 }
560
573
574 private:
575 ClientState(const ClientState &) = delete;
577
578 bool attach_called = false;
579
582
583 std::unique_ptr<AsioStopScope> stop_scope_local;
584 std::unique_ptr<AsioStopScope> stop_scope_global;
585
586 openvpn_io::io_context *io_context_ = nullptr;
587 bool io_context_owned = false;
588
589 std::atomic<bool> foreign_thread_ready{false};
590};
591}; // namespace Private
592
594{
595#ifndef OPENVPN_NORESET_TIME
596 // We keep track of time as binary milliseconds since a time base, and
597 // this can wrap after ~48 days on 32 bit systems, so it's a good idea
598 // to periodically reinitialize the base.
600#endif
601
604}
605
607{
608 try
609 {
610 // validate proto_override
611 if (!config.protoOverride.empty())
613
614 // validate IPv6 setting
615 if (!config.allowUnusedAddrFamilies.empty())
616 TriStateSetting::parse(config.allowUnusedAddrFamilies);
617
618 // parse config
620 kvl.reserve(config.contentList.size());
621 for (size_t i = 0; i < config.contentList.size(); ++i)
622 {
623 const KeyValue &kv = config.contentList[i];
624 kvl.push_back(new OptionList::KeyValue(kv.key, kv.value));
625 }
626 const ParseClientConfig cc = ParseClientConfig::parse(config.content, &kvl, options);
627
629
630#ifdef OPENVPN_DUMP_CONFIG
631 std::cout << "---------- ARGS ----------" << std::endl;
632 std::cout << options.render(Option::RENDER_PASS_FMT | Option::RENDER_NUMBER | Option::RENDER_BRACKET) << std::endl;
633 std::cout << "---------- MAP ----------" << std::endl;
634 std::cout << options.render_map() << std::endl;
635#endif
636 eval.error = cc.error();
637 eval.message = cc.message();
639 eval.profileName = cc.profileName();
640 eval.friendlyName = cc.friendlyName();
641 eval.autologin = cc.autologin();
642 eval.externalPki = cc.externalPki();
643 eval.vpnCa = cc.vpnCa();
648 eval.remoteHost = config.serverOverride.empty() ? cc.firstRemoteListItem().host : config.serverOverride;
651 eval.windowsDriver = cc.windowsDriver();
652 for (ParseClientConfig::ServerList::const_iterator i = cc.serverList().begin(); i != cc.serverList().end(); ++i)
653 {
654 ServerEntry se;
655 se.server = i->server;
656 se.friendlyName = i->friendlyName;
657 eval.serverList.push_back(std::move(se));
658 }
659 }
660 catch (const std::exception &e)
661 {
662 eval.error = true;
663 eval.message = Unicode::utf8_printable<std::string>(std::string("ERR_PROFILE_GENERIC: ") + e.what(), 256);
664 }
665}
666
668{
669 try
670 {
672
673 if (!config.compressionMode.empty())
675
676 if (eval.externalPki)
677 state->clientconf.external_pki_alias = config.externalPkiAlias;
678
679 if (!config.gremlinConfig.empty())
680 {
681#ifdef OPENVPN_GREMLIN
682 state->gremlin_config.reset(new Gremlin::Config(config.gremlinConfig));
683#else
684 throw Exception("client not built with OPENVPN_GREMLIN");
685#endif
686 }
688 if (!config.proxyHost.empty())
689 {
691 ho->set_proxy_server(config.proxyHost, config.proxyPort);
692 ho->username = config.proxyUsername;
693 ho->password = config.proxyPassword;
694 ho->allow_cleartext_auth = config.proxyAllowCleartextAuth;
696 }
697 }
698 catch (const std::exception &e)
699 {
700 eval.error = true;
701 eval.message = Unicode::utf8_printable<std::string>(e.what(), 256);
702 }
703}
704
706 : init(new InitProcess::Init())
707{
708}
709
714
719
721 bool follow_references)
722{
723 ProfileMerge pm(path,
724 "ovpn",
725 "",
729 return build_merge_config(pm);
730}
731
741
743{
745 ret.status = pm.status_string();
746 ret.basename = pm.basename();
748 {
749 ret.refPathList = pm.ref_path_list();
750 ret.profileContent = pm.profile_content();
751 }
752 else
753 {
754 ret.errorText = pm.error();
755 }
756 return ret;
757}
758
760{
761 EvalConfig eval;
762 OptionList options;
763 parse_config(config, eval, options);
764 return eval;
765}
766
767// API client submits the configuration here before calling connect()
769{
770 // parse and validate configuration file
771 EvalConfig eval;
773 if (eval.error)
774 return eval;
775
776 // handle extra settings in config
777 parse_extras(config, eval);
778 state->eval = eval;
779 return eval;
780}
781
783{
784 Status ret;
785 try
786 {
787 ClientCreds::Ptr cc = new ClientCreds();
788 cc->set_username(creds.username);
790 cc->set_password(creds.password);
793 cc->set_response(creds.response);
795 state->creds = cc;
796 }
797 catch (const std::exception &e)
798 {
799 ret.error = true;
800 ret.message = Unicode::utf8_printable<std::string>(e.what(), 256);
801 }
802 return ret;
803}
804
805OPENVPN_CLIENT_EXPORT bool OpenVPNClient::socket_protect(openvpn_io::detail::socket_type socket, std::string remote, bool ipv6)
806{
807 return true;
808}
809
811{
812 try
813 {
814 ChallengeResponse cr(cookie);
816 dc.echo = cr.get_echo();
818 dc.stateID = cr.get_state_id();
819 return true;
820 }
821 catch (const std::exception &)
822 {
823 return false;
824 }
825}
826
828{
829 // Get cert and add to options list
830 if (!req.cert.empty())
831 {
832 Option o;
833 o.push_back("cert");
834 o.push_back(req.cert);
836 }
837
838 // Get the supporting chain, if it exists, and use
839 // it for ca (if ca isn't defined), or otherwise use
840 // it for extra-certs (if ca is defined but extra-certs
841 // is not).
842 if (!req.supportingChain.empty())
843 {
844 if (!state->options.exists("ca"))
845 {
846 Option o;
847 o.push_back("ca");
850 }
851 else if (!state->options.exists("extra-certs"))
852 {
853 Option o;
854 o.push_back("extra-certs");
857 }
858 }
859}
860
862{
863#if !defined(OPENVPN_OVPNCLI_SINGLE_THREAD)
864 openvpn_io::detail::signal_blocker signal_blocker; // signals should be handled by parent thread
865#endif
866#if defined(OPENVPN_LOG_LOGTHREAD_H) && !defined(OPENVPN_LOG_LOGBASE_H)
867#ifdef OPENVPN_LOG_GLOBAL
868#error ovpn3 core logging object only supports thread-local scope
869#endif
870 Log::Context log_context(this);
871#endif
872
874
875 return do_connect();
876}
877
879{
880 Status status;
881 bool session_started = false;
882 try
883 {
885#if defined(OPENVPN_OVPNCLI_ASYNC_SETUP)
886 openvpn_io::post(*state->io_context(), [this]()
887 { do_connect_async(); });
888#else
889 connect_setup(status, session_started);
890#endif
891 connect_run();
892 return status;
893 }
894 catch (const std::exception &e)
895 {
896 if (session_started)
898 return status_from_exception(e);
899 }
900}
901
903{
904 enum StopType
905 {
906 NONE,
907 SESSION,
908 EXPLICIT,
909 };
910 StopType stop_type = NONE;
911 Status status;
912 bool session_started = false;
913 try
914 {
915 connect_setup(status, session_started);
916 }
917 catch (const std::exception &e)
918 {
919 stop_type = session_started ? SESSION : EXPLICIT;
920 status = status_from_exception(e);
921 }
922 if (status.error)
923 {
925 state->events->add_event(std::move(ev));
926 }
927 if (stop_type == SESSION)
929#ifdef OPENVPN_IO_REQUIRES_STOP
930 if (stop_type == EXPLICIT)
931 state->io_context()->stop();
932#endif
933}
934
936{
937 // set global MbedTLS debug level
938#if defined(USE_MBEDTLS) || defined(USE_MBEDTLS_APPLE_HYBRID)
939 mbedtls_debug_set_threshold(state->clientconf.sslDebugLevel); // fixme -- using a global method for this seems wrong
940#endif
941
942 // load options
945 cc.cli_stats = state->stats;
946 cc.cli_events = state->events;
947
956#if defined(USE_TUN_BUILDER)
957 cc.builder = this;
958#endif
959#if defined(OPENVPN_EXTERNAL_TUN_FACTORY)
960 cc.extern_tun_factory = this;
961#endif
962#if defined(OPENVPN_EXTERNAL_TRANSPORT_FACTORY)
963 cc.extern_transport_factory = this;
964#endif
965
966 // external PKI
967#if !defined(USE_APPLE_SSL)
969 {
970 if (!state->clientconf.external_pki_alias.empty())
971 {
975 if (!req.error)
976 {
977 cc.external_pki = this;
979 }
980 else
981 {
983 return;
984 }
985 }
986 else
987 {
988 status.error = true;
989 status.message = "Missing External PKI alias";
990 return;
991 }
992 }
993#endif
994
995#ifdef USE_OPENSSL
996 if (state->options.exists("allow-name-constraints"))
997 {
998 ClientEvent::Base::Ptr ev = new ClientEvent::UnsupportedFeature("allow-name-constraints",
999 "Always verified correctly with OpenSSL",
1000 false);
1001 state->events->add_event(std::move(ev));
1002 }
1003#endif
1004
1005 // build client options object
1006 ClientOptions::Ptr client_options = new ClientOptions(state->options, cc);
1007
1008 // configure creds in options
1009 client_options->submit_creds(state->creds);
1010
1011 // instantiate top-level client session
1012 state->session.reset(new ClientConnect(*state->io_context(), client_options));
1013
1014 // convenience clock tick
1016 {
1018 state->clock_tick->schedule();
1019 }
1020
1021 // start VPN
1022 state->session->start(); // queue reads on socket/tun
1023 session_started = true;
1024
1025 // wire up async stop
1027
1028 // prepare to start reactor
1031}
1032
1034{
1035 Status ret;
1036 ret.error = true;
1037 ret.message = Unicode::utf8_printable<std::string>(e.what(), 2048 | Unicode::UTF8_PASS_FMT);
1038
1039 // if exception is an ExceptionCode, translate the code
1040 // to return status string
1041 {
1042 const ExceptionCode *ec = dynamic_cast<const ExceptionCode *>(&e);
1043 if (ec && ec->code_defined())
1044 ret.status = Error::name(ec->code());
1045 }
1046 return ret;
1047}
1048
1055
1059
1064
1066{
1067 state->session->stop(); // On exception, stop client...
1068 state->io_context()->poll(); // and execute completion handlers.
1069}
1070
1072{
1073 ConnectionInfo ci;
1075 {
1076 MyClientEvents *events = state->events.get();
1077 if (events)
1078 events->get_connection_info(ci);
1079 }
1080 return ci;
1081}
1082
1084{
1086 {
1087 ClientCreds *cc = state->creds.get();
1088 if (cc && cc->session_id_defined())
1089 {
1090 tok.username = cc->get_username();
1091 tok.session_id = cc->get_password();
1092 return true;
1093 }
1094 }
1095 return false;
1096}
1097
1102
1104{
1105 if (req.error)
1106 {
1107 if (req.invalidAlias)
1108 {
1110 state->events->add_event(std::move(ev));
1111 }
1112
1114 state->events->add_event(std::move(ev));
1115
1116 state->stats->error(err_type);
1117 if (state->session)
1119 }
1120}
1121
1122OPENVPN_CLIENT_EXPORT bool OpenVPNClient::sign(const std::string &alias,
1123 const std::string &data,
1124 std::string &sig,
1125 const std::string &algorithm,
1126 const std::string &hashalg,
1127 const std::string &saltlen)
1128{
1130 req.alias = alias;
1131 req.data = data;
1132 req.algorithm = algorithm;
1133 req.hashalg = hashalg;
1134 req.saltlen = saltlen;
1135 external_pki_sign_request(req); // call out to derived class for RSA signature
1136 if (!req.error)
1137 {
1138 sig = req.sig;
1139 return true;
1140 }
1141 else
1142 {
1144 return false;
1145 }
1146}
1147
1152
1156
1161
1163{
1164 return MySessionStats::combined_name(index);
1165}
1166
1168{
1170 {
1171 MySessionStats *stats = state->stats.get();
1172 if (stats)
1173 {
1174 if (index == SessionStats::BYTES_IN || index == SessionStats::BYTES_OUT)
1175 stats->dco_update();
1176 return stats->combined_value(index);
1177 }
1178 }
1179 return 0;
1180}
1181
1183{
1184 std::vector<long long> sv;
1185 const size_t n = MySessionStats::combined_n();
1186 sv.reserve(n);
1188 {
1189 MySessionStats *stats = state->stats.get();
1190 if (stats)
1191 stats->dco_update();
1192 for (size_t i = 0; i < n; ++i)
1193 sv.push_back(stats ? stats->combined_value(i) : 0);
1194 }
1195 else
1196 {
1197 for (size_t i = 0; i < n; ++i)
1198 sv.push_back(0);
1199 }
1200 return sv;
1201}
1202
1204{
1207 {
1208 MySessionStats *stats = state->stats.get();
1209
1210 // The reason for the apparent inversion between in/out below is
1211 // that TUN_*_OUT stats refer to data written to tun device,
1212 // but from the perspective of tun interface, this is incoming
1213 // data. Vice versa for TUN_*_IN.
1214 if (stats)
1215 {
1216 stats->dco_update();
1217 ret.bytesOut = stats->stat_count(SessionStats::TUN_BYTES_IN);
1218 ret.bytesIn = stats->stat_count(SessionStats::TUN_BYTES_OUT);
1219 ret.packetsOut = stats->stat_count(SessionStats::TUN_PACKETS_IN);
1220 ret.packetsIn = stats->stat_count(SessionStats::TUN_PACKETS_OUT);
1221 ret.errorsOut = stats->error_count(Error::TUN_READ_ERROR);
1222 ret.errorsIn = stats->error_count(Error::TUN_WRITE_ERROR);
1223 return ret;
1224 }
1225 }
1226
1227 ret.bytesOut = 0;
1228 ret.bytesIn = 0;
1229 ret.packetsOut = 0;
1230 ret.packetsIn = 0;
1231 ret.errorsOut = 0;
1232 ret.errorsIn = 0;
1233 return ret;
1234}
1235
1237{
1239 ret.lastPacketReceived = -1; // undefined
1240
1242 {
1243 MySessionStats *stats = state->stats.get();
1244 if (stats)
1245 {
1246 stats->dco_update();
1247 ret.bytesOut = stats->stat_count(SessionStats::BYTES_OUT);
1248 ret.bytesIn = stats->stat_count(SessionStats::BYTES_IN);
1249 ret.packetsOut = stats->stat_count(SessionStats::PACKETS_OUT);
1250 ret.packetsIn = stats->stat_count(SessionStats::PACKETS_IN);
1251
1252 // calculate time since last packet received
1253 {
1254 const Time &lpr = stats->last_packet_received();
1255 if (lpr.defined())
1256 {
1257 const Time::Duration dur = Time::now() - lpr;
1258 const unsigned int delta = (unsigned int)dur.to_binary_ms();
1259 if (delta <= 60 * 60 * 24 * 1024) // only define for time periods <= 1 day
1260 ret.lastPacketReceived = delta;
1261 }
1262 }
1263 return ret;
1264 }
1265 }
1266
1267 ret.bytesOut = 0;
1268 ret.bytesIn = 0;
1269 ret.packetsOut = 0;
1270 ret.packetsIn = 0;
1271 return ret;
1272}
1273
1279
1280OPENVPN_CLIENT_EXPORT void OpenVPNClient::pause(const std::string &reason)
1281{
1283 {
1284 ClientConnect *session = state->session.get();
1285 if (session)
1286 session->thread_safe_pause(reason);
1287 }
1288}
1289
1291{
1293 {
1294 ClientConnect *session = state->session.get();
1295 if (session)
1296 session->thread_safe_resume();
1297 }
1298}
1299
1301{
1303 {
1304 ClientConnect *session = state->session.get();
1305 if (session)
1306 session->thread_safe_reconnect(seconds);
1307 }
1308}
1309
1311{
1313 {
1314 ClientConnect *session = state->session.get();
1315 if (session)
1316 session->thread_safe_post_cc_msg(msg);
1317 }
1318}
1319
1320OPENVPN_CLIENT_EXPORT void OpenVPNClient::send_app_control_channel_msg(const std::string &protocol, const std::string &msg)
1321{
1323 {
1324 ClientConnect *session = state->session.get();
1325 if (session)
1327 }
1328}
1329
1330static SSLLib::SSLAPI::Config::Ptr setup_certcheck_ssl_config(const std::string &client_cert,
1331 const std::string &extra_certs,
1332 const std::optional<const std::string> &ca)
1333{
1334 SSLLib::SSLAPI::Config::Ptr config = new SSLLib::SSLAPI::Config;
1335 config->set_frame(new Frame(Frame::Context(128, 4096, 4096 - 128, 0, 16, 0)));
1336 config->set_mode(Mode(Mode::CLIENT));
1337 config->load_cert(client_cert, extra_certs);
1338 unsigned int flags = SSLConst::LOG_VERIFY_STATUS;
1339
1340 if (ca)
1341 config->load_ca(*ca, false);
1342 else
1344
1345 config->set_flags(flags);
1346
1347 return config;
1348}
1349
1350OPENVPN_CLIENT_EXPORT void OpenVPNClient::start_cert_check(const std::string &client_cert,
1351 const std::string &clientkey,
1352 const std::optional<const std::string> &ca)
1353{
1355 {
1356 ClientConnect *session = state->session.get();
1357 if (session)
1358 {
1359 SSLLib::SSLAPI::Config::Ptr config = setup_certcheck_ssl_config(client_cert, "", ca);
1360 config->load_private_key(clientkey);
1361
1362 session->start_acc_certcheck(config);
1363 }
1364 }
1365}
1366
1367OPENVPN_CLIENT_EXPORT void OpenVPNClient::start_cert_check_epki(const std::string &alias, const std::optional<const std::string> &ca)
1368{
1370 {
1371 ClientConnect *session = state->session.get();
1372 if (session)
1373 {
1375 req.alias = alias;
1377
1378 if (req.error)
1379 {
1381 return;
1382 }
1383
1384 SSLLib::SSLAPI::Config::Ptr config = setup_certcheck_ssl_config(req.cert, req.supportingChain, ca);
1385
1386 config->set_external_pki_callback(this, alias);
1387
1388
1389 session->start_acc_certcheck(config);
1390 }
1391 }
1392}
1393
1397
1402
1407
1409{
1410 return openvpn_copyright;
1411}
1412
1414{
1415 std::string ret = platform_string();
1416#ifdef PRIVATE_TUNNEL_PROXY
1417 ret += " PT_PROXY";
1418#endif
1419#ifdef ENABLE_KOVPN
1420 ret += " KOVPN";
1421#elif defined(ENABLE_OVPNDCO) || defined(ENABLE_OVPNDCOWIN)
1422 ret += " OVPN-DCO";
1423#endif
1424#ifdef OPENVPN_GREMLIN
1425 ret += " GREMLIN";
1426#endif
1427#ifdef OPENVPN_DEBUG
1428 ret += " built on " __DATE__ " " __TIME__;
1429#endif
1430 return ret;
1431}
1432
1437} // namespace ClientAPI
1438} // namespace openvpn
#define OPENVPN_ASYNC_HANDLER
Definition bigmutex.hpp:36
void error(const size_t err_type, const std::string *text=nullptr) override
Definition ovpnagent.cpp:75
std::size_t expires_after(const Time::Duration &d)
Definition asiotimer.hpp:69
bool get_echo() const
Definition cr.hpp:215
const std::string & get_state_id() const
Definition cr.hpp:207
bool get_response_required() const
Definition cr.hpp:219
const std::string & get_challenge_text() const
Definition cr.hpp:223
void get_connection_info(ConnectionInfo &ci)
Definition ovpncli.cpp:220
RCPtr< MyClientEvents > Ptr
Definition ovpncli.cpp:182
void add_event(ClientEvent::Base::Ptr event) override
Definition ovpncli.cpp:189
ClientEvent::Base::Ptr last_connected
Definition ovpncli.cpp:254
MyClientEvents(OpenVPNClient *parent_arg)
Definition ovpncli.cpp:184
MyClockTick(openvpn_io::io_context &io_context, OpenVPNClient *parent_arg, const unsigned int ms)
Definition ovpncli.cpp:386
const Time::Duration period
Definition ovpncli.cpp:424
bool pause_on_connection_timeout() override
Definition ovpncli.cpp:319
void set_parent(OpenVPNClient *parent_arg)
Definition ovpncli.cpp:309
void set_parent(OpenVPNClient *parent_arg)
Definition ovpncli.cpp:334
RemoteList::Item::Ptr get() override
Definition ovpncli.cpp:344
count_t errors[Error::N_ERRORS]
Definition ovpncli.cpp:176
void error(const size_t err, const std::string *text=nullptr) override
Definition ovpncli.cpp:160
MySessionStats(OpenVPNClient *parent_arg)
Definition ovpncli.cpp:105
count_t error_count(const size_t index) const
Definition ovpncli.cpp:150
count_t combined_value(const size_t index) const
Definition ovpncli.cpp:132
RCPtr< MySessionStats > Ptr
Definition ovpncli.cpp:103
static std::string combined_name(const size_t index)
Definition ovpncli.cpp:119
count_t stat_count(const size_t index) const
Definition ovpncli.cpp:145
bool socket_protect(openvpn_io::detail::socket_type socket, IP::Addr endpoint) override
Definition ovpncli.cpp:275
void set_rg_local(bool rg_local_arg)
Definition ovpncli.cpp:270
void set_parent(OpenVPNClient *parent_arg)
Definition ovpncli.cpp:265
EvalConfig eval_config(const Config &config)
Definition ovpncli.cpp:759
MergeConfig merge_config(const std::string &path, bool follow_references)
Definition ovpncli.cpp:720
static void parse_config(const Config &, EvalConfig &, OptionList &)
Definition ovpncli.cpp:606
static bool parse_dynamic_challenge(const std::string &cookie, DynamicChallenge &dc)
Definition ovpncli.cpp:810
MergeConfig merge_config_string(const std::string &config_content)
Definition ovpncli.cpp:732
static MergeConfig build_merge_config(const ProfileMerge &)
Definition ovpncli.cpp:742
void send_app_control_channel_msg(const std::string &protocol, const std::string &msg)
Definition ovpncli.cpp:1320
void external_pki_error(const ExternalPKIRequestBase &, const size_t)
Definition ovpncli.cpp:1103
virtual void external_pki_sign_request(ExternalPKISignRequest &)=0
TransportStats transport_stats() const
Definition ovpncli.cpp:1236
void post_cc_msg(const std::string &msg)
Definition ovpncli.cpp:1310
virtual void event(const Event &)=0
void start_cert_check_epki(const std::string &alias, const std::optional< const std::string > &ca)
Start up the cert check handshake using the given epki_alias string.
Definition ovpncli.cpp:1367
bool session_token(SessionToken &tok)
Definition ovpncli.cpp:1083
static Status status_from_exception(const std::exception &)
Definition ovpncli.cpp:1033
virtual void remote_override(RemoteOverride &)
Definition ovpncli.cpp:1153
InterfaceStats tun_stats() const
Definition ovpncli.cpp:1203
std::vector< long long > stats_bundle() const
Definition ovpncli.cpp:1182
void start_cert_check(const std::string &client_cert, const std::string &clientkey, const std::optional< const std::string > &ca=std::nullopt)
Start up the cert check handshake using the given certs and key.
Definition ovpncli.cpp:1350
void process_epki_cert_chain(const ExternalPKICertRequest &)
Definition ovpncli.cpp:827
Status provide_creds(const ProvideCreds &)
Definition ovpncli.cpp:782
static std::string stats_name(int index)
Definition ovpncli.cpp:1162
virtual bool pause_on_connection_timeout()=0
void connect_setup(Status &, bool &)
Definition ovpncli.cpp:935
long long stats_value(int index) const
Definition ovpncli.cpp:1167
virtual void external_pki_cert_request(ExternalPKICertRequest &)=0
virtual bool socket_protect(openvpn_io::detail::socket_type socket, std::string remote, bool ipv6)
Definition ovpncli.cpp:805
Private::ClientState * state
Definition ovpncli.hpp:759
void pause(const std::string &reason)
Definition ovpncli.cpp:1280
EvalConfig eval_config(const Config &)
Definition ovpncli.cpp:768
bool sign(const std::string &alias, const std::string &data, std::string &sig, const std::string &algorithm, const std::string &hashalg, const std::string &saltlen) override
Definition ovpncli.cpp:1122
virtual void acc_event(const AppCustomControlMessageEvent &)=0
void parse_extras(const Config &, EvalConfig &)
Definition ovpncli.cpp:667
std::unique_ptr< AsioStopScope > stop_scope_global
Definition ovpncli.cpp:584
ProtoContextCompressionOptions::Ptr proto_context_options
Definition ovpncli.cpp:446
HTTPProxyTransport::Options::Ptr http_proxy_options
Definition ovpncli.cpp:448
void attach(OpenVPNClient *parent, openvpn_io::io_context *io_context, Stop *async_stop_global)
Definition ovpncli.cpp:457
ClientState & operator=(const ClientState &)=delete
std::unique_ptr< AsioStopScope > stop_scope_local
Definition ovpncli.cpp:583
openvpn_io::io_context * io_context_
Definition ovpncli.cpp:586
openvpn_io::io_context * io_context()
Definition ovpncli.cpp:532
ClientState(const ClientState &)=delete
std::unique_ptr< MyClockTick > clock_tick
Definition ovpncli.cpp:441
void thread_safe_post_cc_msg(std::string msg)
void thread_safe_reconnect(int seconds)
void start_acc_certcheck(ArgsT &&...args)
Passes the given arguments through to start_acc_certcheck.
void thread_safe_pause(const std::string &reason)
void thread_safe_send_app_control_channel_msg(std::string protocol, std::string msg)
void set_http_proxy_username(const std::string &username)
Definition clicreds.hpp:51
void set_dynamic_challenge_cookie(const std::string &cookie, const std::string &username)
Definition clicreds.hpp:70
std::string get_password() const
Definition clicreds.hpp:105
void set_username(const std::string &username_arg)
Definition clicreds.hpp:37
void set_http_proxy_password(const std::string &password)
Definition clicreds.hpp:56
std::string get_username() const
Definition clicreds.hpp:95
void set_response(const std::string &response_arg)
Definition clicreds.hpp:61
bool session_id_defined() const
Definition clicreds.hpp:150
void set_password(const std::string &password_arg)
Definition clicreds.hpp:42
void save_username_for_session_id()
Definition clicreds.hpp:169
static std::tuple< bool, std::string > check_dco_compatibility(const ClientAPI::ConfigCommon &config, const OptionList &opt)
Definition cliopt.hpp:599
void submit_creds(const ClientCreds::Ptr &creds_arg)
Definition cliopt.hpp:1183
Error::Type code() const
Definition excode.hpp:54
bool code_defined() const
Definition excode.hpp:63
std::string to_string() const
Definition ip.hpp:528
bool is_ipv6() const
Definition ip.hpp:949
std::string render_map() const
Definition options.hpp:1497
void add_item(const Option &opt)
Definition options.hpp:1551
std::string render(const unsigned int flags) const
Definition options.hpp:1465
bool exists(const std::string &name) const
Definition options.hpp:1325
void push_back(const std::string &item)
Definition options.hpp:335
static ParseClientConfig parse(const std::string &content)
const std::string & windowsDriver() const
const std::string & profileName() const
const std::string & friendlyName() const
const RemoteItem & firstRemoteListItem() const
std::string vpnCa() const
const std::string & staticChallenge() const
const std::string & message() const
const std::string & userlockedUsername() const
const ServerList & serverList() const
bool privateKeyPasswordRequired() const
const std::string & basename() const
Definition merge.hpp:77
const std::string & error() const
Definition merge.hpp:71
const char * status_string() const
Definition merge.hpp:95
const std::string & profile_content() const
Definition merge.hpp:83
const std::vector< std::string > & ref_path_list() const
Definition merge.hpp:89
Status status() const
Definition merge.hpp:67
static Protocol parse(const std::string &str, const AllowSuffix allow_suffix, const char *title=nullptr)
Definition protocol.hpp:157
The smart pointer class.
Definition rc.hpp:119
void reset() noexcept
Points this RCPtr<T> to nullptr safely.
Definition rc.hpp:290
T * get() const noexcept
Returns the raw pointer to the object T, or nullptr.
Definition rc.hpp:321
count_t get_stat_fast(const size_t type) const
const Time & last_packet_received() const
void session_stats_set_verbose(const bool v)
static const char * stat_name(const size_t type)
count_t get_stat(const size_t type) const
void stop()
Definition stop.hpp:85
static TimeType now()
Definition time.hpp:305
static void reset_base_conditional()
Definition time.hpp:414
bool defined() const
Definition time.hpp:283
static TriStateSetting parse(const std::string &str)
static bool add_bypass_route(IP::Addr endpoint)
Definition cmdagent.hpp:50
static bool add_bypass_route(IP::Addr endpoint)
Definition cmdagent.hpp:47
#define OPENVPN_SIMPLE_EXCEPTION(C)
Definition exception.hpp:75
#define OPENVPN_LOG(args)
static SSLLib::SSLAPI::Config::Ptr setup_certcheck_ssl_config(const std::string &client_cert, const std::string &extra_certs, const std::optional< const std::string > &ca)
Definition ovpncli.cpp:1330
const char * name(const size_t type)
Definition error.hpp:117
void validate_host(const std::string &host, const std::string &title)
Definition hostport.hpp:93
void validate_port(const std::string &port, const std::string &title, unsigned int *value=nullptr)
Definition hostport.hpp:34
std::string crypto_self_test()
Definition selftest.hpp:37
Support deferred server-side state creation when client connects.
Definition ovpncli.cpp:95
std::string platform_string()
long long count_t
Definition count.hpp:16
#define OPENVPN_CLIENT_EXPORT
Definition ovpncli.cpp:35
Struct containing configuration details parsed from an OpenVPN configuration file.
Definition ovpncli.hpp:55
std::vector< ServerEntry > serverList
Definition ovpncli.hpp:102
std::string external_pki_alias
Definition cliopt.hpp:140
void import_client_settings(const ClientAPI::Config &config)
Definition cliopt.hpp:115
ReconnectNotify * reconnect_notify
Definition cliopt.hpp:180
ClientEvent::Queue::Ptr cli_events
Definition cliopt.hpp:161
ClientConfigParsed clientconf
Definition cliopt.hpp:157
PeerInfo::Set::Ptr extra_peer_info
Definition cliopt.hpp:168
RemoteList::RemoteOverride * remote_override
Definition cliopt.hpp:181
ExternalPKIBase * external_pki
Definition cliopt.hpp:178
SessionStats::Ptr cli_stats
Definition cliopt.hpp:160
ProtoContextCompressionOptions::Ptr proto_context_options
Definition cliopt.hpp:162
HTTPProxyTransport::Options::Ptr http_proxy_options
Definition cliopt.hpp:163
SocketProtect * socket_protect
Definition cliopt.hpp:179
Scoped RAII for the global_log pointer.
static Ptr new_from_foreign_set(const SET &other)
Definition peerinfo.hpp:59
void parse_compression_mode(const std::string &mode)
reroute_gw flags
remote_address ipv6
std::string ret
static const char config[]
#define msg(flags,...)