2014-08-25 09:02:40 +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
|
|
|
//
|
2015-01-06 20:56:21 +01:00
|
|
|
// Copyright (C) 2012-2015 OpenVPN Technologies, Inc.
|
2012-08-24 23:13:42 +02:00
|
|
|
//
|
2014-08-25 09:02:40 +02:00
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU Affero General Public License Version 3
|
|
|
|
// as published by the Free Software Foundation.
|
2012-08-24 23:13:42 +02:00
|
|
|
//
|
2014-08-25 09:02:40 +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
|
|
|
|
// GNU Affero General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
|
|
// along with this program in the COPYING file.
|
|
|
|
// If not, see <http://www.gnu.org/licenses/>.
|
2012-08-24 23:13:42 +02:00
|
|
|
|
2012-02-16 21:46:38 +01:00
|
|
|
// package OPENVPN_PACKAGE
|
|
|
|
|
2012-03-07 12:21:09 +01:00
|
|
|
import java.util.HashSet;
|
|
|
|
|
2012-03-01 09:11:00 +01:00
|
|
|
public class OpenVPNClientThread extends ClientAPI_OpenVPNClient implements Runnable {
|
2012-02-15 16:13:35 +01:00
|
|
|
private EventReceiver parent;
|
2012-02-19 18:43:42 +01:00
|
|
|
private TunBuilder tun_builder;
|
2012-02-15 19:59:24 +01:00
|
|
|
private Thread thread;
|
2012-03-07 12:21:09 +01:00
|
|
|
private ClientAPI_Status m_connect_status;
|
|
|
|
private boolean connect_called = false;
|
2012-02-15 15:45:55 +01:00
|
|
|
|
2012-02-24 20:50:14 +01:00
|
|
|
private int bytes_in_index = -1;
|
|
|
|
private int bytes_out_index = -1;
|
|
|
|
|
2012-03-07 12:21:09 +01:00
|
|
|
// thrown if instantiator attempts to call connect more than once
|
|
|
|
public static class ConnectCalledTwice extends RuntimeException {
|
|
|
|
}
|
|
|
|
|
2012-02-15 16:13:35 +01:00
|
|
|
public interface EventReceiver {
|
2012-02-19 18:43:42 +01:00
|
|
|
// Called with events from core
|
2012-03-01 09:11:00 +01:00
|
|
|
void event(ClientAPI_Event event);
|
2012-02-19 18:43:42 +01:00
|
|
|
|
|
|
|
// Called with log text from core
|
2012-03-01 09:11:00 +01:00
|
|
|
void log(ClientAPI_LogInfo loginfo);
|
2012-02-19 18:43:42 +01:00
|
|
|
|
|
|
|
// Called when connect() thread exits
|
2012-03-01 09:11:00 +01:00
|
|
|
void done(ClientAPI_Status status);
|
2012-02-19 18:43:42 +01:00
|
|
|
|
|
|
|
// Called to "protect" a socket from being routed through the tunnel
|
|
|
|
boolean socket_protect(int socket);
|
|
|
|
|
2012-10-23 15:10:39 +02:00
|
|
|
// When a connection is close to timeout, the core will call this
|
|
|
|
// method. If it returns false, the core will disconnect with a
|
|
|
|
// CONNECTION_TIMEOUT event. If true, the core will enter a PAUSE
|
|
|
|
// state.
|
|
|
|
boolean pause_on_connection_timeout();
|
|
|
|
|
2012-02-19 18:43:42 +01:00
|
|
|
// Callback to construct a new tun builder
|
|
|
|
TunBuilder tun_builder_new();
|
2012-03-06 07:06:54 +01:00
|
|
|
|
|
|
|
// Callback to get a certificate
|
|
|
|
void external_pki_cert_request(ClientAPI_ExternalPKICertRequest req);
|
|
|
|
|
|
|
|
// Callback to sign data
|
|
|
|
void external_pki_sign_request(ClientAPI_ExternalPKISignRequest req);
|
2012-02-19 18:43:42 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public interface TunBuilder {
|
2012-08-25 07:05:35 +02:00
|
|
|
// Tun builder methods.
|
|
|
|
// Methods documented in openvpn/tun/builder/base.hpp
|
|
|
|
|
|
|
|
boolean tun_builder_set_remote_address(String address, boolean ipv6);
|
2014-02-16 07:34:33 +01:00
|
|
|
boolean tun_builder_add_address(String address, int prefix_length, String gateway, boolean ipv6, boolean net30);
|
2014-02-28 05:51:28 +01:00
|
|
|
boolean tun_builder_reroute_gw(boolean ipv4, boolean ipv6, long flags);
|
2012-08-25 07:05:35 +02:00
|
|
|
boolean tun_builder_add_route(String address, int prefix_length, boolean ipv6);
|
|
|
|
boolean tun_builder_exclude_route(String address, int prefix_length, boolean ipv6);
|
2013-01-26 07:53:31 +01:00
|
|
|
boolean tun_builder_add_dns_server(String address, boolean ipv6);
|
|
|
|
boolean tun_builder_add_search_domain(String domain);
|
2012-02-19 18:43:42 +01:00
|
|
|
boolean tun_builder_set_mtu(int mtu);
|
|
|
|
boolean tun_builder_set_session_name(String name);
|
|
|
|
int tun_builder_establish();
|
2014-08-25 07:09:16 +02:00
|
|
|
void tun_builder_teardown(boolean disconnect);
|
2012-02-15 16:13:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public OpenVPNClientThread() {
|
2012-02-24 20:50:14 +01:00
|
|
|
final int n = stats_n();
|
|
|
|
for (int i = 0; i < n; ++i)
|
|
|
|
{
|
|
|
|
String name = stats_name(i);
|
|
|
|
if (name.equals("BYTES_IN"))
|
|
|
|
bytes_in_index = i;
|
|
|
|
if (name.equals("BYTES_OUT"))
|
|
|
|
bytes_out_index = i;
|
|
|
|
}
|
2012-02-15 15:45:55 +01:00
|
|
|
}
|
|
|
|
|
2012-02-15 19:59:24 +01:00
|
|
|
// start connect session in worker thread
|
|
|
|
public void connect(EventReceiver parent_arg) {
|
2012-03-07 12:21:09 +01:00
|
|
|
if (connect_called)
|
|
|
|
throw new ConnectCalledTwice();
|
|
|
|
connect_called = true;
|
|
|
|
|
2012-02-15 15:45:55 +01:00
|
|
|
// direct client callbacks to parent
|
|
|
|
parent = parent_arg;
|
|
|
|
|
2012-02-15 19:59:24 +01:00
|
|
|
// clear status
|
2012-03-07 12:21:09 +01:00
|
|
|
m_connect_status = null;
|
2012-02-15 19:59:24 +01:00
|
|
|
|
2012-02-15 15:45:55 +01:00
|
|
|
// execute client in a worker thread
|
2012-02-15 19:59:24 +01:00
|
|
|
thread = new Thread(this, "OpenVPNClientThread");
|
2012-02-15 15:45:55 +01:00
|
|
|
thread.start();
|
2012-02-15 19:59:24 +01:00
|
|
|
}
|
2012-02-15 15:45:55 +01:00
|
|
|
|
2012-03-08 11:50:26 +01:00
|
|
|
// Wait for worker thread to complete; to stop thread,
|
|
|
|
// first call super stop() method then wait_thread().
|
|
|
|
// This method will give the thread one second to
|
|
|
|
// exit and will abandon it after this time.
|
|
|
|
public void wait_thread_short() {
|
2012-10-10 13:04:34 +02:00
|
|
|
final int wait_millisecs = 5000; // max time that we will wait for thread to exit
|
2012-03-07 12:21:09 +01:00
|
|
|
Thread th = thread;
|
|
|
|
if (th != null) {
|
|
|
|
try {
|
|
|
|
th.join(wait_millisecs);
|
|
|
|
}
|
|
|
|
catch (InterruptedException e) {
|
|
|
|
}
|
2012-02-15 20:39:51 +01:00
|
|
|
|
2012-03-07 12:21:09 +01:00
|
|
|
// thread failed to stop?
|
|
|
|
if (th.isAlive()) {
|
|
|
|
// abandon thread and deliver our own status object to instantiator.
|
|
|
|
ClientAPI_Status status = new ClientAPI_Status();
|
2012-03-31 18:08:20 +02:00
|
|
|
status.setError(true);
|
|
|
|
status.setMessage("CORE_THREAD_ABANDONED");
|
2012-03-07 12:21:09 +01:00
|
|
|
call_done(status);
|
|
|
|
}
|
|
|
|
}
|
2012-02-15 15:45:55 +01:00
|
|
|
}
|
|
|
|
|
2012-03-08 11:50:26 +01:00
|
|
|
// Wait for worker thread to complete; to stop thread,
|
|
|
|
// first call super stop() method then wait_thread().
|
|
|
|
// This method will wait forever for the thread to exit.
|
|
|
|
public void wait_thread_long() {
|
|
|
|
if (thread != null) {
|
|
|
|
boolean interrupted;
|
|
|
|
do {
|
|
|
|
interrupted = false;
|
|
|
|
try {
|
|
|
|
thread.join();
|
|
|
|
}
|
|
|
|
catch (InterruptedException e) {
|
|
|
|
interrupted = true;
|
|
|
|
super.stop(); // send thread a stop message
|
|
|
|
}
|
|
|
|
} while (interrupted);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-24 20:50:14 +01:00
|
|
|
public long bytes_in()
|
|
|
|
{
|
|
|
|
return super.stats_value(bytes_in_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
public long bytes_out()
|
|
|
|
{
|
|
|
|
return super.stats_value(bytes_out_index);
|
|
|
|
}
|
|
|
|
|
2012-03-07 12:21:09 +01:00
|
|
|
private void call_done(ClientAPI_Status status)
|
|
|
|
{
|
|
|
|
EventReceiver p = finalize_thread(status);
|
|
|
|
if (p != null)
|
|
|
|
p.done(m_connect_status);
|
|
|
|
}
|
|
|
|
|
|
|
|
private synchronized EventReceiver finalize_thread(ClientAPI_Status connect_status)
|
|
|
|
{
|
|
|
|
EventReceiver p = parent;
|
|
|
|
if (p != null) {
|
|
|
|
// save thread connection status
|
|
|
|
m_connect_status = connect_status;
|
|
|
|
|
|
|
|
// disassociate client callbacks from parent
|
|
|
|
parent = null;
|
|
|
|
tun_builder = null;
|
|
|
|
thread = null;
|
|
|
|
}
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2012-02-19 18:43:42 +01:00
|
|
|
// Runnable overrides
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void run() {
|
2012-03-07 12:21:09 +01:00
|
|
|
// Call out to core to start connection.
|
|
|
|
// Doesn't return until connection has terminated.
|
|
|
|
ClientAPI_Status status = super.connect();
|
|
|
|
call_done(status);
|
2012-02-19 18:43:42 +01:00
|
|
|
}
|
|
|
|
|
2012-03-01 09:11:00 +01:00
|
|
|
// ClientAPI_OpenVPNClient (C++ class) overrides
|
2012-02-19 18:43:42 +01:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean socket_protect(int socket) {
|
2012-03-07 12:21:09 +01:00
|
|
|
EventReceiver p = parent;
|
|
|
|
if (p != null)
|
|
|
|
return p.socket_protect(socket);
|
2012-02-19 18:43:42 +01:00
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-10-23 15:10:39 +02:00
|
|
|
@Override
|
|
|
|
public boolean pause_on_connection_timeout() {
|
|
|
|
EventReceiver p = parent;
|
|
|
|
if (p != null)
|
|
|
|
return p.pause_on_connection_timeout();
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-02-15 15:45:55 +01:00
|
|
|
@Override
|
2012-03-01 09:11:00 +01:00
|
|
|
public void event(ClientAPI_Event event) {
|
2012-03-07 12:21:09 +01:00
|
|
|
EventReceiver p = parent;
|
|
|
|
if (p != null)
|
|
|
|
p.event(event);
|
2012-02-15 15:45:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2012-03-01 09:11:00 +01:00
|
|
|
public void log(ClientAPI_LogInfo loginfo) {
|
2012-03-07 12:21:09 +01:00
|
|
|
EventReceiver p = parent;
|
|
|
|
if (p != null)
|
|
|
|
p.log(loginfo);
|
2012-02-15 15:45:55 +01:00
|
|
|
}
|
|
|
|
|
2012-03-06 07:06:54 +01:00
|
|
|
@Override
|
|
|
|
public void external_pki_cert_request(ClientAPI_ExternalPKICertRequest req) {
|
2012-03-07 12:21:09 +01:00
|
|
|
EventReceiver p = parent;
|
|
|
|
if (p != null)
|
|
|
|
p.external_pki_cert_request(req);
|
2012-03-06 07:06:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void external_pki_sign_request(ClientAPI_ExternalPKISignRequest req) {
|
2012-03-07 12:21:09 +01:00
|
|
|
EventReceiver p = parent;
|
|
|
|
if (p != null)
|
|
|
|
p.external_pki_sign_request(req);
|
2012-03-06 07:06:54 +01:00
|
|
|
}
|
|
|
|
|
2012-02-19 18:43:42 +01:00
|
|
|
// TunBuilderBase (C++ class) overrides
|
|
|
|
|
2012-02-15 15:45:55 +01:00
|
|
|
@Override
|
2012-02-19 18:43:42 +01:00
|
|
|
public boolean tun_builder_new() {
|
2012-03-07 12:21:09 +01:00
|
|
|
EventReceiver p = parent;
|
|
|
|
if (p != null) {
|
|
|
|
tun_builder = p.tun_builder_new();
|
2012-02-19 18:43:42 +01:00
|
|
|
return tun_builder != null;
|
|
|
|
} else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2012-08-25 07:05:35 +02:00
|
|
|
public boolean tun_builder_set_remote_address(String address, boolean ipv6) {
|
2012-03-07 12:21:09 +01:00
|
|
|
TunBuilder tb = tun_builder;
|
|
|
|
if (tb != null)
|
2012-08-25 07:05:35 +02:00
|
|
|
return tb.tun_builder_set_remote_address(address, ipv6);
|
2012-02-19 18:43:42 +01:00
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2014-02-16 07:34:33 +01:00
|
|
|
public boolean tun_builder_add_address(String address, int prefix_length, String gateway, boolean ipv6, boolean net30) {
|
2012-03-07 12:21:09 +01:00
|
|
|
TunBuilder tb = tun_builder;
|
|
|
|
if (tb != null)
|
2014-02-16 07:34:33 +01:00
|
|
|
return tb.tun_builder_add_address(address, prefix_length, gateway, ipv6, net30);
|
2012-02-19 18:43:42 +01:00
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2014-02-28 05:51:28 +01:00
|
|
|
public boolean tun_builder_reroute_gw(boolean ipv4, boolean ipv6, long flags) {
|
2012-03-07 12:21:09 +01:00
|
|
|
TunBuilder tb = tun_builder;
|
|
|
|
if (tb != null)
|
2014-02-28 05:51:28 +01:00
|
|
|
return tb.tun_builder_reroute_gw(ipv4, ipv6, flags);
|
2012-02-19 18:43:42 +01:00
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2012-08-25 07:05:35 +02:00
|
|
|
public boolean tun_builder_add_route(String address, int prefix_length, boolean ipv6) {
|
|
|
|
TunBuilder tb = tun_builder;
|
|
|
|
if (tb != null)
|
|
|
|
return tb.tun_builder_add_route(address, prefix_length, ipv6);
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean tun_builder_exclude_route(String address, int prefix_length, boolean ipv6) {
|
|
|
|
TunBuilder tb = tun_builder;
|
|
|
|
if (tb != null)
|
|
|
|
return tb.tun_builder_exclude_route(address, prefix_length, ipv6);
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2013-01-26 07:53:31 +01:00
|
|
|
public boolean tun_builder_add_dns_server(String address, boolean ipv6) {
|
2012-08-25 07:05:35 +02:00
|
|
|
TunBuilder tb = tun_builder;
|
|
|
|
if (tb != null)
|
2013-01-26 07:53:31 +01:00
|
|
|
return tb.tun_builder_add_dns_server(address, ipv6);
|
2012-08-25 07:05:35 +02:00
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2013-01-26 07:53:31 +01:00
|
|
|
public boolean tun_builder_add_search_domain(String domain)
|
2012-02-19 18:43:42 +01:00
|
|
|
{
|
2012-03-07 12:21:09 +01:00
|
|
|
TunBuilder tb = tun_builder;
|
|
|
|
if (tb != null)
|
2013-01-26 07:53:31 +01:00
|
|
|
return tb.tun_builder_add_search_domain(domain);
|
2012-02-19 18:43:42 +01:00
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean tun_builder_set_mtu(int mtu) {
|
2012-03-07 12:21:09 +01:00
|
|
|
TunBuilder tb = tun_builder;
|
|
|
|
if (tb != null)
|
|
|
|
return tb.tun_builder_set_mtu(mtu);
|
2012-02-19 18:43:42 +01:00
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean tun_builder_set_session_name(String name)
|
|
|
|
{
|
2012-03-07 12:21:09 +01:00
|
|
|
TunBuilder tb = tun_builder;
|
|
|
|
if (tb != null)
|
|
|
|
return tb.tun_builder_set_session_name(name);
|
2012-02-19 18:43:42 +01:00
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int tun_builder_establish() {
|
2012-03-07 12:21:09 +01:00
|
|
|
TunBuilder tb = tun_builder;
|
|
|
|
if (tb != null)
|
|
|
|
return tb.tun_builder_establish();
|
2012-02-19 18:43:42 +01:00
|
|
|
else
|
|
|
|
return -1;
|
2012-02-15 15:45:55 +01:00
|
|
|
}
|
2012-08-25 07:05:35 +02:00
|
|
|
|
|
|
|
@Override
|
2014-08-25 07:09:16 +02:00
|
|
|
public void tun_builder_teardown(boolean disconnect) {
|
2012-08-25 07:05:35 +02:00
|
|
|
TunBuilder tb = tun_builder;
|
|
|
|
if (tb != null)
|
2014-08-25 07:09:16 +02:00
|
|
|
tb.tun_builder_teardown(disconnect);
|
2012-08-25 07:05:35 +02:00
|
|
|
}
|
2012-02-15 15:45:55 +01:00
|
|
|
}
|