Author: zothar
Date: 2007-09-21 23:24:55 +0000 (Fri, 21 Sep 2007)
New Revision: 15251

Added:
   trunk/freenet/src/freenet/support/transport/ip/HostnameSyntaxException.java
   trunk/freenet/src/freenet/support/transport/ip/HostnameUtil.java
Modified:
   trunk/freenet/src/freenet/io/AddressIdentifier.java
   trunk/freenet/src/freenet/io/comm/Peer.java
   trunk/freenet/src/freenet/node/Node.java
   trunk/freenet/src/freenet/node/NodeIPDetector.java
   trunk/freenet/src/freenet/node/OpennetManager.java
   trunk/freenet/src/freenet/node/PeerNode.java
Log:
Do hostname and/or IPv4/IPv6 IP address syntax validation on physical.udp 
values.  This will, for example, prevent the node from making repeated DNS 
requests that will always fail.

Modified: trunk/freenet/src/freenet/io/AddressIdentifier.java
===================================================================
--- trunk/freenet/src/freenet/io/AddressIdentifier.java 2007-09-21 18:33:11 UTC 
(rev 15250)
+++ trunk/freenet/src/freenet/io/AddressIdentifier.java 2007-09-21 23:24:55 UTC 
(rev 15251)
@@ -60,6 +60,21 @@
         *         otherwise
         */
        public static AddressType getAddressType(String address) {
+               return AddressIdentifier.getAddressType(address,false);
+       }
+
+       /**
+        * Tries to detemine the address type of the given address.
+        * 
+        * @param address
+        *            The address to determine the type of
+        * @param allowIPv6PercentScopeID
+        *            If true, match %<scope-id> suffixed IPv6 IP addresses
+        * @return {@link AddressType#OTHER} if <code>address</code> is a
+        *         hostname, {@link AddressType#IPv4} or {@link 
AddressType#IPv6}
+        *         otherwise
+        */
+       public static AddressType getAddressType(String address, boolean 
allowIPv6PercentScopeID) {
                String byteRegex = "([01]?[0-9]?[0-9]?|2[0-4][0-9]|25[0-5])";
                String ipv4AddressRegex = byteRegex + "\\.(" + byteRegex + 
"\\.)?(" + byteRegex + "\\.)?" + byteRegex;
                if (Pattern.matches(ipv4AddressRegex, address)) {
@@ -67,6 +82,9 @@
                }
                String wordRegex = "([0-9a-fA-F]{1,4})";
                String ipv6AddressRegex = wordRegex + "?:" + wordRegex + ':' + 
wordRegex + ':' + wordRegex + ':' + wordRegex + ':' + wordRegex + ':' + 
wordRegex + ':' + wordRegex;
+               if (allowIPv6PercentScopeID) {
+                       ipv6AddressRegex = ipv6AddressRegex + 
"(?:%[0-9]{1,3})?";
+               }
                if (Pattern.matches(ipv6AddressRegex, address)) {
                        return AddressType.IPv6;
                }

Modified: trunk/freenet/src/freenet/io/comm/Peer.java
===================================================================
--- trunk/freenet/src/freenet/io/comm/Peer.java 2007-09-21 18:33:11 UTC (rev 
15250)
+++ trunk/freenet/src/freenet/io/comm/Peer.java 2007-09-21 23:24:55 UTC (rev 
15251)
@@ -25,6 +25,8 @@
 import java.net.InetAddress;
 import java.net.UnknownHostException;

+import freenet.support.transport.ip.HostnameSyntaxException;
+import freenet.support.transport.ip.HostnameUtil;
 import freenet.support.transport.ip.IPUtil;

 /**
@@ -72,11 +74,45 @@
         * @param physical The string to be parsed, in the format [ ip or 
domain name ]:[ port number].
         * @param allowUnknown If true, allow construction of the Peer even if 
the domain name
         * lookup fails.
+        * @param checkHostname If true, validate the syntax of the given DNS 
hostname or IPv4
+        * IP address
+        * @throws HostSyntaxException If the string is not formatted as a 
proper DNS hostname
+        * or IPv4 IP address
         * @throws PeerParseException If the string is not valid e.g. if it 
doesn't contain a 
         * port.
         * @throws UnknownHostException If allowUnknown is not set, and a 
domain name which does
         * not exist was passed in.
         */
+    public Peer(String physical, boolean allowUnknown, boolean checkHostname) 
throws HostnameSyntaxException, PeerParseException, UnknownHostException {
+        int offset = physical.lastIndexOf(':'); // ipv6
+        if(offset < 0) throw new PeerParseException();
+        String host = physical.substring(0, offset);
+        if(checkHostname) {
+               if(!HostnameUtil.isValidHostname(host, true)) throw new 
HostnameSyntaxException();
+               }
+        addr = new FreenetInetAddress(host, allowUnknown);
+        String strport = physical.substring(offset+1);
+        try {
+            _port = Integer.parseInt(strport);
+        } catch (NumberFormatException e) {
+            throw new PeerParseException(e);
+        }
+    }
+
+
+       /**
+        * Create a Peer from a string. This may be an IP address or a domain 
name. If it
+        * is the latter, the name is primary rather than the IP address; 
+        * getHandshakeAddress() will do a new lookup on the name, and change 
the IP address
+        * if the domain name has changed.
+        * @param physical The string to be parsed, in the format [ ip or 
domain name ]:[ port number].
+        * @param allowUnknown If true, allow construction of the Peer even if 
the domain name
+        * lookup fails.
+        * @throws PeerParseException If the string is not valid e.g. if it 
doesn't contain a 
+        * port.
+        * @throws UnknownHostException If allowUnknown is not set, and a 
domain name which does
+        * not exist was passed in.
+        */
     public Peer(String physical, boolean allowUnknown) throws 
PeerParseException, UnknownHostException {
         int offset = physical.lastIndexOf(':'); // ipv6
         if(offset < 0) throw new PeerParseException();
@@ -88,7 +124,7 @@
         } catch (NumberFormatException e) {
             throw new PeerParseException(e);
         }
-    }
+       }

     public Peer(FreenetInetAddress addr, int port) {
        this.addr = addr;

Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java    2007-09-21 18:33:11 UTC (rev 
15250)
+++ trunk/freenet/src/freenet/node/Node.java    2007-09-21 23:24:55 UTC (rev 
15251)
@@ -105,6 +105,7 @@
 import freenet.support.api.LongCallback;
 import freenet.support.api.ShortCallback;
 import freenet.support.api.StringCallback;
+import freenet.support.transport.ip.HostnameSyntaxException;

 /**
  * @author amphibian
@@ -405,7 +406,11 @@
                                // Just keep the first one with the correct 
port number.
                                Peer p;
                                try {
-                                       p = new Peer(udp[i], false);
+                                       p = new Peer(udp[i], false, true);
+                               } catch (HostnameSyntaxException e) {
+                                       Logger.error(this, "Invalid hostname or 
IP Address syntax error while parsing darknet node reference: "+udp[i]);
+                                       System.err.println("Invalid hostname or 
IP Address syntax error while parsing darknet node reference: "+udp[i]);
+                                       continue;
                                } catch (PeerParseException e) {
                                        IOException e1 = new IOException();
                                        e1.initCause(e);

Modified: trunk/freenet/src/freenet/node/NodeIPDetector.java
===================================================================
--- trunk/freenet/src/freenet/node/NodeIPDetector.java  2007-09-21 18:33:11 UTC 
(rev 15250)
+++ trunk/freenet/src/freenet/node/NodeIPDetector.java  2007-09-21 23:24:55 UTC 
(rev 15251)
@@ -11,6 +11,7 @@
 import freenet.config.SubConfig;
 import freenet.io.comm.FreenetInetAddress;
 import freenet.io.comm.Peer;
+import freenet.io.comm.PeerParseException;
 import freenet.l10n.L10n;
 import freenet.node.useralerts.IPUndetectedUserAlert;
 import freenet.node.useralerts.SimpleUserAlert;
@@ -21,6 +22,7 @@
 import freenet.support.Logger;
 import freenet.support.api.BooleanCallback;
 import freenet.support.api.StringCallback;
+import freenet.support.transport.ip.HostnameSyntaxException;
 import freenet.support.transport.ip.IPAddressDetector;
 import freenet.support.transport.ip.IPUtil;

@@ -304,6 +306,17 @@
                                        redetectAddress();
                                        return;
                                }
+                               // Try making a dummy Peer, which will allow us 
to do a syntax check on the given hostname/IP address
+                               try {
+                                       String hostAndDummyPort = val + 
":8888";  // add a dummy port so our string can be parsed by Peer's constructor
+                                       new Peer(hostAndDummyPort, false, true);
+                               } catch (HostnameSyntaxException e) {
+                                       throw new 
InvalidConfigValueException(l10n("unknownHostErrorInIPOverride", "error", 
"hostname or IP address syntax error"));
+                               } catch (PeerParseException e) {
+                                       throw new 
InvalidConfigValueException(l10n("unknownHostErrorInIPOverride", "error", 
"parse error"));
+                               } catch (UnknownHostException e) {
+                                       throw new 
InvalidConfigValueException(l10n("unknownHostErrorInIPOverride", "error", 
e.getMessage()));
+                               }
                                FreenetInetAddress addr;
                                try {
                                        addr = new FreenetInetAddress(val, 
false);

Modified: trunk/freenet/src/freenet/node/OpennetManager.java
===================================================================
--- trunk/freenet/src/freenet/node/OpennetManager.java  2007-09-21 18:33:11 UTC 
(rev 15250)
+++ trunk/freenet/src/freenet/node/OpennetManager.java  2007-09-21 23:24:55 UTC 
(rev 15251)
@@ -21,6 +21,7 @@
 import freenet.support.LRUQueue;
 import freenet.support.Logger;
 import freenet.support.SimpleFieldSet;
+import freenet.support.transport.ip.HostnameSyntaxException;

 /**
  * Central location for all things opennet.
@@ -164,7 +165,11 @@
                                // Just keep the first one with the correct 
port number.
                                Peer p;
                                try {
-                                       p = new Peer(udp[i], false);
+                                       p = new Peer(udp[i], false, true);
+                               } catch (HostnameSyntaxException e) {
+                                       Logger.error(this, "Invalid hostname or 
IP Address syntax error while parsing opennet node reference: "+udp[i]);
+                                       System.err.println("Invalid hostname or 
IP Address syntax error while parsing opennet node reference: "+udp[i]);
+                                       continue;
                                } catch (PeerParseException e) {
                                        IOException e1 = new IOException();
                                        e1.initCause(e);

Modified: trunk/freenet/src/freenet/node/PeerNode.java
===================================================================
--- trunk/freenet/src/freenet/node/PeerNode.java        2007-09-21 18:33:11 UTC 
(rev 15250)
+++ trunk/freenet/src/freenet/node/PeerNode.java        2007-09-21 23:24:55 UTC 
(rev 15251)
@@ -60,6 +60,7 @@
 import freenet.support.math.RunningAverage;
 import freenet.support.math.SimpleRunningAverage;
 import freenet.support.math.TimeDecayingRunningAverage;
+import freenet.support.transport.ip.HostnameSyntaxException;

 /**
  * @author amphibian
@@ -368,14 +369,26 @@
                String physical[]=fs.getAll("physical.udp");
                if(physical==null) {
                        // Be tolerant of nonexistent domains.
-                       Peer p = new Peer(fs.get("physical.udp"), true);
-                       if(p != null)
-                               nominalPeer.addElement(p);
+                       try {
+                               Peer p = new Peer(fs.get("physical.udp"), true, 
true);
+                               if(p != null)
+                               nominalPeer.addElement(p);
+                               } catch (HostnameSyntaxException e) {
+                                       Logger.error(this, "Invalid hostname or 
IP Address syntax error while parsing peer reference: "+fs.get("physical.udp"));
+                                       System.err.println("Invalid hostname or 
IP Address syntax error while parsing peer reference: "+fs.get("physical.udp"));
+                               }
                } else {
                        for(int i=0;i<physical.length;i++) {
-                                       Peer p = new Peer(physical[i], true);
-                                   if(!nominalPeer.contains(p)) 
-                                       nominalPeer.addElement(p);
+                               Peer p;
+                               try {
+                                               p = new Peer(physical[i], true, 
true);
+                                       } catch (HostnameSyntaxException e) {
+                                               Logger.error(this, "Invalid 
hostname or IP Address syntax error while parsing peer reference: 
"+physical[i]);
+                                               System.err.println("Invalid 
hostname or IP Address syntax error while parsing peer reference: 
"+physical[i]);
+                                               continue;
+                                       }
+                                       if(!nominalPeer.contains(p)) 
+                                               nominalPeer.addElement(p);
                        }
                }
         } catch (Exception e1) {
@@ -1742,11 +1755,23 @@
         try {
                String physical[]=fs.getAll("physical.udp");
                if(physical==null) {
-                       Peer p = new Peer(fs.get("physical.udp"), true);
-                       nominalPeer.addElement(p);
+                       try {
+                               Peer p = new Peer(fs.get("physical.udp"), true, 
true);
+                               nominalPeer.addElement(p);
+                               } catch (HostnameSyntaxException e) {
+                                       Logger.error(this, "Invalid hostname or 
IP Address syntax error while parsing peer reference: "+fs.get("physical.udp"));
+                                       System.err.println("Invalid hostname or 
IP Address syntax error while parsing peer reference: "+fs.get("physical.udp"));
+                               }
                } else {
                        for(int i=0;i<physical.length;i++) {
-                                       Peer p = new Peer(physical[i], true);
+                               Peer p;
+                               try {
+                                               p = new Peer(physical[i], true, 
true);
+                                       } catch (HostnameSyntaxException e) {
+                                               Logger.error(this, "Invalid 
hostname or IP Address syntax error while parsing peer reference: 
"+physical[i]);
+                                               System.err.println("Invalid 
hostname or IP Address syntax error while parsing peer reference: 
"+physical[i]);
+                                               continue;
+                                       }
                                    if(!nominalPeer.contains(p)) {
                                        if(oldNominalPeer.contains(p)) {
                                                // Do nothing

Added: 
trunk/freenet/src/freenet/support/transport/ip/HostnameSyntaxException.java
===================================================================
--- trunk/freenet/src/freenet/support/transport/ip/HostnameSyntaxException.java 
                        (rev 0)
+++ trunk/freenet/src/freenet/support/transport/ip/HostnameSyntaxException.java 
2007-09-21 23:24:55 UTC (rev 15251)
@@ -0,0 +1,11 @@
+/* This code is part of Freenet. It is distributed under the GNU General
+ * Public License, version 2 (or at your option any later version). See
+ * http://www.gnu.org/ for further details of the GPL. */
+package freenet.support.transport.ip;
+
+/**
+ * Thrown to indicate an invalid DNS hostname syntax.
+ */
+public class HostnameSyntaxException extends Exception {
+       private static final long serialVersionUID = -1;
+}

Added: trunk/freenet/src/freenet/support/transport/ip/HostnameUtil.java
===================================================================
--- trunk/freenet/src/freenet/support/transport/ip/HostnameUtil.java            
                (rev 0)
+++ trunk/freenet/src/freenet/support/transport/ip/HostnameUtil.java    
2007-09-21 23:24:55 UTC (rev 15251)
@@ -0,0 +1,32 @@
+/* This code is part of Freenet. It is distributed under the GNU General
+ * Public License, version 2 (or at your option any later version). See
+ * http://www.gnu.org/ for further details of the GPL. */
+package freenet.support.transport.ip;
+
+import freenet.io.AddressIdentifier;
+import freenet.support.Logger;
+
+public class HostnameUtil {
+
+       public static boolean isValidHostname(String hn, boolean 
allowIPAddress) {
+               if(allowIPAddress) {    
+                       // debugging log messages because AddressIdentifier 
doesn't appear to handle all IPv6 literals correctly, such as 
"fe80::204:1234:dead:beef"
+                       AddressIdentifier.AddressType addressType = 
AddressIdentifier.getAddressType(hn, true);
+                       Logger.debug(null, "Address type of '"+hn+"' appears to 
be '"+addressType+ '\'');
+                       if(!addressType.toString().equals("Other")) {
+                               // the address typer thinks it's either an IPv4 
or IPv6 IP address
+                               return true;
+                       }
+               }
+               // NOTE: It is believed that this code supports PUNYCODE based
+               //       ASCII Compatible Encoding (ACE) IDNA labels as
+               //       described in RFC3490.  Such an assertion has not be
+               //       thoroughly tested.
+               
if(!hn.matches("(?:[-!#\\$%&'\\*+\\\\/0-9=?A-Z^_`a-z{|}]+\\.)+[a-zA-Z]{2,6}")) {
+                       System.err.println("Failed to match "+hn+" as a 
hostname or IPv4/IPv6 IP address");
+                       return false;
+               }
+               return true;
+       }
+
+}


Reply via email to