From 79a963fcab6ab7a7f0466d6b95085c0c26c2e84e Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Fri, 1 May 2009 00:42:31 +0000
Subject: [PATCH] - Implement config save of new IP address options - Implement
 local address and UPnP configuration of UDP address - Limit received port to
 1024 minimum

---
 .../net/i2p/router/web/ConfigNetHandler.java  | 62 ++++++++++++++-----
 .../net/i2p/router/web/ConfigNetHelper.java   | 32 ++++------
 apps/routerconsole/jsp/config.jsp             | 46 +++++++-------
 router/java/src/net/i2p/router/Router.java    |  5 +-
 .../net/i2p/router/transport/Transport.java   |  6 +-
 .../router/transport/ntcp/NTCPTransport.java  |  6 ++
 .../router/transport/udp/UDPTransport.java    | 60 ++++++++++++++----
 7 files changed, 146 insertions(+), 71 deletions(-)

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 8700f18456..8a671632ff 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java
@@ -26,7 +26,10 @@ public class ConfigNetHandler extends FormHandler {
     private String _ntcpHostname;
     private String _ntcpPort;
     private String _tcpPort;
+    private String _udpHost1;
+    private String _udpHost2;
     private String _udpPort;
+    private String _udpAutoIP;
     private String _ntcpAutoIP;
     private boolean _ntcpAutoPort;
     private boolean _upnp;
@@ -40,6 +43,7 @@ public class ConfigNetHandler extends FormHandler {
     private boolean _enableLoadTesting;
     private String _sharePct;
     private boolean _ratesOnly; // always false
+    private static final String PROP_HIDDEN = Router.PROP_HIDDEN_HIDDEN; // see Router for other choice
     
     protected void processForm() {
         if (_saveRequested || ( (_action != null) && ("Save changes".equals(_action)) )) {
@@ -55,9 +59,12 @@ public class ConfigNetHandler extends FormHandler {
     public void setEnabletimesync(String moo) { _timeSyncEnabled = true; }
     public void setRecheckReachability(String moo) { _recheckReachabilityRequested = true; }
     public void setRequireIntroductions(String moo) { _requireIntroductions = true; }
-    public void setHiddenMode(String moo) { _hiddenMode = true; }
     public void setDynamicKeys(String moo) { _dynamicKeys = true; }
     public void setEnableloadtesting(String moo) { _enableLoadTesting = true; }
+    public void setUdpAutoIP(String mode) {
+        _udpAutoIP = mode;
+        _hiddenMode = "hidden".equals(mode);
+    }
     public void setNtcpAutoIP(String mode) {
         _ntcpAutoIP = mode;
     }
@@ -78,6 +85,12 @@ public class ConfigNetHandler extends FormHandler {
     public void setNtcpport(String port) {
         _ntcpPort = (port != null ? port.trim() : null);
     }
+    public void setUdpHost1(String host) { 
+        _udpHost1 = (host != null ? host.trim() : null); 
+    }
+    public void setUdpHost2(String host) { 
+        _udpHost2 = (host != null ? host.trim() : null); 
+    }
     public void setUdpPort(String port) { 
         _udpPort = (port != null ? port.trim() : null); 
     }
@@ -117,6 +130,28 @@ public class ConfigNetHandler extends FormHandler {
         boolean restartRequired = false;
         
         if (!_ratesOnly) {
+            // IP Settings
+            String oldUdp = _context.getProperty(UDPTransport.PROP_SOURCES, UDPTransport.DEFAULT_SOURCES);
+            String oldUHost = _context.getProperty(UDPTransport.PROP_EXTERNAL_HOST, "");
+            if (_udpAutoIP != null) {
+                String uhost = "";
+                if (_udpAutoIP.equals("fixed")) {
+                    if (_udpHost1 != null && _udpHost1.length() > 0)
+                        uhost =  _udpHost1;
+                    else if (_udpHost2 != null && _udpHost2.length() > 0)
+                        uhost =  _udpHost1;
+                    else
+                        _udpAutoIP = UDPTransport.DEFAULT_SOURCES;
+                }
+                _context.router().setConfigSetting(UDPTransport.PROP_SOURCES, _udpAutoIP);
+                _context.router().setConfigSetting(UDPTransport.PROP_EXTERNAL_HOST, uhost);
+                if ((!oldUdp.equals(_udpAutoIP)) || (!oldUHost.equals(uhost))) {
+                   addFormNotice("Updating IP address");
+                   restartRequired = true;
+                }
+            }
+
+            // NTCP Settings
             // Normalize some things to make the following code a little easier...
             String oldNHost = _context.router().getConfigSetting(ConfigNetHelper.PROP_I2NP_NTCP_HOSTNAME);
             if (oldNHost == null) oldNHost = "";
@@ -154,6 +189,7 @@ public class ConfigNetHandler extends FormHandler {
                 restartRequired = true;
             }
 
+            // UDP Settings
             if ( (_udpPort != null) && (_udpPort.length() > 0) ) {
                 String oldPort = "" + _context.getProperty(UDPTransport.PROP_INTERNAL_PORT, UDPTransport.DEFAULT_INTERNAL_PORT);
                 if (!oldPort.equals(_udpPort)) {
@@ -168,6 +204,7 @@ public class ConfigNetHandler extends FormHandler {
         
         updateRates();
         
+        boolean switchRequired = false;
         if (!_ratesOnly) {
             if (_sharePct != null) {
                 String old = _context.router().getConfigSetting(Router.PROP_BANDWIDTH_SHARE_PERCENTAGE);
@@ -178,19 +215,14 @@ public class ConfigNetHandler extends FormHandler {
             }
 
             // If hidden mode value changes, restart is required
-            if (_hiddenMode && "false".equalsIgnoreCase(_context.getProperty(Router.PROP_HIDDEN, "false"))) {
-                _context.router().setConfigSetting(Router.PROP_HIDDEN, "true");
-                _context.router().addCapabilities(_context.router().getRouterInfo());
-                addFormNotice("Gracefully restarting into Hidden Router Mode. Make sure you have no 0-1 length "
+            switchRequired = _hiddenMode != _context.router().isHidden();
+            if (switchRequired) {
+                _context.router().setConfigSetting(PROP_HIDDEN, "" + _hiddenMode);
+                if (_hiddenMode)
+                    addFormNotice("Gracefully restarting into Hidden Router Mode. Make sure you have no 0-1 length "
                               + "<a href=\"configtunnels.jsp\">tunnels!</a>");
-                hiddenSwitch();
-            }
-
-            if (!_hiddenMode && "true".equalsIgnoreCase(_context.getProperty(Router.PROP_HIDDEN, "false"))) {
-                _context.router().removeConfigSetting(Router.PROP_HIDDEN);
-                _context.router().getRouterInfo().delCapability(RouterInfo.CAPABILITY_HIDDEN);
-                addFormNotice("Gracefully restarting to exit Hidden Router Mode");
-                hiddenSwitch();
+                else
+                    addFormNotice("Gracefully restarting to exit Hidden Router Mode");
             }
 
             _context.router().setConfigSetting(Router.PROP_DYNAMIC_KEYS, "" + _dynamicKeys);
@@ -225,7 +257,9 @@ public class ConfigNetHandler extends FormHandler {
                 addFormNotice("Error saving the configuration (applied but not saved) - please see the error logs");
         }
         
-        if (restartRequired) {
+        if (switchRequired) {
+            hiddenSwitch();
+        } else if (restartRequired) {
             //addFormNotice("Performing a soft restart");
             //_context.router().restart();
             //addFormNotice("Soft restart complete");
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 10ce760614..92e502d3e4 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java
@@ -23,24 +23,19 @@ public class ConfigNetHelper extends HelperBase {
     private final static String DISABLED = " disabled=\"true\" ";
 
     public String getUdphostname() {
-        String hostname = _context.getProperty(UDPTransport.PROP_EXTERNAL_HOST); 
-        if (hostname == null) return "";
-        return hostname;
+        return _context.getProperty(UDPTransport.PROP_EXTERNAL_HOST, ""); 
     }
 
     public String getNtcphostname() {
         if (!TransportManager.enableNTCP(_context))
             return "\" disabled=\"true";
-        String hostname = _context.getProperty(PROP_I2NP_NTCP_HOSTNAME); 
-        if (hostname == null) return "";
-        return hostname;
+        return _context.getProperty(PROP_I2NP_NTCP_HOSTNAME, "");
     }
+
     public String getNtcpport() { 
         if (!TransportManager.enableNTCP(_context))
             return "\" disabled=\"true";
-        String port = _context.getProperty(PROP_I2NP_NTCP_PORT); 
-        if (port == null) return "";
-        return port;
+        return _context.getProperty(PROP_I2NP_NTCP_PORT, ""); 
     }
     
     public String getUdpAddress() {
@@ -90,10 +85,6 @@ public class ConfigNetHelper extends HelperBase {
         return "";
     }
 
-    public String getHiddenModeChecked() {
-        return getChecked(Router.PROP_HIDDEN);
-    }
-
     public String getDynamicKeysChecked() {
         return getChecked(Router.PROP_DYNAMIC_KEYS);
     }
@@ -125,14 +116,17 @@ public class ConfigNetHelper extends HelperBase {
         return "";
     }
 
-//////////////// FIXME
     public String getUdpAutoIPChecked(int mode) {
-        String hostname = _context.getProperty(PROP_I2NP_NTCP_HOSTNAME); 
+        String hostname = _context.getProperty(UDPTransport.PROP_EXTERNAL_HOST);
         boolean specified = hostname != null && hostname.length() > 0;
-        boolean auto = Boolean.valueOf(_context.getProperty(PROP_I2NP_NTCP_AUTO_IP)).booleanValue();
-        if ((mode == 0 && (!specified) && !auto) ||
-            (mode == 1 && specified && !auto) ||
-            (mode == 2 && auto))
+        boolean hidden = _context.router().isHidden();
+        String sources = _context.getProperty(UDPTransport.PROP_SOURCES, UDPTransport.DEFAULT_SOURCES);
+        if ((mode == 0 && sources.equals("ssu") && !hidden) ||
+            (mode == 1 && specified && !hidden) ||
+            (mode == 2 && hidden) ||
+            (mode == 3 && sources.equals("local,upnp,ssu") && !hidden) ||
+            (mode == 4 && sources.equals("local,ssu") && !hidden) ||
+            (mode == 5 && sources.equals("upnp,ssu") && !hidden))
             return CHECKED;
         return "";
     }
diff --git a/apps/routerconsole/jsp/config.jsp b/apps/routerconsole/jsp/config.jsp
index 37ace064f9..a13da220c0 100644
--- a/apps/routerconsole/jsp/config.jsp
+++ b/apps/routerconsole/jsp/config.jsp
@@ -67,22 +67,27 @@
  <a href="oldstats.jsp#test.rtt">test.rtt</a> and related stats.</p>
  <hr />
 -->
- <b>UDP Configuration:</b><br />
+ <p>
+ <b>UPnP Configuration:</b><br />
+    <input type="checkbox" name="upnp" value="true" <jsp:getProperty name="nethelper" property="upnpChecked" /> />
+    Enable UPnP to open firewall ports
+ </p><p>
+ <b>IP Configuration:</b><br />
  Externally reachable hostname or IP address:<br />
-    <input type="radio" name="udpAutoIP" value="0" <%=nethelper.getUdpAutoIPChecked(0) %> />
-    Use SSU detection only<br />
-    <input type="radio" name="udpAutoIP" value="24" <%=nethelper.getUdpAutoIPChecked(24) %> />
+    <input type="radio" name="udpAutoIP" value="local,upnp,ssu" <%=nethelper.getUdpAutoIPChecked(3) %> />
     Use local public address if available, then UPnP detection, then SSU detection<br />
-    <input type="radio" name="udpAutoIP" value="16" <%=nethelper.getUdpAutoIPChecked(16) %> />
+    <input type="radio" name="udpAutoIP" value="local,ssu" <%=nethelper.getUdpAutoIPChecked(4) %> />
     Use local public address if available, then SSU detection<br />
-    <input type="radio" name="udpAutoIP" value="8" <%=nethelper.getUdpAutoIPChecked(8) %> />
+    <input type="radio" name="udpAutoIP" value="upnp,ssu" <%=nethelper.getUdpAutoIPChecked(5) %> />
     Use UPnP detection if available, then SSU detection<br />
-    <input type="radio" name="udpAutoIP" value="1" <%=nethelper.getUdpAutoIPChecked(1) %> />
+    <input type="radio" name="udpAutoIP" value="ssu" <%=nethelper.getUdpAutoIPChecked(0) %> />
+    Use SSU detection only<br />
+    <input type="radio" name="udpAutoIP" value="fixed" <%=nethelper.getUdpAutoIPChecked(1) %> />
     Specify hostname or IP:
-    <input name ="udphost" type="text" size="16" value="<jsp:getProperty name="nethelper" property="udphostname" />" />
+    <input name ="udpHost1" type="text" size="16" value="<jsp:getProperty name="nethelper" property="udphostname" />" />
     <% String[] ips = nethelper.getAddresses();
        if (ips.length > 0) {
-           out.print(" or <select name=\"interface\"><option value=\"\" selected=\"true\">Select Interface</option>\n");
+           out.print(" or <select name=\"udpHost2\"><option value=\"\" selected=\"true\">Select Interface</option>\n");
            for (int i = 0; i < ips.length; i++) {
                out.print("<option value=\"");
                out.print(ips[i]);
@@ -94,14 +99,16 @@
        }
     %>
     <br />
-    <input type="radio" name="udpAutoIP" value="2" <%=nethelper.getUdpAutoIPChecked(2) %> />
-    Hidden mode - do not publish IP<i>(not recommended)</i><br />
+    <input type="radio" name="udpAutoIP" value="hidden" <%=nethelper.getUdpAutoIPChecked(2) %> />
+    Hidden mode - do not publish IP<i>(not recommended; change restarts router)</i><br />
+ </p><p>
+ <b>UDP Configuration:</b><br />
  Internal UDP port:
  <input name ="udpPort" type="text" size="6" value="<jsp:getProperty name="nethelper" property="configuredUdpPort" />" /><br />
 <input type="checkbox" name="requireIntroductions" value="true" <jsp:getProperty name="nethelper" property="requireIntroductionsChecked" /> />
  Require SSU introductions
  <i>(Enable if you cannot open your firewall)</i>
- <p>
+ </p><p>
  Current External UDP address: <i><jsp:getProperty name="nethelper" property="udpAddress" /></i><br />
  </p><p>If you can, please poke a hole in your NAT or firewall to allow unsolicited UDP packets to reach
     you on your external UDP address.  If you can't, I2P now includes supports UDP hole punching
@@ -111,8 +118,8 @@
     the <i>Reachability: Firewalled</i> line), or you can manually require them here.  
     Users behind symmetric NATs, such as OpenBSD's pf, are not currently supported.</p>
 <input type="submit" name="recheckReachability" value="Check network reachability..." />
- <p>
- <b>Inbound TCP connection configuration:</b><br />
+ </p><p>
+ <b>Inbound TCP Configuration:</b><br />
  Externally reachable hostname or IP address:<br />
     <input type="radio" name="ntcpAutoIP" value="false" <%=nethelper.getTcpAutoIPChecked(0) %> />
     Disable (Firewalled)<br />
@@ -125,7 +132,7 @@
     Specify hostname or IP:
     <input name ="ntcphost" type="text" size="16" value="<jsp:getProperty name="nethelper" property="ntcphostname" />" />
     <i>(dyndns and the like are fine)</i><br />
- <p>
+ </p><p>
  Externally reachable TCP port:<br />
     <input type="radio" name="ntcpAutoPort" value="2" <%=nethelper.getTcpAutoPortChecked(2) %> />
     Use the same port configured for SSU
@@ -133,8 +140,8 @@
     <input type="radio" name="ntcpAutoPort" value="1" <%=nethelper.getTcpAutoPortChecked(1) %> />
     Specify Port:
     <input name ="ntcpport" type="text" size="6" value="<jsp:getProperty name="nethelper" property="ntcpport" />" /><br />
- <p>A hostname entered here will be published in the network database.
-    It is <b>not private</b>.
+ </p><p>Hostnames entered here will be published in the network database.
+    They are <b>not private</b>.
     Also, <b>do not enter a private IP address</b> like 127.0.0.1 or 192.168.1.1.
  </p>
  <p>You do <i>not</i> need to allow inbound TCP connections - outbound connections work with no
@@ -142,11 +149,6 @@
     in your NAT or firewall for unsolicited TCP connections.  If you specify the wrong IP address or
     hostname, or do not properly configure your NAT or firewall, your network performance will degrade
     substantially.  When in doubt, leave the hostname and port number blank.</p>
- <p>
- <b>UPnP Configuration:</b><br />
- Open firewall port using UPnP:
-    <input type="checkbox" name="upnp" value="true" <jsp:getProperty name="nethelper" property="upnpChecked" /> /><br />
- </p>
  <p><b>Note: changing any of these settings will terminate all of your connections and effectively
     restart your router.</b>
  </p>
diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java
index 2c9a1319ea..a849e385ca 100644
--- a/router/java/src/net/i2p/router/Router.java
+++ b/router/java/src/net/i2p/router/Router.java
@@ -73,7 +73,10 @@ public class Router {
     /** used to differentiate routerInfo files on different networks */
     public static final int NETWORK_ID = 2;
     
+    /** this puts an 'H' in your routerInfo **/
     public final static String PROP_HIDDEN = "router.hiddenMode";
+    /** this does not put an 'H' in your routerInfo **/
+    public final static String PROP_HIDDEN_HIDDEN = "router.isHidden";
     public final static String PROP_DYNAMIC_KEYS = "router.dynamicKeys";
     public final static String PROP_INFO_FILENAME = "router.info.location";
     public final static String PROP_INFO_FILENAME_DEFAULT = "router.info";
@@ -423,7 +426,7 @@ public class Router {
         RouterInfo ri = _routerInfo;
         if ( (ri != null) && (ri.isHidden()) )
             return true;
-        return Boolean.valueOf(_context.getProperty("router.isHidden", "false")).booleanValue();
+        return Boolean.valueOf(_context.getProperty(PROP_HIDDEN_HIDDEN)).booleanValue();
     }
     public Certificate createCertificate() {
         Certificate cert = new Certificate();
diff --git a/router/java/src/net/i2p/router/transport/Transport.java b/router/java/src/net/i2p/router/transport/Transport.java
index d7d73b77b5..fc5c32153a 100644
--- a/router/java/src/net/i2p/router/transport/Transport.java
+++ b/router/java/src/net/i2p/router/transport/Transport.java
@@ -35,9 +35,9 @@ public interface Transport {
     public RouterAddress startListening();
     public void stopListening();
     public RouterAddress getCurrentAddress();
-    public static final String SOURCE_UPNP = "UPnP";
-    public static final String SOURCE_INTERFACE = "Local interface";
-    public static final String SOURCE_CONFIG = "Configuration change";
+    public static final String SOURCE_UPNP = "upnp";
+    public static final String SOURCE_INTERFACE = "local";
+    public static final String SOURCE_CONFIG = "config"; // unused
     public void externalAddressReceived(String source, byte[] ip, int port);
     public void forwardPortStatus(int port, boolean success, String reason);
     public int getRequestedPort();
diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java
index 21bbcdda18..a6020ae341 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java
@@ -542,6 +542,12 @@ public class NTCPTransport extends TransportImpl {
     /**
      *  If we didn't used to be forwarded, and we have an address,
      *  and we are configured to use UPnP, update our RouterAddress
+     *
+     *  Don't do anything now. If it fails, we don't know if it's
+     *  because there is no firewall, or if the firewall rejected the request.
+     *  So we just use the SSU reachability status
+     *  to decide whether to enable inbound NTCP. SSU will have CSFI build a new
+     *  NTCP address when it transitions to OK.
      */
     public void forwardPortStatus(int port, boolean success, String reason) {
         if (_log.shouldLog(Log.WARN)) {
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 a43213a9ca..e2bae885d4 100644
--- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
+++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
@@ -100,6 +100,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
     public static final String STYLE = "SSU";
     public static final String PROP_INTERNAL_PORT = "i2np.udp.internalPort";
     public static final int DEFAULT_INTERNAL_PORT = 8887;
+    private static final int MIN_EXTERNAL_PORT = 1024;
 
     /** define this to explicitly set an external IP address */
     public static final String PROP_EXTERNAL_HOST = "i2np.udp.host";
@@ -118,9 +119,14 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
     public static final String PROP_PREFER_UDP = "i2np.udp.preferred";
     private static final String DEFAULT_PREFER_UDP = "false";
     
+    /** if true (default), we don't change our advertised port no matter what our peers tell us */
     public static final String PROP_FIXED_PORT = "i2np.udp.fixedPort";
     private static final String DEFAULT_FIXED_PORT = "true";
 
+    /** allowed sources of address updates */
+    public static final String PROP_SOURCES = "i2np.udp.addressSources";
+    public static final String DEFAULT_SOURCES = "local,upnp,ssu";
+
     /** do we require introducers, regardless of our status? */
     public static final String PROP_FORCE_INTRODUCERS = "i2np.udp.forceIntroducers";
     /** do we allow direct SSU connections, sans introducers?  */
@@ -326,11 +332,21 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
     
     /**
      * From config, UPnP, local i/f, ...
+     *
+     * @param source used for logging only
+     * @param ip publicly routable IPv4 only
+     * @param port 0 if unknown
      */
     public void externalAddressReceived(String source, byte[] ip, int port) {
         String s = RemoteHostId.toString(ip);
         if (_log.shouldLog(Log.WARN))
             _log.warn("Received address: " + s + " port: " + port + " from: " + source);
+        if (explicitAddressSpecified())
+            return;
+        String sources = _context.getProperty(PROP_SOURCES, DEFAULT_SOURCES);
+        if (!sources.contains(source))
+            return;
+        changeAddress(ip, port);
     }
 
     /**
@@ -338,9 +354,15 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
      * Right now, we just blindly trust them, changing our IP and port on a
      * whim.  this is not good ;)
      *
+     * Todo:
+     *   - Much better tracking of troublemakers
+     *   - Disable if we have good local address or UPnP
+     *
+     * @param ip publicly routable IPv4 only
+     * @param ourPort >= 1024
      */
     void externalAddressReceived(Hash from, byte ourIP[], int ourPort) {
-        boolean isValid = isValid(ourIP);
+        boolean isValid = isValid(ourIP) && ourPort >= MIN_EXTERNAL_PORT;
         boolean explicitSpecified = explicitAddressSpecified();
         boolean inboundRecent = _lastInboundReceivedOn + ALLOW_IP_CHANGE_INTERVAL > System.currentTimeMillis();
         if (_log.shouldLog(Log.INFO))
@@ -350,15 +372,15 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
         
         if (explicitSpecified) 
             return;
+        String sources = _context.getProperty(PROP_SOURCES, DEFAULT_SOURCES);
+        if (!sources.contains("ssu"))
+            return;
         
-        boolean fixedPort = getIsPortFixed();
-        boolean updated = false;
-        boolean fireTest = false;
         if (!isValid) {
             // ignore them 
             if (_log.shouldLog(Log.ERROR))
                 _log.error("The router " + from.toBase64() + " told us we have an invalid IP - " 
-                           + RemoteHostId.toString(ourIP) + ".  Lets throw tomatoes at them");
+                           + RemoteHostId.toString(ourIP) + " port " +  ourPort + ".  Lets throw tomatoes at them");
             markUnreachable(from);
             //_context.shitlist().shitlistRouter(from, "They said we had an invalid IP", STYLE);
             return;
@@ -367,6 +389,19 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
             if (_log.shouldLog(Log.INFO))
                 _log.info("Ignoring IP address suggestion, since we have received an inbound con recently");
         } else {
+            changeAddress(ourIP, ourPort);
+        }
+        
+    }
+    
+    /**
+     * @param ourPort >= 1024 or 0 for no change
+     */
+    private void changeAddress(byte ourIP[], int ourPort) {
+        boolean fixedPort = getIsPortFixed();
+        boolean updated = false;
+        boolean fireTest = false;
+
             synchronized (this) {
                 if ( (_externalListenHost == null) ||
                      (!eq(_externalListenHost.getAddress(), _externalListenPort, ourIP, ourPort)) ) {
@@ -378,11 +413,13 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
                             _log.info("Trying to change our external address...");
                         try {
                             _externalListenHost = InetAddress.getByAddress(ourIP);
-                            if (!fixedPort)
+                            if (ourPort >= MIN_EXTERNAL_PORT && !fixedPort)
                                 _externalListenPort = ourPort;
-                            rebuildExternalAddress();
-                            replaceAddress(_externalAddress);
-                            updated = true;
+                            if (_externalListenPort >= MIN_EXTERNAL_PORT)  {
+                                rebuildExternalAddress();
+                                replaceAddress(_externalAddress);
+                                updated = true;
+                            }
                         } catch (UnknownHostException uhe) {
                             _externalListenHost = null;
                             if (_log.shouldLog(Log.INFO))
@@ -401,8 +438,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
                         _log.info("Same address as the current one");
                 }
             }
-        }
-        
+
         if (fireTest) {
             _context.statManager().addRateData("udp.addressTestInsteadOfUpdate", 1, 0);
             _testEvent.forceRun();
@@ -417,7 +453,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
             SimpleTimer.getInstance().addEvent(_testEvent, 5*1000);
         }
     }
-    
+
     private static final boolean eq(byte laddr[], int lport, byte raddr[], int rport) {
         return (rport == lport) && DataHelper.eq(laddr, raddr);
     }
-- 
GitLab