2014-07-21 05:22:06 +02:00
|
|
|
// 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.
|
2012-08-24 23:13:42 +02:00
|
|
|
//
|
2017-12-21 22:15:36 +01:00
|
|
|
// Copyright (C) 2012-2017 OpenVPN Inc.
|
2012-08-24 23:13:42 +02:00
|
|
|
//
|
2014-07-21 05:22:06 +02:00
|
|
|
// This program is free software: you can redistribute it and/or modify
|
2017-12-21 21:42:20 +01:00
|
|
|
// it under the terms of the GNU Affero General Public License Version 3
|
2014-07-21 05:22:06 +02:00
|
|
|
// as published by the Free Software Foundation.
|
2012-08-24 23:13:42 +02:00
|
|
|
//
|
2014-07-21 05:22:06 +02:00
|
|
|
// 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
|
2017-12-21 21:42:20 +01:00
|
|
|
// GNU Affero General Public License for more details.
|
2014-07-21 05:22:06 +02:00
|
|
|
//
|
2017-12-21 21:42:20 +01:00
|
|
|
// You should have received a copy of the GNU Affero General Public License
|
2014-07-21 05:22:06 +02:00
|
|
|
// along with this program in the COPYING file.
|
|
|
|
// If not, see <http://www.gnu.org/licenses/>.
|
2012-08-24 23:13:42 +02:00
|
|
|
|
2013-01-30 21:17:30 +01:00
|
|
|
// Implementation file for OpenVPNClient API defined in ovpncli.hpp.
|
2012-02-11 15:02:51 +01:00
|
|
|
|
|
|
|
#include <iostream>
|
2014-01-15 00:28:29 +01:00
|
|
|
#include <string>
|
2016-06-27 07:00:37 +02:00
|
|
|
#include <memory>
|
|
|
|
#include <utility>
|
|
|
|
#include <atomic>
|
2012-02-11 15:02:51 +01:00
|
|
|
|
2017-03-30 23:10:56 +02:00
|
|
|
#include <openvpn/io/io.hpp>
|
2015-11-25 03:33:08 +01:00
|
|
|
|
2012-07-01 17:37:46 +02:00
|
|
|
// Set up export of our public interface unless
|
2012-08-01 14:28:13 +02:00
|
|
|
// OPENVPN_CORE_API_VISIBILITY_HIDDEN is defined
|
2012-03-25 01:26:50 +01:00
|
|
|
#if defined(__GNUC__)
|
|
|
|
#define OPENVPN_CLIENT_EXPORT
|
2012-08-01 14:28:13 +02:00
|
|
|
#ifndef OPENVPN_CORE_API_VISIBILITY_HIDDEN
|
2012-03-25 01:26:50 +01:00
|
|
|
#pragma GCC visibility push(default)
|
2012-07-01 17:37:46 +02:00
|
|
|
#endif
|
2012-03-25 01:26:50 +01:00
|
|
|
#include "ovpncli.hpp" // public interface
|
2012-08-01 14:28:13 +02:00
|
|
|
#ifndef OPENVPN_CORE_API_VISIBILITY_HIDDEN
|
2012-03-25 01:26:50 +01:00
|
|
|
#pragma GCC visibility pop
|
2012-07-01 17:37:46 +02:00
|
|
|
#endif
|
2012-03-25 01:26:50 +01:00
|
|
|
#else
|
2014-02-08 05:51:59 +01:00
|
|
|
// no public interface export defined for this compiler
|
|
|
|
#define OPENVPN_CLIENT_EXPORT
|
|
|
|
#include "ovpncli.hpp" // public interface
|
2012-03-25 01:26:50 +01:00
|
|
|
#endif
|
2012-02-11 15:02:51 +01:00
|
|
|
|
2013-06-07 23:55:54 +02:00
|
|
|
// debug settings (production setting in parentheses)
|
2012-02-11 15:02:51 +01:00
|
|
|
|
2013-06-08 18:10:35 +02:00
|
|
|
//#define OPENVPN_DUMP_CONFIG // dump parsed configuration (comment out)
|
2013-05-22 07:13:11 +02:00
|
|
|
//#define OPENVPN_DEBUG_CLIPROTO // shows packets in/out (comment out)
|
|
|
|
#define OPENVPN_DEBUG_PROTO 1 // increases low-level protocol verbosity (1)
|
2016-02-07 15:37:17 +01:00
|
|
|
//#define OPENVPN_DEBUG_PROTO_DUMP // dump hex of transport-layer packets, requires OPENVPN_DEBUG_CLIPROTO (comment out)
|
2013-05-22 07:13:11 +02:00
|
|
|
//#define OPENVPN_DEBUG_VERBOSE_ERRORS // verbosely log Error::Type errors (comment out)
|
2013-06-14 02:34:49 +02:00
|
|
|
#define OPENVPN_DEBUG_TUN 2 // debug level for tun object (2)
|
|
|
|
#define OPENVPN_DEBUG_UDPLINK 2 // debug level for UDP link object (2)
|
|
|
|
#define OPENVPN_DEBUG_TCPLINK 2 // debug level for TCP link object (2)
|
|
|
|
#define OPENVPN_DEBUG_COMPRESS 1 // debug level for compression objects (1)
|
|
|
|
#define OPENVPN_DEBUG_REMOTELIST 0 // debug level for RemoteList object (0)
|
|
|
|
#define OPENVPN_DEBUG_TUN_BUILDER 0 // debug level for tun/builder/client.hpp (0)
|
2013-07-30 23:03:31 +02:00
|
|
|
//#define OPENVPN_SHOW_SESSION_TOKEN // show server-pushed auth-token (comment out)
|
2014-02-16 09:13:26 +01:00
|
|
|
//#define OPENVPN_DEBUG_TAPWIN // shows Windows TAP driver debug logging (comment out)
|
2013-05-22 07:13:11 +02:00
|
|
|
|
|
|
|
// enable assertion checks (can safely be disabled in production)
|
2012-03-12 13:42:02 +01:00
|
|
|
//#define OPENVPN_ENABLE_ASSERT
|
2013-05-22 07:13:11 +02:00
|
|
|
|
|
|
|
// force null tun device (useful for testing)
|
2012-02-11 15:02:51 +01:00
|
|
|
//#define OPENVPN_FORCE_TUN_NULL
|
2013-05-22 07:13:11 +02:00
|
|
|
|
|
|
|
// log cleartext tunnel packets to file for debugging/analysis
|
2012-02-11 15:02:51 +01:00
|
|
|
//#define OPENVPN_PACKET_LOG "pkt.log"
|
|
|
|
|
2015-04-16 06:31:22 +02:00
|
|
|
#ifndef OPENVPN_LOG
|
2012-02-11 15:02:51 +01:00
|
|
|
// log thread settings
|
2016-03-15 22:02:01 +01:00
|
|
|
#define OPENVPN_LOG_CLASS openvpn::ClientAPI::LogReceiver
|
2017-08-24 12:06:15 +02:00
|
|
|
#define OPENVPN_LOG_INFO openvpn::ClientAPI::LogInfo
|
2015-04-16 06:31:22 +02:00
|
|
|
#include <openvpn/log/logthread.hpp> // should be included early
|
|
|
|
#endif
|
2012-02-11 15:02:51 +01:00
|
|
|
|
2012-03-11 13:09:25 +01:00
|
|
|
// log SSL handshake messages
|
|
|
|
#define OPENVPN_LOG_SSL(x) OPENVPN_LOG(x)
|
|
|
|
|
2012-07-01 17:37:46 +02:00
|
|
|
// on Android and iOS, use TunBuilderBase abstraction
|
2012-02-20 04:27:20 +01:00
|
|
|
#include <openvpn/common/platform.hpp>
|
2017-04-13 21:28:34 +02:00
|
|
|
#if (defined(OPENVPN_PLATFORM_ANDROID) || defined(OPENVPN_PLATFORM_IPHONE)) && !defined(OPENVPN_FORCE_TUN_NULL) && !defined(OPENVPN_EXTERNAL_TUN_FACTORY)
|
2012-02-19 20:06:44 +01:00
|
|
|
#define USE_TUN_BUILDER
|
|
|
|
#endif
|
|
|
|
|
2012-02-11 15:02:51 +01:00
|
|
|
#include <openvpn/init/initprocess.hpp>
|
2018-03-23 15:23:45 +01:00
|
|
|
#include <openvpn/common/bigmutex.hpp>
|
2015-05-17 21:27:34 +02:00
|
|
|
#include <openvpn/common/size.hpp>
|
2014-01-15 00:28:29 +01:00
|
|
|
#include <openvpn/common/platform_string.hpp>
|
2015-05-17 21:17:24 +02:00
|
|
|
#include <openvpn/common/count.hpp>
|
2017-03-30 00:15:35 +02:00
|
|
|
#include <openvpn/asio/asiostop.hpp>
|
2017-04-12 20:37:41 +02:00
|
|
|
#include <openvpn/time/asiotimer.hpp>
|
2012-02-11 15:02:51 +01:00
|
|
|
#include <openvpn/client/cliconnect.hpp>
|
2012-11-26 02:51:24 +01:00
|
|
|
#include <openvpn/client/cliopthelper.hpp>
|
2012-10-18 14:24:14 +02:00
|
|
|
#include <openvpn/options/merge.hpp>
|
2012-11-16 05:13:48 +01:00
|
|
|
#include <openvpn/error/excode.hpp>
|
2013-06-14 02:34:49 +02:00
|
|
|
#include <openvpn/crypto/selftest.hpp>
|
2012-02-11 15:02:51 +01:00
|
|
|
|
2012-04-18 00:12:27 +02:00
|
|
|
// copyright
|
|
|
|
#include <openvpn/legal/copyright.hpp>
|
|
|
|
|
2012-02-11 15:02:51 +01:00
|
|
|
namespace openvpn {
|
|
|
|
namespace ClientAPI {
|
|
|
|
|
2012-03-10 05:55:32 +01:00
|
|
|
OPENVPN_SIMPLE_EXCEPTION(app_expired);
|
|
|
|
|
2012-02-11 15:02:51 +01:00
|
|
|
class MySessionStats : public SessionStats
|
|
|
|
{
|
|
|
|
public:
|
2015-05-18 05:26:53 +02:00
|
|
|
typedef RCPtr<MySessionStats> Ptr;
|
2012-02-11 15:02:51 +01:00
|
|
|
|
2012-03-01 09:11:00 +01:00
|
|
|
MySessionStats(OpenVPNClient* parent_arg)
|
2012-02-11 15:02:51 +01:00
|
|
|
: parent(parent_arg)
|
|
|
|
{
|
|
|
|
std::memset(errors, 0, sizeof(errors));
|
2013-05-22 07:13:11 +02:00
|
|
|
#ifdef OPENVPN_DEBUG_VERBOSE_ERRORS
|
|
|
|
session_stats_set_verbose(true);
|
|
|
|
#endif
|
2012-02-11 15:02:51 +01:00
|
|
|
}
|
|
|
|
|
2012-02-13 00:09:28 +01:00
|
|
|
static size_t combined_n()
|
|
|
|
{
|
|
|
|
return N_STATS + Error::N_ERRORS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::string combined_name(const size_t index)
|
|
|
|
{
|
|
|
|
if (index < N_STATS + Error::N_ERRORS)
|
|
|
|
{
|
|
|
|
if (index < N_STATS)
|
|
|
|
return stat_name(index);
|
|
|
|
else
|
|
|
|
return Error::name(index - N_STATS);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
count_t combined_value(const size_t index) const
|
|
|
|
{
|
|
|
|
if (index < N_STATS + Error::N_ERRORS)
|
|
|
|
{
|
|
|
|
if (index < N_STATS)
|
|
|
|
return get_stat(index);
|
|
|
|
else
|
|
|
|
return errors[index - N_STATS];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-07-01 17:37:46 +02:00
|
|
|
count_t stat_count(const size_t index) const
|
|
|
|
{
|
|
|
|
return get_stat_fast(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
count_t error_count(const size_t index) const
|
|
|
|
{
|
|
|
|
return errors[index];
|
|
|
|
}
|
|
|
|
|
2012-02-19 18:43:42 +01:00
|
|
|
void detach_from_parent()
|
|
|
|
{
|
2015-05-17 10:53:37 +02:00
|
|
|
parent = nullptr;
|
2012-02-19 18:43:42 +01:00
|
|
|
}
|
|
|
|
|
2015-05-17 10:53:37 +02:00
|
|
|
virtual void error(const size_t err, const std::string* text=nullptr)
|
2012-02-11 15:02:51 +01:00
|
|
|
{
|
|
|
|
if (err < Error::N_ERRORS)
|
2013-05-22 07:13:11 +02:00
|
|
|
{
|
|
|
|
#ifdef OPENVPN_DEBUG_VERBOSE_ERRORS
|
|
|
|
if (text)
|
|
|
|
OPENVPN_LOG("ERROR: " << Error::name(err) << " : " << *text);
|
|
|
|
else
|
|
|
|
OPENVPN_LOG("ERROR: " << Error::name(err));
|
|
|
|
#endif
|
|
|
|
++errors[err];
|
|
|
|
}
|
2012-02-11 15:02:51 +01:00
|
|
|
}
|
|
|
|
|
2012-03-07 12:21:09 +01:00
|
|
|
private:
|
2012-03-01 09:11:00 +01:00
|
|
|
OpenVPNClient* parent;
|
2012-02-11 15:02:51 +01:00
|
|
|
count_t errors[Error::N_ERRORS];
|
|
|
|
};
|
|
|
|
|
|
|
|
class MyClientEvents : public ClientEvent::Queue
|
|
|
|
{
|
|
|
|
public:
|
2015-05-18 05:26:53 +02:00
|
|
|
typedef RCPtr<MyClientEvents> Ptr;
|
2012-02-11 15:02:51 +01:00
|
|
|
|
2012-03-01 09:11:00 +01:00
|
|
|
MyClientEvents(OpenVPNClient* parent_arg) : parent(parent_arg) {}
|
2012-02-11 15:02:51 +01:00
|
|
|
|
2016-05-11 05:26:34 +02:00
|
|
|
virtual void add_event(ClientEvent::Base::Ptr event) override
|
2012-02-11 15:02:51 +01:00
|
|
|
{
|
2012-02-19 18:43:42 +01:00
|
|
|
if (parent)
|
|
|
|
{
|
|
|
|
Event ev;
|
|
|
|
ev.name = event->name();
|
2016-05-11 01:53:09 +02:00
|
|
|
ev.info = event->render();
|
2012-02-19 18:43:42 +01:00
|
|
|
ev.error = event->is_error();
|
2016-04-01 04:24:28 +02:00
|
|
|
ev.fatal = event->is_fatal();
|
2012-07-02 22:52:58 +02:00
|
|
|
|
|
|
|
// save connected event
|
|
|
|
if (event->id() == ClientEvent::CONNECTED)
|
2016-05-11 05:26:34 +02:00
|
|
|
last_connected = std::move(event);
|
2017-04-12 20:37:41 +02:00
|
|
|
else if (event->id() == ClientEvent::DISCONNECTED)
|
|
|
|
parent->on_disconnect();
|
2012-02-19 18:43:42 +01:00
|
|
|
parent->event(ev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-02 22:52:58 +02:00
|
|
|
void get_connection_info(ConnectionInfo& ci)
|
|
|
|
{
|
|
|
|
ClientEvent::Base::Ptr connected = last_connected;
|
|
|
|
if (connected)
|
|
|
|
{
|
|
|
|
const ClientEvent::Connected* c = connected->connected_cast();
|
|
|
|
if (c)
|
|
|
|
{
|
|
|
|
ci.user = c->user;
|
|
|
|
ci.serverHost = c->server_host;
|
|
|
|
ci.serverPort = c->server_port;
|
|
|
|
ci.serverProto = c->server_proto;
|
|
|
|
ci.serverIp = c->server_ip;
|
2012-10-03 11:03:02 +02:00
|
|
|
ci.vpnIp4 = c->vpn_ip4;
|
|
|
|
ci.vpnIp6 = c->vpn_ip6;
|
2016-06-27 06:23:08 +02:00
|
|
|
ci.gw4 = c->vpn_gw4;
|
|
|
|
ci.gw6 = c->vpn_gw6;
|
2012-10-03 11:03:02 +02:00
|
|
|
ci.clientIp = c->client_ip;
|
2012-07-02 22:52:58 +02:00
|
|
|
ci.tunName = c->tun_name;
|
|
|
|
ci.defined = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ci.defined = false;
|
|
|
|
}
|
|
|
|
|
2012-02-19 18:43:42 +01:00
|
|
|
void detach_from_parent()
|
|
|
|
{
|
2015-05-17 10:53:37 +02:00
|
|
|
parent = nullptr;
|
2012-02-19 18:43:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2012-03-01 09:11:00 +01:00
|
|
|
OpenVPNClient* parent;
|
2012-07-02 22:52:58 +02:00
|
|
|
ClientEvent::Base::Ptr last_connected;
|
2012-02-19 18:43:42 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
class MySocketProtect : public SocketProtect
|
|
|
|
{
|
|
|
|
public:
|
2015-05-17 10:53:37 +02:00
|
|
|
MySocketProtect() : parent(nullptr) {}
|
2012-02-19 18:43:42 +01:00
|
|
|
|
2012-03-01 09:11:00 +01:00
|
|
|
void set_parent(OpenVPNClient* parent_arg)
|
2012-02-19 18:43:42 +01:00
|
|
|
{
|
|
|
|
parent = parent_arg;
|
|
|
|
}
|
|
|
|
|
2018-10-26 14:43:06 +02:00
|
|
|
bool socket_protect(int socket, IP::Addr endpoint) override
|
2012-02-19 18:43:42 +01:00
|
|
|
{
|
|
|
|
if (parent)
|
2019-10-04 15:47:06 +02:00
|
|
|
{
|
|
|
|
#if defined(OPENVPN_COMMAND_AGENT) && defined(OPENVPN_PLATFORM_WIN)
|
|
|
|
return WinCommandAgent::add_bypass_route(endpoint);
|
2019-10-29 10:05:12 +01:00
|
|
|
#elif defined(OPENVPN_COMMAND_AGENT) && defined(OPENVPN_PLATFORM_MAC)
|
|
|
|
return UnixCommandAgent::add_bypass_route(endpoint);
|
2019-10-04 15:47:06 +02:00
|
|
|
#else
|
|
|
|
return parent->socket_protect(socket, endpoint.to_string(), endpoint.is_ipv6());
|
|
|
|
#endif
|
|
|
|
}
|
2012-02-19 18:43:42 +01:00
|
|
|
else
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void detach_from_parent()
|
|
|
|
{
|
2015-05-17 10:53:37 +02:00
|
|
|
parent = nullptr;
|
2012-02-11 15:02:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2012-03-01 09:11:00 +01:00
|
|
|
OpenVPNClient* parent;
|
2012-02-11 15:02:51 +01:00
|
|
|
};
|
|
|
|
|
2012-10-23 15:10:39 +02:00
|
|
|
class MyReconnectNotify : public ReconnectNotify
|
|
|
|
{
|
|
|
|
public:
|
2015-05-17 10:53:37 +02:00
|
|
|
MyReconnectNotify() : parent(nullptr) {}
|
2012-10-23 15:10:39 +02:00
|
|
|
|
|
|
|
void set_parent(OpenVPNClient* parent_arg)
|
|
|
|
{
|
|
|
|
parent = parent_arg;
|
|
|
|
}
|
|
|
|
|
|
|
|
void detach_from_parent()
|
|
|
|
{
|
2015-05-17 10:53:37 +02:00
|
|
|
parent = nullptr;
|
2012-10-23 15:10:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool pause_on_connection_timeout()
|
|
|
|
{
|
|
|
|
if (parent)
|
|
|
|
return parent->pause_on_connection_timeout();
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
OpenVPNClient* parent;
|
|
|
|
};
|
|
|
|
|
2016-07-02 09:00:09 +02:00
|
|
|
class MyRemoteOverride : public RemoteList::RemoteOverride
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
void set_parent(OpenVPNClient* parent_arg)
|
|
|
|
{
|
|
|
|
parent = parent_arg;
|
|
|
|
}
|
|
|
|
|
|
|
|
void detach_from_parent()
|
|
|
|
{
|
|
|
|
parent = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual RemoteList::Item::Ptr get() override
|
|
|
|
{
|
|
|
|
if (parent)
|
|
|
|
{
|
|
|
|
const std::string title = "remote-override";
|
|
|
|
ClientAPI::RemoteOverride ro;
|
2018-04-06 01:44:28 +02:00
|
|
|
try {
|
|
|
|
parent->remote_override(ro);
|
|
|
|
}
|
|
|
|
catch (const std::exception& e)
|
|
|
|
{
|
|
|
|
ro.error = e.what();
|
|
|
|
}
|
2016-07-02 09:00:09 +02:00
|
|
|
RemoteList::Item::Ptr ri(new RemoteList::Item);
|
2018-04-06 01:44:28 +02:00
|
|
|
if (ro.error.empty())
|
|
|
|
{
|
|
|
|
if (!ro.ip.empty())
|
|
|
|
ri->set_ip_addr(IP::Addr(ro.ip, title));
|
|
|
|
if (ro.host.empty())
|
|
|
|
ro.host = ro.ip;
|
|
|
|
HostPort::validate_host(ro.host, title);
|
|
|
|
HostPort::validate_port(ro.port, title);
|
|
|
|
ri->server_host = std::move(ro.host);
|
|
|
|
ri->server_port = std::move(ro.port);
|
|
|
|
ri->transport_protocol = Protocol::parse(ro.proto, Protocol::CLIENT_SUFFIX, title.c_str());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
throw Exception("remote override exception: " + ro.error);
|
2016-07-02 09:00:09 +02:00
|
|
|
return ri;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return RemoteList::Item::Ptr();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
OpenVPNClient* parent = nullptr;
|
|
|
|
};
|
|
|
|
|
2017-04-12 20:37:41 +02:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
2012-02-11 15:02:51 +01:00
|
|
|
namespace Private {
|
2016-06-27 07:00:37 +02:00
|
|
|
class ClientState
|
2012-02-11 15:02:51 +01:00
|
|
|
{
|
2016-06-27 07:00:37 +02:00
|
|
|
public:
|
|
|
|
// state objects
|
2012-02-11 15:02:51 +01:00
|
|
|
OptionList options;
|
2012-03-06 07:06:54 +01:00
|
|
|
EvalConfig eval;
|
2012-02-19 18:43:42 +01:00
|
|
|
MySocketProtect socket_protect;
|
2012-10-23 15:10:39 +02:00
|
|
|
MyReconnectNotify reconnect_notify;
|
2016-07-02 09:00:09 +02:00
|
|
|
MyRemoteOverride remote_override;
|
2012-02-28 00:00:29 +01:00
|
|
|
ClientCreds::Ptr creds;
|
2012-02-11 15:02:51 +01:00
|
|
|
MySessionStats::Ptr stats;
|
|
|
|
MyClientEvents::Ptr events;
|
|
|
|
ClientConnect::Ptr session;
|
2017-04-12 20:37:41 +02:00
|
|
|
std::unique_ptr<MyClockTick> clock_tick;
|
2012-03-03 12:09:05 +01:00
|
|
|
|
|
|
|
// extra settings submitted by API client
|
|
|
|
std::string server_override;
|
2017-10-21 00:24:37 +02:00
|
|
|
std::string port_override;
|
2012-03-03 12:09:05 +01:00
|
|
|
Protocol proto_override;
|
2016-02-05 20:16:20 +01:00
|
|
|
IPv6Setting ipv6;
|
2016-02-04 00:30:02 +01:00
|
|
|
int conn_timeout = 0;
|
|
|
|
bool tun_persist = false;
|
2019-05-17 10:49:36 +02:00
|
|
|
bool wintun = false;
|
2016-02-04 00:30:02 +01:00
|
|
|
bool google_dns_fallback = false;
|
2017-10-09 14:03:55 +02:00
|
|
|
bool synchronous_dns_lookup = false;
|
2016-02-04 19:39:44 +01:00
|
|
|
bool autologin_sessions = false;
|
2018-02-06 22:12:58 +01:00
|
|
|
bool retry_on_auth_failed = false;
|
2012-11-15 23:48:13 +01:00
|
|
|
std::string private_key_password;
|
2012-03-06 07:06:54 +01:00
|
|
|
std::string external_pki_alias;
|
2016-02-04 00:30:02 +01:00
|
|
|
bool disable_client_cert = false;
|
2016-08-05 04:43:43 +02:00
|
|
|
int ssl_debug_level = 0;
|
2016-02-04 00:30:02 +01:00
|
|
|
int default_key_direction = -1;
|
|
|
|
bool force_aes_cbc_ciphersuites = false;
|
2015-02-05 04:29:43 +01:00
|
|
|
std::string tls_version_min_override;
|
2017-02-28 19:50:28 +01:00
|
|
|
std::string tls_cert_profile_override;
|
2014-01-07 19:49:48 +01:00
|
|
|
std::string gui_version;
|
2019-04-29 16:10:19 +02:00
|
|
|
std::string sso_methods;
|
2018-07-16 16:05:35 +02:00
|
|
|
bool allow_local_lan_access;
|
2019-08-05 19:26:18 +02:00
|
|
|
std::string hw_addr_override;
|
|
|
|
std::string platform_version;
|
2012-09-08 03:36:54 +02:00
|
|
|
ProtoContextOptions::Ptr proto_context_options;
|
2015-09-22 04:42:24 +02:00
|
|
|
PeerInfo::Set::Ptr extra_peer_info;
|
2012-10-24 08:38:20 +02:00
|
|
|
HTTPProxyTransport::Options::Ptr http_proxy_options;
|
2017-04-12 20:37:41 +02:00
|
|
|
unsigned int clock_tick_ms = 0;
|
Added gremlin option to client, controllable via
ClientAPI::Config::gremlinConfig string.
The gremlin option allows extra packet latency
or unreliability to be added to the tunnel.
The format of the option is a comma-separated list
of numerical parameters:
send_delay_ms, recv_delay_ms, send_drop_prob, recv_drop_prob
Parameter description:
send_delay_ms : delay packets by n milliseconds before
transmission (UDP/TCP).
recv_delay_ms : delay received packets by n milliseconds
before processing them (UDP/TCP).
send_drop_prob : drop sent packets with probability 1/n
(UDP only).
recv_drop_prob : drop received packets with probability
1/n (UDP only).
Set any parameter to 0 to disable.
Gremlin parameters currently work with UDP and TCP
transport as documented above, but not for proxy transport.
Client must be built with the OPENVPN_GREMLIN flag to compile
gremlin functionality.
Command-line client can set the gremlin config
string using --gremlin or -G, for example:
--gremlin=250,250,64,64
When using the above parameters, an extra 500 milliseconds
will be added to round-trip latency, and 1/64 sent or
received packets will be dropped.
2016-01-26 08:27:11 +01:00
|
|
|
#ifdef OPENVPN_GREMLIN
|
|
|
|
Gremlin::Config::Ptr gremlin_config;
|
|
|
|
#endif
|
2016-02-04 00:30:02 +01:00
|
|
|
bool alt_proxy = false;
|
|
|
|
bool dco = false;
|
2016-03-28 08:31:35 +02:00
|
|
|
bool echo = false;
|
2016-05-11 01:53:09 +02:00
|
|
|
bool info = false;
|
2015-04-12 19:27:58 +02:00
|
|
|
|
2015-04-14 07:42:23 +02:00
|
|
|
template <typename SESSION_STATS, typename CLIENT_EVENTS>
|
2016-06-27 07:00:37 +02:00
|
|
|
void attach(OpenVPNClient* parent,
|
2017-03-30 23:10:56 +02:00
|
|
|
openvpn_io::io_context* io_context,
|
2016-07-13 07:06:12 +02:00
|
|
|
Stop* async_stop_global)
|
2015-04-12 19:27:58 +02:00
|
|
|
{
|
2016-06-27 07:00:37 +02:00
|
|
|
// only one attachment per instantiation allowed
|
|
|
|
if (attach_called)
|
|
|
|
throw Exception("ClientState::attach() can only be called once per ClientState instantiation");
|
|
|
|
attach_called = true;
|
|
|
|
|
|
|
|
// async stop
|
2016-07-13 07:06:12 +02:00
|
|
|
async_stop_global_ = async_stop_global;
|
2016-06-27 07:00:37 +02:00
|
|
|
|
|
|
|
// io_context
|
|
|
|
if (io_context)
|
|
|
|
io_context_ = io_context;
|
|
|
|
else
|
|
|
|
{
|
2017-03-30 23:10:56 +02:00
|
|
|
io_context_ = new openvpn_io::io_context(1); // concurrency hint=1
|
2016-06-27 07:00:37 +02:00
|
|
|
io_context_owned = true;
|
|
|
|
}
|
|
|
|
|
2015-04-12 19:27:58 +02:00
|
|
|
// client stats
|
2015-04-14 07:42:23 +02:00
|
|
|
stats.reset(new SESSION_STATS(parent));
|
2015-04-12 19:27:58 +02:00
|
|
|
|
|
|
|
// client events
|
2015-04-14 07:42:23 +02:00
|
|
|
events.reset(new CLIENT_EVENTS(parent));
|
2015-04-12 19:27:58 +02:00
|
|
|
|
|
|
|
// socket protect
|
|
|
|
socket_protect.set_parent(parent);
|
|
|
|
|
|
|
|
// reconnect notifications
|
|
|
|
reconnect_notify.set_parent(parent);
|
2016-07-02 09:00:09 +02:00
|
|
|
|
|
|
|
// remote override
|
|
|
|
remote_override.set_parent(parent);
|
2015-04-12 19:27:58 +02:00
|
|
|
}
|
|
|
|
|
2016-06-27 07:00:37 +02:00
|
|
|
ClientState() {}
|
|
|
|
|
|
|
|
~ClientState()
|
2015-04-12 19:27:58 +02:00
|
|
|
{
|
2017-04-18 07:28:36 +02:00
|
|
|
stop_scope_local.reset();
|
|
|
|
stop_scope_global.reset();
|
2015-04-12 19:27:58 +02:00
|
|
|
socket_protect.detach_from_parent();
|
|
|
|
reconnect_notify.detach_from_parent();
|
2016-07-02 09:00:09 +02:00
|
|
|
remote_override.detach_from_parent();
|
2017-04-12 20:37:41 +02:00
|
|
|
if (clock_tick)
|
|
|
|
clock_tick->detach_from_parent();
|
2016-06-30 08:15:31 +02:00
|
|
|
if (stats)
|
|
|
|
stats->detach_from_parent();
|
|
|
|
if (events)
|
|
|
|
events->detach_from_parent();
|
2016-09-23 22:32:48 +02:00
|
|
|
session.reset();
|
2016-06-27 07:00:37 +02:00
|
|
|
if (io_context_owned)
|
|
|
|
delete io_context_;
|
|
|
|
}
|
|
|
|
|
|
|
|
// foreign thread access
|
|
|
|
|
|
|
|
void enable_foreign_thread_access()
|
|
|
|
{
|
|
|
|
foreign_thread_ready.store(true, std::memory_order_release);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_foreign_thread_access()
|
|
|
|
{
|
|
|
|
return foreign_thread_ready.load(std::memory_order_acquire);
|
2015-04-12 19:27:58 +02:00
|
|
|
}
|
2016-06-27 07:00:37 +02:00
|
|
|
|
|
|
|
// io_context
|
|
|
|
|
2017-03-30 23:10:56 +02:00
|
|
|
openvpn_io::io_context* io_context()
|
2016-06-27 07:00:37 +02:00
|
|
|
{
|
|
|
|
return io_context_;
|
|
|
|
}
|
|
|
|
|
|
|
|
// async stop
|
|
|
|
|
2016-07-13 07:06:12 +02:00
|
|
|
Stop* async_stop_local()
|
2016-06-27 07:00:37 +02:00
|
|
|
{
|
2016-07-13 07:06:12 +02:00
|
|
|
return &async_stop_local_;
|
2016-06-27 07:00:37 +02:00
|
|
|
}
|
|
|
|
|
2016-07-13 07:06:12 +02:00
|
|
|
Stop* async_stop_global()
|
2016-06-27 07:00:37 +02:00
|
|
|
{
|
2016-07-13 07:06:12 +02:00
|
|
|
return async_stop_global_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void trigger_async_stop_local()
|
|
|
|
{
|
|
|
|
async_stop_local_.stop();
|
2016-06-27 07:00:37 +02:00
|
|
|
}
|
|
|
|
|
2017-04-12 20:37:41 +02:00
|
|
|
// disconnect
|
|
|
|
void on_disconnect()
|
|
|
|
{
|
|
|
|
if (clock_tick)
|
|
|
|
clock_tick->cancel();
|
|
|
|
}
|
|
|
|
|
2017-04-18 07:28:36 +02:00
|
|
|
void setup_async_stop_scopes()
|
|
|
|
{
|
|
|
|
stop_scope_local.reset(new AsioStopScope(*io_context(), async_stop_local(), [this]() {
|
2018-03-23 15:23:45 +01:00
|
|
|
OPENVPN_ASYNC_HANDLER;
|
2017-04-18 07:28:36 +02:00
|
|
|
session->graceful_stop();
|
|
|
|
}));
|
|
|
|
|
|
|
|
stop_scope_global.reset(new AsioStopScope(*io_context(), async_stop_global(), [this]() {
|
2018-03-23 15:23:45 +01:00
|
|
|
OPENVPN_ASYNC_HANDLER;
|
2017-04-18 07:28:36 +02:00
|
|
|
trigger_async_stop_local();
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2016-06-27 07:00:37 +02:00
|
|
|
private:
|
|
|
|
ClientState(const ClientState&) = delete;
|
|
|
|
ClientState& operator=(const ClientState&) = delete;
|
|
|
|
|
|
|
|
bool attach_called = false;
|
|
|
|
|
2016-07-13 07:06:12 +02:00
|
|
|
Stop async_stop_local_;
|
|
|
|
Stop* async_stop_global_ = nullptr;
|
2016-06-27 07:00:37 +02:00
|
|
|
|
2017-04-18 07:28:36 +02:00
|
|
|
std::unique_ptr<AsioStopScope> stop_scope_local;
|
|
|
|
std::unique_ptr<AsioStopScope> stop_scope_global;
|
|
|
|
|
2017-03-30 23:10:56 +02:00
|
|
|
openvpn_io::io_context* io_context_ = nullptr;
|
2016-06-27 07:00:37 +02:00
|
|
|
bool io_context_owned = false;
|
|
|
|
|
|
|
|
std::atomic<bool> foreign_thread_ready{false};
|
2012-02-11 15:02:51 +01:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2012-07-01 17:37:46 +02:00
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::init_process()
|
2012-02-11 15:02:51 +01:00
|
|
|
{
|
|
|
|
InitProcess::init();
|
2012-07-01 17:37:46 +02:00
|
|
|
}
|
|
|
|
|
2014-08-11 00:44:09 +02:00
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::uninit_process()
|
|
|
|
{
|
|
|
|
InitProcess::uninit();
|
|
|
|
}
|
|
|
|
|
2012-07-01 17:37:46 +02:00
|
|
|
OPENVPN_CLIENT_EXPORT OpenVPNClient::OpenVPNClient()
|
|
|
|
{
|
2016-06-27 06:53:05 +02:00
|
|
|
#ifndef OPENVPN_NORESET_TIME
|
2012-10-20 08:05:51 +02:00
|
|
|
// We keep track of time as binary milliseconds since a time base, and
|
|
|
|
// this can wrap after ~48 days on 32 bit systems, so it's a good idea
|
|
|
|
// to periodically reinitialize the base.
|
|
|
|
Time::reset_base_conditional();
|
2016-06-27 06:53:05 +02:00
|
|
|
#endif
|
2012-10-20 08:05:51 +02:00
|
|
|
|
2012-02-11 15:02:51 +01:00
|
|
|
state = new Private::ClientState();
|
2016-06-27 07:00:37 +02:00
|
|
|
state->proto_context_options.reset(new ProtoContextOptions());
|
2012-02-11 15:02:51 +01:00
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::parse_config(const Config& config, EvalConfig& eval, OptionList& options)
|
2012-02-11 15:02:51 +01:00
|
|
|
{
|
|
|
|
try {
|
2012-03-03 12:09:05 +01:00
|
|
|
// validate proto_override
|
|
|
|
if (!config.protoOverride.empty())
|
2016-05-05 08:13:43 +02:00
|
|
|
Protocol::parse(config.protoOverride, Protocol::NO_SUFFIX);
|
2012-03-03 12:09:05 +01:00
|
|
|
|
2016-02-05 20:16:20 +01:00
|
|
|
// validate IPv6 setting
|
|
|
|
if (!config.ipv6.empty())
|
|
|
|
IPv6Setting::parse(config.ipv6);
|
|
|
|
|
2012-02-11 15:02:51 +01:00
|
|
|
// parse config
|
Initial Apple VPN-On-Demand implementation:
* VoD profiles can be defined using the iPhone Configuration utility:
1. Connection Type should be set to Custom SSL
2. Identifier should be set to net.openvpn.OpenVPN-Connect.vpnplugin
3. Server can be set to a hostname, or "DEFAULT" to use the
hostname(s) from the OpenVPN configuration.
4. User Authentication should be set to Certificate, and the client
certificate+key should be attached as a PKCS#12 file.
5. VPN On Demand should be enabled and match entries should be
defined.
In addition, the OpenVPN client configuration file may be defined
via key/value pairs:
1. VoD requires an autologin profile.
2. Define each OpenVPN directive as a key, with arguments
specified as the value.
3. For Access server meta-directives such as
OVPN_ACCESS_SERVER_USERNAME, remove the "OVPN_ACCESS_SERVER_"
prefix, giving USERNAME as the directive.
4. If no arguments are present, use "NOARGS" as the value.
5. If multiple instances of the same directive are present,
number the directives in the order they should be processed by
appending .<n> to the directive, where n is an integer,
such as remote.1 or remote.2
6. For multi-line directives such as <ca> and <tls-auth>, you must
convert the multi-line argument to a single line by specifying
line breaks as \n -- also note that because of
this escaping model, you must use \\ to pass backslash itself.
* VoD profiles are recognized and listed by the app.
* The app can disconnect but not connect a VoD profile.
* Most app-level functionality such as logging and preferences
work correctly for VoD profiles.
Core changes:
* Added support for key-direction parameter in core.
2012-11-06 18:50:30 +01:00
|
|
|
OptionList::KeyValueList kvl;
|
|
|
|
kvl.reserve(config.contentList.size());
|
|
|
|
for (size_t i = 0; i < config.contentList.size(); ++i)
|
|
|
|
{
|
|
|
|
const KeyValue& kv = config.contentList[i];
|
|
|
|
kvl.push_back(new OptionList::KeyValue(kv.key, kv.value));
|
|
|
|
}
|
|
|
|
const ParseClientConfig cc = ParseClientConfig::parse(config.content, &kvl, options);
|
2013-06-08 18:10:35 +02:00
|
|
|
#ifdef OPENVPN_DUMP_CONFIG
|
|
|
|
std::cout << "---------- ARGS ----------" << std::endl;
|
2013-06-10 02:42:19 +02:00
|
|
|
std::cout << options.render(Option::RENDER_PASS_FMT|Option::RENDER_NUMBER|Option::RENDER_BRACKET) << std::endl;
|
2013-06-08 18:10:35 +02:00
|
|
|
std::cout << "---------- MAP ----------" << std::endl;
|
|
|
|
std::cout << options.render_map() << std::endl;
|
|
|
|
#endif
|
2012-07-02 22:52:58 +02:00
|
|
|
eval.error = cc.error();
|
|
|
|
eval.message = cc.message();
|
|
|
|
eval.userlockedUsername = cc.userlockedUsername();
|
|
|
|
eval.profileName = cc.profileName();
|
|
|
|
eval.friendlyName = cc.friendlyName();
|
|
|
|
eval.autologin = cc.autologin();
|
|
|
|
eval.externalPki = cc.externalPki();
|
|
|
|
eval.staticChallenge = cc.staticChallenge();
|
|
|
|
eval.staticChallengeEcho = cc.staticChallengeEcho();
|
2012-11-15 23:48:13 +01:00
|
|
|
eval.privateKeyPasswordRequired = cc.privateKeyPasswordRequired();
|
2012-11-18 09:55:27 +01:00
|
|
|
eval.allowPasswordSave = cc.allowPasswordSave();
|
2016-03-28 08:29:16 +02:00
|
|
|
eval.remoteHost = config.serverOverride.empty() ? cc.firstRemoteListItem().host : config.serverOverride;
|
|
|
|
eval.remotePort = cc.firstRemoteListItem().port;
|
|
|
|
eval.remoteProto = cc.firstRemoteListItem().proto;
|
2012-07-02 22:52:58 +02:00
|
|
|
for (ParseClientConfig::ServerList::const_iterator i = cc.serverList().begin(); i != cc.serverList().end(); ++i)
|
|
|
|
{
|
|
|
|
ServerEntry se;
|
|
|
|
se.server = i->server;
|
|
|
|
se.friendlyName = i->friendlyName;
|
|
|
|
eval.serverList.push_back(se);
|
|
|
|
}
|
2012-02-11 15:02:51 +01:00
|
|
|
}
|
2012-02-17 20:28:44 +01:00
|
|
|
catch (const std::exception& e)
|
2012-02-11 15:02:51 +01:00
|
|
|
{
|
2012-02-15 15:45:55 +01:00
|
|
|
eval.error = true;
|
2019-09-09 17:55:36 +02:00
|
|
|
eval.message = Unicode::utf8_printable<std::string>(std::string("ERR_PROFILE_GENERIC: ") + e.what(), 256);
|
2012-02-11 15:02:51 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::parse_extras(const Config& config, EvalConfig& eval)
|
2012-03-03 12:09:05 +01:00
|
|
|
{
|
|
|
|
try {
|
|
|
|
state->server_override = config.serverOverride;
|
2017-10-21 00:24:37 +02:00
|
|
|
state->port_override = config.portOverride;
|
2012-03-07 12:21:09 +01:00
|
|
|
state->conn_timeout = config.connTimeout;
|
2012-10-21 11:43:03 +02:00
|
|
|
state->tun_persist = config.tunPersist;
|
2019-05-17 10:49:36 +02:00
|
|
|
state->wintun = config.wintun;
|
2012-10-24 14:37:24 +02:00
|
|
|
state->google_dns_fallback = config.googleDnsFallback;
|
2017-10-09 14:03:55 +02:00
|
|
|
state->synchronous_dns_lookup = config.synchronousDnsLookup;
|
2016-02-04 19:39:44 +01:00
|
|
|
state->autologin_sessions = config.autologinSessions;
|
2018-02-06 22:12:58 +01:00
|
|
|
state->retry_on_auth_failed = config.retryOnAuthFailed;
|
2012-11-15 23:48:13 +01:00
|
|
|
state->private_key_password = config.privateKeyPassword;
|
2012-03-03 12:09:05 +01:00
|
|
|
if (!config.protoOverride.empty())
|
2016-05-05 08:13:43 +02:00
|
|
|
state->proto_override = Protocol::parse(config.protoOverride, Protocol::NO_SUFFIX);
|
2016-02-05 20:16:20 +01:00
|
|
|
if (!config.ipv6.empty())
|
|
|
|
state->ipv6 = IPv6Setting::parse(config.ipv6);
|
2012-09-08 03:36:54 +02:00
|
|
|
if (!config.compressionMode.empty())
|
|
|
|
state->proto_context_options->parse_compression_mode(config.compressionMode);
|
2012-03-06 07:06:54 +01:00
|
|
|
if (eval.externalPki)
|
|
|
|
state->external_pki_alias = config.externalPkiAlias;
|
2013-01-24 14:34:17 +01:00
|
|
|
state->disable_client_cert = config.disableClientCert;
|
2016-08-05 04:43:43 +02:00
|
|
|
state->ssl_debug_level = config.sslDebugLevel;
|
2013-01-28 02:11:28 +01:00
|
|
|
state->default_key_direction = config.defaultKeyDirection;
|
2013-12-27 23:16:05 +01:00
|
|
|
state->force_aes_cbc_ciphersuites = config.forceAesCbcCiphersuites;
|
2015-02-05 04:29:43 +01:00
|
|
|
state->tls_version_min_override = config.tlsVersionMinOverride;
|
2017-02-28 19:50:28 +01:00
|
|
|
state->tls_cert_profile_override = config.tlsCertProfileOverride;
|
2018-07-16 16:05:35 +02:00
|
|
|
state->allow_local_lan_access = config.allowLocalLanAccess;
|
2014-01-07 19:49:48 +01:00
|
|
|
state->gui_version = config.guiVersion;
|
2019-04-29 16:10:19 +02:00
|
|
|
state->sso_methods = config.ssoMethods;
|
2019-08-05 19:26:18 +02:00
|
|
|
state->platform_version = config.platformVersion;
|
|
|
|
state->hw_addr_override = config.hwAddrOverride;
|
2015-02-03 07:11:51 +01:00
|
|
|
state->alt_proxy = config.altProxy;
|
2015-06-17 09:48:33 +02:00
|
|
|
state->dco = config.dco;
|
2016-03-28 08:31:35 +02:00
|
|
|
state->echo = config.echo;
|
2016-05-11 01:53:09 +02:00
|
|
|
state->info = config.info;
|
2017-04-12 20:37:41 +02:00
|
|
|
state->clock_tick_ms = config.clockTickMS;
|
Added gremlin option to client, controllable via
ClientAPI::Config::gremlinConfig string.
The gremlin option allows extra packet latency
or unreliability to be added to the tunnel.
The format of the option is a comma-separated list
of numerical parameters:
send_delay_ms, recv_delay_ms, send_drop_prob, recv_drop_prob
Parameter description:
send_delay_ms : delay packets by n milliseconds before
transmission (UDP/TCP).
recv_delay_ms : delay received packets by n milliseconds
before processing them (UDP/TCP).
send_drop_prob : drop sent packets with probability 1/n
(UDP only).
recv_drop_prob : drop received packets with probability
1/n (UDP only).
Set any parameter to 0 to disable.
Gremlin parameters currently work with UDP and TCP
transport as documented above, but not for proxy transport.
Client must be built with the OPENVPN_GREMLIN flag to compile
gremlin functionality.
Command-line client can set the gremlin config
string using --gremlin or -G, for example:
--gremlin=250,250,64,64
When using the above parameters, an extra 500 milliseconds
will be added to round-trip latency, and 1/64 sent or
received packets will be dropped.
2016-01-26 08:27:11 +01:00
|
|
|
if (!config.gremlinConfig.empty())
|
|
|
|
{
|
|
|
|
#ifdef OPENVPN_GREMLIN
|
|
|
|
state->gremlin_config.reset(new Gremlin::Config(config.gremlinConfig));
|
|
|
|
#else
|
|
|
|
throw Exception("client not built with OPENVPN_GREMLIN");
|
|
|
|
#endif
|
|
|
|
}
|
2015-09-22 04:42:24 +02:00
|
|
|
state->extra_peer_info = PeerInfo::Set::new_from_foreign_set(config.peerInfo);
|
2012-10-24 08:38:20 +02:00
|
|
|
if (!config.proxyHost.empty())
|
|
|
|
{
|
|
|
|
HTTPProxyTransport::Options::Ptr ho(new HTTPProxyTransport::Options());
|
2013-03-12 20:20:37 +01:00
|
|
|
ho->set_proxy_server(config.proxyHost, config.proxyPort);
|
2012-10-24 08:38:20 +02:00
|
|
|
ho->username = config.proxyUsername;
|
|
|
|
ho->password = config.proxyPassword;
|
2012-10-28 11:07:32 +01:00
|
|
|
ho->allow_cleartext_auth = config.proxyAllowCleartextAuth;
|
2012-10-24 08:38:20 +02:00
|
|
|
state->http_proxy_options = ho;
|
|
|
|
}
|
2012-03-03 12:09:05 +01:00
|
|
|
}
|
|
|
|
catch (const std::exception& e)
|
|
|
|
{
|
|
|
|
eval.error = true;
|
2014-10-30 17:18:30 +01:00
|
|
|
eval.message = Unicode::utf8_printable<std::string>(e.what(), 256);
|
2012-03-03 12:09:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-12 02:52:03 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT long OpenVPNClient::max_profile_size()
|
|
|
|
{
|
|
|
|
return ProfileParseLimits::MAX_PROFILE_SIZE;
|
|
|
|
}
|
|
|
|
|
|
|
|
OPENVPN_CLIENT_EXPORT MergeConfig OpenVPNClient::merge_config_static(const std::string& path,
|
|
|
|
bool follow_references)
|
|
|
|
{
|
2015-02-10 23:48:08 +01:00
|
|
|
ProfileMerge pm(path, "ovpn", "", follow_references ? ProfileMerge::FOLLOW_PARTIAL : ProfileMerge::FOLLOW_NONE,
|
2012-11-12 02:52:03 +01:00
|
|
|
ProfileParseLimits::MAX_LINE_SIZE, ProfileParseLimits::MAX_PROFILE_SIZE);
|
|
|
|
return build_merge_config(pm);
|
|
|
|
}
|
|
|
|
|
|
|
|
OPENVPN_CLIENT_EXPORT MergeConfig OpenVPNClient::merge_config_string_static(const std::string& config_content)
|
|
|
|
{
|
2015-01-19 22:30:37 +01:00
|
|
|
ProfileMergeFromString pm(config_content, "", ProfileMerge::FOLLOW_NONE,
|
2012-11-12 02:52:03 +01:00
|
|
|
ProfileParseLimits::MAX_LINE_SIZE, ProfileParseLimits::MAX_PROFILE_SIZE);
|
|
|
|
return build_merge_config(pm);
|
|
|
|
}
|
|
|
|
|
|
|
|
OPENVPN_CLIENT_EXPORT MergeConfig OpenVPNClient::build_merge_config(const ProfileMerge& pm)
|
2012-10-18 14:24:14 +02:00
|
|
|
{
|
|
|
|
MergeConfig ret;
|
|
|
|
ret.status = pm.status_string();
|
|
|
|
ret.basename = pm.basename();
|
|
|
|
if (pm.status() == ProfileMerge::MERGE_SUCCESS)
|
|
|
|
{
|
|
|
|
ret.refPathList = pm.ref_path_list();
|
|
|
|
ret.profileContent = pm.profile_content();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ret.errorText = pm.error();
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT EvalConfig OpenVPNClient::eval_config_static(const Config& config)
|
2012-02-15 15:45:55 +01:00
|
|
|
{
|
|
|
|
EvalConfig eval;
|
|
|
|
OptionList options;
|
|
|
|
parse_config(config, eval, options);
|
|
|
|
return eval;
|
|
|
|
}
|
|
|
|
|
2012-03-03 12:09:05 +01:00
|
|
|
// API client submits the configuration here before calling connect()
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT EvalConfig OpenVPNClient::eval_config(const Config& config)
|
2012-02-15 15:45:55 +01:00
|
|
|
{
|
2012-03-03 12:09:05 +01:00
|
|
|
// parse and validate configuration file
|
2012-02-15 15:45:55 +01:00
|
|
|
EvalConfig eval;
|
|
|
|
parse_config(config, eval, state->options);
|
2012-03-03 12:09:05 +01:00
|
|
|
if (eval.error)
|
|
|
|
return eval;
|
|
|
|
|
|
|
|
// handle extra settings in config
|
|
|
|
parse_extras(config, eval);
|
2012-03-06 07:06:54 +01:00
|
|
|
state->eval = eval;
|
2012-02-15 15:45:55 +01:00
|
|
|
return eval;
|
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT Status OpenVPNClient::provide_creds(const ProvideCreds& creds)
|
2012-02-11 15:02:51 +01:00
|
|
|
{
|
2012-03-03 03:56:58 +01:00
|
|
|
Status ret;
|
|
|
|
try {
|
|
|
|
ClientCreds::Ptr cc = new ClientCreds();
|
|
|
|
cc->set_username(creds.username);
|
|
|
|
cc->set_password(creds.password);
|
|
|
|
cc->set_response(creds.response);
|
2015-05-10 23:39:57 +02:00
|
|
|
cc->set_dynamic_challenge_cookie(creds.dynamicChallengeCookie, creds.username);
|
2012-03-03 03:56:58 +01:00
|
|
|
cc->set_replace_password_with_session_id(creds.replacePasswordWithSessionID);
|
2013-01-25 03:34:20 +01:00
|
|
|
cc->enable_password_cache(creds.cachePassword);
|
2012-03-03 03:56:58 +01:00
|
|
|
state->creds = cc;
|
|
|
|
}
|
|
|
|
catch (const std::exception& e)
|
|
|
|
{
|
|
|
|
ret.error = true;
|
2014-10-30 17:18:30 +01:00
|
|
|
ret.message = Unicode::utf8_printable<std::string>(e.what(), 256);
|
2012-03-03 03:56:58 +01:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2012-03-01 23:50:57 +01:00
|
|
|
|
2019-10-04 15:25:46 +02:00
|
|
|
OPENVPN_CLIENT_EXPORT bool OpenVPNClient::socket_protect(int socket, std::string remote, bool ipv6)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT bool OpenVPNClient::parse_dynamic_challenge(const std::string& cookie, DynamicChallenge& dc)
|
2012-03-03 03:56:58 +01:00
|
|
|
{
|
|
|
|
try {
|
|
|
|
ChallengeResponse cr(cookie);
|
|
|
|
dc.challenge = cr.get_challenge_text();
|
|
|
|
dc.echo = cr.get_echo();
|
|
|
|
dc.responseRequired = cr.get_response_required();
|
2015-05-10 23:39:57 +02:00
|
|
|
dc.stateID = cr.get_state_id();
|
2012-03-03 03:56:58 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
catch (const std::exception&)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2012-02-11 15:02:51 +01:00
|
|
|
}
|
|
|
|
|
2012-10-19 12:29:12 +02:00
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::process_epki_cert_chain(const ExternalPKICertRequest& req)
|
|
|
|
{
|
|
|
|
// Get cert and add to options list
|
2016-03-28 08:12:53 +02:00
|
|
|
if (!req.cert.empty())
|
|
|
|
{
|
|
|
|
Option o;
|
|
|
|
o.push_back("cert");
|
|
|
|
o.push_back(req.cert);
|
|
|
|
state->options.add_item(o);
|
|
|
|
}
|
|
|
|
|
2012-10-19 12:29:12 +02:00
|
|
|
// Get the supporting chain, if it exists, and use
|
|
|
|
// it for ca (if ca isn't defined), or otherwise use
|
|
|
|
// it for extra-certs (if ca is defined but extra-certs
|
|
|
|
// is not).
|
|
|
|
if (!req.supportingChain.empty())
|
|
|
|
{
|
|
|
|
if (!state->options.exists("ca"))
|
|
|
|
{
|
|
|
|
Option o;
|
|
|
|
o.push_back("ca");
|
|
|
|
o.push_back(req.supportingChain);
|
|
|
|
state->options.add_item(o);
|
|
|
|
}
|
|
|
|
else if (!state->options.exists("extra-certs"))
|
|
|
|
{
|
|
|
|
Option o;
|
|
|
|
o.push_back("extra-certs");
|
|
|
|
o.push_back(req.supportingChain);
|
|
|
|
state->options.add_item(o);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT Status OpenVPNClient::connect()
|
2012-02-11 15:02:51 +01:00
|
|
|
{
|
2017-04-12 20:37:41 +02:00
|
|
|
#if !defined(OPENVPN_OVPNCLI_SINGLE_THREAD)
|
2017-03-30 23:10:56 +02:00
|
|
|
openvpn_io::detail::signal_blocker signal_blocker; // signals should be handled by parent thread
|
2017-04-12 20:37:41 +02:00
|
|
|
#endif
|
2015-11-25 19:26:55 +01:00
|
|
|
#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
|
|
|
|
#endif
|
2012-02-11 15:02:51 +01:00
|
|
|
Log::Context log_context(this);
|
2015-04-11 07:50:07 +02:00
|
|
|
#endif
|
2019-01-03 10:30:17 +01:00
|
|
|
|
|
|
|
OPENVPN_LOG(ClientAPI::OpenVPNClient::platform());
|
|
|
|
|
2015-04-12 19:27:58 +02:00
|
|
|
return do_connect();
|
|
|
|
}
|
|
|
|
|
|
|
|
OPENVPN_CLIENT_EXPORT Status OpenVPNClient::do_connect()
|
|
|
|
{
|
2017-04-18 07:28:36 +02:00
|
|
|
Status status;
|
|
|
|
bool session_started = false;
|
|
|
|
try {
|
|
|
|
connect_attach();
|
|
|
|
#if defined(OPENVPN_OVPNCLI_ASYNC_SETUP)
|
|
|
|
openvpn_io::post(*state->io_context(), [this]() {
|
|
|
|
do_connect_async();
|
|
|
|
});
|
|
|
|
#else
|
|
|
|
connect_setup(status, session_started);
|
|
|
|
#endif
|
|
|
|
connect_run();
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
catch (const std::exception& e)
|
|
|
|
{
|
|
|
|
if (session_started)
|
|
|
|
connect_session_stop();
|
|
|
|
return status_from_exception(e);
|
|
|
|
}
|
|
|
|
}
|
2012-02-19 18:43:42 +01:00
|
|
|
|
2017-04-18 07:28:36 +02:00
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::do_connect_async()
|
|
|
|
{
|
|
|
|
enum StopType {
|
|
|
|
NONE,
|
|
|
|
SESSION,
|
|
|
|
EXPLICIT,
|
|
|
|
};
|
|
|
|
StopType stop_type = NONE;
|
|
|
|
Status status;
|
|
|
|
bool session_started = false;
|
2012-10-19 10:52:01 +02:00
|
|
|
try {
|
2017-04-18 07:28:36 +02:00
|
|
|
connect_setup(status, session_started);
|
|
|
|
}
|
|
|
|
catch (const std::exception& e)
|
|
|
|
{
|
|
|
|
stop_type = session_started ? SESSION : EXPLICIT;
|
|
|
|
status = status_from_exception(e);
|
|
|
|
}
|
|
|
|
if (status.error)
|
|
|
|
{
|
|
|
|
ClientEvent::Base::Ptr ev = new ClientEvent::ClientSetup(status.status, status.message);
|
|
|
|
state->events->add_event(std::move(ev));
|
|
|
|
}
|
|
|
|
if (stop_type == SESSION)
|
|
|
|
connect_session_stop();
|
|
|
|
#ifdef OPENVPN_IO_REQUIRES_STOP
|
|
|
|
if (stop_type == EXPLICIT)
|
|
|
|
state->io_context()->stop();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::connect_setup(Status& status, bool& session_started)
|
|
|
|
{
|
|
|
|
// set global MbedTLS debug level
|
2017-02-24 00:59:51 +01:00
|
|
|
#if defined(USE_MBEDTLS) || defined(USE_MBEDTLS_APPLE_HYBRID)
|
2017-04-18 07:28:36 +02:00
|
|
|
mbedtls_debug_set_threshold(state->ssl_debug_level); // fixme -- using a global method for this seems wrong
|
2016-08-05 04:43:43 +02:00
|
|
|
#endif
|
|
|
|
|
2017-04-18 07:28:36 +02:00
|
|
|
// load options
|
|
|
|
ClientOptions::Config cc;
|
|
|
|
cc.cli_stats = state->stats;
|
|
|
|
cc.cli_events = state->events;
|
|
|
|
cc.server_override = state->server_override;
|
2017-10-21 00:24:37 +02:00
|
|
|
cc.port_override = state->port_override;
|
2017-04-18 07:28:36 +02:00
|
|
|
cc.proto_override = state->proto_override;
|
|
|
|
cc.ipv6 = state->ipv6;
|
|
|
|
cc.conn_timeout = state->conn_timeout;
|
|
|
|
cc.tun_persist = state->tun_persist;
|
2019-05-17 10:49:36 +02:00
|
|
|
cc.wintun = state->wintun;
|
2017-04-18 07:28:36 +02:00
|
|
|
cc.google_dns_fallback = state->google_dns_fallback;
|
2017-10-09 14:03:55 +02:00
|
|
|
cc.synchronous_dns_lookup = state->synchronous_dns_lookup;
|
2017-04-18 07:28:36 +02:00
|
|
|
cc.autologin_sessions = state->autologin_sessions;
|
2018-02-06 22:12:58 +01:00
|
|
|
cc.retry_on_auth_failed = state->retry_on_auth_failed;
|
2017-04-18 07:28:36 +02:00
|
|
|
cc.proto_context_options = state->proto_context_options;
|
|
|
|
cc.http_proxy_options = state->http_proxy_options;
|
|
|
|
cc.alt_proxy = state->alt_proxy;
|
|
|
|
cc.dco = state->dco;
|
|
|
|
cc.echo = state->echo;
|
|
|
|
cc.info = state->info;
|
|
|
|
cc.reconnect_notify = &state->reconnect_notify;
|
|
|
|
if (remote_override_enabled())
|
|
|
|
cc.remote_override = &state->remote_override;
|
|
|
|
cc.private_key_password = state->private_key_password;
|
|
|
|
cc.disable_client_cert = state->disable_client_cert;
|
|
|
|
cc.ssl_debug_level = state->ssl_debug_level;
|
|
|
|
cc.default_key_direction = state->default_key_direction;
|
|
|
|
cc.force_aes_cbc_ciphersuites = state->force_aes_cbc_ciphersuites;
|
|
|
|
cc.tls_version_min_override = state->tls_version_min_override;
|
|
|
|
cc.tls_cert_profile_override = state->tls_cert_profile_override;
|
|
|
|
cc.gui_version = state->gui_version;
|
2019-04-29 16:10:19 +02:00
|
|
|
cc.sso_methods = state->sso_methods;
|
2019-08-05 19:26:18 +02:00
|
|
|
cc.hw_addr_override = state->hw_addr_override;
|
|
|
|
cc.platform_version = state->platform_version;
|
2017-04-18 07:28:36 +02:00
|
|
|
cc.extra_peer_info = state->extra_peer_info;
|
|
|
|
cc.stop = state->async_stop_local();
|
2018-07-16 16:05:35 +02:00
|
|
|
cc.allow_local_lan_access = state->allow_local_lan_access;
|
Added gremlin option to client, controllable via
ClientAPI::Config::gremlinConfig string.
The gremlin option allows extra packet latency
or unreliability to be added to the tunnel.
The format of the option is a comma-separated list
of numerical parameters:
send_delay_ms, recv_delay_ms, send_drop_prob, recv_drop_prob
Parameter description:
send_delay_ms : delay packets by n milliseconds before
transmission (UDP/TCP).
recv_delay_ms : delay received packets by n milliseconds
before processing them (UDP/TCP).
send_drop_prob : drop sent packets with probability 1/n
(UDP only).
recv_drop_prob : drop received packets with probability
1/n (UDP only).
Set any parameter to 0 to disable.
Gremlin parameters currently work with UDP and TCP
transport as documented above, but not for proxy transport.
Client must be built with the OPENVPN_GREMLIN flag to compile
gremlin functionality.
Command-line client can set the gremlin config
string using --gremlin or -G, for example:
--gremlin=250,250,64,64
When using the above parameters, an extra 500 milliseconds
will be added to round-trip latency, and 1/64 sent or
received packets will be dropped.
2016-01-26 08:27:11 +01:00
|
|
|
#ifdef OPENVPN_GREMLIN
|
2017-04-18 07:28:36 +02:00
|
|
|
cc.gremlin_config = state->gremlin_config;
|
Added gremlin option to client, controllable via
ClientAPI::Config::gremlinConfig string.
The gremlin option allows extra packet latency
or unreliability to be added to the tunnel.
The format of the option is a comma-separated list
of numerical parameters:
send_delay_ms, recv_delay_ms, send_drop_prob, recv_drop_prob
Parameter description:
send_delay_ms : delay packets by n milliseconds before
transmission (UDP/TCP).
recv_delay_ms : delay received packets by n milliseconds
before processing them (UDP/TCP).
send_drop_prob : drop sent packets with probability 1/n
(UDP only).
recv_drop_prob : drop received packets with probability
1/n (UDP only).
Set any parameter to 0 to disable.
Gremlin parameters currently work with UDP and TCP
transport as documented above, but not for proxy transport.
Client must be built with the OPENVPN_GREMLIN flag to compile
gremlin functionality.
Command-line client can set the gremlin config
string using --gremlin or -G, for example:
--gremlin=250,250,64,64
When using the above parameters, an extra 500 milliseconds
will be added to round-trip latency, and 1/64 sent or
received packets will be dropped.
2016-01-26 08:27:11 +01:00
|
|
|
#endif
|
2017-04-18 07:28:36 +02:00
|
|
|
cc.socket_protect = &state->socket_protect;
|
2019-10-04 15:25:46 +02:00
|
|
|
#if defined(USE_TUN_BUILDER)
|
2017-04-18 07:28:36 +02:00
|
|
|
cc.builder = this;
|
2012-02-19 20:06:44 +01:00
|
|
|
#endif
|
2017-04-13 21:28:34 +02:00
|
|
|
#if defined(OPENVPN_EXTERNAL_TUN_FACTORY)
|
2017-04-18 07:28:36 +02:00
|
|
|
cc.extern_tun_factory = this;
|
2017-04-13 21:28:34 +02:00
|
|
|
#endif
|
2017-10-09 15:59:46 +02:00
|
|
|
#if defined(OPENVPN_EXTERNAL_TRANSPORT_FACTORY)
|
|
|
|
cc.extern_transport_factory = this;
|
|
|
|
#endif
|
2017-04-18 07:28:36 +02:00
|
|
|
// force Session ID use and disable password cache if static challenge is enabled
|
|
|
|
if (state->creds
|
|
|
|
&& !state->creds->get_replace_password_with_session_id()
|
|
|
|
&& !state->eval.autologin
|
|
|
|
&& !state->eval.staticChallenge.empty())
|
|
|
|
{
|
|
|
|
state->creds->set_replace_password_with_session_id(true);
|
|
|
|
state->creds->enable_password_cache(false);
|
|
|
|
}
|
2012-11-18 19:53:10 +01:00
|
|
|
|
2017-04-18 07:28:36 +02:00
|
|
|
// external PKI
|
2012-05-23 15:50:41 +02:00
|
|
|
#if !defined(USE_APPLE_SSL)
|
2017-04-18 07:28:36 +02:00
|
|
|
if (state->eval.externalPki && !state->disable_client_cert)
|
|
|
|
{
|
|
|
|
if (!state->external_pki_alias.empty())
|
|
|
|
{
|
|
|
|
ExternalPKICertRequest req;
|
|
|
|
req.alias = state->external_pki_alias;
|
|
|
|
external_pki_cert_request(req);
|
|
|
|
if (!req.error)
|
|
|
|
{
|
|
|
|
cc.external_pki = this;
|
|
|
|
process_epki_cert_chain(req);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
external_pki_error(req, Error::EPKI_CERT_ERROR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
status.error = true;
|
|
|
|
status.message = "Missing External PKI alias";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2012-05-23 15:50:41 +02:00
|
|
|
#endif
|
2012-03-06 07:06:54 +01:00
|
|
|
|
2018-03-08 18:03:38 +01:00
|
|
|
#ifdef USE_OPENSSL
|
|
|
|
if (state->options.exists("allow-name-constraints"))
|
|
|
|
{
|
|
|
|
ClientEvent::Base::Ptr ev = new ClientEvent::UnsupportedFeature("allow-name-constraints",
|
|
|
|
"Always verified correctly with OpenSSL", false);
|
|
|
|
state->events->add_event(std::move(ev));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-04-18 07:28:36 +02:00
|
|
|
// build client options object
|
|
|
|
ClientOptions::Ptr client_options = new ClientOptions(state->options, cc);
|
2012-02-11 15:02:51 +01:00
|
|
|
|
2017-04-18 07:28:36 +02:00
|
|
|
// configure creds in options
|
|
|
|
client_options->submit_creds(state->creds);
|
2012-02-11 15:02:51 +01:00
|
|
|
|
2017-04-18 07:28:36 +02:00
|
|
|
// instantiate top-level client session
|
|
|
|
state->session.reset(new ClientConnect(*state->io_context(), client_options));
|
2012-02-11 15:02:51 +01:00
|
|
|
|
2017-04-18 07:28:36 +02:00
|
|
|
// 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();
|
|
|
|
}
|
2017-04-12 20:37:41 +02:00
|
|
|
|
2017-04-18 07:28:36 +02:00
|
|
|
// raise an exception if app has expired
|
|
|
|
check_app_expired();
|
2012-03-10 05:55:32 +01:00
|
|
|
|
2017-04-18 07:28:36 +02:00
|
|
|
// start VPN
|
|
|
|
state->session->start(); // queue reads on socket/tun
|
|
|
|
session_started = true;
|
2012-02-11 15:02:51 +01:00
|
|
|
|
2017-04-18 07:28:36 +02:00
|
|
|
// wire up async stop
|
|
|
|
state->setup_async_stop_scopes();
|
2016-06-27 07:00:37 +02:00
|
|
|
|
2017-04-18 07:28:36 +02:00
|
|
|
// prepare to start reactor
|
|
|
|
connect_pre_run();
|
|
|
|
state->enable_foreign_thread_access();
|
|
|
|
}
|
2015-04-12 19:27:58 +02:00
|
|
|
|
2017-04-18 07:28:36 +02:00
|
|
|
OPENVPN_CLIENT_EXPORT Status OpenVPNClient::status_from_exception(const std::exception& e)
|
|
|
|
{
|
|
|
|
Status ret;
|
|
|
|
ret.error = true;
|
|
|
|
ret.message = Unicode::utf8_printable<std::string>(e.what(), 256);
|
2012-11-16 05:13:48 +01:00
|
|
|
|
2017-04-18 07:28:36 +02:00
|
|
|
// if exception is an ExceptionCode, translate the code
|
|
|
|
// to return status string
|
|
|
|
{
|
|
|
|
const ExceptionCode *ec = dynamic_cast<const ExceptionCode *>(&e);
|
|
|
|
if (ec && ec->code_defined())
|
|
|
|
ret.status = Error::name(ec->code());
|
|
|
|
}
|
2012-02-11 15:02:51 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-04-12 19:27:58 +02:00
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::connect_attach()
|
|
|
|
{
|
2016-06-27 07:00:37 +02:00
|
|
|
state->attach<MySessionStats, MyClientEvents>(this,
|
|
|
|
nullptr,
|
|
|
|
get_async_stop());
|
2015-04-12 19:27:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::connect_pre_run()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::connect_run()
|
|
|
|
{
|
2016-06-27 07:00:37 +02:00
|
|
|
state->io_context()->run();
|
2015-04-12 19:27:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::connect_session_stop()
|
|
|
|
{
|
|
|
|
state->session->stop(); // On exception, stop client...
|
2016-06-27 07:00:37 +02:00
|
|
|
state->io_context()->poll(); // and execute completion handlers.
|
2015-04-12 19:27:58 +02:00
|
|
|
}
|
|
|
|
|
2012-07-02 22:52:58 +02:00
|
|
|
OPENVPN_CLIENT_EXPORT ConnectionInfo OpenVPNClient::connection_info()
|
|
|
|
{
|
|
|
|
ConnectionInfo ci;
|
2016-06-27 07:00:37 +02:00
|
|
|
if (state->is_foreign_thread_access())
|
|
|
|
{
|
|
|
|
MyClientEvents* events = state->events.get();
|
|
|
|
if (events)
|
|
|
|
events->get_connection_info(ci);
|
|
|
|
}
|
2012-07-02 22:52:58 +02:00
|
|
|
return ci;
|
|
|
|
}
|
|
|
|
|
2012-08-21 23:32:51 +02:00
|
|
|
OPENVPN_CLIENT_EXPORT bool OpenVPNClient::session_token(SessionToken& tok)
|
|
|
|
{
|
2016-06-27 07:00:37 +02:00
|
|
|
if (state->is_foreign_thread_access())
|
2012-08-21 23:32:51 +02:00
|
|
|
{
|
2016-06-27 07:00:37 +02:00
|
|
|
ClientCreds* cc = state->creds.get();
|
|
|
|
if (cc && cc->session_id_defined())
|
|
|
|
{
|
|
|
|
tok.username = cc->get_username();
|
|
|
|
tok.session_id = cc->get_password();
|
|
|
|
return true;
|
|
|
|
}
|
2012-08-21 23:32:51 +02:00
|
|
|
}
|
2016-06-27 07:00:37 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
OPENVPN_CLIENT_EXPORT Stop* OpenVPNClient::get_async_stop()
|
|
|
|
{
|
|
|
|
return nullptr;
|
2012-08-21 23:32:51 +02:00
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::external_pki_error(const ExternalPKIRequestBase& req, const size_t err_type)
|
2012-03-06 07:06:54 +01:00
|
|
|
{
|
|
|
|
if (req.error)
|
|
|
|
{
|
|
|
|
if (req.invalidAlias)
|
|
|
|
{
|
|
|
|
ClientEvent::Base::Ptr ev = new ClientEvent::EpkiInvalidAlias(req.alias);
|
2016-05-11 05:26:34 +02:00
|
|
|
state->events->add_event(std::move(ev));
|
2012-03-06 07:06:54 +01:00
|
|
|
}
|
2012-10-19 10:52:01 +02:00
|
|
|
|
|
|
|
ClientEvent::Base::Ptr ev = new ClientEvent::EpkiError(req.errorText);
|
2016-05-11 05:26:34 +02:00
|
|
|
state->events->add_event(std::move(ev));
|
2012-10-19 10:52:01 +02:00
|
|
|
|
2012-03-07 12:21:09 +01:00
|
|
|
state->stats->error(err_type);
|
2017-02-23 23:03:38 +01:00
|
|
|
if (state->session)
|
|
|
|
state->session->dont_restart();
|
2012-03-06 07:06:54 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-23 13:08:44 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT bool OpenVPNClient::sign(const std::string& data, std::string& sig, const std::string& algorithm)
|
2012-03-06 07:06:54 +01:00
|
|
|
{
|
|
|
|
ExternalPKISignRequest req;
|
|
|
|
req.data = data;
|
|
|
|
req.alias = state->external_pki_alias;
|
2018-11-23 13:08:44 +01:00
|
|
|
req.algorithm = algorithm;
|
2012-03-06 07:06:54 +01:00
|
|
|
external_pki_sign_request(req); // call out to derived class for RSA signature
|
|
|
|
if (!req.error)
|
|
|
|
{
|
|
|
|
sig = req.sig;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-03-07 12:21:09 +01:00
|
|
|
external_pki_error(req, Error::EPKI_SIGN_ERROR);
|
2012-03-06 07:06:54 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-02 09:00:09 +02:00
|
|
|
OPENVPN_CLIENT_EXPORT bool OpenVPNClient::remote_override_enabled()
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::remote_override(RemoteOverride&)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT int OpenVPNClient::stats_n()
|
2012-02-13 00:09:28 +01:00
|
|
|
{
|
2013-11-11 20:33:35 +01:00
|
|
|
return (int)MySessionStats::combined_n();
|
2012-02-13 00:09:28 +01:00
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT std::string OpenVPNClient::stats_name(int index)
|
2012-02-13 00:09:28 +01:00
|
|
|
{
|
|
|
|
return MySessionStats::combined_name(index);
|
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT long long OpenVPNClient::stats_value(int index) const
|
2012-02-11 15:02:51 +01:00
|
|
|
{
|
2016-06-27 07:00:37 +02:00
|
|
|
if (state->is_foreign_thread_access())
|
|
|
|
{
|
|
|
|
MySessionStats* stats = state->stats.get();
|
|
|
|
if (stats)
|
2016-09-06 17:44:15 +02:00
|
|
|
{
|
|
|
|
if (index == SessionStats::BYTES_IN || index == SessionStats::BYTES_OUT)
|
|
|
|
stats->dco_update();
|
|
|
|
return stats->combined_value(index);
|
|
|
|
}
|
2016-06-27 07:00:37 +02:00
|
|
|
}
|
|
|
|
return 0;
|
2012-02-11 15:02:51 +01:00
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT std::vector<long long> OpenVPNClient::stats_bundle() const
|
2012-03-07 12:21:09 +01:00
|
|
|
{
|
|
|
|
std::vector<long long> sv;
|
|
|
|
const size_t n = MySessionStats::combined_n();
|
|
|
|
sv.reserve(n);
|
2016-06-27 07:00:37 +02:00
|
|
|
if (state->is_foreign_thread_access())
|
|
|
|
{
|
|
|
|
MySessionStats* stats = state->stats.get();
|
2016-09-06 17:44:15 +02:00
|
|
|
if (stats)
|
|
|
|
stats->dco_update();
|
2016-06-27 07:00:37 +02:00
|
|
|
for (size_t i = 0; i < n; ++i)
|
|
|
|
sv.push_back(stats ? stats->combined_value(i) : 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < n; ++i)
|
|
|
|
sv.push_back(0);
|
|
|
|
}
|
2012-03-07 12:21:09 +01:00
|
|
|
return sv;
|
|
|
|
}
|
|
|
|
|
2012-07-01 17:37:46 +02:00
|
|
|
OPENVPN_CLIENT_EXPORT InterfaceStats OpenVPNClient::tun_stats() const
|
|
|
|
{
|
|
|
|
InterfaceStats ret;
|
2016-06-27 07:00:37 +02:00
|
|
|
if (state->is_foreign_thread_access())
|
2012-07-02 22:52:58 +02:00
|
|
|
{
|
2016-06-27 07:00:37 +02:00
|
|
|
MySessionStats* stats = state->stats.get();
|
|
|
|
|
|
|
|
// The reason for the apparent inversion between in/out below is
|
|
|
|
// that TUN_*_OUT stats refer to data written to tun device,
|
|
|
|
// but from the perspective of tun interface, this is incoming
|
|
|
|
// data. Vice versa for TUN_*_IN.
|
|
|
|
if (stats)
|
|
|
|
{
|
|
|
|
ret.bytesOut = stats->stat_count(SessionStats::TUN_BYTES_IN);
|
|
|
|
ret.bytesIn = stats->stat_count(SessionStats::TUN_BYTES_OUT);
|
|
|
|
ret.packetsOut = stats->stat_count(SessionStats::TUN_PACKETS_IN);
|
|
|
|
ret.packetsIn = stats->stat_count(SessionStats::TUN_PACKETS_OUT);
|
|
|
|
ret.errorsOut = stats->error_count(Error::TUN_READ_ERROR);
|
|
|
|
ret.errorsIn = stats->error_count(Error::TUN_WRITE_ERROR);
|
|
|
|
return ret;
|
|
|
|
}
|
2012-07-02 22:52:58 +02:00
|
|
|
}
|
2016-06-27 07:00:37 +02:00
|
|
|
|
|
|
|
ret.bytesOut = 0;
|
|
|
|
ret.bytesIn = 0;
|
|
|
|
ret.packetsOut = 0;
|
|
|
|
ret.packetsIn = 0;
|
|
|
|
ret.errorsOut = 0;
|
|
|
|
ret.errorsIn = 0;
|
2012-07-01 17:37:46 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-07-24 11:16:43 +02:00
|
|
|
OPENVPN_CLIENT_EXPORT TransportStats OpenVPNClient::transport_stats() const
|
|
|
|
{
|
|
|
|
TransportStats ret;
|
2012-09-06 00:03:26 +02:00
|
|
|
ret.lastPacketReceived = -1; // undefined
|
2016-06-27 07:00:37 +02:00
|
|
|
|
|
|
|
if (state->is_foreign_thread_access())
|
2012-07-24 11:16:43 +02:00
|
|
|
{
|
2016-06-27 07:00:37 +02:00
|
|
|
MySessionStats* stats = state->stats.get();
|
|
|
|
if (stats)
|
|
|
|
{
|
2016-09-06 17:44:15 +02:00
|
|
|
stats->dco_update();
|
2016-06-27 07:00:37 +02:00
|
|
|
ret.bytesOut = stats->stat_count(SessionStats::BYTES_OUT);
|
|
|
|
ret.bytesIn = stats->stat_count(SessionStats::BYTES_IN);
|
|
|
|
ret.packetsOut = stats->stat_count(SessionStats::PACKETS_OUT);
|
|
|
|
ret.packetsIn = stats->stat_count(SessionStats::PACKETS_IN);
|
2012-09-06 00:03:26 +02:00
|
|
|
|
2016-06-27 07:00:37 +02:00
|
|
|
// calculate time since last packet received
|
2012-09-06 00:03:26 +02:00
|
|
|
{
|
2016-06-27 07:00:37 +02:00
|
|
|
const Time& lpr = stats->last_packet_received();
|
|
|
|
if (lpr.defined())
|
|
|
|
{
|
|
|
|
const Time::Duration dur = Time::now() - lpr;
|
|
|
|
const unsigned int delta = (unsigned int)dur.to_binary_ms();
|
|
|
|
if (delta <= 60*60*24*1024) // only define for time periods <= 1 day
|
|
|
|
ret.lastPacketReceived = delta;
|
|
|
|
}
|
2012-09-06 00:03:26 +02:00
|
|
|
}
|
2016-06-27 07:00:37 +02:00
|
|
|
return ret;
|
|
|
|
}
|
2012-07-24 11:16:43 +02:00
|
|
|
}
|
2016-06-27 07:00:37 +02:00
|
|
|
|
|
|
|
ret.bytesOut = 0;
|
|
|
|
ret.bytesIn = 0;
|
|
|
|
ret.packetsOut = 0;
|
|
|
|
ret.packetsIn = 0;
|
2012-07-24 11:16:43 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::stop()
|
2012-02-11 15:02:51 +01:00
|
|
|
{
|
2016-06-27 07:00:37 +02:00
|
|
|
if (state->is_foreign_thread_access())
|
2016-07-13 07:06:12 +02:00
|
|
|
state->trigger_async_stop_local();
|
2012-02-11 15:02:51 +01:00
|
|
|
}
|
|
|
|
|
2014-03-25 00:28:46 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::pause(const std::string& reason)
|
2012-02-27 06:11:22 +01:00
|
|
|
{
|
2016-06-27 07:00:37 +02:00
|
|
|
if (state->is_foreign_thread_access())
|
|
|
|
{
|
|
|
|
ClientConnect* session = state->session.get();
|
|
|
|
if (session)
|
|
|
|
session->thread_safe_pause(reason);
|
|
|
|
}
|
2012-02-27 06:11:22 +01:00
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::resume()
|
2012-02-27 06:11:22 +01:00
|
|
|
{
|
2016-06-27 07:00:37 +02:00
|
|
|
if (state->is_foreign_thread_access())
|
|
|
|
{
|
|
|
|
ClientConnect* session = state->session.get();
|
|
|
|
if (session)
|
2017-04-12 20:35:57 +02:00
|
|
|
session->thread_safe_resume();
|
2016-06-27 07:00:37 +02:00
|
|
|
}
|
2012-02-27 06:11:22 +01:00
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::reconnect(int seconds)
|
2012-02-27 06:11:22 +01:00
|
|
|
{
|
2016-06-27 07:00:37 +02:00
|
|
|
if (state->is_foreign_thread_access())
|
|
|
|
{
|
|
|
|
ClientConnect* session = state->session.get();
|
|
|
|
if (session)
|
2017-04-12 20:35:57 +02:00
|
|
|
session->thread_safe_reconnect(seconds);
|
2016-06-27 07:00:37 +02:00
|
|
|
}
|
2012-02-27 06:11:22 +01:00
|
|
|
}
|
|
|
|
|
2016-12-08 23:23:01 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::post_cc_msg(const std::string& msg)
|
|
|
|
{
|
|
|
|
if (state->is_foreign_thread_access())
|
|
|
|
{
|
|
|
|
ClientConnect* session = state->session.get();
|
|
|
|
if (session)
|
2017-04-12 20:35:57 +02:00
|
|
|
session->thread_safe_post_cc_msg(msg);
|
2016-12-08 23:23:01 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-12 20:37:41 +02:00
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::clock_tick()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::on_disconnect()
|
|
|
|
{
|
|
|
|
state->on_disconnect();
|
|
|
|
}
|
|
|
|
|
2013-06-14 02:34:49 +02:00
|
|
|
OPENVPN_CLIENT_EXPORT std::string OpenVPNClient::crypto_self_test()
|
|
|
|
{
|
|
|
|
return SelfTest::crypto_self_test();
|
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT int OpenVPNClient::app_expire()
|
2012-03-10 05:55:32 +01:00
|
|
|
{
|
|
|
|
#ifdef APP_EXPIRE_TIME
|
|
|
|
return APP_EXPIRE_TIME;
|
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::check_app_expired()
|
2012-03-10 05:55:32 +01:00
|
|
|
{
|
|
|
|
#ifdef APP_EXPIRE_TIME
|
|
|
|
if (Time::now().seconds_since_epoch() >= APP_EXPIRE_TIME)
|
|
|
|
throw app_expired();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2012-04-18 00:12:27 +02:00
|
|
|
OPENVPN_CLIENT_EXPORT std::string OpenVPNClient::copyright()
|
|
|
|
{
|
|
|
|
return openvpn_copyright;
|
|
|
|
}
|
|
|
|
|
2014-01-15 00:28:29 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT std::string OpenVPNClient::platform()
|
|
|
|
{
|
2015-03-08 20:34:50 +01:00
|
|
|
std::string ret = platform_string();
|
|
|
|
#ifdef PRIVATE_TUNNEL_PROXY
|
|
|
|
ret += " PT_PROXY";
|
2015-06-18 22:37:12 +02:00
|
|
|
#endif
|
|
|
|
#ifdef ENABLE_DCO
|
|
|
|
ret += " DCO";
|
Added gremlin option to client, controllable via
ClientAPI::Config::gremlinConfig string.
The gremlin option allows extra packet latency
or unreliability to be added to the tunnel.
The format of the option is a comma-separated list
of numerical parameters:
send_delay_ms, recv_delay_ms, send_drop_prob, recv_drop_prob
Parameter description:
send_delay_ms : delay packets by n milliseconds before
transmission (UDP/TCP).
recv_delay_ms : delay received packets by n milliseconds
before processing them (UDP/TCP).
send_drop_prob : drop sent packets with probability 1/n
(UDP only).
recv_drop_prob : drop received packets with probability
1/n (UDP only).
Set any parameter to 0 to disable.
Gremlin parameters currently work with UDP and TCP
transport as documented above, but not for proxy transport.
Client must be built with the OPENVPN_GREMLIN flag to compile
gremlin functionality.
Command-line client can set the gremlin config
string using --gremlin or -G, for example:
--gremlin=250,250,64,64
When using the above parameters, an extra 500 milliseconds
will be added to round-trip latency, and 1/64 sent or
received packets will be dropped.
2016-01-26 08:27:11 +01:00
|
|
|
#endif
|
|
|
|
#ifdef OPENVPN_GREMLIN
|
|
|
|
ret += " GREMLIN";
|
2015-03-08 20:34:50 +01:00
|
|
|
#endif
|
2019-02-27 18:28:26 +01:00
|
|
|
#ifdef OPENVPN_DEBUG
|
2015-06-07 08:52:02 +02:00
|
|
|
ret += " built on " __DATE__ " " __TIME__;
|
2019-02-27 18:28:26 +01:00
|
|
|
#endif
|
2015-03-08 20:34:50 +01:00
|
|
|
return ret;
|
2014-01-15 00:28:29 +01:00
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT OpenVPNClient::~OpenVPNClient()
|
2012-02-11 15:02:51 +01:00
|
|
|
{
|
|
|
|
delete state;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|