2012-02-14 18:47:01 +01:00
|
|
|
// OpenVPN client ("OpenVPNClientBase" class) intended for wrapping as a Java class using swig
|
2012-02-11 15:02:51 +01:00
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
#include "ovpncli.hpp" // objects that we bridge with java
|
|
|
|
|
|
|
|
// debug settings
|
|
|
|
|
|
|
|
#define OPENVPN_DEBUG
|
|
|
|
//#define OPENVPN_DEBUG_CLIPROTO
|
|
|
|
//#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-02-14 18:47:01 +01:00
|
|
|
#define OPENVPN_LOG_CLASS openvpn::ClientAPI::OpenVPNClientBase
|
2012-02-11 15:02:51 +01:00
|
|
|
#define OPENVPN_LOG_INFO openvpn::ClientAPI::LogInfo
|
|
|
|
|
2012-02-19 20:06:44 +01:00
|
|
|
// on Android, use TunBuilderBase abstraction
|
2012-02-20 04:27:20 +01:00
|
|
|
#include <openvpn/common/platform.hpp>
|
2012-02-19 20:06:44 +01:00
|
|
|
#if defined(OPENVPN_PLATFORM_ANDROID) && !defined(OPENVPN_FORCE_TUN_NULL)
|
|
|
|
#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>
|
|
|
|
|
|
|
|
namespace openvpn {
|
|
|
|
namespace ClientAPI {
|
|
|
|
|
|
|
|
class MySessionStats : public SessionStats
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
typedef boost::intrusive_ptr<MySessionStats> Ptr;
|
|
|
|
|
2012-02-14 18:47:01 +01:00
|
|
|
MySessionStats(OpenVPNClientBase* 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-02-19 18:43:42 +01:00
|
|
|
void detach_from_parent()
|
|
|
|
{
|
|
|
|
parent = NULL;
|
|
|
|
}
|
|
|
|
|
2012-02-13 00:09:28 +01:00
|
|
|
private:
|
|
|
|
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-02-14 18:47:01 +01:00
|
|
|
OpenVPNClientBase* 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-02-14 18:47:01 +01:00
|
|
|
MyClientEvents(OpenVPNClientBase* 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();
|
|
|
|
parent->event(ev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void detach_from_parent()
|
|
|
|
{
|
|
|
|
parent = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
OpenVPNClientBase* parent;
|
|
|
|
};
|
|
|
|
|
|
|
|
class MySocketProtect : public SocketProtect
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
MySocketProtect() : parent(NULL) {}
|
|
|
|
|
|
|
|
void set_parent(OpenVPNClientBase* parent_arg)
|
|
|
|
{
|
|
|
|
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-02-14 18:47:01 +01:00
|
|
|
OpenVPNClientBase* parent;
|
2012-02-11 15:02:51 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
namespace Private {
|
|
|
|
struct ClientState
|
|
|
|
{
|
|
|
|
OptionList options;
|
2012-02-15 15:45:55 +01:00
|
|
|
ProvideCreds creds;
|
2012-02-19 18:43:42 +01:00
|
|
|
MySocketProtect socket_protect;
|
2012-02-11 15:02:51 +01:00
|
|
|
MySessionStats::Ptr stats;
|
|
|
|
MyClientEvents::Ptr events;
|
|
|
|
ClientConnect::Ptr session;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2012-02-14 18:47:01 +01:00
|
|
|
inline OpenVPNClientBase::OpenVPNClientBase()
|
2012-02-11 15:02:51 +01:00
|
|
|
{
|
|
|
|
InitProcess::init();
|
|
|
|
state = new Private::ClientState();
|
|
|
|
}
|
|
|
|
|
2012-02-15 15:45:55 +01:00
|
|
|
inline void OpenVPNClientBase::parse_config(const Config& config, EvalConfig& eval, OptionList& options)
|
2012-02-11 15:02:51 +01:00
|
|
|
{
|
|
|
|
try {
|
|
|
|
// parse config
|
2012-02-15 15:45:55 +01:00
|
|
|
options.parse_from_config(config.content);
|
|
|
|
options.update_map();
|
2012-02-11 15:02:51 +01:00
|
|
|
|
|
|
|
// fill out RequestCreds struct
|
|
|
|
{
|
2012-02-15 15:45:55 +01:00
|
|
|
const Option *o = options.get_ptr("auth-user-pass");
|
|
|
|
eval.autologin = !o;
|
2012-02-11 15:02:51 +01:00
|
|
|
}
|
|
|
|
{
|
2012-02-15 15:45:55 +01:00
|
|
|
const Option *o = options.get_ptr("static-challenge");
|
2012-02-11 15:02:51 +01:00
|
|
|
if (o)
|
|
|
|
{
|
2012-02-15 15:45:55 +01:00
|
|
|
eval.staticChallenge = o->get(1);
|
2012-02-11 15:02:51 +01:00
|
|
|
if (o->get(2) == "1")
|
2012-02-15 15:45:55 +01:00
|
|
|
eval.staticChallengeEcho = true;
|
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-02-15 15:45:55 +01:00
|
|
|
EvalConfig OpenVPNClientBase::eval_config_static(const Config& config)
|
|
|
|
{
|
|
|
|
EvalConfig eval;
|
|
|
|
OptionList options;
|
|
|
|
parse_config(config, eval, options);
|
|
|
|
return eval;
|
|
|
|
}
|
|
|
|
|
|
|
|
EvalConfig OpenVPNClientBase::eval_config(const Config& config) const
|
|
|
|
{
|
|
|
|
EvalConfig eval;
|
|
|
|
state->options.clear();
|
|
|
|
parse_config(config, eval, state->options);
|
|
|
|
return eval;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OpenVPNClientBase::provide_creds(const ProvideCreds& creds)
|
2012-02-11 15:02:51 +01:00
|
|
|
{
|
2012-02-15 15:45:55 +01:00
|
|
|
state->creds = creds;
|
2012-02-11 15:02:51 +01:00
|
|
|
}
|
|
|
|
|
2012-02-15 15:45:55 +01:00
|
|
|
inline Status OpenVPNClientBase::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-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-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
|
|
|
|
client_options->submit_creds(state->creds.username, state->creds.password);
|
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));
|
|
|
|
|
|
|
|
// 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-02-14 18:47:01 +01:00
|
|
|
int OpenVPNClientBase::stats_n()
|
2012-02-13 00:09:28 +01:00
|
|
|
{
|
|
|
|
return MySessionStats::combined_n();
|
|
|
|
}
|
|
|
|
|
2012-02-14 18:47:01 +01:00
|
|
|
std::string OpenVPNClientBase::stats_name(int index)
|
2012-02-13 00:09:28 +01:00
|
|
|
{
|
|
|
|
return MySessionStats::combined_name(index);
|
|
|
|
}
|
|
|
|
|
2012-02-14 18:47:01 +01:00
|
|
|
long long OpenVPNClientBase::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-02-14 18:47:01 +01:00
|
|
|
inline void OpenVPNClientBase::stop()
|
2012-02-11 15:02:51 +01:00
|
|
|
{
|
|
|
|
ClientConnect::Ptr session = state->session;
|
|
|
|
if (session)
|
|
|
|
session->thread_safe_stop();
|
|
|
|
}
|
|
|
|
|
2012-02-14 18:47:01 +01:00
|
|
|
inline OpenVPNClientBase::~OpenVPNClientBase()
|
2012-02-11 15:02:51 +01:00
|
|
|
{
|
|
|
|
delete state;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|