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#ifdef __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 return Error::name(index - N_STATS);
128 }
129 return "";
130 }
131
132 count_t combined_value(const size_t index) const
133 {
134 if (index < combined_n())
135 {
136 if (index < N_STATS)
137 return get_stat(index);
138 return errors[index - N_STATS];
139 }
140 return 0;
141 }
142
143 count_t stat_count(const size_t index) const
144 {
145 return get_stat_fast(index);
146 }
147
148 count_t error_count(const size_t index) const
149 {
150 return errors[index];
151 }
152
154 {
155 parent = nullptr;
156 }
157
158 void error(const size_t err, const std::string *text = nullptr) override
159 {
160 if (err < Error::N_ERRORS)
161 {
162#ifdef OPENVPN_DEBUG_VERBOSE_ERRORS
163 if (text)
164 OPENVPN_LOG("ERROR: " << Error::name(err) << " : " << *text);
165 else
166 OPENVPN_LOG("ERROR: " << Error::name(err));
167#endif
168 ++errors[err];
169 }
170 }
171
172 private:
175};
176
178{
179 public:
181
183 : parent(parent_arg)
184 {
185 }
186
188 {
189 if (parent)
190 {
191 if (event->id() == ClientEvent::CUSTOM_CONTROL)
192 {
195 ev.protocol = accm->protocol;
196 ev.payload = accm->custommessage;
197 parent->acc_event(ev);
198 }
199 else
200 {
201 Event ev;
202 ev.name = event->name();
203 ev.info = event->render();
204 ev.error = event->is_error();
205 ev.fatal = event->is_fatal();
206
207 // save connected event
208 if (event->id() == ClientEvent::CONNECTED)
209 last_connected = std::move(event);
210 else if (event->id() == ClientEvent::DISCONNECTED)
212
213 parent->event(ev);
214 }
215 }
216 }
217
219 {
221 if (connected)
222 {
223 const ClientEvent::Connected *c = connected->connected_cast();
224 if (c)
225 {
226 ci.user = c->user;
227 ci.serverHost = c->server_host;
228 ci.serverPort = c->server_port;
230 ci.serverIp = c->server_ip;
231 ci.vpnIp4 = c->vpn_ip4;
232 ci.vpnIp6 = c->vpn_ip6;
233 ci.gw4 = c->vpn_gw4;
234 ci.gw6 = c->vpn_gw6;
235 ci.clientIp = c->client_ip;
236 ci.tunName = c->tun_name;
237 ci.defined = true;
238 ci.vpnMtu = c->vpn_mtu;
239 return;
240 }
241 }
242 ci.defined = false;
243 }
244
246 {
247 parent = nullptr;
248 }
249
250 private:
253};
254
256{
257 public:
259 : parent(nullptr)
260 {
261 }
262
263 void set_parent(OpenVPNClient *parent_arg)
264 {
265 parent = parent_arg;
266 }
267
268 void set_rg_local(bool rg_local_arg)
269 {
270 rg_local = rg_local_arg;
271 }
272
273 bool socket_protect(openvpn_io::detail::socket_type socket, IP::Addr endpoint) override
274 {
275 if (parent)
276 {
277#if defined(OPENVPN_COMMAND_AGENT) && defined(OPENVPN_PLATFORM_WIN)
278 return rg_local ? true : WinCommandAgent::add_bypass_route(endpoint);
279#elif defined(OPENVPN_COMMAND_AGENT) && defined(OPENVPN_PLATFORM_MAC)
280 return rg_local ? true : UnixCommandAgent::add_bypass_route(endpoint);
281#else
282 return parent->socket_protect(socket, endpoint.to_string(), endpoint.is_ipv6());
283#endif
284 }
285 else
286 return true;
287 }
288
290 {
291 parent = nullptr;
292 }
293
294 private:
296 bool rg_local = false; // do not add bypass route if true
297};
298
300{
301 public:
303 : parent(nullptr)
304 {
305 }
306
307 void set_parent(OpenVPNClient *parent_arg)
308 {
309 parent = parent_arg;
310 }
311
313 {
314 parent = nullptr;
315 }
316
318 {
319 if (parent)
321 return false;
322 }
323
324 private:
326};
327
329{
330 public:
331 void set_parent(OpenVPNClient *parent_arg)
332 {
333 parent = parent_arg;
334 }
335
337 {
338 parent = nullptr;
339 }
340
342 {
343 if (parent)
344 {
345 const std::string title = "remote-override";
347 try
348 {
350 }
351 catch (const std::exception &e)
352 {
353 ro.error = e.what();
354 }
356 if (ro.error.empty())
357 {
358 if (!ro.ip.empty())
359 ri->set_ip_addr(IP::Addr(ro.ip, title));
360 if (ro.host.empty())
361 ro.host = ro.ip;
362 HostPort::validate_host(ro.host, title);
363 HostPort::validate_port(ro.port, title);
364 ri->server_host = std::move(ro.host);
365 ri->server_port = std::move(ro.port);
366 ri->transport_protocol = Protocol::parse(ro.proto, Protocol::CLIENT_SUFFIX, title.c_str());
367 }
368 else
369 throw Exception("remote override exception: " + ro.error);
370 return ri;
371 }
372 return RemoteList::Item::Ptr();
373 }
374
375 private:
377};
378
380{
381 public:
382 MyClockTick(openvpn_io::io_context &io_context,
383 OpenVPNClient *parent_arg,
384 const unsigned int ms)
385 : timer(io_context),
386 parent(parent_arg),
387 period(Time::Duration::milliseconds(ms))
388 {
389 }
390
391 void cancel()
392 {
393 timer.cancel();
394 }
395
397 {
398 parent = nullptr;
399 }
400
401 void schedule()
402 {
404 timer.async_wait([this](const openvpn_io::error_code &error)
405 {
406 if (!parent || error)
407 return;
408 try {
410 }
411 catch (...)
412 {
413 }
414 schedule(); });
415 }
416
417 private:
420 const Time::Duration period;
421};
422
423namespace Private {
425{
426 public:
427 // state objects
437 std::unique_ptr<MyClockTick> clock_tick;
438
439 // extra settings submitted by API client
441
445
446#ifdef OPENVPN_GREMLIN
447 Gremlin::Config::Ptr gremlin_config;
448#endif
449 // Ensure that init is called
451
452 template <typename SESSION_STATS, typename CLIENT_EVENTS>
453 void attach(OpenVPNClient *parent,
454 openvpn_io::io_context *io_context,
456 {
457 // only one attachment per instantiation allowed
458 if (attach_called)
459 throw Exception("ClientState::attach() can only be called once per ClientState instantiation");
460 attach_called = true;
461
462 // async stop
464
465 // io_context
466 if (io_context)
468 else
469 {
470 io_context_ = new openvpn_io::io_context(1); // concurrency hint=1
471 io_context_owned = true;
472 }
473
474 // client stats
475 stats.reset(new SESSION_STATS(parent));
476
477 // client events
478 events.reset(new CLIENT_EVENTS(parent));
479
480 // socket protect
483 socket_protect.set_rg_local(rg_flags.redirect_gateway_local());
484
485 // reconnect notifications
487
488 // remote override
490 }
491
492 ClientState() = default;
493
495 {
496 stop_scope_local.reset();
497 stop_scope_global.reset();
501 if (clock_tick)
502 clock_tick->detach_from_parent();
503 if (stats)
504 stats->detach_from_parent();
505 if (events)
506 events->detach_from_parent();
507 session.reset();
509 delete io_context_;
510 }
511
512 // foreign thread access
513
515 {
516 foreign_thread_ready.store(true, std::memory_order_release);
517 }
518
520 {
521 return foreign_thread_ready.load(std::memory_order_acquire);
522 }
523
524 // io_context
525
526 openvpn_io::io_context *io_context()
527 {
528 return io_context_;
529 }
530
531 // async stop
532
534 {
535 return &async_stop_local_;
536 }
537
539 {
540 return async_stop_global_;
541 }
542
547
548 // disconnect
550 {
551 if (clock_tick)
552 clock_tick->cancel();
553 }
554
567
568 private:
569 ClientState(const ClientState &) = delete;
571
572 bool attach_called = false;
573
576
577 std::unique_ptr<AsioStopScope> stop_scope_local;
578 std::unique_ptr<AsioStopScope> stop_scope_global;
579
580 openvpn_io::io_context *io_context_ = nullptr;
581 bool io_context_owned = false;
582
583 std::atomic<bool> foreign_thread_ready{false};
584};
585}; // namespace Private
586
588{
589#ifndef OPENVPN_NORESET_TIME
590 // We keep track of time as binary milliseconds since a time base, and
591 // this can wrap after ~48 days on 32 bit systems, so it's a good idea
592 // to periodically reinitialize the base.
594#endif
595
598}
599
601{
602 try
603 {
604 // validate proto_override
605 if (!config.protoOverride.empty())
607
608 // validate IPv6 setting
609 if (!config.allowUnusedAddrFamilies.empty())
610 TriStateSetting::parse(config.allowUnusedAddrFamilies);
611
612 // parse config
614 kvl.reserve(config.contentList.size());
615 for (size_t i = 0; i < config.contentList.size(); ++i)
616 {
617 const KeyValue &kv = config.contentList[i];
618 kvl.push_back(new OptionList::KeyValue(kv.key, kv.value));
619 }
620 const ParseClientConfig cc = ParseClientConfig::parse(config.content, &kvl, options);
621
623
624#ifdef OPENVPN_DUMP_CONFIG
625 std::cout << "---------- ARGS ----------\n";
627 std::cout << "---------- MAP ----------\n";
628 std::cout << options.render_map() << "\n";
629#endif
630 eval.error = cc.error();
631 eval.message = cc.message();
633 eval.profileName = cc.profileName();
634 eval.friendlyName = cc.friendlyName();
635 eval.autologin = cc.autologin();
636 eval.externalPki = cc.externalPki();
637 eval.vpnCa = cc.vpnCa();
642 eval.remoteHost = config.serverOverride.empty() ? cc.firstRemoteListItem().host : config.serverOverride;
645 eval.windowsDriver = cc.windowsDriver();
646 for (ParseClientConfig::ServerList::const_iterator i = cc.serverList().begin(); i != cc.serverList().end(); ++i)
647 {
648 ServerEntry se;
649 se.server = i->server;
650 se.friendlyName = i->friendlyName;
651 eval.serverList.push_back(std::move(se));
652 }
653 }
654 catch (const std::exception &e)
655 {
656 eval.error = true;
657 eval.message = Unicode::utf8_printable<std::string>(std::string("ERR_PROFILE_GENERIC: ") + e.what(), 256);
658 }
659}
660
662{
663 try
664 {
666
667 if (!config.compressionMode.empty())
669
670 if (eval.externalPki)
671 state->clientconf.external_pki_alias = config.externalPkiAlias;
672
673 if (!config.gremlinConfig.empty())
674 {
675#ifdef OPENVPN_GREMLIN
676 state->gremlin_config.reset(new Gremlin::Config(config.gremlinConfig));
677#else
678 throw Exception("client not built with OPENVPN_GREMLIN");
679#endif
680 }
682 if (!config.proxyHost.empty())
683 {
685 ho->set_proxy_server(config.proxyHost, config.proxyPort);
686 ho->username = config.proxyUsername;
687 ho->password = config.proxyPassword;
688 ho->allow_cleartext_auth = config.proxyAllowCleartextAuth;
690 }
691 }
692 catch (const std::exception &e)
693 {
694 eval.error = true;
695 eval.message = Unicode::utf8_printable<std::string>(e.what(), 256);
696 }
697}
698
700 : init(new InitProcess::Init())
701{
702}
703
708
713
715 bool follow_references)
716{
717 ProfileMerge pm(path,
718 "ovpn",
719 "",
723 return build_merge_config(pm);
724}
725
735
737{
739 ret.status = pm.status_string();
740 ret.basename = pm.basename();
742 {
743 ret.refPathList = pm.ref_path_list();
744 ret.profileContent = pm.profile_content();
745 }
746 else
747 {
748 ret.errorText = pm.error();
749 }
750 return ret;
751}
752
754{
755 EvalConfig eval;
756 OptionList options;
757 parse_config(config, eval, options);
758 return eval;
759}
760
761// API client submits the configuration here before calling connect()
763{
764 // parse and validate configuration file
765 EvalConfig eval;
767 if (eval.error)
768 return eval;
769
770 // handle extra settings in config
771 parse_extras(config, eval);
772 state->eval = eval;
773 return eval;
774}
775
777{
778 Status ret;
779 try
780 {
781 ClientCreds::Ptr cc = new ClientCreds();
782 cc->set_username(creds.username);
784 cc->set_password(creds.password);
787 cc->set_response(creds.response);
789 state->creds = cc;
790 }
791 catch (const std::exception &e)
792 {
793 ret.error = true;
794 ret.message = Unicode::utf8_printable<std::string>(e.what(), 256);
795 }
796 return ret;
797}
798
799OPENVPN_CLIENT_EXPORT bool OpenVPNClient::socket_protect(openvpn_io::detail::socket_type socket, std::string remote, bool ipv6)
800{
801 return true;
802}
803
805{
806 try
807 {
808 ChallengeResponse cr(cookie);
810 dc.echo = cr.get_echo();
812 dc.stateID = cr.get_state_id();
813 return true;
814 }
815 catch (const std::exception &)
816 {
817 return false;
818 }
819}
820
822{
823 // Get cert and add to options list
824 if (!req.cert.empty())
825 {
826 Option o;
827 o.push_back("cert");
828 o.push_back(req.cert);
830 }
831
832 // Get the supporting chain, if it exists, and use
833 // it for ca (if ca isn't defined), or otherwise use
834 // it for extra-certs (if ca is defined but extra-certs
835 // is not).
836 if (!req.supportingChain.empty())
837 {
838 if (!state->options.exists("ca"))
839 {
840 Option o;
841 o.push_back("ca");
844 }
845 else if (!state->options.exists("extra-certs"))
846 {
847 Option o;
848 o.push_back("extra-certs");
851 }
852 }
853}
854
856{
857#ifndef OPENVPN_OVPNCLI_SINGLE_THREAD
858 openvpn_io::detail::signal_blocker signal_blocker; // signals should be handled by parent thread
859#endif
860#if defined(OPENVPN_LOG_LOGTHREAD_H) && !defined(OPENVPN_LOG_LOGBASE_H)
861#ifdef OPENVPN_LOG_GLOBAL
862#error ovpn3 core logging object only supports thread-local scope
863#endif
864 Log::Context log_context(this);
865#endif
866
868
869 return do_connect();
870}
871
873{
874 Status status;
875 bool session_started = false;
876 try
877 {
879#ifdef OPENVPN_OVPNCLI_ASYNC_SETUP
880 openvpn_io::post(*state->io_context(), [this]()
881 { do_connect_async(); });
882#else
883 connect_setup(status, session_started);
884#endif
885 connect_run();
886 return status;
887 }
888 catch (const std::exception &e)
889 {
890 if (session_started)
892 return status_from_exception(e);
893 }
894}
895
897{
898 enum StopType
899 {
900 NONE,
901 SESSION,
902 EXPLICIT,
903 };
904 StopType stop_type = NONE;
905 Status status;
906 bool session_started = false;
907 try
908 {
909 connect_setup(status, session_started);
910 }
911 catch (const std::exception &e)
912 {
913 stop_type = session_started ? SESSION : EXPLICIT;
914 status = status_from_exception(e);
915 }
916 if (status.error)
917 {
919 state->events->add_event(std::move(ev));
920 }
921 if (stop_type == SESSION)
923#ifdef OPENVPN_IO_REQUIRES_STOP
924 if (stop_type == EXPLICIT)
925 state->io_context()->stop();
926#endif
927}
928
930{
931 // set global MbedTLS debug level
932#if defined(USE_MBEDTLS) || defined(USE_MBEDTLS_APPLE_HYBRID)
933 mbedtls_debug_set_threshold(state->clientconf.sslDebugLevel); // fixme -- using a global method for this seems wrong
934#endif
935
936 // load options
939 cc.cli_stats = state->stats;
940 cc.cli_events = state->events;
941
950#ifdef USE_TUN_BUILDER
951 cc.builder = this;
952#endif
953#ifdef OPENVPN_EXTERNAL_TUN_FACTORY
954 cc.extern_tun_factory = this;
955#endif
956#ifdef OPENVPN_EXTERNAL_TRANSPORT_FACTORY
957 cc.extern_transport_factory = this;
958#endif
959
960 // external PKI
961#ifndef USE_APPLE_SSL
963 {
964 if (!state->clientconf.external_pki_alias.empty())
965 {
969 if (!req.error)
970 {
971 cc.external_pki = this;
973 }
974 else
975 {
977 return;
978 }
979 }
980 else
981 {
982 status.error = true;
983 status.message = "Missing External PKI alias";
984 return;
985 }
986 }
987#endif
988
989#ifdef USE_OPENSSL
990 if (state->options.exists("allow-name-constraints"))
991 {
992 ClientEvent::Base::Ptr ev = new ClientEvent::UnsupportedFeature("allow-name-constraints",
993 "Always verified correctly with OpenSSL",
994 false);
995 state->events->add_event(std::move(ev));
996 }
997#endif
998
999 // build client options object
1000 ClientOptions::Ptr client_options = new ClientOptions(state->options, cc);
1001
1002 // configure creds in options
1003 client_options->submit_creds(state->creds);
1004
1005 // instantiate top-level client session
1006 state->session.reset(new ClientConnect(*state->io_context(), client_options));
1007
1008 // convenience clock tick
1010 {
1012 state->clock_tick->schedule();
1013 }
1014
1015 // start VPN
1016 state->session->start(); // queue reads on socket/tun
1017 session_started = true;
1018
1019 // wire up async stop
1021
1022 // prepare to start reactor
1025}
1026
1028{
1029 Status ret;
1030 ret.error = true;
1031 ret.message = Unicode::utf8_printable<std::string>(e.what(), 2048 | Unicode::UTF8_PASS_FMT);
1032
1033 // if exception is an ExceptionCode, translate the code
1034 // to return status string
1035 {
1036 const ExceptionCode *ec = dynamic_cast<const ExceptionCode *>(&e);
1037 if (ec && ec->code_defined())
1038 ret.status = Error::name(ec->code());
1039 }
1040 return ret;
1041}
1042
1049
1053
1058
1060{
1061 state->session->stop(); // On exception, stop client...
1062 state->io_context()->poll(); // and execute completion handlers.
1063}
1064
1066{
1067 ConnectionInfo ci;
1069 {
1070 MyClientEvents *events = state->events.get();
1071 if (events)
1072 events->get_connection_info(ci);
1073 }
1074 return ci;
1075}
1076
1078{
1080 {
1081 ClientCreds *cc = state->creds.get();
1082 if (cc && cc->session_id_defined())
1083 {
1084 tok.username = cc->get_username();
1085 tok.session_id = cc->get_password();
1086 return true;
1087 }
1088 }
1089 return false;
1090}
1091
1096
1098{
1099 if (req.error)
1100 {
1101 if (req.invalidAlias)
1102 {
1104 state->events->add_event(std::move(ev));
1105 }
1106
1108 state->events->add_event(std::move(ev));
1109
1110 state->stats->error(err_type);
1111 if (state->session)
1113 }
1114}
1115
1116OPENVPN_CLIENT_EXPORT bool OpenVPNClient::sign(const std::string &alias,
1117 const std::string &data,
1118 std::string &sig,
1119 const std::string &algorithm,
1120 const std::string &hashalg,
1121 const std::string &saltlen)
1122{
1124 req.alias = alias;
1125 req.data = data;
1126 req.algorithm = algorithm;
1127 req.hashalg = hashalg;
1128 req.saltlen = saltlen;
1129 external_pki_sign_request(req); // call out to derived class for RSA signature
1130 if (!req.error)
1131 {
1132 sig = req.sig;
1133 return true;
1134 }
1135
1137 return false;
1138}
1139
1144
1148
1153
1155{
1156 return MySessionStats::combined_name(index);
1157}
1158
1160{
1162 {
1163 MySessionStats *stats = state->stats.get();
1164 if (stats)
1165 {
1166 if (index == SessionStats::BYTES_IN || index == SessionStats::BYTES_OUT)
1167 stats->dco_update();
1168 return stats->combined_value(index);
1169 }
1170 }
1171 return 0;
1172}
1173
1175{
1176 std::vector<long long> sv;
1177 constexpr size_t n = MySessionStats::combined_n();
1178 sv.reserve(n);
1180 {
1181 MySessionStats *stats = state->stats.get();
1182 if (stats)
1183 stats->dco_update();
1184 for (size_t i = 0; i < n; ++i)
1185 sv.push_back(stats ? stats->combined_value(i) : 0);
1186 }
1187 else
1188 {
1189 for (size_t i = 0; i < n; ++i)
1190 sv.push_back(0);
1191 }
1192 return sv;
1193}
1194
1196{
1199 {
1200 MySessionStats *stats = state->stats.get();
1201
1202 // The reason for the apparent inversion between in/out below is
1203 // that TUN_*_OUT stats refer to data written to tun device,
1204 // but from the perspective of tun interface, this is incoming
1205 // data. Vice versa for TUN_*_IN.
1206 if (stats)
1207 {
1208 stats->dco_update();
1209 ret.bytesOut = stats->stat_count(SessionStats::TUN_BYTES_IN);
1210 ret.bytesIn = stats->stat_count(SessionStats::TUN_BYTES_OUT);
1211 ret.packetsOut = stats->stat_count(SessionStats::TUN_PACKETS_IN);
1212 ret.packetsIn = stats->stat_count(SessionStats::TUN_PACKETS_OUT);
1213 ret.errorsOut = stats->error_count(Error::TUN_READ_ERROR);
1214 ret.errorsIn = stats->error_count(Error::TUN_WRITE_ERROR);
1215 return ret;
1216 }
1217 }
1218
1219 ret.bytesOut = 0;
1220 ret.bytesIn = 0;
1221 ret.packetsOut = 0;
1222 ret.packetsIn = 0;
1223 ret.errorsOut = 0;
1224 ret.errorsIn = 0;
1225 return ret;
1226}
1227
1229{
1231 ret.lastPacketReceived = -1; // undefined
1232
1234 {
1235 MySessionStats *stats = state->stats.get();
1236 if (stats)
1237 {
1238 stats->dco_update();
1239 ret.bytesOut = stats->stat_count(SessionStats::BYTES_OUT);
1240 ret.bytesIn = stats->stat_count(SessionStats::BYTES_IN);
1241 ret.packetsOut = stats->stat_count(SessionStats::PACKETS_OUT);
1242 ret.packetsIn = stats->stat_count(SessionStats::PACKETS_IN);
1243
1244 // calculate time since last packet received
1245 {
1246 const Time &lpr = stats->last_packet_received();
1247 if (lpr.defined())
1248 {
1249 const Time::Duration dur = Time::now() - lpr;
1250 const unsigned int delta = (unsigned int)dur.to_binary_ms();
1251 if (delta <= 60 * 60 * 24 * 1024) // only define for time periods <= 1 day
1252 ret.lastPacketReceived = delta;
1253 }
1254 }
1255 return ret;
1256 }
1257 }
1258
1259 ret.bytesOut = 0;
1260 ret.bytesIn = 0;
1261 ret.packetsOut = 0;
1262 ret.packetsIn = 0;
1263 return ret;
1264}
1265
1271
1272OPENVPN_CLIENT_EXPORT void OpenVPNClient::pause(const std::string &reason)
1273{
1275 {
1276 ClientConnect *session = state->session.get();
1277 if (session)
1278 session->thread_safe_pause(reason);
1279 }
1280}
1281
1283{
1285 {
1286 ClientConnect *session = state->session.get();
1287 if (session)
1288 session->thread_safe_resume();
1289 }
1290}
1291
1293{
1295 {
1296 ClientConnect *session = state->session.get();
1297 if (session)
1298 session->thread_safe_reconnect(seconds);
1299 }
1300}
1301
1303{
1305 {
1306 ClientConnect *session = state->session.get();
1307 if (session)
1308 session->thread_safe_post_cc_msg(msg);
1309 }
1310}
1311
1312OPENVPN_CLIENT_EXPORT void OpenVPNClient::send_app_control_channel_msg(const std::string &protocol, const std::string &msg)
1313{
1315 {
1316 ClientConnect *session = state->session.get();
1317 if (session)
1319 }
1320}
1321
1322static SSLLib::SSLAPI::Config::Ptr setup_certcheck_ssl_config(const std::string &client_cert,
1323 const std::string &extra_certs,
1324 const std::optional<const std::string> &ca)
1325{
1326 SSLLib::SSLAPI::Config::Ptr config = new SSLLib::SSLAPI::Config;
1327 config->set_frame(new Frame(Frame::Context(128, 4096, 4096 - 128, 0, 16, BufAllocFlags::NO_FLAGS)));
1328 config->set_mode(Mode(Mode::CLIENT));
1329 config->load_cert(client_cert, extra_certs);
1330 unsigned int flags = SSLConst::LOG_VERIFY_STATUS;
1331
1332 if (ca)
1333 config->load_ca(*ca, false);
1334 else
1336
1337 config->set_flags(flags);
1338
1339 return config;
1340}
1341
1342OPENVPN_CLIENT_EXPORT void OpenVPNClient::start_cert_check(const std::string &client_cert,
1343 const std::string &clientkey,
1344 const std::optional<const std::string> &ca)
1345{
1347 {
1348 ClientConnect *session = state->session.get();
1349 if (session)
1350 {
1351 SSLLib::SSLAPI::Config::Ptr config = setup_certcheck_ssl_config(client_cert, "", ca);
1352 config->load_private_key(clientkey);
1353
1354 session->start_acc_certcheck(config);
1355 }
1356 }
1357}
1358
1359OPENVPN_CLIENT_EXPORT void OpenVPNClient::start_cert_check_epki(const std::string &alias, const std::optional<const std::string> &ca)
1360{
1362 {
1363 ClientConnect *session = state->session.get();
1364 if (session)
1365 {
1367 req.alias = alias;
1369
1370 if (req.error)
1371 {
1373 return;
1374 }
1375
1376 SSLLib::SSLAPI::Config::Ptr config = setup_certcheck_ssl_config(req.cert, req.supportingChain, ca);
1377
1378 config->set_external_pki_callback(this, alias);
1379
1380
1381 session->start_acc_certcheck(config);
1382 }
1383 }
1384}
1385
1389
1394
1399
1401{
1402 return openvpn_copyright;
1403}
1404
1406{
1407 std::string ret = platform_string();
1408#ifdef PRIVATE_TUNNEL_PROXY
1409 ret += " PT_PROXY";
1410#endif
1411#ifdef ENABLE_KOVPN
1412 ret += " KOVPN";
1413#elif defined(ENABLE_OVPNDCO) || defined(ENABLE_OVPNDCOWIN)
1414 ret += " OVPN-DCO";
1415#endif
1416#ifdef OPENVPN_GREMLIN
1417 ret += " GREMLIN";
1418#endif
1419#ifdef OPENVPN_DEBUG
1420 ret += " built on " __DATE__ " " __TIME__;
1421#endif
1422 return ret;
1423}
1424
1429} // namespace ClientAPI
1430} // 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:210
const std::string & get_state_id() const
Definition cr.hpp:202
bool get_response_required() const
Definition cr.hpp:214
const std::string & get_challenge_text() const
Definition cr.hpp:218
void get_connection_info(ConnectionInfo &ci)
Definition ovpncli.cpp:218
void add_event(ClientEvent::Base::Ptr event) override
Definition ovpncli.cpp:187
ClientEvent::Base::Ptr last_connected
Definition ovpncli.cpp:252
MyClientEvents(OpenVPNClient *parent_arg)
Definition ovpncli.cpp:182
MyClockTick(openvpn_io::io_context &io_context, OpenVPNClient *parent_arg, const unsigned int ms)
Definition ovpncli.cpp:382
const Time::Duration period
Definition ovpncli.cpp:420
bool pause_on_connection_timeout() override
Definition ovpncli.cpp:317
void set_parent(OpenVPNClient *parent_arg)
Definition ovpncli.cpp:307
void set_parent(OpenVPNClient *parent_arg)
Definition ovpncli.cpp:331
RemoteList::Item::Ptr get() override
Definition ovpncli.cpp:341
count_t errors[Error::N_ERRORS]
Definition ovpncli.cpp:174
void error(const size_t err, const std::string *text=nullptr) override
Definition ovpncli.cpp:158
MySessionStats(OpenVPNClient *parent_arg)
Definition ovpncli.cpp:107
count_t error_count(const size_t index) const
Definition ovpncli.cpp:148
count_t combined_value(const size_t index) const
Definition ovpncli.cpp:132
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:143
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:273
void set_rg_local(bool rg_local_arg)
Definition ovpncli.cpp:268
void set_parent(OpenVPNClient *parent_arg)
Definition ovpncli.cpp:263
EvalConfig eval_config(const Config &config)
Definition ovpncli.cpp:753
MergeConfig merge_config(const std::string &path, bool follow_references)
Definition ovpncli.cpp:714
static void parse_config(const Config &, EvalConfig &, OptionList &)
Definition ovpncli.cpp:600
static bool parse_dynamic_challenge(const std::string &cookie, DynamicChallenge &dc)
Definition ovpncli.cpp:804
MergeConfig merge_config_string(const std::string &config_content)
Definition ovpncli.cpp:726
static MergeConfig build_merge_config(const ProfileMerge &)
Definition ovpncli.cpp:736
void send_app_control_channel_msg(const std::string &protocol, const std::string &msg)
Definition ovpncli.cpp:1312
virtual void external_pki_sign_request(ExternalPKISignRequest &)=0
TransportStats transport_stats() const
Definition ovpncli.cpp:1228
void post_cc_msg(const std::string &msg)
Definition ovpncli.cpp:1302
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:1359
bool session_token(SessionToken &tok)
Definition ovpncli.cpp:1077
static Status status_from_exception(const std::exception &)
Definition ovpncli.cpp:1027
virtual void remote_override(RemoteOverride &)
Definition ovpncli.cpp:1145
InterfaceStats tun_stats() const
Definition ovpncli.cpp:1195
std::vector< long long > stats_bundle() const
Definition ovpncli.cpp:1174
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:1342
void process_epki_cert_chain(const ExternalPKICertRequest &)
Definition ovpncli.cpp:821
void external_pki_error(const ExternalPKIRequestBase &, const Error::Type)
Definition ovpncli.cpp:1097
Status provide_creds(const ProvideCreds &)
Definition ovpncli.cpp:776
static std::string stats_name(int index)
Definition ovpncli.cpp:1154
virtual bool pause_on_connection_timeout()=0
void connect_setup(Status &, bool &)
Definition ovpncli.cpp:929
long long stats_value(int index) const
Definition ovpncli.cpp:1159
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:799
Private::ClientState * state
Definition ovpncli.hpp:757
void pause(const std::string &reason)
Definition ovpncli.cpp:1272
EvalConfig eval_config(const Config &)
Definition ovpncli.cpp:762
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:1116
virtual void acc_event(const AppCustomControlMessageEvent &)=0
void parse_extras(const Config &, EvalConfig &)
Definition ovpncli.cpp:661
std::unique_ptr< AsioStopScope > stop_scope_global
Definition ovpncli.cpp:578
ProtoContextCompressionOptions::Ptr proto_context_options
Definition ovpncli.cpp:442
HTTPProxyTransport::Options::Ptr http_proxy_options
Definition ovpncli.cpp:444
void attach(OpenVPNClient *parent, openvpn_io::io_context *io_context, Stop *async_stop_global)
Definition ovpncli.cpp:453
ClientState & operator=(const ClientState &)=delete
std::unique_ptr< AsioStopScope > stop_scope_local
Definition ovpncli.cpp:577
openvpn_io::io_context * io_context_
Definition ovpncli.cpp:580
openvpn_io::io_context * io_context()
Definition ovpncli.cpp:526
ClientState(const ClientState &)=delete
std::unique_ptr< MyClockTick > clock_tick
Definition ovpncli.cpp:437
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:49
void set_dynamic_challenge_cookie(const std::string &cookie, const std::string &username)
Definition clicreds.hpp:68
std::string get_password() const
Definition clicreds.hpp:102
void set_username(const std::string &username_arg)
Definition clicreds.hpp:35
void set_http_proxy_password(const std::string &password)
Definition clicreds.hpp:54
std::string get_username() const
Definition clicreds.hpp:93
void set_response(const std::string &response_arg)
Definition clicreds.hpp:59
bool session_id_defined() const
Definition clicreds.hpp:145
void set_password(const std::string &password_arg)
Definition clicreds.hpp:40
void save_username_for_session_id()
Definition clicreds.hpp:164
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:1181
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:1476
void add_item(const Option &opt)
Definition options.hpp:1530
std::string render(const unsigned int flags) const
Definition options.hpp:1444
bool exists(const std::string &name) const
Definition options.hpp:1308
void push_back(const std::string &item)
Definition options.hpp:328
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
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:83
static TimeType now()
Definition time.hpp:302
static void reset_base_conditional()
Definition time.hpp:409
bool defined() const
Definition time.hpp:280
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:74
#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:1322
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
long long count_t
Definition count.hpp:16
std::string platform_string()
#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,...)