2012-03-01 09:11:00 +01:00
|
|
|
// OpenVPN client ("OpenVPNClient" class) intended to be wrapped by swig
|
|
|
|
// for a target language.
|
2012-02-11 15:02:51 +01:00
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
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
|
|
|
|
#error no public interface export defined for this compiler
|
|
|
|
#endif
|
2012-02-11 15:02:51 +01:00
|
|
|
|
|
|
|
// debug settings
|
|
|
|
|
|
|
|
#define OPENVPN_DEBUG
|
2012-03-12 13:42:02 +01:00
|
|
|
//#define OPENVPN_ENABLE_ASSERT
|
2012-03-11 05:59:51 +01:00
|
|
|
//#define OPENVPN_SSL_DEBUG
|
2012-02-27 09:16:27 +01:00
|
|
|
//#define OPENVPN_DEBUG_CLIPROTO
|
2012-02-11 15:02:51 +01:00
|
|
|
//#define OPENVPN_FORCE_TUN_NULL
|
|
|
|
//#define OPENVPN_DEBUG_PROTO
|
|
|
|
#define OPENVPN_DEBUG_TUN 2
|
|
|
|
#define OPENVPN_DEBUG_UDPLINK 2
|
|
|
|
#define OPENVPN_DEBUG_TCPLINK 2
|
|
|
|
//#define OPENVPN_DEBUG_COMPRESS
|
|
|
|
//#define OPENVPN_DEBUG_PACKET_ID
|
|
|
|
//#define OPENVPN_PACKET_LOG "pkt.log"
|
|
|
|
|
|
|
|
// log thread settings
|
2012-03-01 09:11:00 +01:00
|
|
|
#define OPENVPN_LOG_CLASS openvpn::ClientAPI::OpenVPNClient
|
2012-02-11 15:02:51 +01:00
|
|
|
#define OPENVPN_LOG_INFO openvpn::ClientAPI::LogInfo
|
|
|
|
|
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>
|
2012-07-01 17:37:46 +02:00
|
|
|
#if (defined(OPENVPN_PLATFORM_ANDROID) || defined(OPENVPN_PLATFORM_IPHONE)) && !defined(OPENVPN_FORCE_TUN_NULL)
|
2012-02-19 20:06:44 +01:00
|
|
|
#define USE_TUN_BUILDER
|
|
|
|
#endif
|
|
|
|
|
2012-02-20 04:27:20 +01:00
|
|
|
#include <openvpn/log/logthread.hpp> // should be included early
|
2012-02-11 15:02:51 +01:00
|
|
|
|
|
|
|
#include <openvpn/init/initprocess.hpp>
|
|
|
|
#include <openvpn/common/types.hpp>
|
|
|
|
#include <openvpn/common/scoped_ptr.hpp>
|
|
|
|
#include <openvpn/client/cliconnect.hpp>
|
2012-03-06 07:06:54 +01:00
|
|
|
#include <openvpn/options/cliopthelper.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:
|
|
|
|
typedef boost::intrusive_ptr<MySessionStats> Ptr;
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
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()
|
|
|
|
{
|
|
|
|
parent = NULL;
|
|
|
|
}
|
|
|
|
|
2012-02-13 00:09:28 +01:00
|
|
|
virtual void error(const size_t err, const std::string* text=NULL)
|
2012-02-11 15:02:51 +01:00
|
|
|
{
|
|
|
|
if (err < Error::N_ERRORS)
|
|
|
|
++errors[err];
|
|
|
|
}
|
|
|
|
|
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:
|
|
|
|
typedef boost::intrusive_ptr<MyClientEvents> Ptr;
|
|
|
|
|
2012-03-01 09:11:00 +01:00
|
|
|
MyClientEvents(OpenVPNClient* parent_arg) : parent(parent_arg) {}
|
2012-02-11 15:02:51 +01:00
|
|
|
|
|
|
|
virtual void add_event(const ClientEvent::Base::Ptr& event)
|
|
|
|
{
|
2012-02-19 18:43:42 +01:00
|
|
|
if (parent)
|
|
|
|
{
|
|
|
|
Event ev;
|
|
|
|
ev.name = event->name();
|
|
|
|
ev.info = event->render();
|
|
|
|
ev.error = event->is_error();
|
2012-07-02 22:52:58 +02:00
|
|
|
|
|
|
|
// save connected event
|
|
|
|
if (event->id() == ClientEvent::CONNECTED)
|
|
|
|
last_connected = event;
|
|
|
|
|
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;
|
|
|
|
ci.vpnIp = c->vpn_ip;
|
|
|
|
ci.tunName = c->tun_name;
|
|
|
|
ci.defined = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ci.defined = false;
|
|
|
|
}
|
|
|
|
|
2012-02-19 18:43:42 +01:00
|
|
|
void detach_from_parent()
|
|
|
|
{
|
|
|
|
parent = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
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:
|
|
|
|
MySocketProtect() : parent(NULL) {}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool socket_protect(int socket)
|
|
|
|
{
|
|
|
|
if (parent)
|
|
|
|
return parent->socket_protect(socket);
|
|
|
|
else
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void detach_from_parent()
|
|
|
|
{
|
|
|
|
parent = NULL;
|
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
|
|
|
};
|
|
|
|
|
|
|
|
namespace Private {
|
|
|
|
struct ClientState
|
|
|
|
{
|
2012-03-07 12:21:09 +01:00
|
|
|
ClientState() : conn_timeout(0) {}
|
|
|
|
|
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-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;
|
2012-03-03 12:09:05 +01:00
|
|
|
|
|
|
|
// extra settings submitted by API client
|
|
|
|
std::string server_override;
|
|
|
|
Protocol proto_override;
|
2012-03-07 12:21:09 +01:00
|
|
|
int conn_timeout;
|
2012-03-06 07:06:54 +01:00
|
|
|
std::string external_pki_alias;
|
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
|
|
|
}
|
|
|
|
|
|
|
|
OPENVPN_CLIENT_EXPORT OpenVPNClient::OpenVPNClient()
|
|
|
|
{
|
2012-02-11 15:02:51 +01:00
|
|
|
state = new Private::ClientState();
|
|
|
|
}
|
|
|
|
|
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())
|
|
|
|
Protocol::parse(config.protoOverride);
|
|
|
|
|
2012-02-11 15:02:51 +01:00
|
|
|
// parse config
|
2012-07-02 22:52:58 +02:00
|
|
|
const ParseClientConfig cc = ParseClientConfig::parse(config.content, options);
|
|
|
|
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();
|
|
|
|
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;
|
|
|
|
eval.message = e.what();
|
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;
|
2012-03-07 12:21:09 +01:00
|
|
|
state->conn_timeout = config.connTimeout;
|
2012-03-03 12:09:05 +01:00
|
|
|
if (!config.protoOverride.empty())
|
|
|
|
state->proto_override = Protocol::parse(config.protoOverride);
|
2012-03-06 07:06:54 +01:00
|
|
|
if (eval.externalPki)
|
|
|
|
state->external_pki_alias = config.externalPkiAlias;
|
2012-03-03 12:09:05 +01:00
|
|
|
}
|
|
|
|
catch (const std::exception& e)
|
|
|
|
{
|
|
|
|
eval.error = true;
|
|
|
|
eval.message = e.what();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
cc->set_dynamic_challenge_cookie(creds.dynamicChallengeCookie);
|
|
|
|
cc->set_replace_password_with_session_id(creds.replacePasswordWithSessionID);
|
|
|
|
state->creds = cc;
|
|
|
|
}
|
|
|
|
catch (const std::exception& e)
|
|
|
|
{
|
|
|
|
ret.error = true;
|
|
|
|
ret.message = e.what();
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2012-03-01 23:50:57 +01:00
|
|
|
|
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();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
catch (const std::exception&)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2012-02-11 15:02:51 +01:00
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT Status OpenVPNClient::connect()
|
2012-02-11 15:02:51 +01:00
|
|
|
{
|
|
|
|
boost::asio::detail::signal_blocker signal_blocker; // signals should be handled by parent thread
|
|
|
|
Log::Context log_context(this);
|
|
|
|
Status ret;
|
|
|
|
bool in_run = false;
|
|
|
|
ScopedPtr<boost::asio::io_service> io_service;
|
|
|
|
|
|
|
|
try {
|
|
|
|
// client stats
|
|
|
|
state->stats.reset(new MySessionStats(this));
|
|
|
|
|
|
|
|
// client events
|
|
|
|
state->events.reset(new MyClientEvents(this));
|
|
|
|
|
2012-02-19 18:43:42 +01:00
|
|
|
// socket protect
|
|
|
|
state->socket_protect.set_parent(this);
|
|
|
|
|
2012-02-11 15:02:51 +01:00
|
|
|
// load options
|
2012-02-20 04:27:20 +01:00
|
|
|
ClientOptions::Config cc;
|
|
|
|
cc.cli_stats = state->stats;
|
|
|
|
cc.cli_events = state->events;
|
2012-03-03 12:09:05 +01:00
|
|
|
cc.server_override = state->server_override;
|
|
|
|
cc.proto_override = state->proto_override;
|
2012-03-07 12:21:09 +01:00
|
|
|
cc.conn_timeout = state->conn_timeout;
|
2012-02-19 20:06:44 +01:00
|
|
|
#if defined(USE_TUN_BUILDER)
|
2012-02-25 08:37:31 +01:00
|
|
|
cc.socket_protect = &state->socket_protect;
|
2012-02-20 04:27:20 +01:00
|
|
|
cc.builder = this;
|
2012-02-19 20:06:44 +01:00
|
|
|
#endif
|
2012-03-06 07:06:54 +01:00
|
|
|
|
|
|
|
// external PKI
|
2012-05-23 15:50:41 +02:00
|
|
|
#if !defined(USE_APPLE_SSL)
|
2012-03-06 07:06:54 +01:00
|
|
|
if (state->eval.externalPki)
|
|
|
|
{
|
|
|
|
if (!state->external_pki_alias.empty())
|
|
|
|
{
|
|
|
|
ExternalPKICertRequest req;
|
|
|
|
req.alias = state->external_pki_alias;
|
|
|
|
external_pki_cert_request(req);
|
|
|
|
if (!req.error)
|
|
|
|
{
|
|
|
|
Option o;
|
|
|
|
o.push_back("cert");
|
|
|
|
o.push_back(req.cert);
|
|
|
|
state->options.add_item(o);
|
|
|
|
cc.external_pki = this;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-03-07 12:21:09 +01:00
|
|
|
external_pki_error(req, Error::EPKI_CERT_ERROR);
|
2012-03-06 07:06:54 +01:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ret.error = true;
|
|
|
|
ret.message = "Missing External PKI alias";
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
2012-05-23 15:50:41 +02:00
|
|
|
#endif
|
2012-03-06 07:06:54 +01:00
|
|
|
|
|
|
|
// build client options object
|
2012-02-20 04:27:20 +01:00
|
|
|
ClientOptions::Ptr client_options = new ClientOptions(state->options, cc);
|
2012-02-11 15:02:51 +01:00
|
|
|
|
2012-02-15 15:45:55 +01:00
|
|
|
// configure creds in options
|
2012-02-28 00:00:29 +01:00
|
|
|
client_options->submit_creds(state->creds);
|
2012-02-11 15:02:51 +01:00
|
|
|
|
|
|
|
// initialize the Asio io_service object
|
|
|
|
io_service.reset(new boost::asio::io_service(1)); // concurrency hint=1
|
|
|
|
|
|
|
|
// instantiate top-level client session
|
|
|
|
state->session.reset(new ClientConnect(*io_service, client_options));
|
|
|
|
|
2012-03-10 05:55:32 +01:00
|
|
|
// raise an exception if app has expired
|
|
|
|
check_app_expired();
|
|
|
|
|
2012-02-11 15:02:51 +01:00
|
|
|
// start VPN
|
|
|
|
state->session->start(); // queue parallel async reads
|
|
|
|
|
|
|
|
// run i/o reactor
|
|
|
|
in_run = true;
|
|
|
|
io_service->run();
|
|
|
|
}
|
2012-02-17 20:28:44 +01:00
|
|
|
catch (const std::exception& e)
|
2012-02-11 15:02:51 +01:00
|
|
|
{
|
|
|
|
if (in_run)
|
|
|
|
{
|
|
|
|
state->session->stop(); // On exception, stop client...
|
|
|
|
io_service->poll(); // and execute completion handlers.
|
|
|
|
}
|
|
|
|
ret.error = true;
|
|
|
|
ret.message = e.what();
|
|
|
|
}
|
2012-02-19 18:43:42 +01:00
|
|
|
state->socket_protect.detach_from_parent();
|
|
|
|
state->stats->detach_from_parent();
|
|
|
|
state->events->detach_from_parent();
|
2012-02-11 15:02:51 +01:00
|
|
|
state->session.reset();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-07-02 22:52:58 +02:00
|
|
|
OPENVPN_CLIENT_EXPORT ConnectionInfo OpenVPNClient::connection_info()
|
|
|
|
{
|
|
|
|
ConnectionInfo ci;
|
|
|
|
MyClientEvents::Ptr events = state->events;
|
|
|
|
if (events)
|
|
|
|
events->get_connection_info(ci);
|
|
|
|
return ci;
|
|
|
|
}
|
|
|
|
|
2012-08-21 23:32:51 +02:00
|
|
|
OPENVPN_CLIENT_EXPORT bool OpenVPNClient::session_token(SessionToken& tok)
|
|
|
|
{
|
|
|
|
ClientCreds::Ptr cc = state->creds;
|
|
|
|
if (cc && cc->session_id_defined())
|
|
|
|
{
|
|
|
|
tok.username = cc->get_username();
|
|
|
|
tok.session_id = cc->get_password();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
state->events->add_event(ev);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ClientEvent::Base::Ptr ev = new ClientEvent::EpkiError(req.errorText);
|
|
|
|
state->events->add_event(ev);
|
|
|
|
}
|
2012-03-07 12:21:09 +01:00
|
|
|
state->stats->error(err_type);
|
2012-03-06 07:06:54 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT bool OpenVPNClient::sign(const std::string& data, std::string& sig)
|
2012-03-06 07:06:54 +01:00
|
|
|
{
|
|
|
|
ExternalPKISignRequest req;
|
|
|
|
req.data = data;
|
|
|
|
req.alias = state->external_pki_alias;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT int OpenVPNClient::stats_n()
|
2012-02-13 00:09:28 +01:00
|
|
|
{
|
|
|
|
return MySessionStats::combined_n();
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
|
|
|
MySessionStats::Ptr stats = state->stats;
|
|
|
|
if (stats)
|
2012-02-13 00:09:28 +01:00
|
|
|
return stats->combined_value(index);
|
|
|
|
else
|
|
|
|
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;
|
|
|
|
MySessionStats::Ptr stats = state->stats;
|
|
|
|
const size_t n = MySessionStats::combined_n();
|
|
|
|
sv.reserve(n);
|
|
|
|
for (size_t i = 0; i < n; ++i)
|
|
|
|
sv.push_back(stats ? stats->combined_value(i) : 0);
|
|
|
|
return sv;
|
|
|
|
}
|
|
|
|
|
2012-07-01 17:37:46 +02:00
|
|
|
OPENVPN_CLIENT_EXPORT InterfaceStats OpenVPNClient::tun_stats() const
|
|
|
|
{
|
|
|
|
MySessionStats::Ptr stats = state->stats;
|
|
|
|
InterfaceStats ret;
|
|
|
|
|
|
|
|
// 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.
|
2012-07-02 22:52:58 +02:00
|
|
|
if (stats)
|
|
|
|
{
|
|
|
|
ret.bytes_out = stats->stat_count(SessionStats::TUN_BYTES_IN);
|
|
|
|
ret.bytes_in = stats->stat_count(SessionStats::TUN_BYTES_OUT);
|
|
|
|
ret.packets_out = stats->stat_count(SessionStats::TUN_PACKETS_IN);
|
|
|
|
ret.packets_in = stats->stat_count(SessionStats::TUN_PACKETS_OUT);
|
|
|
|
ret.errors_out = stats->error_count(Error::TUN_READ_ERROR);
|
|
|
|
ret.errors_in = stats->error_count(Error::TUN_WRITE_ERROR);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ret.bytes_out = 0;
|
|
|
|
ret.bytes_in = 0;
|
|
|
|
ret.packets_out = 0;
|
|
|
|
ret.packets_in = 0;
|
|
|
|
ret.errors_out = 0;
|
|
|
|
ret.errors_in = 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
|
|
|
|
{
|
|
|
|
MySessionStats::Ptr stats = state->stats;
|
|
|
|
TransportStats ret;
|
|
|
|
|
|
|
|
if (stats)
|
|
|
|
{
|
|
|
|
ret.bytes_out = stats->stat_count(SessionStats::BYTES_OUT);
|
|
|
|
ret.bytes_in = stats->stat_count(SessionStats::BYTES_IN);
|
|
|
|
ret.packets_out = stats->stat_count(SessionStats::PACKETS_OUT);
|
|
|
|
ret.packets_in = stats->stat_count(SessionStats::PACKETS_IN);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ret.bytes_out = 0;
|
|
|
|
ret.bytes_in = 0;
|
|
|
|
ret.packets_out = 0;
|
|
|
|
ret.packets_in = 0;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::stop()
|
2012-02-11 15:02:51 +01:00
|
|
|
{
|
|
|
|
ClientConnect::Ptr session = state->session;
|
|
|
|
if (session)
|
|
|
|
session->thread_safe_stop();
|
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::pause()
|
2012-02-27 06:11:22 +01:00
|
|
|
{
|
|
|
|
ClientConnect::Ptr session = state->session;
|
|
|
|
if (session)
|
|
|
|
session->thread_safe_pause();
|
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::resume()
|
2012-02-27 06:11:22 +01:00
|
|
|
{
|
|
|
|
ClientConnect::Ptr session = state->session;
|
|
|
|
if (session)
|
|
|
|
session->thread_safe_resume();
|
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT void OpenVPNClient::reconnect(int seconds)
|
2012-02-27 06:11:22 +01:00
|
|
|
{
|
|
|
|
ClientConnect::Ptr session = state->session;
|
|
|
|
if (session)
|
|
|
|
session->thread_safe_reconnect(seconds);
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-03-24 21:22:24 +01:00
|
|
|
OPENVPN_CLIENT_EXPORT OpenVPNClient::~OpenVPNClient()
|
2012-02-11 15:02:51 +01:00
|
|
|
{
|
|
|
|
delete state;
|
|
|
|
}
|
2012-03-24 21:22:24 +01:00
|
|
|
|
2012-02-11 15:02:51 +01:00
|
|
|
}
|
|
|
|
}
|