OpenVPNClientThread.java
1 // OpenVPN -- An application to securely tunnel IP networks 2 // over a single port, with support for SSL/TLS-based 3 // session authentication and key exchange, 4 // packet encryption, packet authentication, and 5 // packet compression. 6 // 7 // Copyright (C) 2012- OpenVPN Inc. 8 // 9 // SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception 10 // 11 12 // package OPENVPN_PACKAGE 13 14 import java.util.HashSet; 15 16 public class OpenVPNClientThread extends ClientAPI_OpenVPNClient implements Runnable { 17 private EventReceiver parent; 18 private TunBuilder tun_builder; 19 private Thread thread; 20 private ClientAPI_Status m_connect_status; 21 private boolean connect_called = false; 22 23 private int bytes_in_index = -1; 24 private int bytes_out_index = -1; 25 26 // thrown if instantiator attempts to call connect more than once 27 public static class ConnectCalledTwice extends RuntimeException { 28 } 29 30 public interface EventReceiver { 31 // Called with events from core 32 void event(ClientAPI_Event event); 33 34 // Called with log text from core 35 void log(ClientAPI_LogInfo loginfo); 36 37 // Called when connect() thread exits 38 void done(ClientAPI_Status status); 39 40 // Called to "protect" a socket from being routed through the tunnel 41 boolean socket_protect(int socket); 42 43 // When a connection is close to timeout, the core will call this 44 // method. If it returns false, the core will disconnect with a 45 // CONNECTION_TIMEOUT event. If true, the core will enter a PAUSE 46 // state. 47 boolean pause_on_connection_timeout(); 48 49 // Callback to construct a new tun builder 50 TunBuilder tun_builder_new(); 51 52 // Callback to get a certificate 53 void external_pki_cert_request(ClientAPI_ExternalPKICertRequest req); 54 55 // Callback to sign data 56 void external_pki_sign_request(ClientAPI_ExternalPKISignRequest req); 57 } 58 59 public interface TunBuilder { 60 // Tun builder methods. 61 // Methods documented in openvpn/tun/builder/base.hpp 62 63 boolean tun_builder_set_remote_address(String address, boolean ipv6); 64 boolean tun_builder_add_address(String address, int prefix_length, String gateway, boolean ipv6, boolean net30); 65 boolean tun_builder_reroute_gw(boolean ipv4, boolean ipv6, long flags); 66 boolean tun_builder_add_route(String address, int prefix_length, boolean ipv6); 67 boolean tun_builder_exclude_route(String address, int prefix_length, boolean ipv6); 68 boolean tun_builder_add_dns_server(String address, boolean ipv6); 69 boolean tun_builder_add_search_domain(String domain); 70 boolean tun_builder_set_mtu(int mtu); 71 boolean tun_builder_set_session_name(String name); 72 int tun_builder_establish(); 73 void tun_builder_teardown(boolean disconnect); 74 } 75 76 public OpenVPNClientThread() { 77 final int n = stats_n(); 78 for (int i = 0; i < n; ++i) 79 { 80 String name = stats_name(i); 81 if (name.equals("BYTES_IN")) 82 bytes_in_index = i; 83 if (name.equals("BYTES_OUT")) 84 bytes_out_index = i; 85 } 86 } 87 88 // start connect session in worker thread 89 public void connect(EventReceiver parent_arg) { 90 if (connect_called) 91 throw new ConnectCalledTwice(); 92 connect_called = true; 93 94 // direct client callbacks to parent 95 parent = parent_arg; 96 97 // clear status 98 m_connect_status = null; 99 100 // execute client in a worker thread 101 thread = new Thread(this, "OpenVPNClientThread"); 102 thread.start(); 103 } 104 105 // Wait for worker thread to complete; to stop thread, 106 // first call super stop() method then wait_thread(). 107 // This method will give the thread one second to 108 // exit and will abandon it after this time. 109 public void wait_thread_short() { 110 final int wait_millisecs = 5000; // max time that we will wait for thread to exit 111 Thread th = thread; 112 if (th != null) { 113 try { 114 th.join(wait_millisecs); 115 } 116 catch (InterruptedException e) { 117 } 118 119 // thread failed to stop? 120 if (th.isAlive()) { 121 // abandon thread and deliver our own status object to instantiator. 122 ClientAPI_Status status = new ClientAPI_Status(); 123 status.setError(true); 124 status.setMessage("CORE_THREAD_ABANDONED"); 125 call_done(status); 126 } 127 } 128 } 129 130 // Wait for worker thread to complete; to stop thread, 131 // first call super stop() method then wait_thread(). 132 // This method will wait forever for the thread to exit. 133 public void wait_thread_long() { 134 if (thread != null) { 135 boolean interrupted; 136 do { 137 interrupted = false; 138 try { 139 thread.join(); 140 } 141 catch (InterruptedException e) { 142 interrupted = true; 143 super.stop(); // send thread a stop message 144 } 145 } while (interrupted); 146 } 147 } 148 149 public long bytes_in() 150 { 151 return super.stats_value(bytes_in_index); 152 } 153 154 public long bytes_out() 155 { 156 return super.stats_value(bytes_out_index); 157 } 158 159 private void call_done(ClientAPI_Status status) 160 { 161 EventReceiver p = finalize_thread(status); 162 if (p != null) 163 p.done(m_connect_status); 164 } 165 166 private synchronized EventReceiver finalize_thread(ClientAPI_Status connect_status) 167 { 168 EventReceiver p = parent; 169 if (p != null) { 170 // save thread connection status 171 m_connect_status = connect_status; 172 173 // disassociate client callbacks from parent 174 parent = null; 175 tun_builder = null; 176 thread = null; 177 } 178 return p; 179 } 180 181 // Runnable overrides 182 183 @Override 184 public void run() { 185 // Call out to core to start connection. 186 // Doesn't return until connection has terminated. 187 ClientAPI_Status status = super.connect(); 188 call_done(status); 189 } 190 191 // ClientAPI_OpenVPNClient (C++ class) overrides 192 193 @Override 194 public boolean socket_protect(int socket) { 195 EventReceiver p = parent; 196 if (p != null) 197 return p.socket_protect(socket); 198 else 199 return false; 200 } 201 202 @Override 203 public boolean pause_on_connection_timeout() { 204 EventReceiver p = parent; 205 if (p != null) 206 return p.pause_on_connection_timeout(); 207 else 208 return false; 209 } 210 211 @Override 212 public void event(ClientAPI_Event event) { 213 EventReceiver p = parent; 214 if (p != null) 215 p.event(event); 216 } 217 218 @Override 219 public void log(ClientAPI_LogInfo loginfo) { 220 EventReceiver p = parent; 221 if (p != null) 222 p.log(loginfo); 223 } 224 225 @Override 226 public void external_pki_cert_request(ClientAPI_ExternalPKICertRequest req) { 227 EventReceiver p = parent; 228 if (p != null) 229 p.external_pki_cert_request(req); 230 } 231 232 @Override 233 public void external_pki_sign_request(ClientAPI_ExternalPKISignRequest req) { 234 EventReceiver p = parent; 235 if (p != null) 236 p.external_pki_sign_request(req); 237 } 238 239 // TunBuilderBase (C++ class) overrides 240 241 @Override 242 public boolean tun_builder_new() { 243 EventReceiver p = parent; 244 if (p != null) { 245 tun_builder = p.tun_builder_new(); 246 return tun_builder != null; 247 } else 248 return false; 249 } 250 251 @Override 252 public boolean tun_builder_set_remote_address(String address, boolean ipv6) { 253 TunBuilder tb = tun_builder; 254 if (tb != null) 255 return tb.tun_builder_set_remote_address(address, ipv6); 256 else 257 return false; 258 } 259 260 @Override 261 public boolean tun_builder_add_address(String address, int prefix_length, String gateway, boolean ipv6, boolean net30) { 262 TunBuilder tb = tun_builder; 263 if (tb != null) 264 return tb.tun_builder_add_address(address, prefix_length, gateway, ipv6, net30); 265 else 266 return false; 267 } 268 269 @Override 270 public boolean tun_builder_reroute_gw(boolean ipv4, boolean ipv6, long flags) { 271 TunBuilder tb = tun_builder; 272 if (tb != null) 273 return tb.tun_builder_reroute_gw(ipv4, ipv6, flags); 274 else 275 return false; 276 } 277 278 @Override 279 public boolean tun_builder_add_route(String address, int prefix_length, int metric, boolean ipv6) { 280 TunBuilder tb = tun_builder; 281 if (tb != null) 282 return tb.tun_builder_add_route(address, prefix_length, ipv6); 283 else 284 return false; 285 } 286 287 @Override 288 public boolean tun_builder_exclude_route(String address, int prefix_length, int metric, boolean ipv6) { 289 TunBuilder tb = tun_builder; 290 if (tb != null) 291 return tb.tun_builder_exclude_route(address, prefix_length, ipv6); 292 else 293 return false; 294 } 295 296 @Override 297 public boolean tun_builder_add_dns_server(String address, boolean ipv6) { 298 TunBuilder tb = tun_builder; 299 if (tb != null) 300 return tb.tun_builder_add_dns_server(address, ipv6); 301 else 302 return false; 303 } 304 305 @Override 306 public boolean tun_builder_add_search_domain(String domain) 307 { 308 TunBuilder tb = tun_builder; 309 if (tb != null) 310 return tb.tun_builder_add_search_domain(domain); 311 else 312 return false; 313 } 314 315 @Override 316 public boolean tun_builder_set_mtu(int mtu) { 317 TunBuilder tb = tun_builder; 318 if (tb != null) 319 return tb.tun_builder_set_mtu(mtu); 320 else 321 return false; 322 } 323 324 @Override 325 public boolean tun_builder_set_session_name(String name) 326 { 327 TunBuilder tb = tun_builder; 328 if (tb != null) 329 return tb.tun_builder_set_session_name(name); 330 else 331 return false; 332 } 333 334 @Override 335 public int tun_builder_establish() { 336 TunBuilder tb = tun_builder; 337 if (tb != null) 338 return tb.tun_builder_establish(); 339 else 340 return -1; 341 } 342 343 @Override 344 public void tun_builder_teardown(boolean disconnect) { 345 TunBuilder tb = tun_builder; 346 if (tb != null) 347 tb.tun_builder_teardown(disconnect); 348 } 349 }