diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java index 90f02596a..0da8bdc24 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java @@ -4,7 +4,7 @@ import net.i2p.router.Router; import net.i2p.router.transport.FIFOBandwidthRefiller; import net.i2p.router.transport.TransportManager; import net.i2p.router.transport.udp.UDPTransport; -import net.i2p.router.web.ConfigServiceHandler.UpdateWrapperManagerAndRekeyTask; +import net.i2p.router.web.ConfigServiceHandler; /** * Handler to deal with form submissions from the main config form and act @@ -30,6 +30,7 @@ public class ConfigNetHandler extends FormHandler { private String _ntcpAutoIP; private boolean _ntcpAutoPort; private boolean _upnp; + private boolean _laptop; private String _inboundRate; private String _inboundBurstRate; private String _inboundBurst; @@ -70,6 +71,7 @@ public class ConfigNetHandler extends FormHandler { _ntcpAutoPort = mode.equals("2"); } public void setUpnp(String moo) { _upnp = true; } + public void setLaptop(String moo) { _laptop = true; } public void setHostname(String hostname) { _hostname = (hostname != null ? hostname.trim() : null); @@ -230,6 +232,16 @@ public class ConfigNetHandler extends FormHandler { } _context.router().setConfigSetting(TransportManager.PROP_ENABLE_UPNP, "" + _upnp); + if (Boolean.valueOf(_context.getProperty(UDPTransport.PROP_LAPTOP_MODE)).booleanValue() != + _laptop) { + // This is minor, don't set restartRequired + if (_laptop) + addFormNotice(_("Enabling laptop mode")); + else + addFormNotice(_("Disabling laptop mode")); + } + _context.router().setConfigSetting(UDPTransport.PROP_LAPTOP_MODE, "" + _laptop); + if (_requireIntroductions) { _context.router().setConfigSetting(UDPTransport.PROP_FORCE_INTRODUCERS, "true"); addFormNotice(_("Requiring SSU introducers")); @@ -274,6 +286,7 @@ public class ConfigNetHandler extends FormHandler { // There's a few changes that don't really require restart (e.g. enabling inbound TCP) // But it would be hard to get right, so just do a restart. addFormError(_("Gracefully restarting I2P to change published router address")); + _context.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerTask(Router.EXIT_GRACEFUL_RESTART)); _context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART); } } @@ -281,7 +294,7 @@ public class ConfigNetHandler extends FormHandler { private void hiddenSwitch() { // Full restart required to generate new keys - _context.addShutdownTask(new UpdateWrapperManagerAndRekeyTask(Router.EXIT_GRACEFUL_RESTART)); + _context.addShutdownTask(new ConfigServiceHandler.UpdateWrapperManagerAndRekeyTask(Router.EXIT_GRACEFUL_RESTART)); _context.router().shutdownGracefully(Router.EXIT_GRACEFUL_RESTART); } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java index b7a692daa..05f49cea6 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java @@ -84,6 +84,10 @@ public class ConfigNetHelper extends HelperBase { return getChecked(Router.PROP_DYNAMIC_KEYS); } + public String getLaptopChecked() { + return getChecked(UDPTransport.PROP_LAPTOP_MODE); + } + public String getTcpAutoPortChecked(int mode) { String port = _context.getProperty(PROP_I2NP_NTCP_PORT); boolean specified = port != null && port.length() > 0; diff --git a/apps/routerconsole/jsp/config.jsp b/apps/routerconsole/jsp/config.jsp index 9a9942c79..edd02bba6 100644 --- a/apps/routerconsole/jsp/config.jsp +++ b/apps/routerconsole/jsp/config.jsp @@ -122,6 +122,11 @@
/> <%=intl._("Hidden mode - do not publish IP")%> <%=intl._("(prevents participating traffic)")%>
+

+ <%=intl._("Action when IP changes")%>:
+ /> + <%=intl._("Laptop mode - Change router identity and UDP port when IP changes for enhanced anonymity")%> + (<%=intl._("Experimental")%>)

<%=intl._("UDP Configuration:")%>
<%=intl._("UDP port:")%> " />
diff --git a/history.txt b/history.txt index 6dbb8c8c3..064ce2c62 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,11 @@ +2010-01-02 zzz + * Console: Save refresh setting + * i2psnark: + - Don't URL-encode chars we don't have to + - CSS tweaks + * Transport: Implement 'laptop mode' to change ident and port + when the IP changes + 2010-01-01 sponge * Happy New year everyone! * Added a target to generate a stand-alone BOB jar file. diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java index 4ed70a772..6c97b2124 100644 --- a/router/java/src/net/i2p/router/Router.java +++ b/router/java/src/net/i2p/router/Router.java @@ -37,6 +37,7 @@ import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade; import net.i2p.router.startup.StartupJob; import net.i2p.router.startup.WorkingDir; import net.i2p.router.transport.FIFOBandwidthLimiter; +import net.i2p.router.transport.udp.UDPTransport; import net.i2p.stat.Rate; import net.i2p.stat.RateStat; import net.i2p.stat.StatManager; @@ -314,10 +315,10 @@ public class Router { readConfig(); setupHandlers(); - if (ALLOW_DYNAMIC_KEYS) { - if ("true".equalsIgnoreCase(_context.getProperty(Router.PROP_HIDDEN, "false"))) - killKeys(); - } + //if (ALLOW_DYNAMIC_KEYS) { + // if ("true".equalsIgnoreCase(_context.getProperty(Router.PROP_HIDDEN, "false"))) + // killKeys(); + //} _context.messageValidator().startup(); _context.tunnelDispatcher().startup(); @@ -526,7 +527,7 @@ public class Router { static final String IDENTLOG = "identlog.txt"; public void killKeys() { - new Exception("Clearing identity files").printStackTrace(); + //new Exception("Clearing identity files").printStackTrace(); int remCount = 0; for (int i = 0; i < _rebuildFiles.length; i++) { File f = new File(_context.getRouterDir(),_rebuildFiles[i]); @@ -540,6 +541,12 @@ public class Router { } } } + + // now that we have random ports, keeping the same port would be bad + removeConfigSetting(UDPTransport.PROP_INTERNAL_PORT); + removeConfigSetting(UDPTransport.PROP_EXTERNAL_PORT); + saveConfig(); + if (remCount > 0) { FileOutputStream log = null; try { @@ -909,11 +916,11 @@ public class Router { */ private static final boolean ALLOW_DYNAMIC_KEYS = false; - public void finalShutdown(int exitCode) { + private void finalShutdown(int exitCode) { _log.log(Log.CRIT, "Shutdown(" + exitCode + ") complete", new Exception("Shutdown")); try { _context.logManager().shutdown(); } catch (Throwable t) { } if (ALLOW_DYNAMIC_KEYS) { - if ("true".equalsIgnoreCase(_context.getProperty(PROP_DYNAMIC_KEYS, "false"))) + if (Boolean.valueOf(_context.getProperty(PROP_DYNAMIC_KEYS)).booleanValue()) killKeys(); } diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 983dd2f06..8c1e82035 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -18,7 +18,7 @@ public class RouterVersion { /** deprecated */ public final static String ID = "Monotone"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 13; + public final static long BUILD = 14; /** for example "-test" */ public final static String EXTRA = ""; public final static String FULL_VERSION = VERSION + "-" + BUILD + EXTRA; diff --git a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java index c5d5e6106..075326c53 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -132,6 +132,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority /** remember IP changes */ public static final String PROP_IP= "i2np.lastIP"; public static final String PROP_IP_CHANGE = "i2np.lastIPChange"; + public static final String PROP_LAPTOP_MODE = "i2np.laptopMode"; /** do we require introducers, regardless of our status? */ public static final String PROP_FORCE_INTRODUCERS = "i2np.udp.forceIntroducers"; @@ -516,9 +517,35 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority // store these for laptop-mode (change ident on restart... or every time... when IP changes) String oldIP = _context.getProperty(PROP_IP); if (!_externalListenHost.getHostAddress().equals(oldIP)) { + long lastChanged = 0; + long now = _context.clock().now(); + String lcs = _context.getProperty(PROP_IP_CHANGE); + if (lcs != null) { + try { + lastChanged = Long.parseLong(lcs); + } catch (NumberFormatException nfe) {} + } + _context.router().setConfigSetting(PROP_IP, _externalListenHost.getHostAddress()); - _context.router().setConfigSetting(PROP_IP_CHANGE, "" + _context.clock().now()); + _context.router().setConfigSetting(PROP_IP_CHANGE, "" + now); _context.router().saveConfig(); + + // laptop mode + // For now, only do this at startup + if (oldIP != null && + System.getProperty("wrapper.version") != null && + Boolean.valueOf(_context.getProperty(PROP_LAPTOP_MODE)).booleanValue() && + now - lastChanged > 10*60*1000 && + _context.router().getUptime() < 10*60*1000) { + _log.log(Log.CRIT, "IP changed, restarting with a new identity and port"); + // this removes the UDP port config + _context.router().killKeys(); + // do we need WrapperManager.signalStopped() like in ConfigServiceHandler ??? + // without it, the wrapper complains "shutdown unexpectedly" + // but we can't have that dependency in the router + _context.router().shutdown(Router.EXIT_HARD_RESTART); + // doesn't return + } } _context.router().rebuildRouterInfo(); }