diff --git a/history.txt b/history.txt index 366c3858df..c6da813c3d 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,6 @@ +2015-01-29 zzz + * SSU: Fix replaceExternalAddress churn when firewalled + 2015-01-28 zzz * UPnP: - Rescan for devices periodically and when reachability changes (tickets #661, #959) diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index e36cd3b143..7f4edb9752 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 = 12; + public final static long BUILD = 13; /** for example "-test" */ public final static String 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 913c3b92cc..bdf4aa8937 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -111,6 +111,10 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority private Hash _lastFrom; private byte[] _lastOurIP; private int _lastOurPort; + /** since we don't publish our IP/port if introduced anymore, we need + to store it somewhere. */ + private RouterAddress _currentOurV4Address; + private RouterAddress _currentOurV6Address; private static final int DROPLIST_PERIOD = 10*60*1000; public static final String STYLE = "SSU"; @@ -162,6 +166,9 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority /** override the "large" (max) MTU, default is PeerState.LARGE_MTU */ private static final String PROP_DEFAULT_MTU = "i2np.udp.mtu"; + private static final String CAP_TESTING = "" + UDPAddress.CAPACITY_TESTING; + private static final String CAP_TESTING_INTRO = "" + UDPAddress.CAPACITY_TESTING + UDPAddress.CAPACITY_INTRODUCER; + /** how many relays offered to us will we use at a time? */ public static final int PUBLIC_RELAY_COUNT = 3; @@ -782,7 +789,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority //_context.banlist().banlistRouter(from, "They said we had an invalid IP", STYLE); return; } - RouterAddress addr = getCurrentAddress(false); + + RouterAddress addr = getCurrentExternalAddress(false); if (inboundRecent && addr != null && addr.getPort() > 0 && addr.getHost() != null) { // use OS clock since its an ordering thing, not a time thing // Note that this fails us if we switch from one IP to a second, then back to the first, @@ -833,7 +841,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority boolean fireTest = false; boolean isIPv6 = ourIP.length == 16; - RouterAddress current = getCurrentAddress(isIPv6); + RouterAddress current = getCurrentExternalAddress(isIPv6); byte[] externalListenHost = current != null ? current.getIP() : null; int externalListenPort = current != null ? current.getPort() : getRequestedPort(isIPv6); @@ -1867,7 +1875,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority } else { directIncluded = false; } - + boolean introducersIncluded = false; if (introducersRequired) { // FIXME intro manager doesn't sort introducers, so @@ -1889,9 +1897,9 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority // if we have explicit external addresses, they had better be reachable if (introducersRequired) - options.setProperty(UDPAddress.PROP_CAPACITY, ""+UDPAddress.CAPACITY_TESTING); + options.setProperty(UDPAddress.PROP_CAPACITY, CAP_TESTING); else - options.setProperty(UDPAddress.PROP_CAPACITY, ""+UDPAddress.CAPACITY_TESTING + UDPAddress.CAPACITY_INTRODUCER); + options.setProperty(UDPAddress.PROP_CAPACITY, CAP_TESTING_INTRO); // MTU since 0.9.2 int mtu; @@ -1934,6 +1942,20 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority RouterAddress current = getCurrentAddress(isIPv6); boolean wantsRebuild = !addr.deepEquals(current); + // save the external address, even if we didn't publish it + if (port > 0 && host != null) { + RouterAddress local; + if (directIncluded) { + local = addr; + } else { + OrderedProperties localOpts = new OrderedProperties(); + localOpts.setProperty(UDPAddress.PROP_PORT, String.valueOf(port)); + localOpts.setProperty(UDPAddress.PROP_HOST, host); + local = new RouterAddress(STYLE, localOpts, cost); + } + replaceCurrentExternalAddress(local, isIPv6); + } + if (wantsRebuild) { if (_log.shouldLog(Log.INFO)) _log.info("Address rebuilt: " + addr); @@ -1943,6 +1965,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority } else { addr = null; } + if (!isIPv6) _needsRebuild = false; return addr; @@ -1955,6 +1978,35 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority } } + /** + * Simple storage of IP and port, since + * we don't put them in the real, published RouterAddress anymore + * if we are firewalled. + * + * Caller must sync on _rebuildLock + * + * @since 0.9.18 + */ + private void replaceCurrentExternalAddress(RouterAddress ra, boolean isIPv6) { + if (isIPv6) + _currentOurV6Address = ra; + else + _currentOurV4Address = ra; + } + + /** + * Simple fetch of stored IP and port, since + * we don't put them in the real, published RouterAddress anymore + * if we are firewalled. + * + * @since 0.9.18 + */ + private RouterAddress getCurrentExternalAddress(boolean isIPv6) { + synchronized (_rebuildLock) { + return isIPv6 ? _currentOurV6Address : _currentOurV4Address; + } + } + /** * Replace then tell NTCP that we changed. *