fixes for transproxy/iptables rules
- not all rules were not being cleared in flush - per-app transproxy now still transproxies DNS for full device (not all DNS is done under the app UID) - root shell now created only once and shared across calls
This commit is contained in:
parent
ee10ac0f07
commit
08317a94d7
|
@ -76,7 +76,6 @@ import android.support.v4.app.NotificationCompat;
|
||||||
import android.support.v4.app.NotificationCompat.Builder;
|
import android.support.v4.app.NotificationCompat.Builder;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.RemoteViews;
|
import android.widget.RemoteViews;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
public class TorService extends Service implements TorServiceConstants, TorConstants, EventHandler
|
public class TorService extends Service implements TorServiceConstants, TorConstants, EventHandler
|
||||||
{
|
{
|
||||||
|
@ -420,7 +419,7 @@ public class TorService extends Service implements TorServiceConstants, TorConst
|
||||||
mCurrentStatus = STATUS_OFF;
|
mCurrentStatus = STATUS_OFF;
|
||||||
|
|
||||||
if (mHasRoot && mEnableTransparentProxy)
|
if (mHasRoot && mEnableTransparentProxy)
|
||||||
disableTransparentProxy();
|
disableTransparentProxy(Shell.startRootShell());
|
||||||
|
|
||||||
clearNotifications();
|
clearNotifications();
|
||||||
|
|
||||||
|
@ -762,8 +761,12 @@ public class TorService extends Service implements TorServiceConstants, TorConst
|
||||||
|
|
||||||
if (mHasRoot && mEnableTransparentProxy)
|
if (mHasRoot && mEnableTransparentProxy)
|
||||||
{
|
{
|
||||||
disableTransparentProxy();
|
Shell shell = Shell.startRootShell();
|
||||||
enableTransparentProxy();
|
|
||||||
|
disableTransparentProxy(shell);
|
||||||
|
enableTransparentProxy(shell);
|
||||||
|
|
||||||
|
shell.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
getHiddenServiceHostname ();
|
getHiddenServiceHostname ();
|
||||||
|
@ -802,7 +805,7 @@ public class TorService extends Service implements TorServiceConstants, TorConst
|
||||||
*
|
*
|
||||||
* the idea is that if Tor is off then transproxy is off
|
* the idea is that if Tor is off then transproxy is off
|
||||||
*/
|
*/
|
||||||
private boolean enableTransparentProxy () throws Exception
|
private boolean enableTransparentProxy (Shell shell) throws Exception
|
||||||
{
|
{
|
||||||
|
|
||||||
if (mTransProxy == null)
|
if (mTransProxy == null)
|
||||||
|
@ -824,39 +827,21 @@ public class TorService extends Service implements TorServiceConstants, TorConst
|
||||||
|
|
||||||
mTransProxy.setTransProxyPort(Integer.parseInt(transProxy));
|
mTransProxy.setTransProxyPort(Integer.parseInt(transProxy));
|
||||||
mTransProxy.setDNSPort(Integer.parseInt(dnsPort));
|
mTransProxy.setDNSPort(Integer.parseInt(dnsPort));
|
||||||
|
|
||||||
|
|
||||||
//TODO: Find a nice place for the next (commented) line
|
|
||||||
//TorTransProxy.setDNSProxying();
|
|
||||||
|
|
||||||
int code = 0; // Default state is "okay"
|
int code = 0; // Default state is "okay"
|
||||||
|
|
||||||
debug ("Transparent Proxying: clearing existing rules...");
|
|
||||||
|
|
||||||
//clear rules first
|
|
||||||
// mTransProxy.clearTransparentProxyingAll(this);
|
|
||||||
|
|
||||||
if(mTransProxyAll)
|
if(mTransProxyAll)
|
||||||
{
|
{
|
||||||
// showToolbarNotification(getString(R.string.setting_up_full_transparent_proxying_), TRANSPROXY_NOTIFY_ID, R.drawable.ic_stat_tor);
|
|
||||||
|
|
||||||
//clear existing rules
|
code = mTransProxy.setTransparentProxyingAll(this, true, shell);
|
||||||
//code = mTransProxy.setTransparentProxyingAll(this, false);
|
|
||||||
|
|
||||||
code = mTransProxy.setTransparentProxyingAll(this, true);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//showToolbarNotification(getString(R.string.setting_up_app_based_transparent_proxying_), TRANSPROXY_NOTIFY_ID, R.drawable.ic_stat_tor);
|
|
||||||
ArrayList<TorifiedApp> apps = AppManager.getApps(this, TorServiceUtils.getSharedPrefs(getApplicationContext()));
|
ArrayList<TorifiedApp> apps = AppManager.getApps(this, TorServiceUtils.getSharedPrefs(getApplicationContext()));
|
||||||
|
|
||||||
//clear exiting rules
|
|
||||||
//code = mTransProxy.setTransparentProxyingByApp(this,apps, false);
|
|
||||||
|
|
||||||
code = mTransProxy.setTransparentProxyingByApp(this,apps, true);
|
code = mTransProxy.setTransparentProxyingByApp(this,apps, true, shell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
debug ("TorTransProxy resp code: " + code);
|
debug ("TorTransProxy resp code: " + code);
|
||||||
|
|
||||||
if (code == 0)
|
if (code == 0)
|
||||||
|
@ -866,7 +851,7 @@ public class TorService extends Service implements TorServiceConstants, TorConst
|
||||||
{
|
{
|
||||||
showToolbarNotification(getString(R.string.transproxy_enabled_for_tethering_), TRANSPROXY_NOTIFY_ID, R.drawable.ic_stat_tor);
|
showToolbarNotification(getString(R.string.transproxy_enabled_for_tethering_), TRANSPROXY_NOTIFY_ID, R.drawable.ic_stat_tor);
|
||||||
|
|
||||||
mTransProxy.enableTetheringRules(this);
|
mTransProxy.enableTetheringRules(this, Shell.startRootShell());
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -890,7 +875,7 @@ public class TorService extends Service implements TorServiceConstants, TorConst
|
||||||
*
|
*
|
||||||
* the idea is that if Tor is off then transproxy is off
|
* the idea is that if Tor is off then transproxy is off
|
||||||
*/
|
*/
|
||||||
private boolean disableTransparentProxy () throws Exception
|
private boolean disableTransparentProxy (Shell shell) throws Exception
|
||||||
{
|
{
|
||||||
|
|
||||||
debug ("Transparent Proxying: disabling...");
|
debug ("Transparent Proxying: disabling...");
|
||||||
|
@ -898,9 +883,9 @@ public class TorService extends Service implements TorServiceConstants, TorConst
|
||||||
if (mTransProxy == null)
|
if (mTransProxy == null)
|
||||||
mTransProxy = new TorTransProxy(this, fileXtables);
|
mTransProxy = new TorTransProxy(this, fileXtables);
|
||||||
|
|
||||||
mTransProxy.setTransparentProxyingAll(this, false);
|
mTransProxy.setTransparentProxyingAll(this, false, shell);
|
||||||
ArrayList<TorifiedApp> apps = AppManager.getApps(this, TorServiceUtils.getSharedPrefs(getApplicationContext()));
|
ArrayList<TorifiedApp> apps = AppManager.getApps(this, TorServiceUtils.getSharedPrefs(getApplicationContext()));
|
||||||
mTransProxy.setTransparentProxyingByApp(this, apps, false);
|
mTransProxy.setTransparentProxyingByApp(this, apps, false, shell);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1735,14 +1720,15 @@ public class TorService extends Service implements TorServiceConstants, TorConst
|
||||||
|
|
||||||
if (mHasRoot)
|
if (mHasRoot)
|
||||||
{
|
{
|
||||||
if (hadEnableTransparentProxy)
|
Shell shell = Shell.startRootShell();
|
||||||
disableTransparentProxy();
|
|
||||||
|
|
||||||
if (mEnableTransparentProxy)
|
if (hadEnableTransparentProxy)
|
||||||
{
|
disableTransparentProxy(shell);
|
||||||
disableTransparentProxy();
|
|
||||||
enableTransparentProxy();
|
if (mEnableTransparentProxy)
|
||||||
}
|
enableTransparentProxy(shell);
|
||||||
|
|
||||||
|
shell.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2056,8 +2042,13 @@ public class TorService extends Service implements TorServiceConstants, TorConst
|
||||||
|
|
||||||
if (mHasRoot && mEnableTransparentProxy && mTransProxyNetworkRefresh)
|
if (mHasRoot && mEnableTransparentProxy && mTransProxyNetworkRefresh)
|
||||||
{
|
{
|
||||||
disableTransparentProxy();
|
|
||||||
enableTransparentProxy();
|
Shell shell = Shell.startRootShell();
|
||||||
|
|
||||||
|
disableTransparentProxy(shell);
|
||||||
|
enableTransparentProxy(shell);
|
||||||
|
|
||||||
|
shell.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ public class TorTransProxy implements TorServiceConstants {
|
||||||
private TorService mTorService = null;
|
private TorService mTorService = null;
|
||||||
private File mFileXtables = null;
|
private File mFileXtables = null;
|
||||||
|
|
||||||
private final static String ALLOW_LOCAL = " ! -o lo ! -d 127.0.0.1 ! -s 127.0.0.1 ";
|
private final static String ALLOW_LOCAL = " ! -d 127.0.0.1";
|
||||||
|
|
||||||
private int mTransProxyPort = TorServiceConstants.TOR_TRANSPROXY_PORT_DEFAULT;
|
private int mTransProxyPort = TorServiceConstants.TOR_TRANSPROXY_PORT_DEFAULT;
|
||||||
private int mDNSPort = TorServiceConstants.TOR_DNS_PORT_DEFAULT;
|
private int mDNSPort = TorServiceConstants.TOR_DNS_PORT_DEFAULT;
|
||||||
|
@ -335,7 +335,7 @@ public class TorTransProxy implements TorServiceConstants {
|
||||||
return code;
|
return code;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
public int setTransparentProxyingByApp(Context context, ArrayList<TorifiedApp> apps, boolean enableRule) throws Exception
|
public int setTransparentProxyingByApp(Context context, ArrayList<TorifiedApp> apps, boolean enableRule, Shell shell) throws Exception
|
||||||
{
|
{
|
||||||
String ipTablesPath = getIpTablesPath(context);
|
String ipTablesPath = getIpTablesPath(context);
|
||||||
|
|
||||||
|
@ -353,30 +353,45 @@ public class TorTransProxy implements TorServiceConstants {
|
||||||
|
|
||||||
//reset script
|
//reset script
|
||||||
|
|
||||||
Shell shell = Shell.startRootShell();
|
|
||||||
int lastExit = -1;
|
int lastExit = -1;
|
||||||
StringBuilder script;
|
StringBuilder script;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Same for DNS
|
||||||
|
script = new StringBuilder();
|
||||||
|
script.append(ipTablesPath);
|
||||||
|
script.append(" -t nat");
|
||||||
|
script.append(action).append(srcChainName);
|
||||||
|
script.append(" -p udp");
|
||||||
|
//script.append(" -m owner --uid-owner ");
|
||||||
|
//script.append(tApp.getUid());
|
||||||
|
//script.append(" -m udp --dport ");
|
||||||
|
script.append(" --dport ");
|
||||||
|
script.append(STANDARD_DNS_PORT);
|
||||||
|
script.append(" -j REDIRECT --to-ports ");
|
||||||
|
script.append(mDNSPort);
|
||||||
|
executeCommand (shell, script.toString());
|
||||||
|
|
||||||
// Allow everything for Tor
|
// Allow everything for Tor
|
||||||
|
|
||||||
//build up array of shell cmds to execute under one root context
|
//build up array of shell cmds to execute under one root context
|
||||||
for (TorifiedApp tApp:apps)
|
for (TorifiedApp tApp:apps)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (tApp.isTorified()
|
if (((!enableRule) || tApp.isTorified())
|
||||||
&& (!tApp.getUsername().equals(TorServiceConstants.TOR_APP_USERNAME))
|
&& (!tApp.getUsername().equals(TorServiceConstants.TOR_APP_USERNAME))
|
||||||
) //if app is set to true
|
) //if app is set to true
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
logMessage("enabling transproxy for app: " + tApp.getUsername() + " (" + tApp.getUid() + ")");
|
logMessage("transproxy for app: " + tApp.getUsername() + " (" + tApp.getUid() + "): enable=" + enableRule);
|
||||||
|
|
||||||
dropAllIPv6Traffic(context, tApp.getUid(),enableRule);
|
dropAllIPv6Traffic(context, tApp.getUid(),enableRule, shell);
|
||||||
|
|
||||||
script = new StringBuilder();
|
script = new StringBuilder();
|
||||||
|
|
||||||
// Allow loopback
|
// Allow loopback
|
||||||
|
/**
|
||||||
script.append(ipTablesPath);
|
script.append(ipTablesPath);
|
||||||
script.append(" -t filter");
|
script.append(" -t filter");
|
||||||
script.append(action).append(srcChainName);
|
script.append(action).append(srcChainName);
|
||||||
|
@ -387,6 +402,7 @@ public class TorTransProxy implements TorServiceConstants {
|
||||||
|
|
||||||
executeCommand (shell, script.toString());
|
executeCommand (shell, script.toString());
|
||||||
script = new StringBuilder();
|
script = new StringBuilder();
|
||||||
|
**/
|
||||||
|
|
||||||
// Set up port redirection
|
// Set up port redirection
|
||||||
script.append(ipTablesPath);
|
script.append(ipTablesPath);
|
||||||
|
@ -401,21 +417,8 @@ public class TorTransProxy implements TorServiceConstants {
|
||||||
script.append(mTransProxyPort);
|
script.append(mTransProxyPort);
|
||||||
|
|
||||||
executeCommand (shell, script.toString());
|
executeCommand (shell, script.toString());
|
||||||
script = new StringBuilder();
|
|
||||||
|
|
||||||
// Same for DNS
|
|
||||||
script.append(ipTablesPath);
|
|
||||||
script.append(" -t nat");
|
|
||||||
script.append(action).append(srcChainName);
|
|
||||||
script.append(" -p udp");
|
|
||||||
script.append(" -m owner --uid-owner ");
|
|
||||||
script.append(tApp.getUid());
|
|
||||||
script.append(" -m udp --dport ");
|
|
||||||
script.append(STANDARD_DNS_PORT);
|
|
||||||
script.append(" -j REDIRECT --to-ports ");
|
|
||||||
script.append(mDNSPort);
|
|
||||||
|
|
||||||
executeCommand (shell, script.toString());
|
|
||||||
script = new StringBuilder();
|
script = new StringBuilder();
|
||||||
|
|
||||||
// Reject all other outbound packets
|
// Reject all other outbound packets
|
||||||
|
@ -433,14 +436,12 @@ public class TorTransProxy implements TorServiceConstants {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shell.close();
|
|
||||||
|
|
||||||
return lastExit;
|
return lastExit;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int executeCommand (Shell shell, String cmdString) throws IOException, TimeoutException
|
private int executeCommand (Shell shell, String cmdString) throws IOException, TimeoutException
|
||||||
{
|
{
|
||||||
SimpleCommand cmd = new SimpleCommand(cmdString + "|| exit");
|
SimpleCommand cmd = new SimpleCommand(cmdString);
|
||||||
shell.add(cmd);
|
shell.add(cmd);
|
||||||
int exitCode = cmd.getExitCode();
|
int exitCode = cmd.getExitCode();
|
||||||
String output = cmd.getOutput();
|
String output = cmd.getOutput();
|
||||||
|
@ -451,7 +452,7 @@ public class TorTransProxy implements TorServiceConstants {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public int enableTetheringRules (Context context) throws Exception
|
public int enableTetheringRules (Context context, Shell shell) throws Exception
|
||||||
{
|
{
|
||||||
|
|
||||||
String ipTablesPath = getIpTablesPath(context);
|
String ipTablesPath = getIpTablesPath(context);
|
||||||
|
@ -460,7 +461,6 @@ public class TorTransProxy implements TorServiceConstants {
|
||||||
|
|
||||||
String[] hwinterfaces = {"usb0","wl0.1"};
|
String[] hwinterfaces = {"usb0","wl0.1"};
|
||||||
|
|
||||||
Shell shell = Shell.startRootShell();
|
|
||||||
|
|
||||||
int lastExit = -1;
|
int lastExit = -1;
|
||||||
|
|
||||||
|
@ -492,8 +492,6 @@ public class TorTransProxy implements TorServiceConstants {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
shell.close();
|
|
||||||
|
|
||||||
return lastExit;
|
return lastExit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -505,12 +503,10 @@ public class TorTransProxy implements TorServiceConstants {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public int fixTransproxyLeak (Context context) throws Exception
|
public int fixTransproxyLeak (Context context, Shell shell) throws Exception
|
||||||
{
|
{
|
||||||
String ipTablesPath = getIpTablesPath(context);
|
String ipTablesPath = getIpTablesPath(context);
|
||||||
|
|
||||||
Shell shell = Shell.startRootShell();
|
|
||||||
|
|
||||||
StringBuilder script = new StringBuilder();
|
StringBuilder script = new StringBuilder();
|
||||||
script.append(ipTablesPath);
|
script.append(ipTablesPath);
|
||||||
script.append(" -I OUTPUT ! -o lo ! -d 127.0.0.1 ! -s 127.0.0.1 -p tcp -m tcp --tcp-flags ACK,FIN ACK,FIN -j DROP");
|
script.append(" -I OUTPUT ! -o lo ! -d 127.0.0.1 ! -s 127.0.0.1 -p tcp -m tcp --tcp-flags ACK,FIN ACK,FIN -j DROP");
|
||||||
|
@ -525,13 +521,11 @@ public class TorTransProxy implements TorServiceConstants {
|
||||||
int lastExit = executeCommand (shell, script.toString());
|
int lastExit = executeCommand (shell, script.toString());
|
||||||
script = new StringBuilder();
|
script = new StringBuilder();
|
||||||
|
|
||||||
shell.close();
|
|
||||||
|
|
||||||
return lastExit;
|
return lastExit;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int dropAllIPv6Traffic (Context context, int appUid, boolean enableDrop) throws Exception
|
public int dropAllIPv6Traffic (Context context, int appUid, boolean enableDrop, Shell shell) throws Exception
|
||||||
{
|
{
|
||||||
|
|
||||||
String action = " -A ";
|
String action = " -A ";
|
||||||
|
@ -541,9 +535,7 @@ public class TorTransProxy implements TorServiceConstants {
|
||||||
action = " -D ";
|
action = " -D ";
|
||||||
|
|
||||||
String ip6tablesPath = getIp6TablesPath(context);
|
String ip6tablesPath = getIp6TablesPath(context);
|
||||||
Shell shell = Shell.startRootShell();
|
|
||||||
|
|
||||||
|
|
||||||
StringBuilder script;
|
StringBuilder script;
|
||||||
|
|
||||||
script = new StringBuilder();
|
script = new StringBuilder();
|
||||||
|
@ -561,8 +553,6 @@ public class TorTransProxy implements TorServiceConstants {
|
||||||
|
|
||||||
int lastExit = executeCommand (shell, script.toString());
|
int lastExit = executeCommand (shell, script.toString());
|
||||||
|
|
||||||
shell.close();
|
|
||||||
|
|
||||||
return lastExit;
|
return lastExit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -589,27 +579,29 @@ public class TorTransProxy implements TorServiceConstants {
|
||||||
public int flushTransproxyRules (Context context) throws Exception
|
public int flushTransproxyRules (Context context) throws Exception
|
||||||
{
|
{
|
||||||
int exit = -1;
|
int exit = -1;
|
||||||
|
|
||||||
String ipTablesPath = getIpTablesPath(context);
|
String ipTablesPath = getIpTablesPath(context);
|
||||||
|
Shell shell = Shell.startRootShell();
|
||||||
|
|
||||||
StringBuilder script = new StringBuilder();
|
StringBuilder script = new StringBuilder();
|
||||||
script.append(ipTablesPath);
|
script.append(ipTablesPath);
|
||||||
script.append(" -t nat");
|
script.append(" -t nat ");
|
||||||
script.append(" -F ");
|
script.append(" -F ");
|
||||||
|
|
||||||
Shell shell = Shell.startRootShell();
|
executeCommand (shell, script.toString());
|
||||||
executeCommand (shell, script.toString());
|
|
||||||
|
|
||||||
script = new StringBuilder();
|
script = new StringBuilder();
|
||||||
script.append(ipTablesPath);
|
script.append(ipTablesPath);
|
||||||
script.append(" -t filter");
|
script.append(" -t filter ");
|
||||||
script.append(" -F ");
|
script.append(" -F ");
|
||||||
|
executeCommand (shell, script.toString());
|
||||||
|
|
||||||
dropAllIPv6Traffic(context,-1,false);
|
dropAllIPv6Traffic(context,-1,false, shell);
|
||||||
|
|
||||||
return exit;
|
return exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int setTransparentProxyingAll(Context context, boolean enable) throws Exception
|
public int setTransparentProxyingAll(Context context, boolean enable, Shell shell) throws Exception
|
||||||
{
|
{
|
||||||
|
|
||||||
String action = " -A ";
|
String action = " -A ";
|
||||||
|
@ -617,12 +609,11 @@ public class TorTransProxy implements TorServiceConstants {
|
||||||
|
|
||||||
if (!enable)
|
if (!enable)
|
||||||
action = " -D ";
|
action = " -D ";
|
||||||
|
|
||||||
dropAllIPv6Traffic(context,-1,enable);
|
dropAllIPv6Traffic(context,-1,enable, shell);
|
||||||
|
|
||||||
String ipTablesPath = getIpTablesPath(context);
|
String ipTablesPath = getIpTablesPath(context);
|
||||||
|
|
||||||
Shell shell = Shell.startRootShell();
|
|
||||||
|
|
||||||
int torUid = context.getApplicationInfo().uid;
|
int torUid = context.getApplicationInfo().uid;
|
||||||
|
|
||||||
|
@ -674,7 +665,8 @@ public class TorTransProxy implements TorServiceConstants {
|
||||||
script.append(ALLOW_LOCAL); //allow access to localhost
|
script.append(ALLOW_LOCAL); //allow access to localhost
|
||||||
script.append(" -m owner ! --uid-owner ");
|
script.append(" -m owner ! --uid-owner ");
|
||||||
script.append(torUid);
|
script.append(torUid);
|
||||||
script.append(" -m udp --dport ");
|
//script.append(" -m udp --dport ");
|
||||||
|
script.append(" --dport ");
|
||||||
script.append(STANDARD_DNS_PORT);
|
script.append(STANDARD_DNS_PORT);
|
||||||
script.append(" -j REDIRECT --to-ports ");
|
script.append(" -j REDIRECT --to-ports ");
|
||||||
script.append(mDNSPort);
|
script.append(mDNSPort);
|
||||||
|
@ -773,8 +765,6 @@ public class TorTransProxy implements TorServiceConstants {
|
||||||
|
|
||||||
// fixTransproxyLeak (context);
|
// fixTransproxyLeak (context);
|
||||||
|
|
||||||
shell.close();
|
|
||||||
|
|
||||||
return lastExit;
|
return lastExit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue