From ae1d5648d506f96c6667b85f4e2f34f883782057 Mon Sep 17 00:00:00 2001 From: zzz Date: Sun, 9 Nov 2014 13:51:19 +0000 Subject: [PATCH] Router, i2ptunnel: Add option for per-pool persistent random key, so peer ordering does not change across restarts --- .../src/net/i2p/i2ptunnel/web/IndexBean.java | 15 +++++++++++++++ router/java/src/net/i2p/router/Router.java | 19 ++++++++++++++++++- .../net/i2p/router/TunnelPoolSettings.java | 15 +++++++++++++-- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java index 53f3681b6..8deb1ac99 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java @@ -25,6 +25,7 @@ import net.i2p.I2PAppContext; import net.i2p.app.ClientAppManager; import net.i2p.app.Outproxy; import net.i2p.client.I2PClient; +import net.i2p.data.Base64; import net.i2p.data.Certificate; import net.i2p.data.DataHelper; import net.i2p.data.Destination; @@ -1331,6 +1332,20 @@ public class IndexBean { } } + // As of 0.9.17, add a persistent random key if not present + if (!isClient(_type) || _booleanOptions.contains("persistentClientKey")) { + String p = OPT + "inbound.randomKey"; + if (!config.containsKey(p)) { + // as of 0.9.17, add a random key if not previously present + byte[] rk = new byte[32]; + _context.random().nextBytes(rk); + config.setProperty(OPT + p, Base64.encode(rk)); + p = OPT + "outbound.randomKey"; + _context.random().nextBytes(rk); + config.setProperty(OPT + p, Base64.encode(rk)); + } + } + return config; } diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java index d71681eaf..bb597d2e2 100644 --- a/router/java/src/net/i2p/router/Router.java +++ b/router/java/src/net/i2p/router/Router.java @@ -25,6 +25,7 @@ import java.util.concurrent.ConcurrentHashMap; import gnu.getopt.Getopt; +import net.i2p.data.Base64; import net.i2p.data.Certificate; import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; @@ -101,6 +102,8 @@ public class Router implements RouterClock.ClockShiftListener { public final static String PROP_HIDDEN_HIDDEN = "router.isHidden"; public final static String PROP_DYNAMIC_KEYS = "router.dynamicKeys"; public final static String PROP_SHUTDOWN_IN_PROGRESS = "__shutdownInProgress"; + private static final String PROP_IB_RANDOM_KEY = TunnelPoolSettings.PREFIX_INBOUND_EXPLORATORY + TunnelPoolSettings.PROP_RANDOM_KEY; + private static final String PROP_OB_RANDOM_KEY = TunnelPoolSettings.PREFIX_OUTBOUND_EXPLORATORY + TunnelPoolSettings.PROP_RANDOM_KEY; public final static String DNS_CACHE_TIME = "" + (5*60); private static final String EVENTLOG = "eventlog.txt"; private static final String PROP_JBIGI = "jbigi.loadedResource"; @@ -486,6 +489,18 @@ public class Router implements RouterClock.ClockShiftListener { //_sessionKeyPersistenceHelper.startup(); //_context.adminManager().startup(); _context.blocklist().startup(); + + synchronized(_configFileLock) { + // persistent key for peer ordering since 0.9.17 + if (!_config.containsKey(PROP_IB_RANDOM_KEY)) { + byte rk[] = new byte[32]; + _context.random().nextBytes(rk); + _config.put(PROP_IB_RANDOM_KEY, Base64.encode(rk)); + _context.random().nextBytes(rk); + _config.put(PROP_OB_RANDOM_KEY, Base64.encode(rk)); + saveConfig(); + } + } // let the timestamper get us sync'ed // this will block for quite a while on a disconnected machine @@ -711,9 +726,11 @@ public class Router implements RouterClock.ClockShiftListener { } // now that we have random ports, keeping the same port would be bad - synchronized(this) { + synchronized(_configFileLock) { removeConfigSetting(UDPTransport.PROP_INTERNAL_PORT); removeConfigSetting(UDPTransport.PROP_EXTERNAL_PORT); + removeConfigSetting(PROP_IB_RANDOM_KEY); + removeConfigSetting(PROP_OB_RANDOM_KEY); saveConfig(); } } diff --git a/router/java/src/net/i2p/router/TunnelPoolSettings.java b/router/java/src/net/i2p/router/TunnelPoolSettings.java index f86b8f959..481836d17 100644 --- a/router/java/src/net/i2p/router/TunnelPoolSettings.java +++ b/router/java/src/net/i2p/router/TunnelPoolSettings.java @@ -4,6 +4,7 @@ import java.util.Locale; import java.util.Map; import java.util.Properties; +import net.i2p.data.Base64; import net.i2p.data.Hash; import net.i2p.util.NativeBigInteger; import net.i2p.util.RandomSource; @@ -28,7 +29,7 @@ public class TunnelPoolSettings { private boolean _allowZeroHop; private int _IPRestriction; private final Properties _unknownOptions; - private final Hash _randomKey; + private Hash _randomKey; private int _priority; /** prefix used to override the router's defaults for clients */ @@ -51,6 +52,8 @@ public class TunnelPoolSettings { public static final String PROP_ALLOW_ZERO_HOP = "allowZeroHop"; public static final String PROP_IP_RESTRICTION = "IPRestriction"; public static final String PROP_PRIORITY = "priority"; + /** @since 0.9.17 */ + public static final String PROP_RANDOM_KEY = "randomKey"; public static final int DEFAULT_QUANTITY = 2; public static final int DEFAULT_BACKUP_QUANTITY = 0; @@ -204,7 +207,11 @@ public class TunnelPoolSettings { /** what destination is this a client tunnel for (or null if exploratory) */ public Hash getDestination() { return _destination; } - /** random key used for peer ordering */ + /** + * random key used for peer ordering + * + * @return non-null + */ public Hash getRandomKey() { return _randomKey; } /** what user supplied name was given to the client connected (can be null) */ @@ -265,6 +272,10 @@ public class TunnelPoolSettings { int def = _isExploratory ? EXPLORATORY_PRIORITY : 0; int max = _isExploratory ? EXPLORATORY_PRIORITY : MAX_PRIORITY; _priority = Math.min(max, Math.max(MIN_PRIORITY, getInt(value, def))); + } else if (name.equalsIgnoreCase(prefix + PROP_RANDOM_KEY)) { + byte[] rk = Base64.decode(value); + if (rk != null && rk.length == Hash.HASH_LENGTH) + _randomKey = new Hash(rk); } else _unknownOptions.setProperty(name.substring(prefix.length()), value); }