diff --git a/OpenVPN Adapter/Vendors/openvpn/client/ovpncli.cpp b/OpenVPN Adapter/Vendors/openvpn/client/ovpncli.cpp index 36f6259..221067e 100644 --- a/OpenVPN Adapter/Vendors/openvpn/client/ovpncli.cpp +++ b/OpenVPN Adapter/Vendors/openvpn/client/ovpncli.cpp @@ -83,7 +83,7 @@ // on Android and iOS, use TunBuilderBase abstraction #include -#if (defined(OPENVPN_PLATFORM_ANDROID) || defined(OPENVPN_PLATFORM_IPHONE)) && !defined(OPENVPN_FORCE_TUN_NULL) && !defined(OPENVPN_CUSTOM_TUN_FACTORY) +#if (defined(OPENVPN_PLATFORM_ANDROID) || defined(OPENVPN_PLATFORM_IPHONE)) && !defined(OPENVPN_FORCE_TUN_NULL) && !defined(OPENVPN_EXTERNAL_TUN_FACTORY) #define USE_TUN_BUILDER #endif @@ -92,6 +92,7 @@ #include #include #include +#include #include #include #include @@ -205,7 +206,8 @@ namespace openvpn { // save connected event if (event->id() == ClientEvent::CONNECTED) last_connected = std::move(event); - + else if (event->id() == ClientEvent::DISCONNECTED) + parent->on_disconnect(); parent->event(ev); } } @@ -341,6 +343,51 @@ namespace openvpn { OpenVPNClient* parent = nullptr; }; + class MyClockTick + { + public: + MyClockTick(openvpn_io::io_context& io_context, + OpenVPNClient* parent_arg, + const unsigned int ms) + : timer(io_context), + parent(parent_arg), + period(Time::Duration::milliseconds(ms)) + { + } + + void cancel() + { + timer.cancel(); + } + + void detach_from_parent() + { + parent = nullptr; + } + + void schedule() + { + timer.expires_after(period); + timer.async_wait([this](const openvpn_io::error_code& error) + { + if (!parent || error) + return; + try { + parent->clock_tick(); + } + catch (...) + { + } + schedule(); + }); + } + + private: + AsioTimer timer; + OpenVPNClient* parent; + const Time::Duration period; + }; + namespace Private { class ClientState { @@ -355,6 +402,7 @@ namespace openvpn { MySessionStats::Ptr stats; MyClientEvents::Ptr events; ClientConnect::Ptr session; + std::unique_ptr clock_tick; // extra settings submitted by API client std::string server_override; @@ -376,6 +424,7 @@ namespace openvpn { ProtoContextOptions::Ptr proto_context_options; PeerInfo::Set::Ptr extra_peer_info; HTTPProxyTransport::Options::Ptr http_proxy_options; + unsigned int clock_tick_ms = 0; #ifdef OPENVPN_GREMLIN Gremlin::Config::Ptr gremlin_config; #endif @@ -429,6 +478,8 @@ namespace openvpn { socket_protect.detach_from_parent(); reconnect_notify.detach_from_parent(); remote_override.detach_from_parent(); + if (clock_tick) + clock_tick->detach_from_parent(); if (stats) stats->detach_from_parent(); if (events) @@ -474,6 +525,13 @@ namespace openvpn { async_stop_local_.stop(); } + // disconnect + void on_disconnect() + { + if (clock_tick) + clock_tick->cancel(); + } + private: ClientState(const ClientState&) = delete; ClientState& operator=(const ClientState&) = delete; @@ -596,6 +654,7 @@ namespace openvpn { state->dco = config.dco; state->echo = config.echo; state->info = config.info; + state->clock_tick_ms = config.clockTickMS; if (!config.gremlinConfig.empty()) { #ifdef OPENVPN_GREMLIN @@ -755,7 +814,9 @@ namespace openvpn { OPENVPN_CLIENT_EXPORT Status OpenVPNClient::connect() { +#if !defined(OPENVPN_OVPNCLI_SINGLE_THREAD) openvpn_io::detail::signal_blocker signal_blocker; // signals should be handled by parent thread +#endif #if defined(OPENVPN_LOG_LOGTHREAD_H) && !defined(OPENVPN_LOG_LOGBASE_H) #ifdef OPENVPN_LOG_GLOBAL #error ovpn3 core logging object only supports thread-local scope @@ -815,6 +876,9 @@ namespace openvpn { cc.socket_protect = &state->socket_protect; cc.builder = this; #endif +#if defined(OPENVPN_EXTERNAL_TUN_FACTORY) + cc.extern_tun_factory = this; +#endif // force Session ID use and disable password cache if static challenge is enabled if (state->creds @@ -864,6 +928,13 @@ namespace openvpn { // instantiate top-level client session state->session.reset(new ClientConnect(*state->io_context(), client_options)); + // convenience clock tick + if (state->clock_tick_ms) + { + state->clock_tick.reset(new MyClockTick(*state->io_context(), this, state->clock_tick_ms)); + state->clock_tick->schedule(); + } + // raise an exception if app has expired check_app_expired(); @@ -1142,7 +1213,7 @@ namespace openvpn { { ClientConnect* session = state->session.get(); if (session) - state->session->thread_safe_resume(); + session->thread_safe_resume(); } } @@ -1152,7 +1223,7 @@ namespace openvpn { { ClientConnect* session = state->session.get(); if (session) - state->session->thread_safe_reconnect(seconds); + session->thread_safe_reconnect(seconds); } } @@ -1162,10 +1233,19 @@ namespace openvpn { { ClientConnect* session = state->session.get(); if (session) - state->session->thread_safe_post_cc_msg(msg); + session->thread_safe_post_cc_msg(msg); } } + OPENVPN_CLIENT_EXPORT void OpenVPNClient::clock_tick() + { + } + + OPENVPN_CLIENT_EXPORT void OpenVPNClient::on_disconnect() + { + state->on_disconnect(); + } + OPENVPN_CLIENT_EXPORT std::string OpenVPNClient::crypto_self_test() { return SelfTest::crypto_self_test(); diff --git a/OpenVPN Adapter/Vendors/openvpn/client/ovpncli.hpp b/OpenVPN Adapter/Vendors/openvpn/client/ovpncli.hpp index 93039d7..e3581b0 100644 --- a/OpenVPN Adapter/Vendors/openvpn/client/ovpncli.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/client/ovpncli.hpp @@ -29,6 +29,7 @@ #include #include +#include #include namespace openvpn { @@ -269,6 +270,11 @@ namespace openvpn { // pass through control channel INFO notifications via "INFO" event bool info = false; + // Periodic convenience clock tick in milliseconds. + // Will call clock_tick() at a frequency defined by this parameter. + // Set to 0 to disable. + unsigned int clockTickMS = 0; + // Gremlin configuration (requires that the core is built with OPENVPN_GREMLIN) std::string gremlinConfig; }; @@ -403,7 +409,11 @@ namespace openvpn { }; // Top-level OpenVPN client class. - class OpenVPNClient : public TunBuilderBase, public LogReceiver, private ExternalPKIBase { + class OpenVPNClient : public TunBuilderBase, // expose tun builder virtual methods + public LogReceiver, // log message notification + public ExternalTun::Factory, // low-level tun override + private ExternalPKIBase + { public: OpenVPNClient(); virtual ~OpenVPNClient(); @@ -523,6 +533,9 @@ namespace openvpn { virtual bool remote_override_enabled(); virtual void remote_override(RemoteOverride&); + // Periodic convenience clock tick, controlled by Config::clock_tick_ms + virtual void clock_tick(); + // Do a crypto library self test static std::string crypto_self_test(); @@ -561,6 +574,9 @@ namespace openvpn { void check_app_expired(); static MergeConfig build_merge_config(const ProfileMerge&); + friend class MyClientEvents; + void on_disconnect(); + // from ExternalPKIBase virtual bool sign(const std::string& data, std::string& sig); diff --git a/OpenVPN Adapter/Vendors/openvpn/javacli/ovpncli.i b/OpenVPN Adapter/Vendors/openvpn/javacli/ovpncli.i index bacae3b..6fc07c5 100644 --- a/OpenVPN Adapter/Vendors/openvpn/javacli/ovpncli.i +++ b/OpenVPN Adapter/Vendors/openvpn/javacli/ovpncli.i @@ -12,8 +12,9 @@ #include "ovpncli.hpp" %} -// ignore ClientAPI::OpenVPNClient bases other than TunBuilderBase +// ignore these ClientAPI::OpenVPNClient bases %ignore openvpn::ClientAPI::LogReceiver; +%ignore openvpn::ExternalTun::Factory; // modify exported C++ class names to incorporate their enclosing namespace %rename(ClientAPI_OpenVPNClient) OpenVPNClient; @@ -47,4 +48,5 @@ namespace std { // interface to be bridged between C++ and target language %include "openvpn/pki/epkibase.hpp" %include "openvpn/tun/builder/base.hpp" +%import "openvpn/tun/extern/fw.hpp" // ignored %include "ovpncli.hpp" diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/cf/cf.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/cf.hpp similarity index 88% rename from OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/cf/cf.hpp rename to OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/cf.hpp index bb48652..cbef799 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/cf/cf.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/cf.hpp @@ -26,13 +26,11 @@ #include #include #include +#include +#include #include -#include -#include -#include - // Wrapper classes for Apple Core Foundation objects. #define OPENVPN_CF_WRAP(cls, castmeth, cftype, idmeth) \ @@ -52,7 +50,7 @@ { \ CFTypeRef o = Type::cast(obj); \ if (o) \ - return cls(cftype(o), BORROW); \ + return cls(cftype(o), GET); \ else \ return cls(); \ } @@ -60,9 +58,9 @@ namespace openvpn { namespace CF { - enum Own { - OWN, - BORROW + enum Rule { + CREATE, // create rule + GET // get rule }; template struct Type {}; @@ -73,10 +71,9 @@ namespace openvpn { public: Wrap() : obj_(nullptr) {} - // Set own=BORROW if we don't currently own the object - explicit Wrap(T obj, const Own own=OWN) + explicit Wrap(T obj, const Rule rule=CREATE) { - if (own == BORROW && obj) + if (rule == GET && obj) CFRetain(obj); obj_ = obj; } @@ -118,9 +115,9 @@ namespace openvpn { std::swap(obj_, other.obj_); } - void reset(T obj=nullptr, const Own own=OWN) + void reset(T obj=nullptr, const Rule rule=CREATE) { - if (own == BORROW && obj) + if (rule == GET && obj) CFRetain(obj); if (obj_) CFRelease(obj_); @@ -129,15 +126,20 @@ namespace openvpn { bool defined() const { return obj_ != nullptr; } + explicit operator bool() const noexcept + { + return defined(); + } + T operator()() const { return obj_; } CFTypeRef generic() const { return (CFTypeRef)obj_; } static T cast(CFTypeRef obj) { return T(Type::cast(obj)); } - static Wrap from_generic(CFTypeRef obj, const Own own=OWN) + static Wrap from_generic(CFTypeRef obj, const Rule rule=CREATE) { - return Wrap(cast(obj), own); + return Wrap(cast(obj), rule); } T release() @@ -155,7 +157,7 @@ namespace openvpn { } // Intended for use with Core Foundation methods that require - // a T* for saving a (non-borrowed) return value + // a T* for saving a create-rule return value T* mod_ref() { if (obj_) @@ -181,14 +183,11 @@ namespace openvpn { } private: - Wrap& operator=(T obj); // prevent use because no way to pass ownership parameter + Wrap& operator=(T obj) = delete; // prevent use because no way to pass rule parameter T obj_; }; - // essentially a vector of void *, used as source for array and dictionary constructors - typedef BufferAllocatedType SrcList; - // common CF types OPENVPN_CF_WRAP(String, string_cast, CFStringRef, CFStringGetTypeID) @@ -207,7 +206,7 @@ namespace openvpn { inline Generic generic_cast(CFTypeRef obj) { - return Generic(obj, BORROW); + return Generic(obj, GET); } // constructors @@ -219,7 +218,7 @@ namespace openvpn { inline String string(CFStringRef str) { - return String(str, BORROW); + return String(str, GET); } inline String string(const String& str) @@ -267,11 +266,6 @@ namespace openvpn { return Array(CFArrayCreate(kCFAllocatorDefault, values, numValues, &kCFTypeArrayCallBacks)); } - inline Array array(const SrcList& values) - { - return array((const void **)values.c_data(), values.size()); - } - inline Dict dict(const void **keys, const void **values, CFIndex numValues) { return Dict(CFDictionaryCreate(kCFAllocatorDefault, @@ -282,19 +276,14 @@ namespace openvpn { &kCFTypeDictionaryValueCallBacks)); } - inline Dict dict(const SrcList& keys, const SrcList& values) - { - return dict((const void **)keys.c_data(), (const void **)values.c_data(), std::min(keys.size(), values.size())); - } - inline Dict const_dict(MutableDict& mdict) { - return Dict(mdict(), CF::BORROW); + return Dict(mdict(), CF::GET); } inline Array const_array(MutableArray& marray) { - return Array(marray(), CF::BORROW); + return Array(marray(), CF::GET); } inline Dict empty_dict() @@ -374,7 +363,13 @@ namespace openvpn { // string methods - OPENVPN_SIMPLE_EXCEPTION(cppstring_error); + struct cppstring_error : public std::exception + { + virtual const char* what() const throw() + { + return "cppstring_error"; + } + }; inline std::string cppstring(CFStringRef str) { diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/cf/cfhelper.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/cfhelper.hpp similarity index 93% rename from OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/cf/cfhelper.hpp rename to OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/cfhelper.hpp index da77899..fab4a18 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/cf/cfhelper.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/cfhelper.hpp @@ -22,7 +22,8 @@ #ifndef OPENVPN_APPLECRYPTO_CF_CFHELPER_H #define OPENVPN_APPLECRYPTO_CF_CFHELPER_H -#include +#include +#include // These methods build on the Wrapper classes for Apple Core Foundation objects // defined in cf.hpp. They add additional convenience methods, such as dictionary @@ -31,6 +32,19 @@ namespace openvpn { namespace CF { + // essentially a vector of void *, used as source for array and dictionary constructors + typedef BufferAllocatedType SrcList; + + inline Array array(const SrcList& values) + { + return array((const void **)values.c_data(), values.size()); + } + + inline Dict dict(const SrcList& keys, const SrcList& values) + { + return dict((const void **)keys.c_data(), (const void **)values.c_data(), std::min(keys.size(), values.size())); + } + inline CFTypeRef mutable_dict_new() { return CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/cfhost.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/cfhost.hpp new file mode 100644 index 0000000..ea66f7c --- /dev/null +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/cfhost.hpp @@ -0,0 +1,33 @@ +// OpenVPN -- An application to securely tunnel IP networks +// over a single port, with support for SSL/TLS-based +// session authentication and key exchange, +// packet encryption, packet authentication, and +// packet compression. +// +// Copyright (C) 2012-2017 OpenVPN Technologies, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License Version 3 +// as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_APPLECRYPTO_CF_CFHOST_H +#define OPENVPN_APPLECRYPTO_CF_CFHOST_H + +#include + +namespace openvpn { + namespace CF { + OPENVPN_CF_WRAP(Host, host_cast, CFHostRef, CFHostGetTypeID) + } +} + +#endif diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/runloop.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/cfrunloop.hpp similarity index 90% rename from OpenVPN Adapter/Vendors/openvpn/openvpn/apple/runloop.hpp rename to OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/cfrunloop.hpp index 1ec2823..78b1587 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/runloop.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/cfrunloop.hpp @@ -19,14 +19,14 @@ // along with this program in the COPYING file. // If not, see . -#ifndef OPENVPN_APPLE_RUNLOOP_H -#define OPENVPN_APPLE_RUNLOOP_H +#ifndef OPENVPN_APPLECRYPTO_CF_CFRUNLOOP_H +#define OPENVPN_APPLECRYPTO_CF_CFRUNLOOP_H -#include +#include namespace openvpn { namespace CF { - OPENVPN_CF_WRAP(RunLoop, runloop_cast, CFRunLoopRef, CFRunLoopGetTypeID); + OPENVPN_CF_WRAP(RunLoop, runloop_cast, CFRunLoopRef, CFRunLoopGetTypeID) OPENVPN_CF_WRAP(RunLoopSource, runloop_source_cast, CFRunLoopSourceRef, CFRunLoopSourceGetTypeID); } } diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/cf/cfsec.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/cfsec.hpp similarity index 98% rename from OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/cf/cfsec.hpp rename to OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/cfsec.hpp index bb3acdd..0a9d9cd 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/cf/cfsec.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/cfsec.hpp @@ -36,7 +36,7 @@ #include #include -#include +#include // Define C++ wrappings for Apple security-related objects. diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/cfsocket.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/cfsocket.hpp new file mode 100644 index 0000000..494da80 --- /dev/null +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/cfsocket.hpp @@ -0,0 +1,33 @@ +// OpenVPN -- An application to securely tunnel IP networks +// over a single port, with support for SSL/TLS-based +// session authentication and key exchange, +// packet encryption, packet authentication, and +// packet compression. +// +// Copyright (C) 2012-2017 OpenVPN Technologies, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License Version 3 +// as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_APPLECRYPTO_CF_CFSTREAM_H +#define OPENVPN_APPLECRYPTO_CF_CFSTREAM_H + +#include + +namespace openvpn { + namespace CF { + OPENVPN_CF_WRAP(Socket, socket_cast, CFSocketRef, CFSocketGetTypeID) + } +} + +#endif diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/cfstream.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/cfstream.hpp new file mode 100644 index 0000000..8183aa8 --- /dev/null +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/cfstream.hpp @@ -0,0 +1,34 @@ +// OpenVPN -- An application to securely tunnel IP networks +// over a single port, with support for SSL/TLS-based +// session authentication and key exchange, +// packet encryption, packet authentication, and +// packet compression. +// +// Copyright (C) 2012-2017 OpenVPN Technologies, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License Version 3 +// as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_APPLECRYPTO_CF_CFSTREAM_H +#define OPENVPN_APPLECRYPTO_CF_CFSTREAM_H + +#include + +namespace openvpn { + namespace CF { + OPENVPN_CF_WRAP(ReadStream, read_stream_cast, CFReadStreamRef, CFReadStreamGetTypeID) + OPENVPN_CF_WRAP(WriteStream, write_stream_cast, CFWriteStreamRef, CFWriteStreamGetTypeID) + } +} + +#endif diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/cf/cftimer.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/cftimer.hpp similarity index 96% rename from OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/cf/cftimer.hpp rename to OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/cftimer.hpp index a4949d2..9c9157c 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/cf/cftimer.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/cftimer.hpp @@ -22,7 +22,7 @@ #ifndef OPENVPN_APPLECRYPTO_CF_CFTIMER_H #define OPENVPN_APPLECRYPTO_CF_CFTIMER_H -#include +#include namespace openvpn { namespace CF { diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/cf/error.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/error.hpp similarity index 100% rename from OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/cf/error.hpp rename to OpenVPN Adapter/Vendors/openvpn/openvpn/apple/cf/error.hpp diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/util/iosactiveiface.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/iosactiveiface.hpp similarity index 97% rename from OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/util/iosactiveiface.hpp rename to OpenVPN Adapter/Vendors/openvpn/openvpn/apple/iosactiveiface.hpp index 1118e8b..a0dfb1a 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/util/iosactiveiface.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/iosactiveiface.hpp @@ -21,7 +21,7 @@ #include -#include +#include #include #ifndef OPENVPN_APPLECRYPTO_UTIL_IOSACTIVEIFACE_H diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/maclife.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/maclife.hpp index 0f75c22..c8eaffe 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/maclife.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/maclife.hpp @@ -28,11 +28,11 @@ #include #include -#include -#include -#include +#include +#include +#include +#include #include -#include #include #include @@ -126,7 +126,7 @@ namespace openvpn { void thread_func() { - runloop.reset(CFRunLoopGetCurrent(), CF::BORROW); + runloop.reset(CFRunLoopGetCurrent(), CF::GET); Log::Context logctx(logwrap); try { // set up dynamic store query object diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/util/reach.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/reach.hpp similarity index 100% rename from OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/util/reach.hpp rename to OpenVPN Adapter/Vendors/openvpn/openvpn/apple/reach.hpp diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/util/reachable.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/reachable.hpp similarity index 99% rename from OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/util/reachable.hpp rename to OpenVPN Adapter/Vendors/openvpn/openvpn/apple/reachable.hpp index f2ce660..3c3ae00 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/util/reachable.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/reachable.hpp @@ -77,8 +77,8 @@ #include #include -#include -#include +#include +#include namespace openvpn { namespace CF { diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/scdynstore.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/scdynstore.hpp index fd92af6..6ed2ab4 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/scdynstore.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/apple/scdynstore.hpp @@ -24,7 +24,7 @@ #include -#include +#include namespace openvpn { namespace CF { diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/crypto/cipher.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/crypto/cipher.hpp index bab02d0..427c5a7 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/crypto/cipher.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/crypto/cipher.hpp @@ -36,7 +36,7 @@ #include #include #include -#include +#include namespace openvpn { namespace AppleCrypto { diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/crypto/digest.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/crypto/digest.hpp index 6ffd762..db18056 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/crypto/digest.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/crypto/digest.hpp @@ -34,7 +34,7 @@ #include #include #include -#include +#include #define OPENVPN_DIGEST_CONTEXT(TYPE) CC_##TYPE##_CTX TYPE##_ctx diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/ssl/sslctx.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/ssl/sslctx.hpp index cdbbe10..ac6afa9 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/ssl/sslctx.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/applecrypto/ssl/sslctx.hpp @@ -47,8 +47,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/asio/asiopolysock.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/asio/asiopolysock.hpp index eaf4520..11a3400 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/asio/asiopolysock.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/asio/asiopolysock.hpp @@ -139,7 +139,9 @@ namespace openvpn { #if !defined(OPENVPN_PLATFORM_WIN) virtual void set_cloexec() override { - SockOpt::set_cloexec(socket.native_handle()); + const int fd = socket.native_handle(); + if (fd >= 0) + SockOpt::set_cloexec(fd); } #endif @@ -207,7 +209,9 @@ namespace openvpn { virtual void set_cloexec() override { - SockOpt::set_cloexec(socket.native_handle()); + const int fd = socket.native_handle(); + if (fd >= 0) + SockOpt::set_cloexec(fd); } virtual void close() override diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/client/cliconnect.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/client/cliconnect.hpp index 6d29a80..ba8b413 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/client/cliconnect.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/client/cliconnect.hpp @@ -156,6 +156,9 @@ namespace openvpn { ClientEvent::Base::Ptr ev = new ClientEvent::Disconnected(); client_options->events().add_event(std::move(ev)); +#ifdef OPENVPN_IO_REQUIRES_STOP + io_context.stop(); +#endif } } @@ -214,7 +217,7 @@ namespace openvpn { OPENVPN_LOG("Client terminated, reconnecting in " << seconds << "..."); server_poll_timer.cancel(); client_options->remote_reset_cache_item(); - restart_wait_timer.expires_at(Time::now() + Time::Duration::seconds(seconds)); + restart_wait_timer.expires_after(Time::Duration::seconds(seconds)); restart_wait_timer.async_wait([self=Ptr(this), gen=generation](const openvpn_io::error_code& error) { self->restart_wait_callback(gen, error); @@ -345,7 +348,7 @@ namespace openvpn { { if (!conn_timer_pending && conn_timeout > 0) { - conn_timer.expires_at(Time::now() + Time::Duration::seconds(conn_timeout)); + conn_timer.expires_after(Time::Duration::seconds(conn_timeout)); conn_timer.async_wait([self=Ptr(this), gen=generation](const openvpn_io::error_code& error) { self->conn_timer_callback(gen, error); @@ -393,7 +396,7 @@ namespace openvpn { server_poll_timer.cancel(); interim_finalize(); client_options->remote_reset_cache_item(); - restart_wait_timer.expires_at(Time::now() + Time::Duration::milliseconds(delay_ms)); + restart_wait_timer.expires_after(Time::Duration::milliseconds(delay_ms)); restart_wait_timer.async_wait([self=Ptr(this), gen=generation](const openvpn_io::error_code& error) { self->restart_wait_callback(gen, error); @@ -589,7 +592,7 @@ namespace openvpn { restart_wait_timer.cancel(); if (client_options->server_poll_timeout_enabled()) { - server_poll_timer.expires_at(Time::now() + client_options->server_poll_timeout()); + server_poll_timer.expires_after(client_options->server_poll_timeout()); server_poll_timer.async_wait([self=Ptr(this), gen=generation](const openvpn_io::error_code& error) { self->server_poll_callback(gen, error); diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/client/cliopt.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/client/cliopt.hpp index b16a612..10e0b9a 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/client/cliopt.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/client/cliopt.hpp @@ -66,8 +66,9 @@ #include #endif -#if defined(OPENVPN_CUSTOM_TUN_FACTORY) -// includer of this file must define OPENVPN_CUSTOM_TUN_FACTORY class +#if defined(OPENVPN_EXTERNAL_TUN_FACTORY) +// requires that client implements ExternalTun::Factory::new_tun_factory +#include #elif defined(USE_TUN_BUILDER) #include #elif defined(OPENVPN_PLATFORM_LINUX) && !defined(OPENVPN_FORCE_TUN_NULL) @@ -151,6 +152,10 @@ namespace openvpn { #if defined(USE_TUN_BUILDER) TunBuilderBase* builder = nullptr; #endif + +#if defined(OPENVPN_EXTERNAL_TUN_FACTORY) + ExternalTun::Factory* extern_tun_factory = nullptr; +#endif }; ClientOptions(const OptionList& opt, // only needs to remain in scope for duration of constructor call @@ -191,7 +196,7 @@ namespace openvpn { rng.reset(new SSLLib::RandomAPI(false)); prng.reset(new SSLLib::RandomAPI(true)); -#if defined(ENABLE_DCO) && !defined(OPENVPN_FORCE_TUN_NULL) && !defined(OPENVPN_CUSTOM_TUN_FACTORY) +#if defined(ENABLE_DCO) && !defined(OPENVPN_FORCE_TUN_NULL) && !defined(OPENVPN_EXTERNAL_TUN_FACTORY) if (config.dco) dco = DCOTransport::new_controller(); #else @@ -292,17 +297,22 @@ namespace openvpn { } else { -#if defined(OPENVPN_CUSTOM_TUN_FACTORY) +#if defined(OPENVPN_EXTERNAL_TUN_FACTORY) { - OPENVPN_CUSTOM_TUN_FACTORY::Ptr tunconf = OPENVPN_CUSTOM_TUN_FACTORY::new_obj(); - tunconf->tun_prop.session_name = session_name; - tunconf->tun_prop.google_dns_fallback = config.google_dns_fallback; + ExternalTun::Config tunconf; + tunconf.tun_prop.layer = layer; + tunconf.tun_prop.session_name = session_name; + tunconf.tun_prop.google_dns_fallback = config.google_dns_fallback; if (tun_mtu) - tunconf->tun_prop.mtu = tun_mtu; - tunconf->frame = frame; - tunconf->stats = cli_stats; - tunconf->tun_prop.remote_list = remote_list; - tun_factory = tunconf; + tunconf.tun_prop.mtu = tun_mtu; + tunconf.frame = frame; + tunconf.stats = cli_stats; + tunconf.tun_prop.remote_list = remote_list; + tunconf.tun_persist = config.tun_persist; + tunconf.stop = config.stop; + tun_factory.reset(config.extern_tun_factory->new_tun_factory(tunconf, opt)); + if (!tun_factory) + throw option_error("OPENVPN_EXTERNAL_TUN_FACTORY: no tun factory"); } #elif defined(USE_TUN_BUILDER) { @@ -448,7 +458,7 @@ namespace openvpn { // IPv6 { const unsigned int n = push_base->singleton.extend(opt, "block-ipv6"); - if (!n && config.ipv6() == IPv6Setting::NO) + if (!n && config.ipv6() == IPv6Setting::No) push_base->singleton.emplace_back("block-ipv6"); } } @@ -463,9 +473,9 @@ namespace openvpn { PeerInfo::Set::Ptr pi(new PeerInfo::Set); // IPv6 - if (config.ipv6() == IPv6Setting::NO) + if (config.ipv6() == IPv6Setting::No) pi->emplace_back("IV_IPv6", "0"); - else if (config.ipv6() == IPv6Setting::YES) + else if (config.ipv6() == IPv6Setting::Yes) pi->emplace_back("IV_IPv6", "1"); // autologin sessions diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/client/cliproto.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/client/cliproto.hpp index c2fa707..8f775d7 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/client/cliproto.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/client/cliproto.hpp @@ -777,7 +777,7 @@ namespace openvpn { { if (!received_options.partial()) { - push_request_timer.expires_at(now() + dur); + push_request_timer.expires_after(dur); push_request_timer.async_wait([self=Ptr(this), dur](const openvpn_io::error_code& error) { self->send_push_request_callback(dur, error); @@ -865,7 +865,7 @@ namespace openvpn { void schedule_inactive_timer() { - inactive_timer.expires_at(now() + inactive_duration); + inactive_timer.expires_after(inactive_duration); inactive_timer.async_wait([self=Ptr(this)](const openvpn_io::error_code& error) { self->inactive_callback(error); @@ -955,7 +955,7 @@ namespace openvpn { void schedule_info_hold_callback() { Base::update_now(); - info_hold_timer.expires_at(now() + Time::Duration::seconds(1)); + info_hold_timer.expires_after(Time::Duration::seconds(1)); info_hold_timer.async_wait([self=Ptr(this)](const openvpn_io::error_code& error) { self->info_hold_callback(error); diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/common/function.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/common/function.hpp index 80879a2..4ad0217 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/common/function.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/common/function.hpp @@ -24,36 +24,72 @@ #ifndef OPENVPN_COMMON_FUNCTION_H #define OPENVPN_COMMON_FUNCTION_H +#include // for std::size_t +#include // for std::move #include -#include namespace openvpn { - template + // F -- function type (usually a lambda expression) + // N (default=3) -- max size of functor in void* machine words before we overflow to dynamic allocation + // INTERN_ONLY (default=false) -- if true, throw a static assertion if functor cannot be stored internally + template class Function; - template - class Function + template + class Function { public: - static constexpr size_t N = 3; // max size of functor in machine words + Function() noexcept + { + methods = nullptr; + } template Function(T&& functor) noexcept { - static_assert(sizeof(Intern) <= sizeof(data), "Functor too large"); - setup_methods(); - new (data) Intern(std::move(functor)); + construct(std::move(functor)); } - Function(Function&& f) noexcept + Function(Function&& other) noexcept { - methods = f.methods; - methods->move(data, f.data); + methods = other.methods; + other.methods = nullptr; + if (methods) + methods->move(data, other.data); + } + + Function& operator=(Function&& other) noexcept + { + if (methods) + methods->destruct(data); + methods = other.methods; + other.methods = nullptr; + if (methods) + methods->move(data, other.data); + return *this; } ~Function() { - methods->destruct(data); + if (methods) + methods->destruct(data); + } + + template + void reset(T&& functor) noexcept + { + if (methods) + methods->destruct(data); + construct(std::move(functor)); + } + + void reset() noexcept + { + if (methods) + { + methods->destruct(data); + methods = nullptr; + } } R operator()(A... args) @@ -61,7 +97,33 @@ namespace openvpn { return methods->invoke(data, args...); } + explicit operator bool() const noexcept + { + return methods != nullptr; + } + private: + template + void construct(T&& functor) noexcept + { + constexpr bool is_intern = (sizeof(Intern) <= sizeof(data)); + static_assert(!INTERN_ONLY || is_intern, "Function: Intern doesn't fit in data[] and INTERN_ONLY=true"); + static_assert(sizeof(Extern) <= sizeof(data), "Function: Extern doesn't fit in data[]"); + + if (is_intern) + { + // store functor internally (in data) + setup_methods_intern(); + new (data) Intern(std::move(functor)); + } + else + { + // store functor externally (using new) + setup_methods_extern(); + new (data) Extern(std::move(functor)); + } + } + struct Methods { R (*invoke)(void *, A...); @@ -70,7 +132,7 @@ namespace openvpn { }; template - void setup_methods() + void setup_methods_intern() { static const struct Methods m = { &Intern::invoke, @@ -80,15 +142,22 @@ namespace openvpn { methods = &m; } + template + void setup_methods_extern() + { + static const struct Methods m = { + &Extern::invoke, + &Extern::move, + &Extern::destruct, + }; + methods = &m; + } + + // store functor internally (in data) template class Intern { public: - Intern(Intern&& obj) noexcept - : functor_(std::move(obj.functor_)) - { - } - Intern(T&& functor) noexcept : functor_(std::move(functor)) { @@ -116,6 +185,40 @@ namespace openvpn { T functor_; }; + // store functor externally (using new) + template + class Extern + { + public: + Extern(T&& functor) noexcept + : functor_(new T(std::move(functor))) + { + } + + static R invoke(void *ptr, A... args) + { + Extern* self = reinterpret_cast*>(ptr); + return (*self->functor_)(args...); + } + + static void move(void *dest, void *src) + { + Extern* d = reinterpret_cast*>(dest); + Extern* s = reinterpret_cast*>(src); + d->functor_ = s->functor_; + // no need to set s->functor_=nullptr because parent will not destruct src after move + } + + static void destruct(void *ptr) + { + Extern* self = reinterpret_cast*>(ptr); + delete self->functor_; + } + + private: + T* functor_; + }; + const Methods* methods; void* data[N]; }; diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/common/process.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/common/process.hpp index f111774..72e594a 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/common/process.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/common/process.hpp @@ -152,12 +152,18 @@ namespace openvpn { { if (!argv.empty()) { - RedirectPipe::InOut inout; os << to_string() << std::endl; +#ifdef OPENVPN_PROCESS_AVOID_PIPES + const int status = system_cmd(argv[0], argv); + if (status < 0) + os << "Error: command failed to execute" << std::endl; +#else + RedirectPipe::InOut inout; const int status = system_cmd(argv[0], argv, nullptr, inout, true); if (status < 0) os << "Error: command failed to execute" << std::endl; os << inout.out; +#endif } else os << "Error: command called with empty argv" << std::endl; diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/common/runcontext.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/common/runcontext.hpp index dd288ba..a8719a3 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/common/runcontext.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/common/runcontext.hpp @@ -123,7 +123,7 @@ namespace openvpn { signal_rearm(); #ifdef OPENVPN_EXIT_IN - exit_timer.expires_at(Time::now() + Time::Duration::seconds(OPENVPN_EXIT_IN)); + exit_timer.expires_after(Time::Duration::seconds(OPENVPN_EXIT_IN)); exit_timer.async_wait([self=Ptr(this)](const openvpn_io::error_code& error) { if (!error) diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/time/asiotimer.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/time/asiotimer.hpp index a0ac5ce..e8ef6cb 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/time/asiotimer.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/time/asiotimer.hpp @@ -54,6 +54,11 @@ namespace openvpn { { return time_point(duration(t.raw())); } + + static duration to_duration(const Time::Duration& d) + { + return duration(d.raw()); + } }; class AsioTimer : public openvpn_io::basic_waitable_timer @@ -67,7 +72,12 @@ namespace openvpn { std::size_t expires_at(const Time& t) { return openvpn_io::basic_waitable_timer::expires_at(AsioClock::to_time_point(t)); - } + } + + std::size_t expires_after(const Time::Duration& d) + { + return openvpn_io::basic_waitable_timer::expires_after(AsioClock::to_duration(d)); + } }; } diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/extern/config.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/extern/config.hpp new file mode 100644 index 0000000..a67c411 --- /dev/null +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/extern/config.hpp @@ -0,0 +1,45 @@ +// OpenVPN -- An application to securely tunnel IP networks +// over a single port, with support for SSL/TLS-based +// session authentication and key exchange, +// packet encryption, packet authentication, and +// packet compression. +// +// Copyright (C) 2012-2017 OpenVPN Technologies, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License Version 3 +// as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_TUN_EXTERN_CONFIG_H +#define OPENVPN_TUN_EXTERN_CONFIG_H + +// These includes are also intended to resolve forward references in fw.hpp +#include +#include +#include +#include +#include +#include + +namespace openvpn { + namespace ExternalTun { + struct Config + { + TunProp::Config tun_prop; + Frame::Ptr frame; + SessionStats::Ptr stats; + Stop* stop = nullptr; + bool tun_persist = false; + }; + } +} +#endif diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/extern/fw.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/extern/fw.hpp new file mode 100644 index 0000000..9ecdfe3 --- /dev/null +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/extern/fw.hpp @@ -0,0 +1,49 @@ +// OpenVPN -- An application to securely tunnel IP networks +// over a single port, with support for SSL/TLS-based +// session authentication and key exchange, +// packet encryption, packet authentication, and +// packet compression. +// +// Copyright (C) 2012-2017 OpenVPN Technologies, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License Version 3 +// as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_TUN_EXTERN_FW_H +#define OPENVPN_TUN_EXTERN_FW_H + +namespace openvpn { + +#if defined(OPENVPN_EXTERNAL_TUN_FACTORY) + + struct TunClientFactory; + class OptionList; + + namespace ExternalTun { + struct Config; // defined in config.hpp + struct Factory + { + virtual TunClientFactory* new_tun_factory(const Config& conf, const OptionList& opt) = 0; + virtual ~Factory() {} + }; + } + +#else + + namespace ExternalTun { + struct Factory {}; + } + +#endif +} +#endif diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/ipv6_setting.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/ipv6_setting.hpp index c0e9af1..fcc1ae1 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/ipv6_setting.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/ipv6_setting.hpp @@ -29,9 +29,9 @@ namespace openvpn { { public: enum Type { - NO, - YES, - DEFAULT, + No, + Yes, + Default, }; IPv6Setting() @@ -49,11 +49,11 @@ namespace openvpn { { switch (type_) { - case NO: + case No: return "no"; - case YES: + case Yes: return "yes"; - case DEFAULT: + case Default: default: return "default"; } @@ -62,11 +62,11 @@ namespace openvpn { static IPv6Setting parse(const std::string& str) { if (str == "no") - return IPv6Setting(NO); + return IPv6Setting(No); else if (str == "yes") - return IPv6Setting(YES); + return IPv6Setting(Yes); else if (str == "default") - return IPv6Setting(DEFAULT); + return IPv6Setting(Default); else throw Exception("IPv6Setting: unrecognized setting: '" + str + '\''); } @@ -82,7 +82,7 @@ namespace openvpn { } private: - Type type_ = DEFAULT; + Type type_ = Default; }; } diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/mac/gwv4.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/mac/gwv4.hpp index 501cc89..057cd0d 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/mac/gwv4.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/mac/gwv4.hpp @@ -26,8 +26,10 @@ #include #include +#include #include #include +#include #include #include diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/mac/macdns.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/mac/macdns.hpp index 00bfb60..9f212c9 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/mac/macdns.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/mac/macdns.hpp @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include namespace openvpn { diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/mac/macdns_watchdog.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/mac/macdns_watchdog.hpp index 794167f..7410d9b 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/mac/macdns_watchdog.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/mac/macdns_watchdog.hpp @@ -29,8 +29,8 @@ #include #include -#include -#include +#include +#include #include namespace openvpn { @@ -183,7 +183,7 @@ namespace openvpn { // as well. void thread_func() { - runloop.reset(CFRunLoopGetCurrent(), CF::BORROW); + runloop.reset(CFRunLoopGetCurrent(), CF::GET); Log::Context logctx(logwrap); try { diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/mac/macgw.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/mac/macgw.hpp index 7737f6b..1dc4545 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/mac/macgw.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/mac/macgw.hpp @@ -28,7 +28,7 @@ #include #include #include -#include +#include namespace openvpn { struct MacGWInfo diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/persist/tunwrapasio.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/persist/tunwrapasio.hpp index e4cc077..7c932ed 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/persist/tunwrapasio.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/persist/tunwrapasio.hpp @@ -22,6 +22,8 @@ #ifndef OPENVPN_TUN_PERSIST_TUNWRAPASIO_H #define OPENVPN_TUN_PERSIST_TUNWRAPASIO_H +#include + namespace openvpn { // This object supports that subset of the Asio stream @@ -48,17 +50,14 @@ namespace openvpn { // subset of methods used by TunIO). // Prototypes from asio/windows/basic_stream_handle.hpp - template - ASIO_INITFN_RESULT_TYPE(ReadHandler, - void (openvpn_io::error_code, std::size_t)) - async_read_some(const MutableBufferSequence& buffers, - ASIO_MOVE_ARG(ReadHandler) handler) + template + void async_read_some(const MUTABLE_BUFFER& buffers, HANDLER&& handler) { - return tun_wrap->obj()->async_read_some(buffers, handler); + return tun_wrap->obj()->async_read_some(buffers, std::move(handler)); } - template - std::size_t write_some(const ConstBufferSequence& buffers) + template + std::size_t write_some(const CONST_BUFFER& buffers) { return tun_wrap->obj()->write_some(buffers); } diff --git a/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/win/client/tuncli.hpp b/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/win/client/tuncli.hpp index 21fea0f..71fe54e 100644 --- a/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/win/client/tuncli.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/openvpn/tun/win/client/tuncli.hpp @@ -388,7 +388,7 @@ namespace openvpn { void layer_2_schedule_timer(const unsigned int seconds) { - l2_timer.expires_at(Time::now() + Time::Duration::seconds(seconds)); + l2_timer.expires_after(Time::Duration::seconds(seconds)); l2_timer.async_wait([self=Ptr(this)](const openvpn_io::error_code& error) { if (!error && !self->halt) diff --git a/OpenVPN Adapter/Vendors/openvpn/scripts/build b/OpenVPN Adapter/Vendors/openvpn/scripts/build index b4988a1..a5a783e 100755 --- a/OpenVPN Adapter/Vendors/openvpn/scripts/build +++ b/OpenVPN Adapter/Vendors/openvpn/scripts/build @@ -292,13 +292,9 @@ fi # Construct command if [ "$OBJC" == "1" ]; then FLAGS="$FLAGS -fobjc-arc" - CPPFLAGS="" - CPPFLAGS="$CPPFLAGS -I$O3/cliobjc" - CPPFLAGS="$CPPFLAGS -I$O3/clilib/dist-static-$PLATFORM/include" - LIBDIRS="-L$O3/clilib/dist-static-$PLATFORM/lib" - LIBS="-lovpncli -framework Foundation $LIBS" - SRC="$1.m $O3/cliobjc/ovpncli.mm " - CMD="$GPP_CMD $FLAGS $GCC_EXTRA $CPPFLAGS $LIBDIRS $SRC $EXTRA_SRC_OBJ $OUTPUT $LIBS" + LIBS="-framework Foundation $LIBS" + SRC="$1.mm" + CMD="$GPP_CMD $FLAGS $GCC_EXTRA $CPPFLAGS $LIBDIRS $SRC $EXTRA_CPP $EXTRA_SRC_OBJ $OUTPUT $LIBS" else CMD="$GPP_CMD $FLAGS $GCC_EXTRA $CPPFLAGS $LIBDIRS $1.cpp $EXTRA_CPP $EXTRA_SRC_OBJ $OUTPUT $LIBS" fi diff --git a/OpenVPN Adapter/Vendors/openvpn/test/ovpncli/cli.cpp b/OpenVPN Adapter/Vendors/openvpn/test/ovpncli/cli.cpp index 66baeda..4075ce8 100644 --- a/OpenVPN Adapter/Vendors/openvpn/test/ovpncli/cli.cpp +++ b/OpenVPN Adapter/Vendors/openvpn/test/ovpncli/cli.cpp @@ -85,6 +85,15 @@ namespace { class Client : public ClientAPI::OpenVPNClient { public: + enum ClockTickAction { + CT_UNDEF, + CT_STOP, + CT_RECONNECT, + CT_PAUSE, + CT_RESUME, + CT_STATS, + }; + bool is_dynamic_challenge() const { return !dc_cookie.empty(); @@ -101,14 +110,33 @@ public: MbedTLSPKI::PKContext epki_ctx; // external PKI context #endif + void set_clock_tick_action(const ClockTickAction action) + { + clock_tick_action = action; + } + + void print_stats() + { + const int n = stats_n(); + std::vector stats = stats_bundle(); + + std::cout << "STATS:" << std::endl; + for (int i = 0; i < n; ++i) + { + const long long value = stats[i]; + if (value) + std::cout << " " << stats_name(i) << " : " << value << std::endl; + } + } + private: - virtual bool socket_protect(int socket) + virtual bool socket_protect(int socket) override { std::cout << "*** socket_protect " << socket << std::endl; return true; } - virtual void event(const ClientAPI::Event& ev) + virtual void event(const ClientAPI::Event& ev) override { std::cout << date_time() << " EVENT: " << ev.name; if (!ev.info.empty()) @@ -155,13 +183,45 @@ private: } } - virtual void log(const ClientAPI::LogInfo& log) + virtual void log(const ClientAPI::LogInfo& log) override { std::lock_guard lock(log_mutex); std::cout << date_time() << ' ' << log.text << std::flush; } - virtual void external_pki_cert_request(ClientAPI::ExternalPKICertRequest& certreq) + virtual void clock_tick() override + { + const ClockTickAction action = clock_tick_action; + clock_tick_action = CT_UNDEF; + + switch (action) + { + case CT_STOP: + std::cout << "signal: CT_STOP" << std::endl; + stop(); + break; + case CT_RECONNECT: + std::cout << "signal: CT_RECONNECT" << std::endl; + reconnect(0); + break; + case CT_PAUSE: + std::cout << "signal: CT_PAUSE" << std::endl; + pause("clock-tick pause"); + break; + case CT_RESUME: + std::cout << "signal: CT_RESUME" << std::endl; + resume(); + break; + case CT_STATS: + std::cout << "signal: CT_STATS" << std::endl; + print_stats(); + break; + default: + break; + } + } + + virtual void external_pki_cert_request(ClientAPI::ExternalPKICertRequest& certreq) override { if (!epki_cert.empty()) { @@ -175,7 +235,7 @@ private: } } - virtual void external_pki_sign_request(ClientAPI::ExternalPKISignRequest& signreq) + virtual void external_pki_sign_request(ClientAPI::ExternalPKISignRequest& signreq) override { #if defined(USE_MBEDTLS) if (epki_ctx.defined()) @@ -239,7 +299,7 @@ private: return self->rng->rand_bytes_noexcept(data, len) ? 0 : -1; // using -1 as a general-purpose mbed TLS error code } - virtual bool pause_on_connection_timeout() + virtual bool pause_on_connection_timeout() override { return false; } @@ -247,13 +307,16 @@ private: std::mutex log_mutex; std::string dc_cookie; RandomAPI::Ptr rng; // random data source for epki + volatile ClockTickAction clock_tick_action = CT_UNDEF; }; static Client *the_client = nullptr; // GLOBAL static void worker_thread() { +#if !defined(OPENVPN_OVPNCLI_SINGLE_THREAD) openvpn_io::detail::signal_blocker signal_blocker; // signals should be handled by parent thread +#endif try { std::cout << "Thread starting..." << std::endl; ClientAPI::Status connect_status = the_client->connect(); @@ -272,21 +335,117 @@ static void worker_thread() std::cout << "Thread finished" << std::endl; } -static void print_stats(const Client& client) +static std::string read_profile(const char *fn, const std::string* profile_content) { - const int n = client.stats_n(); - std::vector stats = client.stats_bundle(); - - std::cout << "STATS:" << std::endl; - for (int i = 0; i < n; ++i) + if (!string::strcasecmp(fn, "http") && profile_content && !profile_content->empty()) + return *profile_content; + else { - const long long value = stats[i]; - if (value) - std::cout << " " << client.stats_name(i) << " : " << value << std::endl; + ProfileMerge pm(fn, "ovpn", "", ProfileMerge::FOLLOW_FULL, + ProfileParseLimits::MAX_LINE_SIZE, ProfileParseLimits::MAX_PROFILE_SIZE); + if (pm.status() != ProfileMerge::MERGE_SUCCESS) + OPENVPN_THROW_EXCEPTION("merge config error: " << pm.status_string() << " : " << pm.error()); + return pm.profile_content(); } } -#if !defined(OPENVPN_PLATFORM_WIN) +#if defined(OPENVPN_PLATFORM_WIN) + +static void start_thread(Client& client) +{ + // Set Windows title bar + const std::string title_text = "F2:Stats F3:Reconnect F4:Stop F5:Pause"; + Win::Console::Title title(ClientAPI::OpenVPNClient::platform() + " " + title_text); + Win::Console::Input console; + + // start connect thread + std::unique_ptr thread; + volatile bool thread_exit = false; + the_client = &client; + thread.reset(new std::thread([&thread_exit]() { + worker_thread(); + thread_exit = true; + })); + + // wait for connect thread to exit, also check for keypresses + while (!thread_exit) + { + while (true) + { + const unsigned int c = console.get(); + if (!c) + break; + else if (c == 0x3C) // F2 + the_client->print_stats(); + else if (c == 0x3D) // F3 + the_client->reconnect(0); + else if (c == 0x3E) // F4 + the_client->stop(); + else if (c == 0x3F) // F5 + the_client->pause("user-pause"); + } + Sleep(1000); + } + + // wait for connect thread to exit + thread->join(); + + the_client = nullptr; +} + +#elif defined(OPENVPN_OVPNCLI_SINGLE_THREAD) + +static void handler(int signum) +{ + switch (signum) + { + case SIGTERM: + case SIGINT: + if (the_client) + the_client->set_clock_tick_action(Client::CT_STOP); + break; + case SIGHUP: + if (the_client) + the_client->set_clock_tick_action(Client::CT_RECONNECT); + break; + case SIGUSR1: + if (the_client) + the_client->set_clock_tick_action(Client::CT_STATS); + break; + case SIGUSR2: + { + // toggle pause/resume + static bool hup = false; + if (the_client) + { + if (hup) + the_client->set_clock_tick_action(Client::CT_RESUME); + else + the_client->set_clock_tick_action(Client::CT_PAUSE); + hup = !hup; + } + } + break; + default: + break; + } +} + +static void start_thread(Client& client) +{ + the_client = &client; + + // capture signals that might occur while we're in worker_thread + Signal signal(handler, Signal::F_SIGINT|Signal::F_SIGTERM|Signal::F_SIGHUP|Signal::F_SIGUSR1|Signal::F_SIGUSR2); + + // run the client + worker_thread(); + + the_client = nullptr; +} + +#else + static void handler(int signum) { switch (signum) @@ -304,7 +463,7 @@ static void handler(int signum) break; case SIGUSR1: if (the_client) - print_stats(*the_client); + the_client->print_stats(); break; case SIGUSR2: { @@ -326,22 +485,29 @@ static void handler(int signum) break; } } -#endif -static std::string read_profile(const char *fn, const std::string* profile_content) +static void start_thread(Client& client) { - if (!string::strcasecmp(fn, "http") && profile_content && !profile_content->empty()) - return *profile_content; - else - { - ProfileMerge pm(fn, "ovpn", "", ProfileMerge::FOLLOW_FULL, - ProfileParseLimits::MAX_LINE_SIZE, ProfileParseLimits::MAX_PROFILE_SIZE); - if (pm.status() != ProfileMerge::MERGE_SUCCESS) - OPENVPN_THROW_EXCEPTION("merge config error: " << pm.status_string() << " : " << pm.error()); - return pm.profile_content(); - } + std::unique_ptr thread; + + // start connect thread + the_client = &client; + thread.reset(new std::thread([]() { + worker_thread(); + })); + + { + // catch signals that might occur while we're in join() + Signal signal(handler, Signal::F_SIGINT|Signal::F_SIGTERM|Signal::F_SIGHUP|Signal::F_SIGUSR1|Signal::F_SIGUSR2); + + // wait for connect thread to exit + thread->join(); + } + the_client = nullptr; } +#endif + int openvpn_client(int argc, char *argv[], const std::string* profile_content) { static const struct option longopts[] = { @@ -388,7 +554,6 @@ int openvpn_client(int argc, char *argv[], const std::string* profile_content) auto cleanup = Cleanup([]() { the_client = nullptr; }); - std::unique_ptr thread; try { if (argc >= 2) @@ -618,6 +783,9 @@ int openvpn_client(int argc, char *argv[], const std::string* profile_content) config.tunPersist = tunPersist; config.gremlinConfig = gremlin; config.info = true; +#if defined(OPENVPN_OVPNCLI_SINGLE_THREAD) + config.clockTickMS = 250; +#endif if (!epki_cert_fn.empty()) config.externalPkiAlias = "epki"; // dummy string @@ -694,60 +862,8 @@ int openvpn_client(int argc, char *argv[], const std::string* profile_content) std::cout << "CONNECTING..." << std::endl; -#if !defined(OPENVPN_PLATFORM_WIN) - // start connect thread - the_client = &client; - thread.reset(new std::thread([]() { - worker_thread(); - })); - - { - // catch signals that might occur while we're in join() - Signal signal(handler, Signal::F_SIGINT|Signal::F_SIGTERM|Signal::F_SIGHUP|Signal::F_SIGUSR1|Signal::F_SIGUSR2); - - // wait for connect thread to exit - thread->join(); - } - the_client = nullptr; -#else - // Set Windows title bar - const std::string title_text = "F2:Stats F3:Reconnect F4:Stop F5:Pause"; - Win::Console::Title title(ClientAPI::OpenVPNClient::platform() + " " + title_text); - Win::Console::Input console; - - // start connect thread - volatile bool thread_exit = false; - the_client = &client; - thread.reset(new std::thread([&thread_exit]() { - worker_thread(); - thread_exit = true; - })); - - // wait for connect thread to exit, also check for keypresses - while (!thread_exit) - { - while (true) - { - const unsigned int c = console.get(); - if (!c) - break; - else if (c == 0x3C) // F2 - print_stats(*the_client); - else if (c == 0x3D) // F3 - the_client->reconnect(0); - else if (c == 0x3E) // F4 - the_client->stop(); - else if (c == 0x3F) // F5 - the_client->pause("user-pause"); - } - Sleep(1000); - } - - // wait for connect thread to exit - thread->join(); - - the_client = nullptr; -#endif + // start the client thread + start_thread(client); // Get dynamic challenge response if (client.is_dynamic_challenge()) @@ -763,7 +879,7 @@ int openvpn_client(int argc, char *argv[], const std::string* profile_content) else { // print closing stats - print_stats(client); + client.print_stats(); } } } while (retry);