0
0
mirror of https://github.com/OpenVPN/openvpn3.git synced 2024-09-20 12:12:15 +02:00
openvpn3/openvpn/client/cliproto.hpp

692 lines
18 KiB
C++
Raw Normal View History

//
// cliproto.hpp
// OpenVPN
//
// Copyright (c) 2012 OpenVPN Technologies, Inc. All rights reserved.
//
#ifndef OPENVPN_CLIENT_CLIPROTO_H
#define OPENVPN_CLIENT_CLIPROTO_H
// This is a middle-layer object in the OpenVPN client protocol stack.
// It is above the general OpenVPN protocol implementation in
// ProtoContext<RAND_API, CRYPTO_API, SSL_API> but below the top
// level object in a client connect (ClientConnect). See ClientConnect for
// a fuller description of the full client stack.
//
// This layer deals with setting up an OpenVPN client connection:
//
// 1. handles creation of transport-layer handler via TransportClientFactory
// 2. handles creation of tun-layer handler via TunClientFactory
// 3. handles sending PUSH_REQUEST to server and processing reply of server-pushed options
// 4. manages the underlying OpenVPN protocol object (ProtoContext<RAND_API, CRYPTO_API, SSL_API>)
// 5. handles timers on behalf of the underlying OpenVPN protocol object
// 6. acts as an exception dispatcher for errors occuring in any of the underlying layers
#include <string>
#include <vector>
#include <boost/asio.hpp>
#include <boost/cstdint.hpp> // for boost::uint...
2012-02-15 19:19:34 +01:00
#include <boost/algorithm/string.hpp> // for boost::algorithm::starts_with and trim_left_copy
#include <openvpn/common/rc.hpp>
#include <openvpn/tun/client/tunbase.hpp>
#include <openvpn/transport/client/transbase.hpp>
#include <openvpn/options/continuation.hpp>
#include <openvpn/options/sanitize.hpp>
#include <openvpn/client/clievent.hpp>
#include <openvpn/client/clicreds.hpp>
#include <openvpn/client/cliconstants.hpp>
Fixed a race condition issue with "hot connect", i.e. sending a connect intent to service when already connected. One of the ramifications of the "hot connect" fix above is that OpenVPNClientBase.is_active() will now return a value that is instantaneously up-to-date, whereas events might lag because of the mechanics of inter-thread message posting. Keep this in mind when correlating received events to is_active() values. For C++ core threads, increased allowed thread-stop delay to 2.5 seconds before thread is marked as unresponsive and abandoned. Previous delay was 1 second. This delay can't be made too long, otherwise Android will tell the user that the app is unresponsive and invite them to kill it. When closing out an abandoned core thread, indicate this condition with a new event type called CORE_THREAD_ABANDONED. If the thread is abandoned due to lack of response to a disconnect request, then the CORE_THREAD_ABANDONED event will occur followed by CORE_THREAD_INACTIVE. For core threads that properly exit, the DISCONNECTED event will be followed by CORE_THREAD_INACTIVE. Added save_as_filename parameter to importProfileRemote method for controlling the filename that the imported profile is saved as. This parameter may be set to null to have the method choose an appropriate name. To have an imported profile replace an existing profile, the filenames much match. Added UI_OVERLOADED debugging constant to OpenVPNClient to allow the UI to connect to a profile when already connected to another profile in order to test "hot connect". Added new events CLIENT_HALT and CLIENT_RESTART for compatibility with an Access Server feature that allows the server to remotely kill or restart the client. When connecting a profile, the core will now automatically fill in the username if it is not specified for userlocked profiles. Version 0.902.
2012-03-31 18:08:20 +02:00
#include <openvpn/options/clihalt.hpp>
#include <openvpn/time/asiotimer.hpp>
#include <openvpn/time/coarsetime.hpp>
2012-11-14 17:41:33 +01:00
#include <openvpn/error/excode.hpp>
#include <openvpn/ssl/proto.hpp>
#ifdef OPENVPN_DEBUG_CLIPROTO
#define OPENVPN_LOG_CLIPROTO(x) OPENVPN_LOG(x)
#else
#define OPENVPN_LOG_CLIPROTO(x)
#endif
namespace openvpn {
namespace ClientProto {
struct NotifyCallback {
virtual void client_proto_terminate() = 0;
virtual void client_proto_connected() {}
};
template <typename RAND_API, typename CRYPTO_API, typename SSL_API>
class Session : public ProtoContext<RAND_API, CRYPTO_API, SSL_API>, TransportClientParent, TunClientParent
{
typedef ProtoContext<RAND_API, CRYPTO_API, SSL_API> Base;
typedef typename Base::PacketType PacketType;
using Base::now;
using Base::stat;
public:
typedef boost::intrusive_ptr<Session> Ptr;
typedef typename Base::Config ProtoConfig;
OPENVPN_EXCEPTION(client_exception);
Fixed a race condition issue with "hot connect", i.e. sending a connect intent to service when already connected. One of the ramifications of the "hot connect" fix above is that OpenVPNClientBase.is_active() will now return a value that is instantaneously up-to-date, whereas events might lag because of the mechanics of inter-thread message posting. Keep this in mind when correlating received events to is_active() values. For C++ core threads, increased allowed thread-stop delay to 2.5 seconds before thread is marked as unresponsive and abandoned. Previous delay was 1 second. This delay can't be made too long, otherwise Android will tell the user that the app is unresponsive and invite them to kill it. When closing out an abandoned core thread, indicate this condition with a new event type called CORE_THREAD_ABANDONED. If the thread is abandoned due to lack of response to a disconnect request, then the CORE_THREAD_ABANDONED event will occur followed by CORE_THREAD_INACTIVE. For core threads that properly exit, the DISCONNECTED event will be followed by CORE_THREAD_INACTIVE. Added save_as_filename parameter to importProfileRemote method for controlling the filename that the imported profile is saved as. This parameter may be set to null to have the method choose an appropriate name. To have an imported profile replace an existing profile, the filenames much match. Added UI_OVERLOADED debugging constant to OpenVPNClient to allow the UI to connect to a profile when already connected to another profile in order to test "hot connect". Added new events CLIENT_HALT and CLIENT_RESTART for compatibility with an Access Server feature that allows the server to remotely kill or restart the client. When connecting a profile, the core will now automatically fill in the username if it is not specified for userlocked profiles. Version 0.902.
2012-03-31 18:08:20 +02:00
OPENVPN_EXCEPTION(client_halt_restart);
OPENVPN_EXCEPTION(tun_exception);
OPENVPN_EXCEPTION(transport_exception);
OPENVPN_EXCEPTION(max_pushed_options_exceeded);
OPENVPN_SIMPLE_EXCEPTION(session_invalidated);
OPENVPN_SIMPLE_EXCEPTION(authentication_failed);
OPENVPN_EXCEPTION(proxy_exception);
struct Config : public RC<thread_unsafe_refcount>
{
typedef boost::intrusive_ptr<Config> Ptr;
Config()
: pushed_options_limit("server-pushed options data too large",
ProfileParseLimits::MAX_PUSH_SIZE,
ProfileParseLimits::OPT_OVERHEAD,
ProfileParseLimits::TERM_OVERHEAD,
2012-11-14 03:35:50 +01:00
0,
ProfileParseLimits::MAX_DIRECTIVE_SIZE)
{}
iOS version: 1.0 Beta 17 Android version: 1.1 beta 1 More alignment of iOS and Android clients: * Normalized building of dependencies for Android and iOS: This build adds some new library dependencies: The library versions required are enumerated in ovpn3/lib-versions, currently: export BOOST_VERSION=boost_1_51_0 export OPENSSL_VERSION=openssl-1.0.1c export POLARSSL_VERSION=polarssl-1.1.4 export LZO_VERSION=lzo-2.06 To build, first mkdir ~/src/android and ~/src/mac if they don't already exist. Set the env var O3 to point to the ovpn3 dir, usually ~/src/ovpn3. Build on iOS: [set PATH to include NDK] cd ~/src/android $O3/scripts/android/build-boost $O3/scripts/android/build-minicrypto $O3/scripts/android/build-polarssl $O3/scripts/android/build-lzo Build on Android: [set PATH to include NDK] cd ~/src/android $O3/scripts/android/build-boost $O3/scripts/android/build-minicrypto $O3/scripts/android/build-polarssl $O3/scripts/android/build-lzo * Integrated Minicrypto library (an assembly language library of low-level crypto functions adapted from OpenSSL). * Added LZO compression with a preference/settings item to enable or disable. * Added special compression handling to support older servers that ignore compression handshake -- this will handle receiving compressed packets even if we didn't ask for them. * Normalized profile naming conventions. iOS changes: * Log tunnel performance stats immediately on disconnection of tunnel. Android changes: * Client now supports loading profiles as attachments opened from other apps. * Added Import Private Tunnel menu item, however current Private Tunnel download page needs to be adapted to fit requirements of Android download manager. * Enter key should advance to the next input field, or connect if entered from the last field. * Import from Access Server now provides the option to download autologin vs. userlogin profiles. * "About" page now shows copyright text for included libraries/content (except for LZO and PolarSSL which will presumably be commercially licensed).
2012-09-05 03:09:34 +02:00
typename ProtoConfig::Ptr proto_context_config;
ProtoContextOptions::Ptr proto_context_options;
PushOptionsBase::Ptr push_base;
TransportClientFactory::Ptr transport_factory;
TunClientFactory::Ptr tun_factory;
SessionStats::Ptr cli_stats;
ClientEvent::Queue::Ptr cli_events;
ClientCreds::Ptr creds;
OptionList::Limits pushed_options_limit;
};
Session(boost::asio::io_service& io_service_arg,
const Config& config,
NotifyCallback* notify_callback_arg)
: Base(config.proto_context_config, config.cli_stats),
io_service(io_service_arg),
transport_factory(config.transport_factory),
tun_factory(config.tun_factory),
notify_callback(notify_callback_arg),
housekeeping_timer(io_service_arg),
push_request_timer(io_service_arg),
halt(false),
received_options(config.push_base),
creds(config.creds),
proto_context_options(config.proto_context_options),
first_packet_received_(false),
sent_push_request(false),
cli_stats(config.cli_stats),
cli_events(config.cli_events),
connected_(false),
fatal_(Error::UNDEF),
pushed_options_limit(config.pushed_options_limit)
{
#ifdef OPENVPN_PACKET_LOG
packet_log.open(OPENVPN_PACKET_LOG, std::ios::binary);
if (!packet_log)
OPENVPN_THROW(open_file_error, "cannot open packet log for output: " << OPENVPN_PACKET_LOG);
#endif
Base::update_now();
Base::reset();
//Base::enable_strict_openvpn_2x();
}
bool first_packet_received() const { return first_packet_received_; }
void start()
{
if (!halt)
{
Base::update_now();
// coarse wakeup range
housekeeping_schedule.init(Time::Duration::binary_ms(512), Time::Duration::binary_ms(1024));
// initialize transport-layer packet handler
transport = transport_factory->new_client_obj(io_service, *this);
transport->start();
}
}
2012-02-27 09:16:27 +01:00
void send_explicit_exit_notify()
{
if (!halt)
Base::send_explicit_exit_notify();
}
void stop(const bool call_terminate_callback)
{
if (!halt)
{
halt = true;
housekeeping_timer.cancel();
push_request_timer.cancel();
if (tun)
tun->stop();
if (transport)
transport->stop();
if (notify_callback && call_terminate_callback)
notify_callback->client_proto_terminate();
}
}
void stop_on_signal(const boost::system::error_code& error, int signal_number)
{
stop(true);
}
bool reached_connected_state() const { return connected_; }
// Fatal error means that we shouldn't retry.
// Returns a value != Error::UNDEF if error
Error::Type fatal() const { return fatal_; }
const std::string& fatal_reason() const { return fatal_reason_; }
2012-02-15 19:19:34 +01:00
virtual ~Session()
{
stop(false);
}
private:
// transport obj calls here with incoming packets
virtual void transport_recv(BufferAllocated& buf)
{
try {
OPENVPN_LOG_CLIPROTO("Transport RECV " << server_endpoint_render() << ' ' << Base::dump_packet(buf));
// update current time
Base::update_now();
// update last packet received
stat().update_last_packet_received(now());
// log connecting event (only on first packet received)
if (!first_packet_received_)
{
ClientEvent::Base::Ptr ev = new ClientEvent::Connecting();
cli_events->add_event(ev);
first_packet_received_ = true;
}
// get packet type
typename Base::PacketType pt = Base::packet_type(buf);
// process packet
if (tun && pt.is_data())
{
// data packet
Base::data_decrypt(pt, buf);
if (buf.size())
{
#ifdef OPENVPN_PACKET_LOG
log_packet(buf, false);
#endif
// make packet appear as incoming on tun interface
OPENVPN_LOG_CLIPROTO("TUN send, size=" << buf.size());
tun->tun_send(buf);
}
// do a lightweight flush
Base::flush(false);
}
else if (pt.is_control())
{
// control packet
Base::control_net_recv(pt, buf);
// do a full flush
Base::flush(true);
}
// schedule housekeeping wakeup
set_housekeeping_timer();
}
catch (const ExceptionCode& e)
{
if (e.code_defined())
{
if (e.fatal())
transport_error((Error::Type)e.code(), e.what());
else
cli_stats->error((Error::Type)e.code());
}
else
2012-11-14 17:41:33 +01:00
process_exception(e, "transport_recv_excode");
}
catch (const std::exception& e)
{
process_exception(e, "transport_recv");
}
}
// tun i/o driver calls here with incoming packets
virtual void tun_recv(BufferAllocated& buf)
{
try {
OPENVPN_LOG_CLIPROTO("TUN recv, size=" << buf.size());
// update current time
Base::update_now();
// encrypt packet
#ifdef OPENVPN_PACKET_LOG
log_packet(buf, true);
#endif
Base::data_encrypt(buf);
if (buf.size())
{
// send packet via transport to destination
OPENVPN_LOG_CLIPROTO("Transport SEND " << server_endpoint_render() << ' ' << Base::dump_packet(buf));
if (transport->transport_send(buf))
Base::update_last_sent();
}
// do a lightweight flush
Base::flush(false);
// schedule housekeeping wakeup
set_housekeeping_timer();
}
catch (const std::exception& e)
{
2012-07-01 17:37:46 +02:00
process_exception(e, "tun_recv");
}
}
virtual void transport_pre_resolve()
{
ClientEvent::Base::Ptr ev = new ClientEvent::Resolve();
cli_events->add_event(ev);
}
std::string server_endpoint_render()
{
std::string server_host, server_port, server_proto, server_ip;
transport->server_endpoint_info(server_host, server_port, server_proto, server_ip);
std::ostringstream out;
out << server_host << ":" << server_port << " (" << server_ip << ") via " << server_proto;
return out.str();
}
virtual void transport_wait_proxy()
{
ClientEvent::Base::Ptr ev = new ClientEvent::WaitProxy();
cli_events->add_event(ev);
}
virtual void transport_wait()
{
ClientEvent::Base::Ptr ev = new ClientEvent::Wait();
cli_events->add_event(ev);
}
virtual void transport_connecting()
{
try {
OPENVPN_LOG("Connecting to " << server_endpoint_render());
Base::start();
Base::flush(true);
set_housekeeping_timer();
}
catch (const std::exception& e)
{
2012-07-01 17:37:46 +02:00
process_exception(e, "transport_connecting");
}
}
virtual void transport_error(const Error::Type fatal_err, const std::string& err_text)
{
if (fatal_err != Error::UNDEF)
{
fatal_ = fatal_err;
fatal_reason_ = err_text;
}
if (notify_callback)
{
OPENVPN_LOG("Transport Error: " << err_text);
stop(true);
}
else
throw transport_exception(err_text);
}
virtual void proxy_error(const Error::Type fatal_err, const std::string& err_text)
{
if (fatal_err != Error::UNDEF)
{
fatal_ = fatal_err;
fatal_reason_ = err_text;
}
if (notify_callback)
{
OPENVPN_LOG("Proxy Error: " << err_text);
stop(true);
}
else
throw proxy_exception(err_text);
}
void extract_auth_token(const OptionList& opt)
{
// if auth-token is present, use it as the password for future renegotiations
const Option* o = opt.get_ptr("auth-token");
if (o)
{
2012-11-14 03:35:50 +01:00
const std::string& sess_id = o->get(1, 256);
Fixed a race condition issue with "hot connect", i.e. sending a connect intent to service when already connected. One of the ramifications of the "hot connect" fix above is that OpenVPNClientBase.is_active() will now return a value that is instantaneously up-to-date, whereas events might lag because of the mechanics of inter-thread message posting. Keep this in mind when correlating received events to is_active() values. For C++ core threads, increased allowed thread-stop delay to 2.5 seconds before thread is marked as unresponsive and abandoned. Previous delay was 1 second. This delay can't be made too long, otherwise Android will tell the user that the app is unresponsive and invite them to kill it. When closing out an abandoned core thread, indicate this condition with a new event type called CORE_THREAD_ABANDONED. If the thread is abandoned due to lack of response to a disconnect request, then the CORE_THREAD_ABANDONED event will occur followed by CORE_THREAD_INACTIVE. For core threads that properly exit, the DISCONNECTED event will be followed by CORE_THREAD_INACTIVE. Added save_as_filename parameter to importProfileRemote method for controlling the filename that the imported profile is saved as. This parameter may be set to null to have the method choose an appropriate name. To have an imported profile replace an existing profile, the filenames much match. Added UI_OVERLOADED debugging constant to OpenVPNClient to allow the UI to connect to a profile when already connected to another profile in order to test "hot connect". Added new events CLIENT_HALT and CLIENT_RESTART for compatibility with an Access Server feature that allows the server to remotely kill or restart the client. When connecting a profile, the core will now automatically fill in the username if it is not specified for userlocked profiles. Version 0.902.
2012-03-31 18:08:20 +02:00
if (creds)
creds->set_session_id(sess_id);
#ifdef OPENVPN_SHOW_SESSION_TOKEN
OPENVPN_LOG("using session token " << sess_id);
#else
OPENVPN_LOG("using session token");
#endif
}
}
// proto base class calls here for control channel network sends
virtual void control_net_send(const Buffer& net_buf)
{
OPENVPN_LOG_CLIPROTO("Transport SEND " << server_endpoint_render() << ' ' << Base::dump_packet(net_buf));
if (transport->transport_send_const(net_buf))
Base::update_last_sent();
}
// proto base class calls here for app-level control-channel messages received
virtual void control_recv(BufferPtr& app_bp)
{
2012-11-14 03:35:50 +01:00
const std::string msg = Unicode::utf8_printable(Base::template read_control_string<std::string>(*app_bp),
Unicode::UTF8_FILTER);
//OPENVPN_LOG("SERVER: " << sanitize_control_message(msg));
2012-02-15 19:19:34 +01:00
if (!received_options.complete() && boost::algorithm::starts_with(msg, "PUSH_REPLY,"))
{
// parse the received options
received_options.add(OptionList::parse_from_csv_static(msg.substr(11), &pushed_options_limit));
if (received_options.complete())
{
// show options
OPENVPN_LOG("OPTIONS:" << std::endl << render_options_sanitized(received_options));
// process auth-token
extract_auth_token(received_options);
// modify proto config (cipher, auth, and compression methods)
Base::process_push(received_options, *proto_context_options);
// initialize tun/routing
tun = tun_factory->new_client_obj(io_service, *this);
tun->client_start(received_options, *transport);
}
else
OPENVPN_LOG("Options continuation...");
}
2012-02-15 19:19:34 +01:00
else if (boost::algorithm::starts_with(msg, "AUTH_FAILED"))
{
fatal_ = Error::AUTH_FAILED;
2012-02-15 19:19:34 +01:00
if (msg.length() >= 13)
fatal_reason_ = boost::algorithm::trim_left_copy(std::string(msg, 12));
if (notify_callback)
{
OPENVPN_LOG("AUTH_FAILED");
stop(true);
}
else
throw authentication_failed();
}
Fixed a race condition issue with "hot connect", i.e. sending a connect intent to service when already connected. One of the ramifications of the "hot connect" fix above is that OpenVPNClientBase.is_active() will now return a value that is instantaneously up-to-date, whereas events might lag because of the mechanics of inter-thread message posting. Keep this in mind when correlating received events to is_active() values. For C++ core threads, increased allowed thread-stop delay to 2.5 seconds before thread is marked as unresponsive and abandoned. Previous delay was 1 second. This delay can't be made too long, otherwise Android will tell the user that the app is unresponsive and invite them to kill it. When closing out an abandoned core thread, indicate this condition with a new event type called CORE_THREAD_ABANDONED. If the thread is abandoned due to lack of response to a disconnect request, then the CORE_THREAD_ABANDONED event will occur followed by CORE_THREAD_INACTIVE. For core threads that properly exit, the DISCONNECTED event will be followed by CORE_THREAD_INACTIVE. Added save_as_filename parameter to importProfileRemote method for controlling the filename that the imported profile is saved as. This parameter may be set to null to have the method choose an appropriate name. To have an imported profile replace an existing profile, the filenames much match. Added UI_OVERLOADED debugging constant to OpenVPNClient to allow the UI to connect to a profile when already connected to another profile in order to test "hot connect". Added new events CLIENT_HALT and CLIENT_RESTART for compatibility with an Access Server feature that allows the server to remotely kill or restart the client. When connecting a profile, the core will now automatically fill in the username if it is not specified for userlocked profiles. Version 0.902.
2012-03-31 18:08:20 +02:00
else if (ClientHalt::match(msg))
{
const ClientHalt ch(msg);
process_halt_restart(ch);
}
}
virtual void tun_pre_tun_config()
{
ClientEvent::Base::Ptr ev = new ClientEvent::AssignIP();
cli_events->add_event(ev);
}
virtual void tun_pre_route_config()
{
ClientEvent::Base::Ptr ev = new ClientEvent::AddRoutes();
cli_events->add_event(ev);
}
virtual void tun_connected()
{
OPENVPN_LOG("Connected via " + tun->tun_name());
ClientEvent::Connected::Ptr ev = new ClientEvent::Connected();
if (creds)
ev->user = creds->get_username();
transport->server_endpoint_info(ev->server_host, ev->server_port, ev->server_proto, ev->server_ip);
ev->vpn_ip4 = tun->vpn_ip4();
ev->vpn_ip6 = tun->vpn_ip6();
try {
2012-11-14 03:35:50 +01:00
std::string client_ip = received_options.get_optional("client-ip", 1, 256);
if (!client_ip.empty())
ev->client_ip = IP::Addr::validate(client_ip, "client-ip");
}
catch (const std::exception& e)
{
OPENVPN_LOG("Error parsing client-ip: " << e.what());
}
ev->tun_name = tun->tun_name();
cli_events->add_event(ev);
connected_ = true;
if (notify_callback)
notify_callback->client_proto_connected();
}
virtual void tun_error(const Error::Type fatal_err, const std::string& err_text)
{
if (fatal_err != Error::UNDEF)
{
fatal_ = fatal_err;
fatal_reason_ = err_text;
}
if (notify_callback)
{
OPENVPN_LOG("TUN Error: " << err_text);
stop(true);
}
else
throw tun_exception(err_text);
}
// proto base class calls here to get auth credentials
virtual void client_auth(Buffer& buf)
{
if (creds)
{
Base::write_auth_string(creds->get_username(), buf);
Base::write_auth_string(creds->get_password(), buf);
}
else
{
Base::write_empty_string(buf); // username
Base::write_empty_string(buf); // password
}
}
void send_push_request_callback(const boost::system::error_code& e)
{
try {
if (!e && !halt && !received_options.partial())
{
Base::update_now();
if (!sent_push_request)
{
ClientEvent::Base::Ptr ev = new ClientEvent::GetConfig();
cli_events->add_event(ev);
sent_push_request = true;
}
OPENVPN_LOG("Sending PUSH_REQUEST to server...");
Base::write_control_string(std::string("PUSH_REQUEST"));
Base::flush(true);
set_housekeeping_timer();
schedule_push_request_callback(false);
}
}
catch (const std::exception& e)
{
2012-07-01 17:37:46 +02:00
process_exception(e, "send_push_request_callback");
}
}
void schedule_push_request_callback(bool short_time)
{
if (!received_options.partial())
{
push_request_timer.expires_at(now() + (short_time ? Time::Duration::seconds(1) : Time::Duration::seconds(3)));
push_request_timer.async_wait(asio_dispatch_timer(&Session::send_push_request_callback, this));
}
}
// base class calls here when primary session transitions to ACTIVE state
virtual void active()
{
OPENVPN_LOG("Session is ACTIVE");
schedule_push_request_callback(true);
}
void housekeeping_callback(const boost::system::error_code& e)
{
try {
if (!e && !halt)
{
// update current time
Base::update_now();
housekeeping_schedule.reset();
Base::housekeeping();
if (Base::invalidated())
{
if (notify_callback)
{
OPENVPN_LOG("Session invalidated");
stop(true);
}
else
throw session_invalidated();
}
set_housekeeping_timer();
}
}
catch (const std::exception& e)
{
2012-07-01 17:37:46 +02:00
process_exception(e, "housekeeping_callback");
}
}
void set_housekeeping_timer()
{
Time next = Base::next_housekeeping();
if (!housekeeping_schedule.similar(next))
{
if (!next.is_infinite())
{
next.max(now());
housekeeping_schedule.reset(next);
housekeeping_timer.expires_at(next);
housekeeping_timer.async_wait(asio_dispatch_timer(&Session::housekeeping_callback, this));
}
else
{
housekeeping_timer.cancel();
}
}
}
2012-07-01 17:37:46 +02:00
void process_exception(const std::exception& e, const char *method_name)
{
if (notify_callback)
{
2012-07-01 17:37:46 +02:00
OPENVPN_LOG("Client exception in " << method_name << ": " << e.what());
stop(true);
}
else
throw client_exception(e.what());
}
Fixed a race condition issue with "hot connect", i.e. sending a connect intent to service when already connected. One of the ramifications of the "hot connect" fix above is that OpenVPNClientBase.is_active() will now return a value that is instantaneously up-to-date, whereas events might lag because of the mechanics of inter-thread message posting. Keep this in mind when correlating received events to is_active() values. For C++ core threads, increased allowed thread-stop delay to 2.5 seconds before thread is marked as unresponsive and abandoned. Previous delay was 1 second. This delay can't be made too long, otherwise Android will tell the user that the app is unresponsive and invite them to kill it. When closing out an abandoned core thread, indicate this condition with a new event type called CORE_THREAD_ABANDONED. If the thread is abandoned due to lack of response to a disconnect request, then the CORE_THREAD_ABANDONED event will occur followed by CORE_THREAD_INACTIVE. For core threads that properly exit, the DISCONNECTED event will be followed by CORE_THREAD_INACTIVE. Added save_as_filename parameter to importProfileRemote method for controlling the filename that the imported profile is saved as. This parameter may be set to null to have the method choose an appropriate name. To have an imported profile replace an existing profile, the filenames much match. Added UI_OVERLOADED debugging constant to OpenVPNClient to allow the UI to connect to a profile when already connected to another profile in order to test "hot connect". Added new events CLIENT_HALT and CLIENT_RESTART for compatibility with an Access Server feature that allows the server to remotely kill or restart the client. When connecting a profile, the core will now automatically fill in the username if it is not specified for userlocked profiles. Version 0.902.
2012-03-31 18:08:20 +02:00
void process_halt_restart(const ClientHalt& ch)
{
if (ch.restart() && (ch.psid() || !creds || !creds->password_defined()))
fatal_ = Error::CLIENT_RESTART;
else
fatal_ = Error::CLIENT_HALT;
fatal_reason_ = ch.reason();
if (notify_callback)
{
OPENVPN_LOG("Client halt/restart: " << ch.render());
stop(true);
}
else
throw client_halt_restart(ch.render());
}
#ifdef OPENVPN_PACKET_LOG
void log_packet(const Buffer& buf, const bool out)
{
if (buf.size())
{
boost::uint16_t len = buf.size() & 0x7FFF;
if (out)
len |= 0x8000;
packet_log.write((const char *)&len, sizeof(len));
packet_log.write((const char *)buf.c_data(), buf.size());
}
}
#endif
boost::asio::io_service& io_service;
TransportClientFactory::Ptr transport_factory;
TransportClient::Ptr transport;
TunClientFactory::Ptr tun_factory;
TunClient::Ptr tun;
NotifyCallback* notify_callback;
CoarseTime housekeeping_schedule;
AsioTimer housekeeping_timer;
AsioTimer push_request_timer;
bool halt;
OptionListContinuation received_options;
ClientCreds::Ptr creds;
ProtoContextOptions::Ptr proto_context_options;
iOS version: 1.0 Beta 17 Android version: 1.1 beta 1 More alignment of iOS and Android clients: * Normalized building of dependencies for Android and iOS: This build adds some new library dependencies: The library versions required are enumerated in ovpn3/lib-versions, currently: export BOOST_VERSION=boost_1_51_0 export OPENSSL_VERSION=openssl-1.0.1c export POLARSSL_VERSION=polarssl-1.1.4 export LZO_VERSION=lzo-2.06 To build, first mkdir ~/src/android and ~/src/mac if they don't already exist. Set the env var O3 to point to the ovpn3 dir, usually ~/src/ovpn3. Build on iOS: [set PATH to include NDK] cd ~/src/android $O3/scripts/android/build-boost $O3/scripts/android/build-minicrypto $O3/scripts/android/build-polarssl $O3/scripts/android/build-lzo Build on Android: [set PATH to include NDK] cd ~/src/android $O3/scripts/android/build-boost $O3/scripts/android/build-minicrypto $O3/scripts/android/build-polarssl $O3/scripts/android/build-lzo * Integrated Minicrypto library (an assembly language library of low-level crypto functions adapted from OpenSSL). * Added LZO compression with a preference/settings item to enable or disable. * Added special compression handling to support older servers that ignore compression handshake -- this will handle receiving compressed packets even if we didn't ask for them. * Normalized profile naming conventions. iOS changes: * Log tunnel performance stats immediately on disconnection of tunnel. Android changes: * Client now supports loading profiles as attachments opened from other apps. * Added Import Private Tunnel menu item, however current Private Tunnel download page needs to be adapted to fit requirements of Android download manager. * Enter key should advance to the next input field, or connect if entered from the last field. * Import from Access Server now provides the option to download autologin vs. userlogin profiles. * "About" page now shows copyright text for included libraries/content (except for LZO and PolarSSL which will presumably be commercially licensed).
2012-09-05 03:09:34 +02:00
bool first_packet_received_;
bool sent_push_request;
SessionStats::Ptr cli_stats;
ClientEvent::Queue::Ptr cli_events;
bool connected_;
Error::Type fatal_;
std::string fatal_reason_;
OptionList::Limits pushed_options_limit;
#ifdef OPENVPN_PACKET_LOG
std::ofstream packet_log;
#endif
};
}
}
#endif