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{
738 MergeConfig ret;
739 ret.status = pm.status_string();
740 ret.basename = pm.basename();
742 {
743 ret.refPathList = pm.ref_path_list();
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#ifdef USE_MBEDTLS
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 OPENVPN_GREMLIN
951 cc.gremlin_config = state->gremlin_config;
952#endif
953#ifdef USE_TUN_BUILDER
954 cc.builder = this;
955#endif
956#ifdef OPENVPN_EXTERNAL_TUN_FACTORY
957 cc.extern_tun_factory = this;
958#endif
959#ifdef OPENVPN_EXTERNAL_TRANSPORT_FACTORY
960 cc.extern_transport_factory = this;
961#endif
962
963 // external PKI
965 {
966 if (!state->clientconf.external_pki_alias.empty())
967 {
971 if (!req.error)
972 {
973 cc.external_pki = this;
975 }
976 else
977 {
979 return;
980 }
981 }
982 else
983 {
984 status.error = true;
985 status.message = "Missing External PKI alias";
986 return;
987 }
988 }
989
990#ifdef USE_OPENSSL
991 if (state->options.exists("allow-name-constraints"))
992 {
993 ClientEvent::Base::Ptr ev = new ClientEvent::UnsupportedFeature("allow-name-constraints",
994 "Always verified correctly with OpenSSL",
995 false);
996 state->events->add_event(std::move(ev));
997 }
998#endif
999
1000 // build client options object
1001 ClientOptions::Ptr client_options = new ClientOptions(state->options, cc);
1002
1003 // configure creds in options
1004 client_options->submit_creds(state->creds);
1005
1006 // instantiate top-level client session
1007 state->session.reset(new ClientConnect(*state->io_context(), client_options));
1008
1009 // convenience clock tick
1011 {
1013 state->clock_tick->schedule();
1014 }
1015
1016 // start VPN
1017 state->session->start(); // queue reads on socket/tun
1018 session_started = true;
1019
1020 // wire up async stop
1022
1023 // prepare to start reactor
1026}
1027
1029{
1030 Status ret;
1031 ret.error = true;
1032 ret.message = Unicode::utf8_printable<std::string>(e.what(), 2048 | Unicode::UTF8_PASS_FMT);
1033
1034 // if exception is an ExceptionCode, translate the code
1035 // to return status string
1036 {
1037 const ExceptionCode *ec = dynamic_cast<const ExceptionCode *>(&e);
1038 if (ec && ec->code_defined())
1039 ret.status = Error::name(ec->code());
1040 }
1041 return ret;
1042}
1043
1050
1054
1059
1061{
1062 state->session->stop(); // On exception, stop client...
1063 state->io_context()->poll(); // and execute completion handlers.
1064}
1065
1067{
1068 ConnectionInfo ci;
1070 {
1071 MyClientEvents *events = state->events.get();
1072 if (events)
1073 events->get_connection_info(ci);
1074 }
1075 return ci;
1076}
1077
1079{
1081 {
1082 ClientCreds *cc = state->creds.get();
1083 if (cc && cc->session_id_defined())
1084 {
1085 tok.username = cc->get_username();
1086 tok.session_id = cc->get_password();
1087 return true;
1088 }
1089 }
1090 return false;
1091}
1092
1097
1099{
1100 if (req.error)
1101 {
1102 if (req.invalidAlias)
1103 {
1105 state->events->add_event(std::move(ev));
1106 }
1107
1109 state->events->add_event(std::move(ev));
1110
1111 state->stats->error(err_type);
1112 if (state->session)
1114 }
1115}
1116
1117OPENVPN_CLIENT_EXPORT bool OpenVPNClient::sign(const std::string &alias,
1118 const std::string &data,
1119 std::string &sig,
1120 const std::string &algorithm,
1121 const std::string &hashalg,
1122 const std::string &saltlen)
1123{
1125 req.alias = alias;
1126 req.data = data;
1127 req.algorithm = algorithm;
1128 req.hashalg = hashalg;
1129 req.saltlen = saltlen;
1130 external_pki_sign_request(req); // call out to derived class for RSA signature
1131 if (!req.error)
1132 {
1133 sig = req.sig;
1134 return true;
1135 }
1136
1138 return false;
1139}
1140
1145
1149
1154
1156{
1157 return MySessionStats::combined_name(index);
1158}
1159
1161{
1163 {
1164 MySessionStats *stats = state->stats.get();
1165 if (stats)
1166 {
1167 if (index == SessionStats::BYTES_IN || index == SessionStats::BYTES_OUT)
1168 stats->dco_update();
1169 return stats->combined_value(index);
1170 }
1171 }
1172 return 0;
1173}
1174
1176{
1177 std::vector<long long> sv;
1178 constexpr size_t n = MySessionStats::combined_n();
1179 sv.reserve(n);
1181 {
1182 MySessionStats *stats = state->stats.get();
1183 if (stats)
1184 stats->dco_update();
1185 for (size_t i = 0; i < n; ++i)
1186 sv.push_back(stats ? stats->combined_value(i) : 0);
1187 }
1188 else
1189 {
1190 for (size_t i = 0; i < n; ++i)
1191 sv.push_back(0);
1192 }
1193 return sv;
1194}
1195
1197{
1198 InterfaceStats ret;
1200 {
1201 MySessionStats *stats = state->stats.get();
1202
1203 // The reason for the apparent inversion between in/out below is
1204 // that TUN_*_OUT stats refer to data written to tun device,
1205 // but from the perspective of tun interface, this is incoming
1206 // data. Vice versa for TUN_*_IN.
1207 if (stats)
1208 {
1209 stats->dco_update();
1216 return ret;
1217 }
1218 }
1219
1220 ret.bytesOut = 0;
1221 ret.bytesIn = 0;
1222 ret.packetsOut = 0;
1223 ret.packetsIn = 0;
1224 ret.errorsOut = 0;
1225 ret.errorsIn = 0;
1226 return ret;
1227}
1228
1230{
1231 TransportStats ret;
1232 ret.lastPacketReceived = -1; // undefined
1233
1235 {
1236 MySessionStats *stats = state->stats.get();
1237 if (stats)
1238 {
1239 stats->dco_update();
1244
1245 // calculate time since last packet received
1246 {
1247 const Time &lpr = stats->last_packet_received();
1248 if (lpr.defined())
1249 {
1250 const Time::Duration dur = Time::now() - lpr;
1251 const unsigned int delta = (unsigned int)dur.to_binary_ms();
1252 if (delta <= 60 * 60 * 24 * 1024) // only define for time periods <= 1 day
1253 ret.lastPacketReceived = delta;
1254 }
1255 }
1256 return ret;
1257 }
1258 }
1259
1260 ret.bytesOut = 0;
1261 ret.bytesIn = 0;
1262 ret.packetsOut = 0;
1263 ret.packetsIn = 0;
1264 return ret;
1265}
1266
1272
1273OPENVPN_CLIENT_EXPORT void OpenVPNClient::pause(const std::string &reason)
1274{
1276 {
1277 ClientConnect *session = state->session.get();
1278 if (session)
1279 session->thread_safe_pause(reason);
1280 }
1281}
1282
1284{
1286 {
1287 ClientConnect *session = state->session.get();
1288 if (session)
1289 session->thread_safe_resume();
1290 }
1291}
1292
1294{
1296 {
1297 ClientConnect *session = state->session.get();
1298 if (session)
1299 session->thread_safe_reconnect(seconds);
1300 }
1301}
1302
1304{
1306 {
1307 ClientConnect *session = state->session.get();
1308 if (session)
1309 session->thread_safe_post_cc_msg(msg);
1310 }
1311}
1312
1313OPENVPN_CLIENT_EXPORT void OpenVPNClient::send_app_control_channel_msg(const std::string &protocol, const std::string &msg)
1314{
1316 {
1317 ClientConnect *session = state->session.get();
1318 if (session)
1320 }
1321}
1322
1323static SSLLib::SSLAPI::Config::Ptr setup_certcheck_ssl_config(const std::string &client_cert,
1324 const std::string &extra_certs,
1325 const std::optional<const std::string> &ca)
1326{
1327 SSLLib::SSLAPI::Config::Ptr config = new SSLLib::SSLAPI::Config;
1328 config->set_frame(new Frame(Frame::Context(128, 4096, 4096 - 128, 0, 16, BufAllocFlags::NO_FLAGS)));
1329 config->set_mode(Mode(Mode::CLIENT));
1330 config->load_cert(client_cert, extra_certs);
1331 unsigned int flags = SSLConst::LOG_VERIFY_STATUS;
1332
1333 if (ca)
1334 config->load_ca(*ca, false);
1335 else
1337
1338 config->set_flags(flags);
1339
1340 return config;
1341}
1342
1343OPENVPN_CLIENT_EXPORT void OpenVPNClient::start_cert_check(const std::string &client_cert,
1344 const std::string &clientkey,
1345 const std::optional<const std::string> &ca)
1346{
1348 {
1349 ClientConnect *session = state->session.get();
1350 if (session)
1351 {
1352 SSLLib::SSLAPI::Config::Ptr config = setup_certcheck_ssl_config(client_cert, "", ca);
1353 config->load_private_key(clientkey);
1354
1355 session->start_acc_certcheck(config);
1356 }
1357 }
1358}
1359
1360OPENVPN_CLIENT_EXPORT void OpenVPNClient::start_cert_check_epki(const std::string &alias, const std::optional<const std::string> &ca)
1361{
1363 {
1364 ClientConnect *session = state->session.get();
1365 if (session)
1366 {
1368 req.alias = alias;
1370
1371 if (req.error)
1372 {
1374 return;
1375 }
1376
1377 SSLLib::SSLAPI::Config::Ptr config = setup_certcheck_ssl_config(req.cert, req.supportingChain, ca);
1378
1379 config->set_external_pki_callback(this, alias);
1380
1381
1382 session->start_acc_certcheck(config);
1383 }
1384 }
1385}
1386
1390
1395
1400
1402{
1403 return openvpn_copyright;
1404}
1405
1407{
1408 std::string ret = platform_string();
1409#ifdef PRIVATE_TUNNEL_PROXY
1410 ret += " PT_PROXY";
1411#endif
1412#ifdef ENABLE_KOVPN
1413 ret += " KOVPN";
1414#elif defined(ENABLE_OVPNDCO) || defined(ENABLE_OVPNDCOWIN)
1415 ret += " OVPN-DCO";
1416#endif
1417#ifdef OPENVPN_GREMLIN
1418 ret += " GREMLIN";
1419#endif
1420#ifdef OPENVPN_DEBUG
1421 ret += " built on " __DATE__ " " __TIME__;
1422#endif
1423 return ret;
1424}
1425
1430} // namespace ClientAPI
1431} // 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:1313
virtual void external_pki_sign_request(ExternalPKISignRequest &)=0
TransportStats transport_stats() const
Definition ovpncli.cpp:1229
void post_cc_msg(const std::string &msg)
Definition ovpncli.cpp:1303
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:1360
bool session_token(SessionToken &tok)
Definition ovpncli.cpp:1078
static Status status_from_exception(const std::exception &)
Definition ovpncli.cpp:1028
virtual void remote_override(RemoteOverride &)
Definition ovpncli.cpp:1146
InterfaceStats tun_stats() const
Definition ovpncli.cpp:1196
std::vector< long long > stats_bundle() const
Definition ovpncli.cpp:1175
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:1343
void process_epki_cert_chain(const ExternalPKICertRequest &)
Definition ovpncli.cpp:821
void external_pki_error(const ExternalPKIRequestBase &, const Error::Type)
Definition ovpncli.cpp:1098
Status provide_creds(const ProvideCreds &)
Definition ovpncli.cpp:776
static std::string stats_name(int index)
Definition ovpncli.cpp:1155
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:1160
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:761
void pause(const std::string &reason)
Definition ovpncli.cpp:1273
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:1117
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:609
void submit_creds(const ClientCreds::Ptr &creds_arg)
Definition cliopt.hpp:1191
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:1481
void add_item(const Option &opt)
Definition options.hpp:1535
std::string render(const unsigned int flags) const
Definition options.hpp:1449
bool exists(const std::string &name) const
Definition options.hpp:1313
void push_back(const std::string &item)
Definition options.hpp:333
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:1323
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:28
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::vector< std::string > refPathList
Definition ovpncli.hpp:485
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)
static const char config[]
#define msg(flags,...)