Tunnel Manager Thread
Tunnel Manager Thread
Tunnel Manager Thread
tunnel;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.ProxyInfo;
import android.os.Build;
import android.os.Handler;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import android.widget.Toast;
import com.trilead.ssh2.Connection;
import com.trilead.ssh2.ConnectionMonitor;
import com.trilead.ssh2.DebugLogger;
import com.trilead.ssh2.DynamicPortForwarder;
import com.trilead.ssh2.InteractiveCallback;
import com.trilead.ssh2.KnownHosts;
import com.trilead.ssh2.ProxyData;
import com.trilead.ssh2.ServerHostKeyVerifier;
import com.trilead.ssh2.transport.TransportManager;
import developer.gretongers.tunnel.config.PasswordCache;
import developer.gretongers.tunnel.config.Settings;
import developer.gretongers.tunnel.logger.SkStatus;
import developer.gretongers.tunnel.tunnel.vpn.TunnelState;
import developer.gretongers.tunnel.tunnel.vpn.TunnelVpnManager;
import developer.gretongers.tunnel.tunnel.vpn.TunnelVpnService;
import developer.gretongers.tunnel.tunnel.vpn.TunnelVpnSettings;
import developer.gretongers.tunnel.tunnel.vpn.VpnUtils;
import com.gretongers.R;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import developer.gretongers.team.SocksHttpMainActivity;
import developer.gretongers.team.adapter.LogsAdapter;
@Override
public void run()
{
mStarting = true;
mTunnelThreadStopSignal = new CountDownLatch(1);
SkStatus.logInfo(mContext.getString(R.string.starting_service_ssh));
int tries = 0;
while (!mStopping) {
try {
if (!TunnelUtils.isNetworkOnline(mContext)) {
SkStatus.updateStateString(SkStatus.SSH_AGUARDANDO_REDE,
mContext.getString(R.string.state_nonetwork));
SkStatus.logInfo(R.string.state_nonetwork);
try {
Thread.sleep(5000);
} catch(InterruptedException e2) {
stopAll();
break;
}
}
else {
if (tries > 0)
SocksHttpMainActivity.mAdapter.clearLog();
//SkStatus.logInfo("<strong>" +
mContext.getString(R.string.state_reconnecting) + "</strong>");
try {
Thread.sleep(500);
} catch(InterruptedException e2) {
stopAll();
break;
}
startClienteSSH();
break;
}
} catch(Exception e) {
SkStatus.logError("<strong>" +
mContext.getString(R.string.state_disconnected) + "</strong>");
closeSSH();
try {
Thread.sleep(500);
} catch(InterruptedException e2) {
stopAll();
break;
}
}
tries++;
}
mStarting = false;
if (!mStopping) {
try {
mTunnelThreadStopSignal.await();
} catch(InterruptedException e) {
Thread.currentThread().interrupt();
}
}
if (mListener != null) {
mListener.onStop();
}
}
SkStatus.updateStateString(SkStatus.SSH_PARANDO,
mContext.getString(R.string.stopping_service_ssh));
SkStatus.logInfo("<strong>" +
mContext.getString(R.string.stopping_service_ssh) + "</strong>");
if (mTunnelThreadStopSignal != null)
mTunnelThreadStopSignal.countDown();
closeSSH();
try {
Thread.sleep(1000);
} catch(InterruptedException e){}
SkStatus.updateStateString(SkStatus.SSH_DESCONECTADO,
mContext.getString(R.string.state_disconnected));
mRunning = false;
mStarting = false;
mReconnecting = false;
}
}).start();
}
/**
* Forwarder
*/
startForwarderSocks(portaLocal);
startTunnelVpnService();
try {
Thread.sleep(2000);
} catch(InterruptedException e) {
break;
}
if (lastPingLatency > 0) {
SkStatus.logInfo(String.format("Ping
Latency: %d ms", lastPingLatency));
break;
}
}
}
}).start();
}
stopForwarderSocks();
}
/**
* Cliente SSH
*/
try {
conectar(servidor, porta);
try {
autenticar(usuario, senha, keyPath);
break;
} catch(IOException e) {
if (i+1 >= AUTH_TRIES) {
throw new IOException("Authentication failed");
}
else {
try {
Thread.sleep(3000);
} catch(InterruptedException e2) {
return;
}
}
}
}
SkStatus.updateStateString(SkStatus.SSH_CONECTADO, "SSH
Connection Established");
SkStatus.logInfo("SSH Connected");
//SocksHttpMainActivity.startTime(true);
if (mConfig.getSSHPinger() > 0) {
startPinger(mConfig.getSSHPinger());
}
startForwarder(portaLocal);
} catch(Exception e) {
mConnected = false;
throw e;
}
}
if (mConfig.getModoDebug() && !
prefs.getBoolean(Settings.CONFIG_PROTEGER_KEY, false)) {
// Desativado, pois estava enchendo o Logger
//mConnection.enableDebugging(true, this);
mHandler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(mContext, "Debug mode
enabled",
Toast.LENGTH_SHORT).show();
}
});
}
// delay sleep
if (mConfig.getIsDisabledDelaySSH()) {
mConnection.setTCPNoDelay(true);
}
// proxy
addProxy(prefs.getBoolean(Settings.CONFIG_PROTEGER_KEY, false),
prefs.getInt(Settings.TUNNELTYPE_KEY, Settings.bTUNNEL_TYPE_SSH_DIRECT),
(!
prefs.getBoolean(Settings.PROXY_USAR_DEFAULT_PAYLOAD, true) ?
mConfig.getPrivString(Settings.CUSTOM_PAYLOAD_KEY) : null),
mConfig.getPrivString(Settings.CUSTOM_SNI) ,
mConnection);
// monitora a conexão
mConnection.addConnectionMonitor(this);
mConnected = true;
} catch(Exception e) {
/**
* Autenticação
*/
SkStatus.updateStateString(SkStatus.SSH_AUTENTICANDO,
mContext.getString(R.string.state_auth));
try {
if (mConnection.isAuthMethodAvailable(usuario,
AUTH_PASSWORD)) {
if (mConnection.authenticateWithPassword(usuario,
senha)) {
SkStatus.logInfo( mContext.getString(R.string.state_auth_success));
}
}
} catch (IllegalStateException e) {
Log.e(TAG,
"Connection went away while we were trying to
authenticate",
e);
} catch (Exception e) {
Log.e(TAG, "Problem during handleAuthentication()", e);
}
try {
if (mConnection.isAuthMethodAvailable(usuario,
if (mConnection.authenticateWithPublicKey(usuario, f,
senha)) {
SkStatus.logInfo("<strong>" +
mContext.getString(R.string.state_auth_success) + "</strong>");
}
}
}
} catch (Exception e) {
Log.d(TAG, "Host does not support 'Public key' authentication.");
}
/*try {
if (mConnection.authenticateWithNone(mSettings.usuario)) {
Log.d(TAG, "Authenticate with none");
return true;
}
} catch (Exception e) {
Log.d(TAG, "Host does not support 'none' authentication.");
}
try {
if (mConnection.isAuthMethodAvailable(mSettings.usuario,
AUTH_KEYBOARDINTERACTIVE)) {
if (mConnection.authenticateWithKeyboardInteractive(
mSettings.usuario, this))
return true;
}
} catch (Exception e) {
Log.d(TAG,
"Host does not support 'Keyboard-Interactive' authentication.");
}*/
if (!mConnection.isAuthenticationComplete()) {
SkStatus.logInfo("Failed to authenticate, User or Password
Expired");
// XXX: Is it right?
@Override
public String[] replyToChallenge(String name, String instruction,
int numPrompts, String[]
prompt, boolean[] echo) throws Exception {
String[] responses = new String[numPrompts];
for (int i = 0; i < numPrompts; i++) {
// request response from user for each prompt
if (prompt[i].toLowerCase().contains("password"))
responses[i] = mConfig.getPrivString(Settings.SENHA_KEY);
}
return responses;
}
/**
* ServerHostKeyVerifier
* Fingerprint
*/
@Override
public boolean verifyServerHostKey(String hostname, int port, String
keyAlgorithm, byte[] hostKey) throws Exception
{
String createHexFingerprint = KnownHosts.createHexFingerprint(keyAlgorithm,
hostKey);
String createHashedHostname = KnownHosts.createHashedHostname(hostname);
String createBubblebabbleFingerprint =
KnownHosts.createBubblebabbleFingerprint(keyAlgorithm, hostKey);
SkStatus.logInfo(new StringBuffer().append("Hostkey fingerprint:
").append(createHexFingerprint).toString());
//sshMsg(new StringBuffer().append("<b>Hashed Hostname:</b>
").append(createHashedHostname).toString());
//SkStatus.logInfo(new StringBuffer().append("<b>Bubble Babble
Fingerprint:</b> ").append(createBubblebabbleFingerprint).toString());
//SkStatus.logInfo(new StringBuffer().append("<b>Key exchange
algorithm:</b> ").append(hostKey).toString());
SkStatus.logInfo(new StringBuffer().append("Using algorithm:
").append(keyAlgorithm).toString());
return true;
}
/**
* Proxy
*/
if (mTunnelType != 0) {
useProxy = true;
switch (mTunnelType) {
case Settings.bTUNNEL_TYPE_SSH_DIRECT:
if (mCustomPayload != null) {
try {
ProxyData proxyData = new
HttpProxyCustom(mConfig.getPrivString(Settings.SERVIDOR_KEY),
Integer.parseInt(mConfig.getPrivString(Settings.SERVIDOR_PORTA_KEY)),
conn.setProxyData(proxyData);
} catch(Exception e) {
throw new
Exception(mContext.getString(R.string.error_proxy_invalid));
}
}
else {
useProxy = false;
}
break;
case Settings.bTUNNEL_TYPE_SSH_PROXY:
String customPayload = mCustomPayload;
String servidor =
mConfig.getPrivString(Settings.PROXY_IP_KEY);
int porta =
Integer.parseInt(mConfig.getPrivString(Settings.PROXY_PORTA_KEY));
try {
ProxyData proxyData = new
HttpProxyCustom(servidor, porta,
if (!isProteger)
// SkStatus.logInfo(String.format("Remote
Proxy: %s:%d", servidor, porta));
conn.setProxyData(proxyData);
} catch(Exception e) {
SkStatus.logError(R.string.error_proxy_invalid);
throw new
Exception(mContext.getString(R.string.error_proxy_invalid));
}
break;
case Settings.bTUNNEL_TYPE_SLOWDNS:
if (mCustomPayload != null) {
try {
ProxyData proxyData = new HttpProxyCustom("127.0.0.1",
Integer.parseInt("8989"),
null, null,
mCustomPayload, true, mContext);
conn.setProxyData(proxyData);
/** if (!mCustomPayload.isEmpty()
&& !isProteger)**/
SkStatus.logInfo(R.string.payload +
mCustomPayload);
} catch(Exception e) {
throw new
Exception(mContext.getString(R.string.error_proxy_invalid));
}
}
else {
useProxy = false;
}
break;
case Settings.bTUNNEL_TYPE_SSH_SSL:
String customSNI = mCustomSNI;
if (customSNI != null && customSNI.isEmpty()) {
customPayload = null;
}
String sshServer =
mConfig.getPrivString(Settings.SERVIDOR_KEY);
int sshPort =
Integer.parseInt(mConfig.getPrivString(Settings.SERVIDOR_PORTA_KEY));
try {
}catch(Exception e) {
SkStatus.logInfo(e.getMessage());
}
break;
case Settings.bTUNNEL_TYPE_SSL_PAYLOAD:
String customSNI2 = mCustomSNI;
if (customSNI2 != null && customSNI2.isEmpty()) {
customSNI2 = null;
}
String customPayload2 = mCustomPayload;
String sshServer2 =
mConfig.getPrivString(Settings.SERVIDOR_KEY);
int sshPort2 =
Integer.parseInt(mConfig.getPrivString(Settings.SERVIDOR_PORTA_KEY));
try{
} catch(Exception e) {
SkStatus.logInfo(e.getMessage());
}
break;
default: useProxy = false;
}
}
}
/**
* Socks5 Forwarder
*/
try {
if (nThreads > 0) {
dpf = mConnection.createDynamicPortForwarder(portaLocal,
nThreads);
} catch (Exception e) {
SkStatus.logError("Socks Local: " + e.getCause().toString());
throw new Exception();
}
}
/**
* Pinger
*/
if (timePing == 0)
return;
if (timePing > 0)
sleep(timePing*1000);
else {
SkStatus.logError("ping invalid");
throw new InterruptedException();
}
}
};
// inicia
thPing.start();
}
/**
* Connection Monitor
*/
@Override
public void connectionLost(Throwable reason)
{
if (mStarting || mStopping || mReconnecting) {
return;
}
SkStatus.logError("<strong>" +
mContext.getString(R.string.log_conection_lost) + "</strong>");
if (reason != null) {
if (reason.getMessage().contains(
"There was a problem during connect")) {
return;
} else if (reason.getMessage().contains(
"Closed due to user request")) {
return;
} else if (reason.getMessage().contains(
"The connect timeout expired")) {
stopAll();
return;
}
} else {
stopAll();
return;
}
reconnectSSH();
}
mReconnecting = true;
closeSSH();
SkStatus.updateStateString(SkStatus.SSH_RECONECTANDO,
"Reconnecting..");
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
mReconnecting = false;
return;
}
int sleepTime = 5;
if (!TunnelUtils.isNetworkOnline(mContext)) {
SkStatus.updateStateString(SkStatus.SSH_AGUARDANDO_REDE,
"Waiting for network ..");
SkStatus.logInfo(R.string.state_nonetwork);
}
else {
sleepTime = 3;
mStarting = true;
SkStatus.updateStateString(SkStatus.SSH_RECONECTANDO,
"Reconnecting..");
SkStatus.logInfo("<strong>" +
mContext.getString(R.string.state_reconnecting) + "</strong>");
try {
startClienteSSH();
mStarting = false;
mReconnecting = false;
//mConnected = true;
return;
} catch(Exception e) {
SkStatus.logInfo("<strong>" +
mContext.getString(R.string.state_disconnected) + "</strong>");
}
mStarting = false;
}
try {
Thread.sleep(sleepTime*1000);
i--;
} catch(InterruptedException e2){
mReconnecting = false;
return;
}
}
mReconnecting = false;
stopAll();
}
@Override
public void onReceiveInfo(int id, String msg) {
if (id == SERVER_BANNER) {
SkStatus.logInfo("<strong>" +
mContext.getString(R.string.log_server_banner) + "</strong> " + msg);
}
}
/**
* Debug Logger
*/
@Override
public void log(int level, String className, String message)
{
SkStatus.logDebug(String.format("%s: %s", className, message));
}
/**
* Vpn Tunnel
*/
String serverAddr;
// Broadcast
IntentFilter broadcastFilter =
new
IntentFilter(TunnelVpnService.TUNNEL_VPN_DISCONNECT_BROADCAST);
broadcastFilter.addAction(TunnelVpnService.TUNNEL_VPN_START_BROADCAST);
// Inicia Broadcast
LocalBroadcastManager.getInstance(mContext)
.registerReceiver(m_vpnTunnelBroadcastReceiver, broadcastFilter);
if (prefs.getInt(Settings.TUNNELTYPE_KEY,
Settings.bTUNNEL_TYPE_SSH_DIRECT) == Settings.bTUNNEL_TYPE_SSH_PROXY) {
try {
servidorIP = mConfig.getPrivString(Settings.PROXY_IP_KEY);
} catch(Exception e) {
SkStatus.logError(R.string.error_proxy_invalid);
throw new
IOException(mContext.getString(R.string.error_proxy_invalid));
}
}
try {
InetAddress servidorAddr =
TransportManager.createInetAddress(servidorIP);
serverAddr = servidorIP = servidorAddr.getHostAddress();
} catch(UnknownHostException e) {
throw new
IOException(mContext.getString(R.string.error_server_ip_invalid));
}
if (isServiceVpnRunning()) {
Log.d(TAG, "already running service");
if (tunnelManager != null) {
tunnelManager.restartTunnel(m_socksServerAddress);
}
return;
}
mConfig.getIsFilterApps(), mConfig.getIsFilterBypassMode(),
mConfig.getFilterApps(), mConfig.getIsTetheringSubnet(), mConfig.getBypass());
startTunnelVpn.putExtra(TunnelVpnManager.VPN_SETTINGS, settings);
if (mContext.startService(startTunnelVpn) == null) {
SkStatus.logInfo("failed to start tunnel vpn service");
throw new IOException("Vpn Service failed to start");
}
TunnelState.getTunnelState().setStartingTunnelManager();
}
if (currentTunnelManager != null) {
currentTunnelManager.signalStopService();
}
// Parando Broadcast
LocalBroadcastManager.getInstance(mContext)
.unregisterReceiver(m_vpnTunnelBroadcastReceiver);
}
// Local BroadcastReceiver
private BroadcastReceiver m_vpnTunnelBroadcastReceiver = new
BroadcastReceiver() {
@Override
public synchronized void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (TunnelVpnService.TUNNEL_VPN_START_BROADCAST.equals(action)) {
boolean startSuccess =
intent.getBooleanExtra(TunnelVpnService.TUNNEL_VPN_START_SUCCESS_EXTRA, true);
if (!startSuccess) {
stopAll();
}
} else if
(TunnelVpnService.TUNNEL_VPN_DISCONNECT_BROADCAST.equals(action)) {
stopAll();
}
}
};