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 33830e8aedc89c4e922eece19e30b1f855e6ea75..cba2007dbc660e124fa9fd2f51de8dff55f3ba23 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -282,6 +282,20 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority // various state bitmaps + private static final Set<Status> STATUS_IPV4_UNK = EnumSet.of(Status.UNKNOWN, + Status.DISCONNECTED, + Status.HOSED, + Status.IPV4_UNKNOWN_IPV6_OK, + Status.IPV4_UNKNOWN_IPV6_FIREWALLED); + + private static final Set<Status> STATUS_IPV6_UNK = EnumSet.of(Status.UNKNOWN, + Status.DISCONNECTED, + Status.HOSED, + Status.IPV4_OK_IPV6_UNKNOWN, + Status.IPV4_FIREWALLED_IPV6_UNKNOWN, + Status.IPV4_SNAT_IPV6_UNKNOWN, + Status.IPV4_DISABLED_IPV6_UNKNOWN); + private static final Set<Status> STATUS_IPV4_FW = EnumSet.of(Status.DIFFERENT, Status.REJECT_UNSOLICITED, Status.IPV4_FIREWALLED_IPV6_OK, @@ -323,10 +337,6 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority Status.IPV4_DISABLED_IPV6_FIREWALLED, Status.DISCONNECTED); - private static final Set<Status> STATUS_NEED_INTRO = EnumSet.of(Status.REJECT_UNSOLICITED, - Status.IPV4_FIREWALLED_IPV6_OK, - Status.IPV4_FIREWALLED_IPV6_UNKNOWN); - private static final Set<Status> STATUS_OK = EnumSet.of(Status.OK, Status.IPV4_DISABLED_IPV6_OK); @@ -541,8 +551,9 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority if (port <= 0) { port = TransportUtil.selectRandomPort(_context, STYLE); Map<String, String> changes = new HashMap<String, String>(2); - changes.put(PROP_INTERNAL_PORT, Integer.toString(port)); - changes.put(PROP_EXTERNAL_PORT, Integer.toString(port)); + String sport = Integer.toString(port); + changes.put(PROP_INTERNAL_PORT, sport); + changes.put(PROP_EXTERNAL_PORT, sport); _context.router().saveConfig(changes, null); _log.logAlways(Log.INFO, "UDP selected random port " + port); } @@ -758,12 +769,14 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority return; } if (newPort > 0 && - (newPort != port || newPort != oldIPort || newPort != oldEPort)) { + (newPort != port || newPort != oldIPort)) { // attempt to use it as our external port - this will be overridden by // externalAddressReceived(...) Map<String, String> changes = new HashMap<String, String>(); - changes.put(PROP_INTERNAL_PORT, Integer.toString(newPort)); - changes.put(PROP_EXTERNAL_PORT, Integer.toString(newPort)); + String sport = Integer.toString(newPort); + changes.put(PROP_INTERNAL_PORT, sport); + if (oldEPort <= 0) + changes.put(PROP_EXTERNAL_PORT, sport); _context.router().saveConfig(changes, null); } @@ -1426,7 +1439,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority if (!isIPv6) { if (from.equals(_lastFromv4) || !eq(_lastOurIPv4, _lastOurPortv4, ourIP, ourPort)) { if (_log.shouldLog(Log.INFO)) - _log.info("The router " + from + " told us we have a new IP - " + _log.info("The router " + from + " told us we have a new IP/port - " + Addresses.toString(ourIP, ourPort) + ". Wait until somebody else tells us the same thing."); } else { changeIt = true; @@ -1438,7 +1451,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority } else { if (from.equals(_lastFromv6) || !eq(_lastOurIPv6, _lastOurPortv6, ourIP, ourPort)) { if (_log.shouldLog(Log.INFO)) - _log.info("The router " + from + " told us we have a new IP - " + _log.info("The router " + from + " told us we have a new IP/port - " + Addresses.toString(ourIP, ourPort) + ". Wait until somebody else tells us the same thing."); } else { changeIt = true; @@ -1470,12 +1483,12 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority * @return true if updated */ private boolean changeAddress(byte ourIP[], int ourPort) { - // this defaults to true when we are firewalled and false otherwise. - boolean fixedPort = getIsPortFixed(); boolean updated = false; boolean fireTest = false; boolean isIPv6 = ourIP.length == 16; + // this defaults to true when we are firewalled or unknown and false otherwise. + boolean fixedPort = getIsPortFixed(isIPv6); synchronized (_rebuildLock) { RouterAddress current = getCurrentExternalAddress(isIPv6); @@ -1539,8 +1552,18 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority //if ( (_reachabilityStatus != CommSystemFacade.STATUS_OK) || // (_externalListenHost == null) || (_externalListenPort <= 0) || // (_context.clock().now() - _reachabilityStatusLastUpdated > 2*TEST_FREQUENCY) ) { - // they told us something different and our tests are either old or failing + + // they told us something different and our tests are either old or failing if (rebuild) { + if (externalListenPort > 0 && ourPort > 0 && + externalListenPort != ourPort && + _context.getProperty(PROP_EXTERNAL_PORT, 0) != ourPort) { + // save the external port setting only + _context.router().saveConfig(PROP_EXTERNAL_PORT, Integer.toString(ourPort)); + _context.router().eventLog().addEvent(EventLog.CHANGE_PORT, "IPv" + + (isIPv6 ? '6' : '4') + + " port " + ourPort); + } if (_enableSSU2) { // flush SSU2 tokens if (ourPort != externalListenPort) { @@ -1668,13 +1691,23 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority * our firewall is changing our port), unless overridden by the property. * We must have an accurate external port when firewalled, or else * our signature of the SessionCreated packet will be invalid. + * + * As of 0.9.58, returns false if status is UNKNOWN */ - private boolean getIsPortFixed() { + private boolean getIsPortFixed(boolean isIPv6) { String prop = _context.getProperty(PROP_FIXED_PORT); if (prop != null) return Boolean.parseBoolean(prop); Status status = getReachabilityStatus(); - return !STATUS_NEED_INTRO.contains(status); + if (isIPv6) { + if (STATUS_IPV6_UNK.contains(status)) + return false; + return !STATUS_IPV6_FW.contains(status); + } else { + if (STATUS_IPV4_UNK.contains(status)) + return false; + return !STATUS_IPV4_FW.contains(status); + } } /** @@ -4002,7 +4035,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority // to prevent thrashing if ((STATUS_OK.contains(old) && STATUS_FW.contains(status)) || (STATUS_OK.contains(status) && STATUS_FW.contains(old)) || - (STATUS_FW.contains(status) && STATUS_FW.contains(old))) { + (STATUS_FW.contains(status) && STATUS_FW.contains(old)) || + (!isIPv6 && STATUS_IPV4_UNK.contains(old) && !STATUS_IPV4_UNK.contains(status))) { if (status != _reachabilityStatusPending) { if (_log.shouldLog(Log.WARN)) _log.warn("Old status: " + old + " status pending confirmation: " + status +