mirror of
https://github.com/amnezia-vpn/openvpn3.git
synced 2026-06-22 10:07:14 +03:00
* Implement a simple DNS cache to work around issue with Seamless Tunnel -- When Seamless Tunnel is enabled, reconnections are unable to send DNS requests because the internet is blocked. This fix caches the IP address used for the initial connection, then reuses it over the lifetime of the Seamless Tunnel. * Try to ensure that connections properly pause on device sleep (when sleep on screen blanking is NOT enabled) so that they will survive until wakeup. iOS: * Don't choke on foreign profiles (such as VPN On Demand) that are imported onto the device but lack critical info such as a config file.
346 lines
9.0 KiB
Java
346 lines
9.0 KiB
Java
//
|
|
// OpenVPNClientThread.java
|
|
// OpenVPN
|
|
//
|
|
// Copyright (c) 2012 OpenVPN Technologies, Inc. All rights reserved.
|
|
//
|
|
|
|
// package OPENVPN_PACKAGE
|
|
|
|
import java.util.HashSet;
|
|
|
|
public class OpenVPNClientThread extends ClientAPI_OpenVPNClient implements Runnable {
|
|
private EventReceiver parent;
|
|
private TunBuilder tun_builder;
|
|
private Thread thread;
|
|
private ClientAPI_Status m_connect_status;
|
|
private boolean connect_called = false;
|
|
|
|
private int bytes_in_index = -1;
|
|
private int bytes_out_index = -1;
|
|
|
|
// thrown if instantiator attempts to call connect more than once
|
|
public static class ConnectCalledTwice extends RuntimeException {
|
|
}
|
|
|
|
public interface EventReceiver {
|
|
// Called with events from core
|
|
void event(ClientAPI_Event event);
|
|
|
|
// Called with log text from core
|
|
void log(ClientAPI_LogInfo loginfo);
|
|
|
|
// Called when connect() thread exits
|
|
void done(ClientAPI_Status status);
|
|
|
|
// Called to "protect" a socket from being routed through the tunnel
|
|
boolean socket_protect(int socket);
|
|
|
|
// 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();
|
|
|
|
// Callback to construct a new tun builder
|
|
TunBuilder tun_builder_new();
|
|
|
|
// 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);
|
|
}
|
|
|
|
public interface TunBuilder {
|
|
// Tun builder methods.
|
|
// Methods documented in openvpn/tun/builder/base.hpp
|
|
|
|
boolean tun_builder_set_remote_address(String address, boolean ipv6);
|
|
boolean tun_builder_add_address(String address, int prefix_length, boolean ipv6);
|
|
boolean tun_builder_reroute_gw(String server_address, boolean server_address_ipv6, boolean ipv6);
|
|
boolean tun_builder_add_route(String address, int prefix_length, boolean ipv6);
|
|
boolean tun_builder_exclude_route(String address, int prefix_length, boolean ipv6);
|
|
boolean tun_builder_add_dns_server(String address, boolean ipv6, boolean reroute_dns);
|
|
boolean tun_builder_add_search_domain(String domain, boolean reroute_dns);
|
|
boolean tun_builder_set_mtu(int mtu);
|
|
boolean tun_builder_set_session_name(String name);
|
|
int tun_builder_establish();
|
|
void tun_builder_teardown();
|
|
}
|
|
|
|
public OpenVPNClientThread() {
|
|
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;
|
|
}
|
|
}
|
|
|
|
// start connect session in worker thread
|
|
public void connect(EventReceiver parent_arg) {
|
|
if (connect_called)
|
|
throw new ConnectCalledTwice();
|
|
connect_called = true;
|
|
|
|
// direct client callbacks to parent
|
|
parent = parent_arg;
|
|
|
|
// clear status
|
|
m_connect_status = null;
|
|
|
|
// execute client in a worker thread
|
|
thread = new Thread(this, "OpenVPNClientThread");
|
|
thread.start();
|
|
}
|
|
|
|
// 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() {
|
|
final int wait_millisecs = 5000; // max time that we will wait for thread to exit
|
|
Thread th = thread;
|
|
if (th != null) {
|
|
try {
|
|
th.join(wait_millisecs);
|
|
}
|
|
catch (InterruptedException e) {
|
|
}
|
|
|
|
// thread failed to stop?
|
|
if (th.isAlive()) {
|
|
// abandon thread and deliver our own status object to instantiator.
|
|
ClientAPI_Status status = new ClientAPI_Status();
|
|
status.setError(true);
|
|
status.setMessage("CORE_THREAD_ABANDONED");
|
|
call_done(status);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
public long bytes_in()
|
|
{
|
|
return super.stats_value(bytes_in_index);
|
|
}
|
|
|
|
public long bytes_out()
|
|
{
|
|
return super.stats_value(bytes_out_index);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
// Runnable overrides
|
|
|
|
@Override
|
|
public void run() {
|
|
// Call out to core to start connection.
|
|
// Doesn't return until connection has terminated.
|
|
ClientAPI_Status status = super.connect();
|
|
call_done(status);
|
|
}
|
|
|
|
// ClientAPI_OpenVPNClient (C++ class) overrides
|
|
|
|
@Override
|
|
public boolean socket_protect(int socket) {
|
|
EventReceiver p = parent;
|
|
if (p != null)
|
|
return p.socket_protect(socket);
|
|
else
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean pause_on_connection_timeout() {
|
|
EventReceiver p = parent;
|
|
if (p != null)
|
|
return p.pause_on_connection_timeout();
|
|
else
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public void event(ClientAPI_Event event) {
|
|
EventReceiver p = parent;
|
|
if (p != null)
|
|
p.event(event);
|
|
}
|
|
|
|
@Override
|
|
public void log(ClientAPI_LogInfo loginfo) {
|
|
EventReceiver p = parent;
|
|
if (p != null)
|
|
p.log(loginfo);
|
|
}
|
|
|
|
@Override
|
|
public void external_pki_cert_request(ClientAPI_ExternalPKICertRequest req) {
|
|
EventReceiver p = parent;
|
|
if (p != null)
|
|
p.external_pki_cert_request(req);
|
|
}
|
|
|
|
@Override
|
|
public void external_pki_sign_request(ClientAPI_ExternalPKISignRequest req) {
|
|
EventReceiver p = parent;
|
|
if (p != null)
|
|
p.external_pki_sign_request(req);
|
|
}
|
|
|
|
// TunBuilderBase (C++ class) overrides
|
|
|
|
@Override
|
|
public boolean tun_builder_new() {
|
|
EventReceiver p = parent;
|
|
if (p != null) {
|
|
tun_builder = p.tun_builder_new();
|
|
return tun_builder != null;
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean tun_builder_set_remote_address(String address, boolean ipv6) {
|
|
TunBuilder tb = tun_builder;
|
|
if (tb != null)
|
|
return tb.tun_builder_set_remote_address(address, ipv6);
|
|
else
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean tun_builder_add_address(String address, int prefix_length, boolean ipv6) {
|
|
TunBuilder tb = tun_builder;
|
|
if (tb != null)
|
|
return tb.tun_builder_add_address(address, prefix_length, ipv6);
|
|
else
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean tun_builder_reroute_gw(String server_address, boolean server_address_ipv6, boolean ipv6) {
|
|
TunBuilder tb = tun_builder;
|
|
if (tb != null)
|
|
return tb.tun_builder_reroute_gw(server_address, server_address_ipv6, ipv6);
|
|
else
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
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
|
|
public boolean tun_builder_add_dns_server(String address, boolean ipv6, boolean reroute_dns) {
|
|
TunBuilder tb = tun_builder;
|
|
if (tb != null)
|
|
return tb.tun_builder_add_dns_server(address, ipv6, reroute_dns);
|
|
else
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean tun_builder_add_search_domain(String domain, boolean reroute_dns)
|
|
{
|
|
TunBuilder tb = tun_builder;
|
|
if (tb != null)
|
|
return tb.tun_builder_add_search_domain(domain, reroute_dns);
|
|
else
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean tun_builder_set_mtu(int mtu) {
|
|
TunBuilder tb = tun_builder;
|
|
if (tb != null)
|
|
return tb.tun_builder_set_mtu(mtu);
|
|
else
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean tun_builder_set_session_name(String name)
|
|
{
|
|
TunBuilder tb = tun_builder;
|
|
if (tb != null)
|
|
return tb.tun_builder_set_session_name(name);
|
|
else
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public int tun_builder_establish() {
|
|
TunBuilder tb = tun_builder;
|
|
if (tb != null)
|
|
return tb.tun_builder_establish();
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
@Override
|
|
public void tun_builder_teardown() {
|
|
TunBuilder tb = tun_builder;
|
|
if (tb != null)
|
|
tb.tun_builder_teardown();
|
|
}
|
|
}
|