package de.blinkt.openvpn.core; import net.openvpn.ovpn3.ClientAPI_Config; import net.openvpn.ovpn3.ClientAPI_EvalConfig; import net.openvpn.ovpn3.ClientAPI_Event; import net.openvpn.ovpn3.ClientAPI_ExternalPKICertRequest; import net.openvpn.ovpn3.ClientAPI_ExternalPKISignRequest; import net.openvpn.ovpn3.ClientAPI_LogInfo; import net.openvpn.ovpn3.ClientAPI_OpenVPNClient; import net.openvpn.ovpn3.ClientAPI_ProvideCreds; import net.openvpn.ovpn3.ClientAPI_Status; import net.openvpn.ovpn3.ClientAPI_TransportStats; import java.lang.Override; import de.blinkt.openvpn.VpnProfile; import android.content.Context; public class OpenVPNThreadv3 extends ClientAPI_OpenVPNClient implements Runnable, OpenVPNManagement { static { /*System.loadLibrary("crypto"); System.loadLibrary("ssl");*/ System.loadLibrary("polarssl-dynamic"); System.loadLibrary("ovpn3"); } private VpnProfile mVp; private OpenVPNService mService; class StatusPoller implements Runnable { private long mSleeptime; boolean mStopped=false; public StatusPoller(long sleeptime) { mSleeptime=sleeptime; } public void run() { while(!mStopped) { try { Thread.sleep(mSleeptime); } catch (InterruptedException e) { } ClientAPI_TransportStats t = transport_stats(); long in = t.getBytesIn(); long out = t.getBytesOut(); VpnStatus.updateByteCount(in, out); } } public void stop() { mStopped=true; } } @Override public void run() { String configstr = mVp.getConfigFile((Context)mService,true); if(!setConfig(configstr)) return; setUserPW(); VpnStatus.logInfo(copyright()); StatusPoller statuspoller = new StatusPoller(5000); new Thread(statuspoller,"Status Poller").start(); ClientAPI_Status status = connect(); if(status.getError()) { VpnStatus.logError(String.format("connect() error: %s: %s",status.getStatus(),status.getMessage())); } else { VpnStatus.logInfo("OpenVPN3 thread finished"); } statuspoller.stop(); } @Override public boolean tun_builder_set_remote_address(String address, boolean ipv6) { mService.setMtu(1500); return true; } @Override public boolean tun_builder_set_mtu(int mtu) { mService.setMtu(mtu); return true; } @Override public boolean tun_builder_add_dns_server(String address, boolean ipv6) { mService.addDNS(address); return true; } @Override public boolean tun_builder_add_route(String address, int prefix_length, boolean ipv6) { if (address.equals("remote_host")) return false; if(ipv6) mService.addRoutev6(address + "/" + prefix_length,"tun"); else mService.addRoute(new CIDRIP(address, prefix_length)); return true; } @Override public boolean tun_builder_add_search_domain(String domain) { mService.setDomain(domain); return true; } @Override public int tun_builder_establish() { return mService.openTun().detachFd(); } @Override public boolean tun_builder_set_session_name(String name) { VpnStatus.logInfo("We should call this session" + name); return true; } @Override public boolean tun_builder_add_address(String address, int prefix_length, boolean ipv6) { if(!ipv6) mService.setLocalIP(new CIDRIP(address, prefix_length)); else mService.setLocalIPv6(address+ "/" + prefix_length); return true; } @Override public boolean tun_builder_new() { return true; } @Override public boolean tun_builder_reroute_gw(String server_address, boolean server_address_ipv6, boolean ipv4, boolean ipv6, long flags) { // ignore return true; } @Override public boolean tun_builder_exclude_route(String address, int prefix_length, boolean ipv6) { //ignore return true; } private boolean setConfig(String vpnconfig) { ClientAPI_Config config = new ClientAPI_Config(); if(mVp.getPasswordPrivateKey()!=null) config.setPrivateKeyPassword(mVp.getPasswordPrivateKey()); config.setContent(vpnconfig); config.setTunPersist(mVp.mPersistTun); config.setGuiVersion(mVp.getVersionEnvString(mService)); config.setExternalPkiAlias("extpki"); ClientAPI_EvalConfig ec = eval_config(config); if(ec.getExternalPki()) { VpnStatus.logError("OpenVPN seem to think as external PKI"); } if (ec.getError()) { VpnStatus.logError("OpenVPN config file parse error: " + ec.getMessage()); return false; } else { config.setContent(vpnconfig); return true; } } @Override public void external_pki_cert_request(ClientAPI_ExternalPKICertRequest certreq) { VpnStatus.logError("EXT PKI CERT"); String[] ks = mVp.getKeyStoreCertificates((Context) mService); if(ks==null) { certreq.setError(true); certreq.setErrorText("Error in pki cert request"); return; } String supcerts = ks[0]; /* FIXME: How to differentiate between chain and ca certs in OpenVPN 3? */ if (ks[1]!=null) supcerts += "\n" + ks[1]; certreq.setSupportingChain(supcerts); certreq.setCert(ks[2]); certreq.setError(false); } @Override public void external_pki_sign_request(ClientAPI_ExternalPKISignRequest signreq) { signreq.setSig(mVp.getSignedData(signreq.getData())); } void setUserPW() { if(mVp.isUserPWAuth()) { ClientAPI_ProvideCreds creds = new ClientAPI_ProvideCreds(); creds.setCachePassword(true); creds.setPassword(mVp.getPasswordAuth()); creds.setUsername(mVp.mUsername); provide_creds(creds); } } @Override public boolean socket_protect(int socket) { boolean b= mService.protect(socket); return b; } public OpenVPNThreadv3(OpenVPNService openVpnService, VpnProfile vp) { init_process(); mVp =vp; mService =openVpnService; } @Override public void pause(pauseReason pauseReason) { pause(); } @Override public void log(ClientAPI_LogInfo arg0) { String logmsg =arg0.getText(); while (logmsg.endsWith("\n")) logmsg = logmsg.substring(0, logmsg.length()-1); VpnStatus.logInfo(logmsg); } @Override public void event(ClientAPI_Event event) { VpnStatus.updateStateString(event.getName(), event.getInfo()); if(event.getError()) VpnStatus.logError(String.format("EVENT(Error): %s: %s",event.getName(),event.getInfo())); } // 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. @Override public boolean pause_on_connection_timeout() { VpnStatus.logInfo("pause on connection timeout?! "); return true; } public boolean stopVPN() { stop(); return true; } @Override public void reconnect() { reconnect(1); } }