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();
}