package org.torproject.jtor.config.impl; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.torproject.jtor.TorConfig; public class TorConfigSaver { @SuppressWarnings("unchecked") public static boolean save(File torrc, TorConfig tc) { BufferedReader reader; String output = ""; Map opts = configToHash(tc); HashMap written = new HashMap(); try { reader = new BufferedReader(new FileReader(torrc)); String line = null; while ((line=reader.readLine()) != null) { if (line.startsWith("#") || line.matches("^\\s*$")) { // copy comments directly // TODO check comments for values that have changed and inject them here instead of the end of file output += line + "\n"; continue; } String comment = ""; if (line.indexOf("#") > 0) { comment = line.substring(line.indexOf("#")); line = line.substring(0, line.indexOf("#")); } int separator = line.indexOf(" "); String key = line.substring(0, separator); if (!opts.containsKey(key.toLowerCase())) { // faulty option continue; } if (written.get(key.toLowerCase()) != null) { // already saved continue; } if (((String)opts.get(key.toLowerCase())).indexOf("\n") == -1) { output += key + " " + (String)opts.get(key.toLowerCase()) + " " + comment + "\n"; written.put(key.toLowerCase(), ""); continue; } String[] out = ((String)opts.get(key.toLowerCase())).split("\n"); written.put(key.toLowerCase(), ""); for (int i = 0; i < out.length; i++) { output += key + " " + out[i] + "\n"; } } } catch (FileNotFoundException e) { torrc.setWritable(true); } catch (IOException e) {} Map defaults = defaultConfigToHash(new TorConfigDefaults()); Iterator it = opts.keySet().iterator(); while (it.hasNext()) { String key = (String)it.next(); if (key.startsWith("__")) // values with __ should never be stored continue; if (written.get(key) == null && opts.get(key) != null) { String val = (String)opts.get(key); if (((String)defaults.get(key)).equals(val)) { // value hasn't changed continue; } if (((String)opts.get(key)).indexOf("\n") == -1) { output += key + " " + val + "\n"; } else { String[] out = ((String)opts.get(key)).split("\n"); for (int i = 0; i < out.length; i++) { output += key + " " + out[i] + "\n"; } } } } try { torrc.delete(); FileOutputStream fos = new FileOutputStream(torrc); fos.write(output.getBytes()); fos.flush(); fos.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); return false; } catch (IOException e) { return false; } return true; } @SuppressWarnings("unchecked") public static Map configToHash(TorConfig tc) { HashMap hm = new HashMap(); hm.put("configfile", tc.getConfigFile()); hm.put("datadirectory", tc.getDataDirectory()); hm.put("bandwidthrate", "" + tc.getBandwidthRate()); hm.put("bandwidthburst", "" + tc.getBandwidthBurst()); hm.put("maxadvertisedbandwidth", "" + tc.getMaxAdvertisedBandwidth()); hm.put("controlport", "" + tc.getControlPort()); hm.put("hashedcontrolpassword", tc.getHashedControlPassword()); hm.put("cookieauthentication", "" + (tc.isCookieAuthentication() ? "1" : "0")); hm.put("dirfetchperiod", "" + tc.getDirFetchPeriod()); hm.put("dirserver", arrayToString(tc.getDirServer())); hm.put("disableallswap", "" + (tc.isDisableAllSwap() ? "1" : "0")); hm.put("group", tc.getGroup()); hm.put("httpproxy", tc.getHttpProxy()); hm.put("httpproxyauthenticator", tc.getHttpProxyAuthenticator()); hm.put("httpsproxy", tc.getHttpsProxy()); hm.put("httpsproxyauthenticator", tc.getHttpsProxyAuthenticator()); hm.put("keepaliveperiod", "" + tc.getKeepalivePeriod()); hm.put("log", arrayToString(tc.getLog())); hm.put("maxconn", "" + tc.getMaxConn()); hm.put("outboundbindaddress", tc.getOutboundBindAddress().getHostAddress()); hm.put("pidfile", tc.getPidFile()); hm.put("runasdaemon", "" + (tc.isRunAsDaemon() ? "1" : "0")); hm.put("safelogging", "" + (tc.isSafeLogging() ? "1" : "0")); hm.put("statusfetchperiod", "" + tc.getStatusFetchPeriod()); hm.put("user", tc.getUser()); hm.put("hardwareaccel", "" + (tc.isHardwareAccel() ? "1" : "0")); hm.put("allowunverifiednodes", tc.getAllowUnverifiedNodes()); hm.put("clientonly", "" + (tc.isClientOnly() ? "1" : "0")); hm.put("entrynodes", arrayToString(tc.getEntryNodes())); hm.put("exitnodes", arrayToString(tc.getExitNodes())); hm.put("excludenodes", arrayToString(tc.getExcludeNodes())); hm.put("strictexitnodes", "" + (tc.isStrictExitNodes() ? "1" : "0")); hm.put("strictentrynodes", "" + (tc.isStrictEntryNodes() ? "1" : "0")); hm.put("fascistfirewall", "" + (tc.isFascistFirewall() ? "1" : "0")); hm.put("firewallports", arrayToString(tc.getFirewallPorts())); hm.put("firewallips", arrayToString(tc.getFirewallIPs())); hm.put("longlivedports", arrayToString(tc.getLongLivedPorts())); hm.put("mapaddress", arrayToString(tc.getMapAddress())); hm.put("newcircuitperiod", "" + tc.getNewCircuitPeriod()); hm.put("maxcircuitdirtiness", "" + tc.getMaxCircuitDirtiness()); hm.put("nodefamily", arrayToString(tc.getNodeFamily())); hm.put("rendnodes", arrayToString(tc.getRendNodes())); hm.put("rendexcludenodes", arrayToString(tc.getRendExcludeNodes())); hm.put("socksport", "" + tc.getSocksPort()); hm.put("socksbindaddress", tc.getSocksBindAddress()); hm.put("sockspolicy", tc.getSocksPolicy()); hm.put("trackhostexits", arrayToString(tc.getTrackHostExits())); hm.put("trackhostexitsexpire", "" + tc.getTrackHostExitsExpire()); hm.put("usehelpernodes", "" + (tc.isUseHelperNodes() ? "1" : "0")); hm.put("numhelpernodes", "" + tc.getNumHelperNodes()); hm.put("hiddenservicedir", arrayToString(tc.getHiddenServiceDir())); hm.put("hiddenserviceport", arrayToString(tc.getHiddenServicePort())); hm.put("hiddenservicenodes", arrayToString(tc.getHiddenServiceNodes())); hm.put("hiddenserviceexcludenodes", arrayToString(tc.getHiddenServiceExcludeNodes())); hm.put("hiddenserviceversion", tc.getHiddenServiceVersion()); hm.put("rendpostperiod", "" + tc.getRendPostPeriod()); return hm; } @SuppressWarnings("unchecked") public static Map defaultConfigToHash(TorConfigDefaults tcd) { HashMap hm = new HashMap(); hm.put("configfile", tcd.getConfigFile()); hm.put("datadirectory", tcd.getDataDirectory().getAbsolutePath()); hm.put("bandwidthrate", "" + tcd.getBandwidthRate()); hm.put("bandwidthburst", "" + tcd.getBandwidthBurst()); hm.put("maxadvertisedbandwidth", "" + tcd.getMaxAdvertisedBandwidth()); hm.put("controlport", "" + tcd.getControlPort()); hm.put("hashedcontrolpassword", tcd.getHashedControlPassword()); hm.put("cookieauthentication", "" + (tcd.isCookieAuthentication() ? "1" : "0")); hm.put("dirfetchperiod", "" + tcd.getDirFetchPeriod()); hm.put("dirserver", arrayToString(tcd.getDirServer())); hm.put("disableallswap", "" + (tcd.isDisableAllSwap() ? "1" : "0")); hm.put("group", tcd.getGroup()); hm.put("httpproxy", tcd.getHttpProxy()); hm.put("httpproxyauthenticator", tcd.getHttpProxyAuthenticator()); hm.put("httpsproxy", tcd.getHttpsProxy()); hm.put("httpsproxyauthenticator", tcd.getHttpsProxyAuthenticator()); hm.put("keepaliveperiod", "" + tcd.getKeepalivePeriod()); hm.put("log", arrayToString(tcd.getLog())); hm.put("maxconn", "" + tcd.getMaxConn()); hm.put("outboundbindaddress", tcd.getOutboundBindAddress().getHostAddress()); hm.put("pidfile", tcd.getPidFile()); hm.put("runasdaemon", "" + (tcd.isRunAsDaemon() ? "1" : "0")); hm.put("safelogging", "" + (tcd.isSafeLogging() ? "1" : "0")); hm.put("statusfetchperiod", "" + tcd.getStatusFetchPeriod()); hm.put("user", tcd.getUser()); hm.put("hardwareaccel", "" + (tcd.isHardwareAccel() ? "1" : "0")); hm.put("allowunverifiednodes", tcd.getAllowUnverifiedNodes()); hm.put("clientonly", "" + (tcd.isClientOnly() ? "1" : "0")); hm.put("entrynodes", arrayToString(tcd.getEntryNodes())); hm.put("exitnodes", arrayToString(tcd.getExitNodes())); hm.put("excludenodes", arrayToString(tcd.getExcludeNodes())); hm.put("strictexitnodes", "" + (tcd.isStrictExitNodes() ? "1" : "0")); hm.put("strictentrynodes", "" + (tcd.isStrictEntryNodes() ? "1" : "0")); hm.put("fascistfirewall", "" + (tcd.isFascistFirewall() ? "1" : "0")); hm.put("firewallports", arrayToString(tcd.getFirewallPorts())); hm.put("firewallips", arrayToString(tcd.getFirewallIPs())); hm.put("longlivedports", arrayToString(tcd.getLongLivedPorts())); hm.put("mapaddress", arrayToString(tcd.getMapAddress())); hm.put("newcircuitperiod", "" + tcd.getNewCircuitPeriod()); hm.put("maxcircuitdirtiness", "" + tcd.getMaxCircuitDirtiness()); hm.put("nodefamily", arrayToString(tcd.getNodeFamily())); hm.put("rendnodes", arrayToString(tcd.getRendNodes())); hm.put("rendexcludenodes", arrayToString(tcd.getRendExcludeNodes())); hm.put("socksport", "" + tcd.getSocksPort()); hm.put("socksbindaddress", tcd.getSocksBindAddress()); hm.put("sockspolicy", tcd.getSocksPolicy()); hm.put("trackhostexits", arrayToString(tcd.getTrackHostExits())); hm.put("trackhostexitsexpire", "" + tcd.getTrackHostExitsExpire()); hm.put("usehelpernodes", "" + (tcd.isUseHelperNodes() ? "1" : "0")); hm.put("numhelpernodes", "" + tcd.getNumHelperNodes()); hm.put("hiddenservicedir", arrayToString(tcd.getHiddenServiceDir())); hm.put("hiddenserviceport", arrayToString(tcd.getHiddenServicePort())); hm.put("hiddenservicenodes", arrayToString(tcd.getHiddenServiceNodes())); hm.put("hiddenserviceexcludenodes", arrayToString(tcd.getHiddenServiceExcludeNodes())); hm.put("hiddenserviceversion", tcd.getHiddenServiceVersion()); hm.put("rendpostperiod", "" + tcd.getRendPostPeriod()); return hm; } public static String arrayToString(String[] in) { if (in == null) { return ""; } String ret = ""; for (int i = 0; i < in.length; i++) { ret += in[i] + "\n"; } ret = ret.replaceAll("\\s*$", ""); return ret; } public static String arrayToString(short[] in) { if (in == null) { return ""; } String ret = ""; for (int i = 0; i < in.length; i++) { ret += in[i] + ", "; } ret = ret.replaceAll("[,\\s]*$", ""); return ret; } }