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
93
94// copyright
96
97namespace openvpn {
98namespace ClientAPI {
99
101
103{
104 public:
106
108 : parent(parent_arg)
109 {
110 std::memset(errors, 0, sizeof(errors));
111#ifdef OPENVPN_DEBUG_VERBOSE_ERRORS
113#endif
114 }
115
116 static constexpr size_t combined_n()
117 {
118 return static_cast<size_t>(N_STATS) + static_cast<size_t>(Error::N_ERRORS);
119 }
120
121 static std::string combined_name(const size_t index)
122 {
123 if (index < combined_n())
124 {
125 if (index < N_STATS)
126 return stat_name(index);
127 else
128 return Error::name(index - N_STATS);
129 }
130 else
131 return "";
132 }
133
134 count_t combined_value(const size_t index) const
135 {
136 if (index < combined_n())
137 {
138 if (index < N_STATS)
139 return get_stat(index);
140 else
141 return errors[index - N_STATS];
142 }
143 else
144 return 0;
145 }
146
147 count_t stat_count(const size_t index) const
148 {
149 return get_stat_fast(index);
150 }
151
152 count_t error_count(const size_t index) const
153 {
154 return errors[index];
155 }
156
158 {
159 parent = nullptr;
160 }
161
162 void error(const size_t err, const std::string *text = nullptr) override
163 {
164 if (err < Error::N_ERRORS)
165 {
166#ifdef OPENVPN_DEBUG_VERBOSE_ERRORS
167 if (text)
168 OPENVPN_LOG("ERROR: " << Error::name(err) << " : " << *text);
169 else
170 OPENVPN_LOG("ERROR: " << Error::name(err));
171#endif
172 ++errors[err];
173 }
174 }
175
176 private:
179};
180
182{
183 public:
185
187 : parent(parent_arg)
188 {
189 }
190
192 {
193 if (parent)
194 {
195 if (event->id() == ClientEvent::CUSTOM_CONTROL)
196 {
199 ev.protocol = accm->protocol;
200 ev.payload = accm->custommessage;
201 parent->acc_event(ev);
202 }
203 else
204 {
205 Event ev;
206 ev.name = event->name();
207 ev.info = event->render();
208 ev.error = event->is_error();
209 ev.fatal = event->is_fatal();
210
211 // save connected event
212 if (event->id() == ClientEvent::CONNECTED)
213 last_connected = std::move(event);
214 else if (event->id() == ClientEvent::DISCONNECTED)
216
217 parent->event(ev);
218 }
219 }
220 }
221
223 {
225 if (connected)
226 {
227 const ClientEvent::Connected *c = connected->connected_cast();
228 if (c)
229 {
230 ci.user = c->user;
231 ci.serverHost = c->server_host;
232 ci.serverPort = c->server_port;
234 ci.serverIp = c->server_ip;
235 ci.vpnIp4 = c->vpn_ip4;
236 ci.vpnIp6 = c->vpn_ip6;
237 ci.gw4 = c->vpn_gw4;
238 ci.gw6 = c->vpn_gw6;
239 ci.clientIp = c->client_ip;
240 ci.tunName = c->tun_name;
241 ci.defined = true;
242 ci.vpnMtu = c->vpn_mtu;
243 return;
244 }
245 }
246 ci.defined = false;
247 }
248
250 {
251 parent = nullptr;
252 }
253
254 private:
257};
258
260{
261 public:
263 : parent(nullptr)
264 {
265 }
266
267 void set_parent(OpenVPNClient *parent_arg)
268 {
269 parent = parent_arg;
270 }
271
272 void set_rg_local(bool rg_local_arg)
273 {
274 rg_local = rg_local_arg;
275 }
276
277 bool socket_protect(openvpn_io::detail::socket_type socket, IP::Addr endpoint) override
278 {
279 if (parent)
280 {
281#if defined(OPENVPN_COMMAND_AGENT) && defined(OPENVPN_PLATFORM_WIN)
282 return rg_local ? true : WinCommandAgent::add_bypass_route(endpoint);
283#elif defined(OPENVPN_COMMAND_AGENT) && defined(OPENVPN_PLATFORM_MAC)
284 return rg_local ? true : UnixCommandAgent::add_bypass_route(endpoint);
285#else
286 return parent->socket_protect(socket, endpoint.to_string(), endpoint.is_ipv6());
287#endif
288 }
289 else
290 return true;
291 }
292
294 {
295 parent = nullptr;
296 }
297
298 private:
300 bool rg_local = false; // do not add bypass route if true
301};
302
304{
305 public:
307 : parent(nullptr)
308 {
309 }
310
311 void set_parent(OpenVPNClient *parent_arg)
312 {
313 parent = parent_arg;
314 }
315
317 {
318 parent = nullptr;
319 }
320
322 {
323 if (parent)
325 else
326 return false;
327 }
328
329 private:
331};
332
334{
335 public:
336 void set_parent(OpenVPNClient *parent_arg)
337 {
338 parent = parent_arg;
339 }
340
342 {
343 parent = nullptr;
344 }
345
347 {
348 if (parent)
349 {
350 const std::string title = "remote-override";
352 try
353 {
355 }
356 catch (const std::exception &e)
357 {
358 ro.error = e.what();
359 }
361 if (ro.error.empty())
362 {
363 if (!ro.ip.empty())
364 ri->set_ip_addr(IP::Addr(ro.ip, title));
365 if (ro.host.empty())
366 ro.host = ro.ip;
367 HostPort::validate_host(ro.host, title);
368 HostPort::validate_port(ro.port, title);
369 ri->server_host = std::move(ro.host);
370 ri->server_port = std::move(ro.port);
371 ri->transport_protocol = Protocol::parse(ro.proto, Protocol::CLIENT_SUFFIX, title.c_str());
372 }
373 else
374 throw Exception("remote override exception: " + ro.error);
375 return ri;
376 }
377 else
378 return RemoteList::Item::Ptr();
379 }
380
381 private:
383};
384
386{
387 public:
388 MyClockTick(openvpn_io::io_context &io_context,
389 OpenVPNClient *parent_arg,
390 const unsigned int ms)
391 : timer(io_context),
392 parent(parent_arg),
393 period(Time::Duration::milliseconds(ms))
394 {
395 }
396
397 void cancel()
398 {
399 timer.cancel();
400 }
401
403 {
404 parent = nullptr;
405 }
406
407 void schedule()
408 {
410 timer.async_wait([this](const openvpn_io::error_code &error)
411 {
412 if (!parent || error)
413 return;
414 try {
416 }
417 catch (...)
418 {
419 }
420 schedule(); });
421 }
422
423 private:
426 const Time::Duration period;
427};
428
429namespace Private {
431{
432 public:
433 // state objects
443 std::unique_ptr<MyClockTick> clock_tick;
444
445 // extra settings submitted by API client
447
451
452#ifdef OPENVPN_GREMLIN
453 Gremlin::Config::Ptr gremlin_config;
454#endif
455 // Ensure that init is called
457
458 template <typename SESSION_STATS, typename CLIENT_EVENTS>
459 void attach(OpenVPNClient *parent,
460 openvpn_io::io_context *io_context,
462 {
463 // only one attachment per instantiation allowed
464 if (attach_called)
465 throw Exception("ClientState::attach() can only be called once per ClientState instantiation");
466 attach_called = true;
467
468 // async stop
470
471 // io_context
472 if (io_context)
474 else
475 {
476 io_context_ = new openvpn_io::io_context(1); // concurrency hint=1
477 io_context_owned = true;
478 }
479
480 // client stats
481 stats.reset(new SESSION_STATS(parent));
482
483 // client events
484 events.reset(new CLIENT_EVENTS(parent));
485
486 // socket protect
489 socket_protect.set_rg_local(rg_flags.redirect_gateway_local());
490
491 // reconnect notifications
493
494 // remote override
496 }
497
499 {
500 }
501
503 {
504 stop_scope_local.reset();
505 stop_scope_global.reset();
509 if (clock_tick)
510 clock_tick->detach_from_parent();
511 if (stats)
512 stats->detach_from_parent();
513 if (events)
514 events->detach_from_parent();
515 session.reset();
517 delete io_context_;
518 }
519
520 // foreign thread access
521
523 {
524 foreign_thread_ready.store(true, std::memory_order_release);
525 }
526
528 {
529 return foreign_thread_ready.load(std::memory_order_acquire);
530 }
531
532 // io_context
533
534 openvpn_io::io_context *io_context()
535 {
536 return io_context_;
537 }
538
539 // async stop
540
542 {
543 return &async_stop_local_;
544 }
545
547 {
548 return async_stop_global_;
549 }
550
555
556 // disconnect
558 {
559 if (clock_tick)
560 clock_tick->cancel();
561 }
562
575
576 private:
577 ClientState(const ClientState &) = delete;
579
580 bool attach_called = false;
581
584
585 std::unique_ptr<AsioStopScope> stop_scope_local;
586 std::unique_ptr<AsioStopScope> stop_scope_global;
587
588 openvpn_io::io_context *io_context_ = nullptr;
589 bool io_context_owned = false;
590
591 std::atomic<bool> foreign_thread_ready{false};
592};
593}; // namespace Private
594
596{
597#ifndef OPENVPN_NORESET_TIME
598 // We keep track of time as binary milliseconds since a time base, and
599 // this can wrap after ~48 days on 32 bit systems, so it's a good idea
600 // to periodically reinitialize the base.
602#endif
603
606}
607
609{
610 try
611 {
612 // validate proto_override
613 if (!config.protoOverride.empty())
615
616 // validate IPv6 setting
617 if (!config.allowUnusedAddrFamilies.empty())
618 TriStateSetting::parse(config.allowUnusedAddrFamilies);
619
620 // parse config
622 kvl.reserve(config.contentList.size());
623 for (size_t i = 0; i < config.contentList.size(); ++i)
624 {
625 const KeyValue &kv = config.contentList[i];
626 kvl.push_back(new OptionList::KeyValue(kv.key, kv.value));
627 }
628 const ParseClientConfig cc = ParseClientConfig::parse(config.content, &kvl, options);
629
631
632#ifdef OPENVPN_DUMP_CONFIG
633 std::cout << "---------- ARGS ----------" << std::endl;
634 std::cout << options.render(Option::RENDER_PASS_FMT | Option::RENDER_NUMBER | Option::RENDER_BRACKET) << std::endl;
635 std::cout << "---------- MAP ----------" << std::endl;
636 std::cout << options.render_map() << std::endl;
637#endif
638 eval.error = cc.error();
639 eval.message = cc.message();
641 eval.profileName = cc.profileName();
642 eval.friendlyName = cc.friendlyName();
643 eval.autologin = cc.autologin();
644 eval.externalPki = cc.externalPki();
645 eval.vpnCa = cc.vpnCa();
650 eval.remoteHost = config.serverOverride.empty() ? cc.firstRemoteListItem().host : config.serverOverride;
653 eval.windowsDriver = cc.windowsDriver();
654 for (ParseClientConfig::ServerList::const_iterator i = cc.serverList().begin(); i != cc.serverList().end(); ++i)
655 {
656 ServerEntry se;
657 se.server = i->server;
658 se.friendlyName = i->friendlyName;
659 eval.serverList.push_back(std::move(se));
660 }
661 }
662 catch (const std::exception &e)
663 {
664 eval.error = true;
665 eval.message = Unicode::utf8_printable<std::string>(std::string("ERR_PROFILE_GENERIC: ") + e.what(), 256);
666 }
667}
668
670{
671 try
672 {
674
675 if (!config.compressionMode.empty())
677
678 if (eval.externalPki)
679 state->clientconf.external_pki_alias = config.externalPkiAlias;
680
681 if (!config.gremlinConfig.empty())
682 {
683#ifdef OPENVPN_GREMLIN
684 state->gremlin_config.reset(new Gremlin::Config(config.gremlinConfig));
685#else
686 throw Exception("client not built with OPENVPN_GREMLIN");
687#endif
688 }
690 if (!config.proxyHost.empty())
691 {
693 ho->set_proxy_server(config.proxyHost, config.proxyPort);
694 ho->username = config.proxyUsername;
695 ho->password = config.proxyPassword;
696 ho->allow_cleartext_auth = config.proxyAllowCleartextAuth;
698 }
699 }
700 catch (const std::exception &e)
701 {
702 eval.error = true;
703 eval.message = Unicode::utf8_printable<std::string>(e.what(), 256);
704 }
705}
706
708 : init(new InitProcess::Init())
709{
710}
711
716
721
723 bool follow_references)
724{
725 ProfileMerge pm(path,
726 "ovpn",
727 "",
731 return build_merge_config(pm);
732}
733
743
745{
747 ret.status = pm.status_string();
748 ret.basename = pm.basename();
750 {
751 ret.refPathList = pm.ref_path_list();
752 ret.profileContent = pm.profile_content();
753 }
754 else
755 {
756 ret.errorText = pm.error();
757 }
758 return ret;
759}
760
762{
763 EvalConfig eval;
764 OptionList options;
765 parse_config(config, eval, options);
766 return eval;
767}
768
769// API client submits the configuration here before calling connect()
771{
772 // parse and validate configuration file
773 EvalConfig eval;
775 if (eval.error)
776 return eval;
777
778 // handle extra settings in config
779 parse_extras(config, eval);
780 state->eval = eval;
781 return eval;
782}
783
785{
786 Status ret;
787 try
788 {
789 ClientCreds::Ptr cc = new ClientCreds();
790 cc->set_username(creds.username);
792 cc->set_password(creds.password);
795 cc->set_response(creds.response);
797 state->creds = cc;
798 }
799 catch (const std::exception &e)
800 {
801 ret.error = true;
802 ret.message = Unicode::utf8_printable<std::string>(e.what(), 256);
803 }
804 return ret;
805}
806
807OPENVPN_CLIENT_EXPORT bool OpenVPNClient::socket_protect(openvpn_io::detail::socket_type socket, std::string remote, bool ipv6)
808{
809 return true;
810}
811
813{
814 try
815 {
816 ChallengeResponse cr(cookie);
818 dc.echo = cr.get_echo();
820 dc.stateID = cr.get_state_id();
821 return true;
822 }
823 catch (const std::exception &)
824 {
825 return false;
826 }
827}
828
830{
831 // Get cert and add to options list
832 if (!req.cert.empty())
833 {
834 Option o;
835 o.push_back("cert");
836 o.push_back(req.cert);
838 }
839
840 // Get the supporting chain, if it exists, and use
841 // it for ca (if ca isn't defined), or otherwise use
842 // it for extra-certs (if ca is defined but extra-certs
843 // is not).
844 if (!req.supportingChain.empty())
845 {
846 if (!state->options.exists("ca"))
847 {
848 Option o;
849 o.push_back("ca");
852 }
853 else if (!state->options.exists("extra-certs"))
854 {
855 Option o;
856 o.push_back("extra-certs");
859 }
860 }
861}
862
864{
865#if !defined(OPENVPN_OVPNCLI_SINGLE_THREAD)
866 openvpn_io::detail::signal_blocker signal_blocker; // signals should be handled by parent thread
867#endif
868#if defined(OPENVPN_LOG_LOGTHREAD_H) && !defined(OPENVPN_LOG_LOGBASE_H)
869#ifdef OPENVPN_LOG_GLOBAL
870#error ovpn3 core logging object only supports thread-local scope
871#endif
872 Log::Context log_context(this);
873#endif
874
876
877 return do_connect();
878}
879
881{
882 Status status;
883 bool session_started = false;
884 try
885 {
887#if defined(OPENVPN_OVPNCLI_ASYNC_SETUP)
888 openvpn_io::post(*state->io_context(), [this]()
889 { do_connect_async(); });
890#else
891 connect_setup(status, session_started);
892#endif
893 connect_run();
894 return status;
895 }
896 catch (const std::exception &e)
897 {
898 if (session_started)
900 return status_from_exception(e);
901 }
902}
903
905{
906 enum StopType
907 {
908 NONE,
909 SESSION,
910 EXPLICIT,
911 };
912 StopType stop_type = NONE;
913 Status status;
914 bool session_started = false;
915 try
916 {
917 connect_setup(status, session_started);
918 }
919 catch (const std::exception &e)
920 {
921 stop_type = session_started ? SESSION : EXPLICIT;
922 status = status_from_exception(e);
923 }
924 if (status.error)
925 {
927 state->events->add_event(std::move(ev));
928 }
929 if (stop_type == SESSION)
931#ifdef OPENVPN_IO_REQUIRES_STOP
932 if (stop_type == EXPLICIT)
933 state->io_context()->stop();
934#endif
935}
936
938{
939 // set global MbedTLS debug level
940#if defined(USE_MBEDTLS) || defined(USE_MBEDTLS_APPLE_HYBRID)
941 mbedtls_debug_set_threshold(state->clientconf.sslDebugLevel); // fixme -- using a global method for this seems wrong
942#endif
943
944 // load options
947 cc.cli_stats = state->stats;
948 cc.cli_events = state->events;
949
958#if defined(USE_TUN_BUILDER)
959 cc.builder = this;
960#endif
961#if defined(OPENVPN_EXTERNAL_TUN_FACTORY)
962 cc.extern_tun_factory = this;
963#endif
964#if defined(OPENVPN_EXTERNAL_TRANSPORT_FACTORY)
965 cc.extern_transport_factory = this;
966#endif
967
968 // external PKI
969#if !defined(USE_APPLE_SSL)
971 {
972 if (!state->clientconf.external_pki_alias.empty())
973 {
977 if (!req.error)
978 {
979 cc.external_pki = this;
981 }
982 else
983 {
985 return;
986 }
987 }
988 else
989 {
990 status.error = true;
991 status.message = "Missing External PKI alias";
992 return;
993 }
994 }
995#endif
996
997#ifdef USE_OPENSSL
998 if (state->options.exists("allow-name-constraints"))
999 {
1000 ClientEvent::Base::Ptr ev = new ClientEvent::UnsupportedFeature("allow-name-constraints",
1001 "Always verified correctly with OpenSSL",
1002 false);
1003 state->events->add_event(std::move(ev));
1004 }
1005#endif
1006
1007 // build client options object
1008 ClientOptions::Ptr client_options = new ClientOptions(state->options, cc);
1009
1010 // configure creds in options
1011 client_options->submit_creds(state->creds);
1012
1013 // instantiate top-level client session
1014 state->session.reset(new ClientConnect(*state->io_context(), client_options));
1015
1016 // convenience clock tick
1018 {
1020 state->clock_tick->schedule();
1021 }
1022
1023 // start VPN
1024 state->session->start(); // queue reads on socket/tun
1025 session_started = true;
1026
1027 // wire up async stop
1029
1030 // prepare to start reactor
1033}
1034
1036{
1037 Status ret;
1038 ret.error = true;
1039 ret.message = Unicode::utf8_printable<std::string>(e.what(), 2048 | Unicode::UTF8_PASS_FMT);
1040
1041 // if exception is an ExceptionCode, translate the code
1042 // to return status string
1043 {
1044 const ExceptionCode *ec = dynamic_cast<const ExceptionCode *>(&e);
1045 if (ec && ec->code_defined())
1046 ret.status = Error::name(ec->code());
1047 }
1048 return ret;
1049}
1050
1057
1061
1066
1068{
1069 state->session->stop(); // On exception, stop client...
1070 state->io_context()->poll(); // and execute completion handlers.
1071}
1072
1074{
1075 ConnectionInfo ci;
1077 {
1078 MyClientEvents *events = state->events.get();
1079 if (events)
1080 events->get_connection_info(ci);
1081 }
1082 return ci;
1083}
1084
1086{
1088 {
1089 ClientCreds *cc = state->creds.get();
1090 if (cc && cc->session_id_defined())
1091 {
1092 tok.username = cc->get_username();
1093 tok.session_id = cc->get_password();
1094 return true;
1095 }
1096 }
1097 return false;
1098}
1099
1104
1106{
1107 if (req.error)
1108 {
1109 if (req.invalidAlias)
1110 {
1112 state->events->add_event(std::move(ev));
1113 }
1114
1116 state->events->add_event(std::move(ev));
1117
1118 state->stats->error(err_type);
1119 if (state->session)
1121 }
1122}
1123
1124OPENVPN_CLIENT_EXPORT bool OpenVPNClient::sign(const std::string &alias,
1125 const std::string &data,
1126 std::string &sig,
1127 const std::string &algorithm,
1128 const std::string &hashalg,
1129 const std::string &saltlen)
1130{
1132 req.alias = alias;
1133 req.data = data;
1134 req.algorithm = algorithm;
1135 req.hashalg = hashalg;
1136 req.saltlen = saltlen;
1137 external_pki_sign_request(req); // call out to derived class for RSA signature
1138 if (!req.error)
1139 {
1140 sig = req.sig;
1141 return true;
1142 }
1143 else
1144 {
1146 return false;
1147 }
1148}
1149
1154
1158
1163
1165{
1166 return MySessionStats::combined_name(index);
1167}
1168
1170{
1172 {
1173 MySessionStats *stats = state->stats.get();
1174 if (stats)
1175 {
1176 if (index == SessionStats::BYTES_IN || index == SessionStats::BYTES_OUT)
1177 stats->dco_update();
1178 return stats->combined_value(index);
1179 }
1180 }
1181 return 0;
1182}
1183
1185{
1186 std::vector<long long> sv;
1187 constexpr size_t n = MySessionStats::combined_n();
1188 sv.reserve(n);
1190 {
1191 MySessionStats *stats = state->stats.get();
1192 if (stats)
1193 stats->dco_update();
1194 for (size_t i = 0; i < n; ++i)
1195 sv.push_back(stats ? stats->combined_value(i) : 0);
1196 }
1197 else
1198 {
1199 for (size_t i = 0; i < n; ++i)
1200 sv.push_back(0);
1201 }
1202 return sv;
1203}
1204
1206{
1209 {
1210 MySessionStats *stats = state->stats.get();
1211
1212 // The reason for the apparent inversion between in/out below is
1213 // that TUN_*_OUT stats refer to data written to tun device,
1214 // but from the perspective of tun interface, this is incoming
1215 // data. Vice versa for TUN_*_IN.
1216 if (stats)
1217 {
1218 stats->dco_update();
1219 ret.bytesOut = stats->stat_count(SessionStats::TUN_BYTES_IN);
1220 ret.bytesIn = stats->stat_count(SessionStats::TUN_BYTES_OUT);
1221 ret.packetsOut = stats->stat_count(SessionStats::TUN_PACKETS_IN);
1222 ret.packetsIn = stats->stat_count(SessionStats::TUN_PACKETS_OUT);
1223 ret.errorsOut = stats->error_count(Error::TUN_READ_ERROR);
1224 ret.errorsIn = stats->error_count(Error::TUN_WRITE_ERROR);
1225 return ret;
1226 }
1227 }
1228
1229 ret.bytesOut = 0;
1230 ret.bytesIn = 0;
1231 ret.packetsOut = 0;
1232 ret.packetsIn = 0;
1233 ret.errorsOut = 0;
1234 ret.errorsIn = 0;
1235 return ret;
1236}
1237
1239{
1241 ret.lastPacketReceived = -1; // undefined
1242
1244 {
1245 MySessionStats *stats = state->stats.get();
1246 if (stats)
1247 {
1248 stats->dco_update();
1249 ret.bytesOut = stats->stat_count(SessionStats::BYTES_OUT);
1250 ret.bytesIn = stats->stat_count(SessionStats::BYTES_IN);
1251 ret.packetsOut = stats->stat_count(SessionStats::PACKETS_OUT);
1252 ret.packetsIn = stats->stat_count(SessionStats::PACKETS_IN);
1253
1254 // calculate time since last packet received
1255 {
1256 const Time &lpr = stats->last_packet_received();
1257 if (lpr.defined())
1258 {
1259 const Time::Duration dur = Time::now() - lpr;
1260 const unsigned int delta = (unsigned int)dur.to_binary_ms();
1261 if (delta <= 60 * 60 * 24 * 1024) // only define for time periods <= 1 day
1262 ret.lastPacketReceived = delta;
1263 }
1264 }
1265 return ret;
1266 }
1267 }
1268
1269 ret.bytesOut = 0;
1270 ret.bytesIn = 0;
1271 ret.packetsOut = 0;
1272 ret.packetsIn = 0;
1273 return ret;
1274}
1275
1281
1282OPENVPN_CLIENT_EXPORT void OpenVPNClient::pause(const std::string &reason)
1283{
1285 {
1286 ClientConnect *session = state->session.get();
1287 if (session)
1288 session->thread_safe_pause(reason);
1289 }
1290}
1291
1293{
1295 {
1296 ClientConnect *session = state->session.get();
1297 if (session)
1298 session->thread_safe_resume();
1299 }
1300}
1301
1303{
1305 {
1306 ClientConnect *session = state->session.get();
1307 if (session)
1308 session->thread_safe_reconnect(seconds);
1309 }
1310}
1311
1313{
1315 {
1316 ClientConnect *session = state->session.get();
1317 if (session)
1318 session->thread_safe_post_cc_msg(msg);
1319 }
1320}
1321
1322OPENVPN_CLIENT_EXPORT void OpenVPNClient::send_app_control_channel_msg(const std::string &protocol, const std::string &msg)
1323{
1325 {
1326 ClientConnect *session = state->session.get();
1327 if (session)
1329 }
1330}
1331
1332static SSLLib::SSLAPI::Config::Ptr setup_certcheck_ssl_config(const std::string &client_cert,
1333 const std::string &extra_certs,
1334 const std::optional<const std::string> &ca)
1335{
1336 SSLLib::SSLAPI::Config::Ptr config = new SSLLib::SSLAPI::Config;
1337 config->set_frame(new Frame(Frame::Context(128, 4096, 4096 - 128, 0, 16, BufAllocFlags::NO_FLAGS)));
1338 config->set_mode(Mode(Mode::CLIENT));
1339 config->load_cert(client_cert, extra_certs);
1340 unsigned int flags = SSLConst::LOG_VERIFY_STATUS;
1341
1342 if (ca)
1343 config->load_ca(*ca, false);
1344 else
1346
1347 config->set_flags(flags);
1348
1349 return config;
1350}
1351
1352OPENVPN_CLIENT_EXPORT void OpenVPNClient::start_cert_check(const std::string &client_cert,
1353 const std::string &clientkey,
1354 const std::optional<const std::string> &ca)
1355{
1357 {
1358 ClientConnect *session = state->session.get();
1359 if (session)
1360 {
1361 SSLLib::SSLAPI::Config::Ptr config = setup_certcheck_ssl_config(client_cert, "", ca);
1362 config->load_private_key(clientkey);
1363
1364 session->start_acc_certcheck(config);
1365 }
1366 }
1367}
1368
1369OPENVPN_CLIENT_EXPORT void OpenVPNClient::start_cert_check_epki(const std::string &alias, const std::optional<const std::string> &ca)
1370{
1372 {
1373 ClientConnect *session = state->session.get();
1374 if (session)
1375 {
1377 req.alias = alias;
1379
1380 if (req.error)
1381 {
1383 return;
1384 }
1385
1386 SSLLib::SSLAPI::Config::Ptr config = setup_certcheck_ssl_config(req.cert, req.supportingChain, ca);
1387
1388 config->set_external_pki_callback(this, alias);
1389
1390
1391 session->start_acc_certcheck(config);
1392 }
1393 }
1394}
1395
1399
1404
1409
1411{
1412 return openvpn_copyright;
1413}
1414
1416{
1417 std::string ret = platform_string();
1418#ifdef PRIVATE_TUNNEL_PROXY
1419 ret += " PT_PROXY";
1420#endif
1421#ifdef ENABLE_KOVPN
1422 ret += " KOVPN";
1423#elif defined(ENABLE_OVPNDCO) || defined(ENABLE_OVPNDCOWIN)
1424 ret += " OVPN-DCO";
1425#endif
1426#ifdef OPENVPN_GREMLIN
1427 ret += " GREMLIN";
1428#endif
1429#ifdef OPENVPN_DEBUG
1430 ret += " built on " __DATE__ " " __TIME__;
1431#endif
1432 return ret;
1433}
1434
1439} // namespace ClientAPI
1440} // 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:222
RCPtr< MyClientEvents > Ptr
Definition ovpncli.cpp:184
void add_event(ClientEvent::Base::Ptr event) override
Definition ovpncli.cpp:191
ClientEvent::Base::Ptr last_connected
Definition ovpncli.cpp:256
MyClientEvents(OpenVPNClient *parent_arg)
Definition ovpncli.cpp:186
MyClockTick(openvpn_io::io_context &io_context, OpenVPNClient *parent_arg, const unsigned int ms)
Definition ovpncli.cpp:388
const Time::Duration period
Definition ovpncli.cpp:426
bool pause_on_connection_timeout() override
Definition ovpncli.cpp:321
void set_parent(OpenVPNClient *parent_arg)
Definition ovpncli.cpp:311
void set_parent(OpenVPNClient *parent_arg)
Definition ovpncli.cpp:336
RemoteList::Item::Ptr get() override
Definition ovpncli.cpp:346
count_t errors[Error::N_ERRORS]
Definition ovpncli.cpp:178
void error(const size_t err, const std::string *text=nullptr) override
Definition ovpncli.cpp:162
MySessionStats(OpenVPNClient *parent_arg)
Definition ovpncli.cpp:107
count_t error_count(const size_t index) const
Definition ovpncli.cpp:152
count_t combined_value(const size_t index) const
Definition ovpncli.cpp:134
RCPtr< MySessionStats > Ptr
Definition ovpncli.cpp:105
static std::string combined_name(const size_t index)
Definition ovpncli.cpp:121
count_t stat_count(const size_t index) const
Definition ovpncli.cpp:147
static constexpr size_t combined_n()
Definition ovpncli.cpp:116
bool socket_protect(openvpn_io::detail::socket_type socket, IP::Addr endpoint) override
Definition ovpncli.cpp:277
void set_rg_local(bool rg_local_arg)
Definition ovpncli.cpp:272
void set_parent(OpenVPNClient *parent_arg)
Definition ovpncli.cpp:267
EvalConfig eval_config(const Config &config)
Definition ovpncli.cpp:761
MergeConfig merge_config(const std::string &path, bool follow_references)
Definition ovpncli.cpp:722
static void parse_config(const Config &, EvalConfig &, OptionList &)
Definition ovpncli.cpp:608
static bool parse_dynamic_challenge(const std::string &cookie, DynamicChallenge &dc)
Definition ovpncli.cpp:812
MergeConfig merge_config_string(const std::string &config_content)
Definition ovpncli.cpp:734
static MergeConfig build_merge_config(const ProfileMerge &)
Definition ovpncli.cpp:744
void send_app_control_channel_msg(const std::string &protocol, const std::string &msg)
Definition ovpncli.cpp:1322
virtual void external_pki_sign_request(ExternalPKISignRequest &)=0
TransportStats transport_stats() const
Definition ovpncli.cpp:1238
void post_cc_msg(const std::string &msg)
Definition ovpncli.cpp:1312
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:1369
bool session_token(SessionToken &tok)
Definition ovpncli.cpp:1085
static Status status_from_exception(const std::exception &)
Definition ovpncli.cpp:1035
virtual void remote_override(RemoteOverride &)
Definition ovpncli.cpp:1155
InterfaceStats tun_stats() const
Definition ovpncli.cpp:1205
std::vector< long long > stats_bundle() const
Definition ovpncli.cpp:1184
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:1352
void process_epki_cert_chain(const ExternalPKICertRequest &)
Definition ovpncli.cpp:829
void external_pki_error(const ExternalPKIRequestBase &, const Error::Type)
Definition ovpncli.cpp:1105
Status provide_creds(const ProvideCreds &)
Definition ovpncli.cpp:784
static std::string stats_name(int index)
Definition ovpncli.cpp:1164
virtual bool pause_on_connection_timeout()=0
void connect_setup(Status &, bool &)
Definition ovpncli.cpp:937
long long stats_value(int index) const
Definition ovpncli.cpp:1169
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:807
Private::ClientState * state
Definition ovpncli.hpp:760
void pause(const std::string &reason)
Definition ovpncli.cpp:1282
EvalConfig eval_config(const Config &)
Definition ovpncli.cpp:770
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:1124
virtual void acc_event(const AppCustomControlMessageEvent &)=0
void parse_extras(const Config &, EvalConfig &)
Definition ovpncli.cpp:669
std::unique_ptr< AsioStopScope > stop_scope_global
Definition ovpncli.cpp:586
ProtoContextCompressionOptions::Ptr proto_context_options
Definition ovpncli.cpp:448
HTTPProxyTransport::Options::Ptr http_proxy_options
Definition ovpncli.cpp:450
void attach(OpenVPNClient *parent, openvpn_io::io_context *io_context, Stop *async_stop_global)
Definition ovpncli.cpp:459
ClientState & operator=(const ClientState &)=delete
std::unique_ptr< AsioStopScope > stop_scope_local
Definition ovpncli.cpp:585
openvpn_io::io_context * io_context_
Definition ovpncli.cpp:588
openvpn_io::io_context * io_context()
Definition ovpncli.cpp:534
ClientState(const ClientState &)=delete
std::unique_ptr< MyClockTick > clock_tick
Definition ovpncli.cpp:443
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:47
bool code_defined() const
Definition excode.hpp:56
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)
constexpr BufferFlags NO_FLAGS(0u)
no flags set
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:1332
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
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:56
std::vector< ServerEntry > serverList
Definition ovpncli.hpp:103
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,...)