You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
846 lines
25 KiB
Java
846 lines
25 KiB
Java
/*
|
|
* Copyright (C) 2009-2017 Alistair Neil <info@dazzleships.net>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
package client;
|
|
|
|
import java.io.BufferedReader;
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.io.InputStreamReader;
|
|
import java.net.URI;
|
|
import java.util.Iterator;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
import java.util.regex.Pattern;
|
|
import javax.swing.JTextArea;
|
|
import javax.swing.text.BadLocationException;
|
|
import lib.ClientProcess;
|
|
import lib.SimpleFile;
|
|
|
|
/**
|
|
*
|
|
* @author Alistair Neil <info@dazzleships.net>
|
|
*/
|
|
public class TorProcess extends ClientProcess {
|
|
|
|
public static final int LOG_DEBUG = 0;
|
|
public static final int LOG_INFO = 1;
|
|
public static final int LOG_NOTICE = 2;
|
|
private static final String TORCONFIGFILE = "torrc";
|
|
public static final String EMPTYSTRING = "";
|
|
|
|
// Event constants
|
|
public static final int TOR_MESSAGE = 0;
|
|
public static final int TOR_BOOT_TIMEOUT = 1;
|
|
public static final int TOR_BOOT_FATAL = 2;
|
|
public static final int TOR_BOOT_ERROR = 3;
|
|
public static final int TOR_CLOCK_ERROR = 4;
|
|
public static final int TOR_NOROUTE = 5;
|
|
public static final int TOR_BOOTED = 6;
|
|
public static final int TOR_RESTARTED = 7;
|
|
public static final int TOR_NOEXITS = 8;
|
|
public static final int TOR_STOPPED = 9;
|
|
public static final int TOR_BRIDGE = 10;
|
|
public static final int TOR_NEWCIRC = 11;
|
|
public static final int TOR_DIRINFO_STALE = 12;
|
|
public static final int TOR_NOHOP0 = 13;
|
|
public static final int TOR_NONET_ACTIVITY = 14;
|
|
private static final String[] EVENTMESSAGES = new String[]{
|
|
"TOR_MESSAGE", "TOR_BOOT_TIMEOUT", "TOR_BOOT_FATAL", "TOR_BOOT_ERROR",
|
|
"TOR_CLOCK_ERROR", "TOR_NOROUTE", "TOR_BOOTED", "TOR_RESTARTED",
|
|
"TOR_NOEXITS", "TOR_STOPPED", "TOR_BRIDGE", "TOR_NEWCIRC",
|
|
"TOR_DIRINFO_STALE", "TOR_NOHOP0", "TOR_NONET_ACTIVITY"
|
|
};
|
|
|
|
private final LinkedHashMap<String, String> lhmCLIOptions;
|
|
private final LinkedHashMap<String, String> lhmTorrcOptions;
|
|
private final String strClientLocation;
|
|
private final String strConfigFolder;
|
|
private String strSecret;
|
|
private String strCachedDataFolder;
|
|
private String invCommas = "\"";
|
|
private String strExternalArgs = "";
|
|
private String strBridges = "";
|
|
private int intListenPort;
|
|
private int intInitialBootEvent;
|
|
private int loglev = LOG_NOTICE;
|
|
private float version = 9999;
|
|
private int maxlines = 50;
|
|
private int nolines;
|
|
private JTextArea jtxtstdout;
|
|
private boolean boolSilentBoot;
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param clientpath Path to Tor client
|
|
* @param configfolder Filepath to torrc
|
|
*/
|
|
public TorProcess(String clientpath, String configfolder) {
|
|
setSilentBootEnabled(false);
|
|
strClientLocation = clientpath;
|
|
this.intInitialBootEvent = TOR_BOOTED;
|
|
this.strConfigFolder = configfolder;
|
|
this.lhmCLIOptions = new LinkedHashMap<>();
|
|
this.lhmTorrcOptions = new LinkedHashMap<>();
|
|
// All our initialisation
|
|
if (SimpleFile.getSeparator().compareTo("/") == 0) {
|
|
this.invCommas = "";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Starts Tor process, and issues booted event on completion
|
|
*
|
|
*/
|
|
public final void startProcess() {
|
|
setStartupTimeout(60);
|
|
// Cache age check
|
|
float age = getCacheAge();
|
|
Logger.getGlobal().logp(Level.INFO, TorProcess.class.getName(),
|
|
"start() on Port=" + getListenPort(), "Cache age = " + (int) age + " minutes.");
|
|
if (age > 180) {
|
|
deleteCacheData();
|
|
Logger.getGlobal().logp(Level.INFO, TorProcess.class.getName(),
|
|
"start() on Port=" + getListenPort(), "Cache stale, deleting old cache data.");
|
|
}
|
|
// Some essential initialisation
|
|
String strConfig = strClientLocation
|
|
+ " -f " + invCommas
|
|
+ getConfigFilePath()
|
|
+ invCommas
|
|
+ " " + getCLIOptionsAsString()
|
|
+ " " + strExternalArgs;
|
|
Logger.getGlobal().logp(Level.INFO, TorProcess.class.getName(),
|
|
"start() on Port=" + getListenPort(),
|
|
"INFO: starting with " + strConfig );
|
|
super.start(strConfig);
|
|
}
|
|
|
|
/**
|
|
* Set the Tor stdout log level
|
|
*
|
|
* @param lev
|
|
*/
|
|
public final void setLogLevel(int lev) {
|
|
loglev = lev;
|
|
}
|
|
|
|
/**
|
|
* Set external user provided startup arguments
|
|
*
|
|
* @param torargs
|
|
*/
|
|
public final void setExternalArgs(String torargs) {
|
|
strExternalArgs = torargs;
|
|
}
|
|
|
|
/**
|
|
* Set the listening port
|
|
*
|
|
* @param port
|
|
*/
|
|
public final void setListenPort(int port) {
|
|
// Setup listening port and control port
|
|
if (intListenPort == port) {
|
|
return;
|
|
}
|
|
intListenPort = port;
|
|
setCLIOption("SocksPort", "127.0.0.1:" + String.valueOf(port));
|
|
setCLIOption("ControlSocket", "/run/tor/control");
|
|
setCLIOption("ControlPort", "127.0.0.1:" + String.valueOf(port + 1));
|
|
// Finish of by creating the default config file and data folders
|
|
createDataFolder();
|
|
}
|
|
|
|
/**
|
|
* Set the event that is issued on process boot completion
|
|
*
|
|
* @param event
|
|
*/
|
|
public final void setInitialBootEvent(int event) {
|
|
intInitialBootEvent = event;
|
|
}
|
|
|
|
/**
|
|
* Client event handler, can be overriden by parent class
|
|
*
|
|
* @param data line data from standard output of Tor client
|
|
*/
|
|
@Override
|
|
public final void clientProcessEventFired(String data) {
|
|
|
|
Logger.getGlobal().logp(Level.FINER, TorProcess.class.getName(),
|
|
"clientProcessEventFired() on Port=" + getListenPort(), data);
|
|
|
|
if (!data.isEmpty()) {
|
|
appendStdout(data);
|
|
}
|
|
|
|
// Check for process stopped
|
|
if (getClientStatus() == CLIENT_STOPPED) {
|
|
torProcessEventFired(TOR_STOPPED, null);
|
|
return;
|
|
}
|
|
|
|
// Check for timeout
|
|
if (getClientStatus() == CLIENT_TIMEDOUT) {
|
|
torProcessEventFired(TOR_BOOT_TIMEOUT, null);
|
|
return;
|
|
}
|
|
|
|
if (getClientStatus() == CLIENT_RUNNING) {
|
|
// Check to see if we need to copy cache
|
|
if (strCachedDataFolder != null) {
|
|
SimpleFile.copyFolderContents(strCachedDataFolder, getDataFolder() + SimpleFile.getSeparator(), "torrc");
|
|
strCachedDataFolder = null;
|
|
}
|
|
// Check for fatal tor process startup errors
|
|
if (data.contains("[warn] Our clock")) {
|
|
torProcessEventFired(TOR_CLOCK_ERROR, data);
|
|
return;
|
|
}
|
|
// Check for errors
|
|
if (data.contains("exception") || data.contains("[err]")) {
|
|
torProcessEventFired(TOR_BOOT_FATAL, data);
|
|
return;
|
|
}
|
|
// Check for network unreachable
|
|
if (data.contains("NOROUTE")) {
|
|
torProcessEventFired(TOR_NOROUTE, data);
|
|
return;
|
|
}
|
|
// Check new tor bridge
|
|
if (data.contains("[notice] new bridge")) {
|
|
torProcessEventFired(TOR_BRIDGE, data);
|
|
return;
|
|
}
|
|
// Check for conditions that may prevent circuit building
|
|
if (data.contains("directory information is no longer up-to-date")) {
|
|
torProcessEventFired(TOR_DIRINFO_STALE, data);
|
|
return;
|
|
}
|
|
// Check for conditions that will prevent circuit building
|
|
if (data.contains("All routers are down")) {
|
|
torProcessEventFired(TOR_NOEXITS, data);
|
|
return;
|
|
}
|
|
// Check for Tor retrying on new circuit
|
|
if (data.contains("Retrying on a new circuit")) {
|
|
torProcessEventFired(TOR_NEWCIRC, data);
|
|
return;
|
|
}
|
|
// Check for Tor failed to find hop zero
|
|
if (data.contains("Failed to find node for hop 0")) {
|
|
torProcessEventFired(TOR_NOHOP0, data);
|
|
return;
|
|
}
|
|
// Check for no net activity
|
|
if (data.contains("Tor has not observed any network activity")) {
|
|
torProcessEventFired(TOR_NONET_ACTIVITY, data);
|
|
return;
|
|
}
|
|
// Check for a bootstrap message
|
|
if (data.contains("Bootstrapped")) {
|
|
// If silent then dont fire bootstrapping messages
|
|
if (!boolSilentBoot) {
|
|
torProcessEventFired(TOR_MESSAGE, data.substring(data.indexOf(']') + 2));
|
|
}
|
|
int percent = getPercentage(data);
|
|
// Set startup timeout based on percentage of Tor progression
|
|
if (percent >= 15) {
|
|
setStartupTimeout(60);
|
|
}
|
|
if (percent >= 40) {
|
|
setStartupTimeout(120);
|
|
}
|
|
if (percent >= 80) {
|
|
setStartupTimeout(30);
|
|
}
|
|
// Check for initial bootup completion
|
|
if (percent >= 100) {
|
|
setStartupTimeout(-1);
|
|
torProcessEventFired(intInitialBootEvent, null);
|
|
intInitialBootEvent = TOR_BOOTED;
|
|
setSilentBootEnabled(false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get percentage value from bootstrap message
|
|
*
|
|
* @param data
|
|
* @return percentage as and int
|
|
*/
|
|
private int getPercentage(String data) {
|
|
int result = -1;
|
|
int idx1 = data.indexOf("Bootstrapped ");
|
|
if (idx1 > -1) {
|
|
idx1 += 13;
|
|
int idx2 = data.indexOf('%', idx1);
|
|
if (idx2 > -1) {
|
|
String temp = data.substring(idx1, idx2);
|
|
result = Integer.parseInt(temp);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Enable/Disable bootstrap message events on startup
|
|
*
|
|
* @param enabled
|
|
*/
|
|
public final void setSilentBootEnabled(boolean enabled) {
|
|
boolSilentBoot = enabled;
|
|
}
|
|
|
|
/**
|
|
* Get textual representation on an event
|
|
*
|
|
* @param event
|
|
* @return Event as text
|
|
*/
|
|
public String getEventMessage(int event) {
|
|
return EVENTMESSAGES[event];
|
|
}
|
|
|
|
/**
|
|
* Called if an event was fired, will be overidden by sub class
|
|
*
|
|
* @param event
|
|
* @param data
|
|
*/
|
|
public void torProcessEventFired(int event, String data) {
|
|
}
|
|
|
|
public final void setControlPassword(String secret, String hashpass) {
|
|
strSecret = secret;
|
|
setCLIOption("hashedcontrolpassword", hashpass);
|
|
}
|
|
|
|
/**
|
|
* Get the currently set authentification secret
|
|
*
|
|
* @return String
|
|
*/
|
|
public final String getSecret() {
|
|
return strSecret;
|
|
}
|
|
|
|
/**
|
|
* Set Tor bridges, supports multiple addresses
|
|
*
|
|
* @param bridges
|
|
*/
|
|
public final void setBridges(String bridges) {
|
|
|
|
clearCLIOption("UseBridges");
|
|
clearCLIOption("Bridge");
|
|
clearCLIOption("UpdateBridgesFromAuthority");
|
|
strBridges = "";
|
|
if (bridges == null || bridges.isEmpty()) {
|
|
return;
|
|
}
|
|
StringBuilder sbBridgesOption = new StringBuilder();
|
|
String sep = "";
|
|
String[] arrBridges = Pattern.compile(",").split(bridges);
|
|
for (String s : arrBridges) {
|
|
sbBridgesOption.append(sep);
|
|
sbBridgesOption.append(s);
|
|
if (sep.isEmpty()) {
|
|
sep = " --Bridge ";
|
|
}
|
|
}
|
|
strBridges = bridges;
|
|
setCLIOption("UseBridges", "1");
|
|
setCLIOption("UpdateBridgesFromAuthority", "1");
|
|
setCLIOption("Bridge", sbBridgesOption.toString());
|
|
}
|
|
|
|
/**
|
|
* Validate bridge addresses
|
|
*
|
|
* @param bridges
|
|
* @return true if valid
|
|
*/
|
|
public boolean validateBridges(String bridges) {
|
|
if (bridges.isEmpty()) {
|
|
return true;
|
|
}
|
|
String[] arrBridges = Pattern.compile(",").split(bridges);
|
|
for (String s : arrBridges) {
|
|
if (!validateHostPort(s)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Validate a host:port ipv4 address
|
|
*
|
|
* @param hostport
|
|
* @return true if valid
|
|
*/
|
|
public final boolean validateHostPort(String hostport) {
|
|
|
|
try {
|
|
URI uri = new URI("my://" + hostport); // may throw URISyntaxException
|
|
if (uri.getHost() == null || uri.getPort() == -1) {
|
|
return false;
|
|
}
|
|
} catch (Exception ex) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get bridges
|
|
*
|
|
* @return bridges as csv string
|
|
*/
|
|
public final String getBridges() {
|
|
return strBridges;
|
|
}
|
|
|
|
/**
|
|
* Set Ownership process id, useful for proper process termination in event
|
|
* of a crash
|
|
*
|
|
* @param processid
|
|
*/
|
|
public void setOwnershipID(String processid) {
|
|
this.setCLIOption("__OwningControllerProcess", processid);
|
|
}
|
|
|
|
/**
|
|
* Return the currently set process ownership ID
|
|
*
|
|
* @return String process id
|
|
*/
|
|
public String getOwnershipID() {
|
|
return getCLIOptions("__OwningControllerProcess");
|
|
}
|
|
|
|
/**
|
|
* Set the path to the geoip file
|
|
*
|
|
* @param filepath File location
|
|
*/
|
|
public final void setGeoIP4(String filepath) {
|
|
if (filepath != null) {
|
|
if (SimpleFile.exists(filepath)) {
|
|
setTorrcOption("GeoIPFile", invCommas + filepath + invCommas);
|
|
} else {
|
|
clearTorrcOption("GeoIPFile");
|
|
}
|
|
} else {
|
|
clearTorrcOption("GeoIPFile");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the path to the geoip file
|
|
*
|
|
* @param filepath File location
|
|
*/
|
|
public final void setGeoIP6(String filepath) {
|
|
if (filepath != null) {
|
|
if (SimpleFile.exists(filepath)) {
|
|
setTorrcOption("GeoIPv6File", invCommas + filepath + invCommas);
|
|
} else {
|
|
clearTorrcOption("GeoIPv6File");
|
|
}
|
|
} else {
|
|
clearTorrcOption("GeoIPv6File");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get Tor client location as a filepath
|
|
*
|
|
* @return filepath as string
|
|
*/
|
|
public final String getClientLocation() {
|
|
return strClientLocation;
|
|
}
|
|
|
|
/**
|
|
* Get the path to the configuration file
|
|
*
|
|
* @return String Path to configuration file
|
|
*/
|
|
public final String getConfigFilePath() {
|
|
return getDataFolder() + File.separator + TORCONFIGFILE;
|
|
}
|
|
|
|
/**
|
|
* Get a previously added tor option string
|
|
*
|
|
* @param option Tor option key
|
|
* @return String Tor option value
|
|
*/
|
|
public final String getCLIOptions(String option) {
|
|
return lhmCLIOptions.get(option);
|
|
}
|
|
|
|
/**
|
|
* Add a tor option string which is passed to the tor client on startup. See
|
|
* Tor documentation for valid options.
|
|
*
|
|
* @param option
|
|
* @param value
|
|
*/
|
|
public final void setCLIOption(String option, String value) {
|
|
lhmCLIOptions.put(option, value);
|
|
}
|
|
|
|
/**
|
|
* Add a tor option boolean value
|
|
*
|
|
* @param option
|
|
* @param value
|
|
*/
|
|
public final void setBoolTorOption(String option, boolean value) {
|
|
lhmCLIOptions.remove(option);
|
|
if (value) {
|
|
lhmCLIOptions.put(option, "1");
|
|
} else {
|
|
lhmCLIOptions.put(option, "0");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a previously added tor option string
|
|
*
|
|
* @param option Tor option key
|
|
* @return String Tor option value
|
|
*/
|
|
public final String getTorrcOption(String option) {
|
|
return lhmTorrcOptions.get(option);
|
|
}
|
|
|
|
/**
|
|
* Add a torrc option string See Tor documentation for valid options.
|
|
*
|
|
* @param option
|
|
* @param value
|
|
*/
|
|
public final void setTorrcOption(String option, String value) {
|
|
if (value.startsWith("\"")) {
|
|
value = value.replace('\\', '/');
|
|
}
|
|
lhmTorrcOptions.put(option, value);
|
|
}
|
|
|
|
/**
|
|
* Gets all the currently set torrc options as single String
|
|
*
|
|
* @return String Tor client formatted cli arguments
|
|
*/
|
|
public final String getTorrcOptionsAsString() {
|
|
Iterator<String> iterator = lhmTorrcOptions.keySet().iterator();
|
|
String key;
|
|
StringBuilder sbResult = new StringBuilder();
|
|
while (iterator.hasNext()) {
|
|
key = iterator.next();
|
|
sbResult.append(key);
|
|
sbResult.append(" ");
|
|
sbResult.append(lhmTorrcOptions.get(key));
|
|
sbResult.append("\r\n");
|
|
}
|
|
return sbResult.toString();
|
|
}
|
|
|
|
/**
|
|
* Remove previously add torrc option
|
|
*
|
|
* @param option
|
|
*/
|
|
public final void clearTorrcOption(String option) {
|
|
lhmTorrcOptions.remove(option);
|
|
}
|
|
|
|
/**
|
|
* Get a previously added tor option boolean value
|
|
*
|
|
* @param option Tor option key
|
|
* @return Boolean value
|
|
*/
|
|
public final boolean getCLIOptionBool(String option) {
|
|
return lhmCLIOptions.get(option).contentEquals("1");
|
|
}
|
|
|
|
/**
|
|
* Remove previously add tor option
|
|
*
|
|
* @param option
|
|
*/
|
|
public final void clearCLIOption(String option) {
|
|
lhmCLIOptions.remove(option);
|
|
}
|
|
|
|
/**
|
|
* Gets all the currently set tor options as single String for use as
|
|
* arguments passed to tor client
|
|
*
|
|
* @return String Tor cleint formatted cli arguments
|
|
*/
|
|
public final String getCLIOptionsAsString() {
|
|
Iterator<String> iterator = lhmCLIOptions.keySet().iterator();
|
|
String key;
|
|
String value;
|
|
StringBuilder sbResult = new StringBuilder();
|
|
while (iterator.hasNext()) {
|
|
key = iterator.next();
|
|
sbResult.append("--");
|
|
sbResult.append(key);
|
|
sbResult.append(" ");
|
|
value = lhmCLIOptions.get(key);
|
|
if (!value.isEmpty()) {
|
|
sbResult.append(value);
|
|
sbResult.append(" ");
|
|
}
|
|
}
|
|
return sbResult.toString().trim();
|
|
}
|
|
|
|
/**
|
|
* Get the listening port
|
|
*
|
|
* @return port
|
|
*/
|
|
public final int getListenPort() {
|
|
return intListenPort;
|
|
}
|
|
|
|
/**
|
|
* Get the control port
|
|
*
|
|
* @return port
|
|
*/
|
|
public final int getControlPort() {
|
|
return intListenPort + 1;
|
|
}
|
|
|
|
/**
|
|
* Creates the default Tor config file
|
|
*/
|
|
public final void createDefaultConfig() {
|
|
SimpleFile sfTorrc = new SimpleFile(getConfigFilePath());
|
|
sfTorrc.openBufferedWrite();
|
|
sfTorrc.writeFile(getTorrcOptionsAsString(), 0);
|
|
switch (loglev) {
|
|
case LOG_DEBUG:
|
|
sfTorrc.writeFile("log debug stdout", 1);
|
|
break;
|
|
case LOG_INFO:
|
|
sfTorrc.writeFile("log info stdout", 1);
|
|
break;
|
|
case LOG_NOTICE:
|
|
sfTorrc.writeFile("log notice stdout", 1);
|
|
break;
|
|
}
|
|
|
|
sfTorrc.writeFile(EMPTYSTRING, 1);
|
|
sfTorrc.closeFile();
|
|
}
|
|
|
|
/**
|
|
* Delete the configuration file
|
|
*/
|
|
public final void deleteConfigFile() {
|
|
SimpleFile.delete(getConfigFilePath());
|
|
}
|
|
|
|
/**
|
|
* Creates a data folder for the Tor client to put its cache data
|
|
*/
|
|
public final void createDataFolder() {
|
|
String folder = getDataFolder();
|
|
if (folder != null) {
|
|
setTorrcOption("DataDirectory", invCommas + getDataFolder() + invCommas);
|
|
SimpleFile.createFolder(getDataFolder());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the datafolder being used by tor client
|
|
*
|
|
* @return Path to datafolder
|
|
*/
|
|
public final String getDataFolder() {
|
|
if (strConfigFolder == null) {
|
|
return null;
|
|
}
|
|
return strConfigFolder + String.valueOf(intListenPort);
|
|
}
|
|
|
|
/**
|
|
* Get the age of the file cache in minutes
|
|
*
|
|
* @return age of cache in minutes
|
|
*/
|
|
public float getCacheAge() {
|
|
|
|
String path = getDataFolder() + SimpleFile.getSeparator()
|
|
+ "cached-consensus";
|
|
if (SimpleFile.exists(path)) {
|
|
return SimpleFile.getAgeOfFile(path, SimpleFile.PERIOD_MINUTES);
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete Tor cache data
|
|
*/
|
|
public final void deleteCacheData() {
|
|
SimpleFile.secureWipe(getDataFolder() + SimpleFile.getSeparator() + "cached-consensus");
|
|
SimpleFile.secureWipe(getDataFolder() + SimpleFile.getSeparator() + "cached-certs");
|
|
SimpleFile.secureWipe(getDataFolder() + SimpleFile.getSeparator() + "cached-descriptors");
|
|
SimpleFile.secureWipe(getDataFolder() + SimpleFile.getSeparator() + "cached-descriptors.new");
|
|
SimpleFile.secureWipe(getDataFolder() + SimpleFile.getSeparator() + "lock");
|
|
SimpleFile.secureWipe(getDataFolder() + SimpleFile.getSeparator() + "state");
|
|
}
|
|
|
|
/**
|
|
* This populates the the current folder whose name is derived from the
|
|
* listening port with data from the given source folder derived by the
|
|
* given port number. This effectively allows each Tor client spawned to
|
|
* have its Tor cache data copied from the first Tor client launched instead
|
|
* of having to go to the net and fetch it and thus start up is a lot
|
|
* faster. I was actually mildly suprised that this actually works.
|
|
*
|
|
* @param port
|
|
*/
|
|
public final void setCachedDataFolder(int port) {
|
|
if (port < 0) {
|
|
strCachedDataFolder = null;
|
|
return;
|
|
}
|
|
strCachedDataFolder = strConfigFolder + String.valueOf(port);
|
|
}
|
|
|
|
/**
|
|
* Get the currently set cached data folder
|
|
*
|
|
* @return path to cached data folder as String
|
|
*/
|
|
public final String getCachedDataFolder() {
|
|
return strCachedDataFolder;
|
|
}
|
|
|
|
/**
|
|
* Set the text area that will receive Stdout output
|
|
*
|
|
* @param jta
|
|
*/
|
|
public void setStdoutTextArea(JTextArea jta) {
|
|
jtxtstdout = jta;
|
|
}
|
|
|
|
/**
|
|
* Set the maximum no of lines to display in the Stdout output
|
|
*
|
|
* @param lines
|
|
*/
|
|
public void setMaxHistory(int lines) {
|
|
maxlines = lines;
|
|
}
|
|
|
|
/**
|
|
* Clear the Stdout text area
|
|
*/
|
|
public void clearStdout() {
|
|
if (jtxtstdout != null) {
|
|
jtxtstdout.setText("");
|
|
}
|
|
nolines = 0;
|
|
}
|
|
|
|
/**
|
|
* Append text to the StdOut text area
|
|
*
|
|
* @param text
|
|
*/
|
|
private void appendStdout(String text) {
|
|
if (jtxtstdout == null) {
|
|
return;
|
|
}
|
|
jtxtstdout.append(text + "\n");
|
|
if (++nolines > maxlines) {
|
|
try {
|
|
int end = jtxtstdout.getLineEndOffset(0);
|
|
jtxtstdout.replaceRange("", 0, end);
|
|
} catch (BadLocationException ex) {
|
|
}
|
|
}
|
|
jtxtstdout.setCaretPosition(jtxtstdout.getText().length());
|
|
}
|
|
|
|
/**
|
|
* Get Tor version as float
|
|
*
|
|
* @return Tor version as String
|
|
*/
|
|
public final float getVersion() {
|
|
if (version == 9999) {
|
|
BufferedReader br;
|
|
String strVer = "";
|
|
Process proc;
|
|
try {
|
|
proc = Runtime.getRuntime().exec(strClientLocation + " --version");
|
|
br = new BufferedReader(new InputStreamReader(proc.getInputStream()), 256);
|
|
String line;
|
|
while (true) {
|
|
line = br.readLine();
|
|
if (line == null) {
|
|
break;
|
|
}
|
|
strVer = line;
|
|
}
|
|
br.close();
|
|
proc.destroy();
|
|
proc.waitFor();
|
|
} catch (IOException | InterruptedException ex) {
|
|
Logger.getLogger(TorProcess.class.getName()).log(Level.SEVERE, null, ex);
|
|
}
|
|
int idx = strVer.indexOf("ion");
|
|
if (idx > -1) {
|
|
strVer = strVer.substring(idx + 4).replace(".", "");
|
|
idx = strVer.indexOf(' ');
|
|
if (idx > -1) {
|
|
strVer = strVer.substring(0, idx);
|
|
}
|
|
try {
|
|
version = Float.parseFloat("0." + strVer) * 10;
|
|
} catch (Exception ex) {
|
|
Logger.getGlobal().logp(Level.SEVERE, this.getClass().getName(), "getVersion() Port=" + intListenPort, "", ex);
|
|
}
|
|
}
|
|
}
|
|
return version;
|
|
}
|
|
|
|
}
|