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;
+ }
+
+}