Author: toad
Date: 2005-11-25 18:03:07 +0000 (Fri, 25 Nov 2005)
New Revision: 7603
Added:
trunk/freenet/src/freenet/transport/
trunk/freenet/src/freenet/transport/IPAddressDetector.java
trunk/freenet/src/freenet/transport/IPUtil.java
Modified:
trunk/freenet/src/freenet/node/Node.java
trunk/freenet/src/freenet/node/Version.java
Log:
221:
Working IP address detection (ported from 0.5).
Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java 2005-11-25 17:21:50 UTC (rev
7602)
+++ trunk/freenet/src/freenet/node/Node.java 2005-11-25 18:03:07 UTC (rev
7603)
@@ -17,7 +17,6 @@
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.SocketException;
-import java.net.UnknownHostException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
@@ -27,7 +26,6 @@
import freenet.client.ArchiveManager;
import freenet.client.HighLevelSimpleClient;
import freenet.client.HighLevelSimpleClientImpl;
-import freenet.client.InsertBlock;
import freenet.crypt.DiffieHellman;
import freenet.crypt.RandomSource;
import freenet.crypt.Yarrow;
@@ -58,6 +56,7 @@
import freenet.support.SimpleFieldSet;
import freenet.support.io.FilenameGenerator;
import freenet.support.io.TempBucketFactory;
+import freenet.transport.IPAddressDetector;
/**
* @author amphibian
@@ -113,6 +112,8 @@
private final HashMap transferringRequestSenders;
/** InsertSender's currently running, by KeyHTLPair */
private final HashMap insertSenders;
+ /** IP address detector */
+ private final IPAddressDetector ipDetector;
/** Locally published stream contexts */
private final Hashtable localStreamContexts;
@@ -299,6 +300,7 @@
portNumber = port;
startupTime = System.currentTimeMillis();
recentlyCompletedIDs = new LRUQueue();
+ ipDetector = new IPAddressDetector(10*1000, this);
if(prefix == null) prefix = "";
filenamesPrefix = prefix;
this.overrideIPAddress = overrideIP;
@@ -526,13 +528,7 @@
return overrideIPAddress;
}
Logger.minor(this, "IP address not overridden");
- try {
- // FIXME we should detect this properly
- return InetAddress.getLocalHost();
- } catch (UnknownHostException e) {
- Logger.error(this, "Caught "+e+" trying to get localhost!");
- return null;
- }
+ return ipDetector.getAddress();
}
/**
@@ -856,4 +852,10 @@
public RequestStarterClient makeStarterClient(short prioClass, short
prio, boolean inserts) {
return new RequestStarterClient(prioClass, prio, random, this,
inserts ? insertStarter : requestStarter);
}
+
+ public void redetectAddress() {
+
+ // TODO Auto-generated method stub
+
+ }
}
Modified: trunk/freenet/src/freenet/node/Version.java
===================================================================
--- trunk/freenet/src/freenet/node/Version.java 2005-11-25 17:21:50 UTC (rev
7602)
+++ trunk/freenet/src/freenet/node/Version.java 2005-11-25 18:03:07 UTC (rev
7603)
@@ -20,7 +20,7 @@
public static final String protocolVersion = "1.0";
/** The build number of the current revision */
- public static final int buildNumber = 221;
+ public static final int buildNumber = 222;
/** Oldest build of Fred we will talk to */
public static final int lastGoodBuild = 221;
Added: trunk/freenet/src/freenet/transport/IPAddressDetector.java
===================================================================
--- trunk/freenet/src/freenet/transport/IPAddressDetector.java 2005-11-25
17:21:50 UTC (rev 7602)
+++ trunk/freenet/src/freenet/transport/IPAddressDetector.java 2005-11-25
18:03:07 UTC (rev 7603)
@@ -0,0 +1,290 @@
+/* -*- Mode: java; c-basic-indent: 4; tab-width: 4 -*- */
+package freenet.transport;
+
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+import freenet.node.Node;
+import freenet.support.Logger;
+
+/**
+ * A class to autodetect our IP address(es)
+ */
+
+public class IPAddressDetector implements Runnable {
+
+ //private String preferedAddressString = null;
+ private final int interval;
+ private final Node node;
+ public IPAddressDetector(int interval, Node node) {
+ this.interval = interval;
+ this.node = node;
+ }
+
+ /**
+ * @return our name
+ */
+ public String getCheckpointName() {
+ return "Autodetection of IP addresses";
+ }
+
+ /**
+ * @return next scheduling point
+ */
+ public long nextCheckpoint() {
+ return System.currentTimeMillis() + interval; // We are pretty
cheap
+ }
+
+ InetAddress lastInetAddress = null;
+ InetAddress[] lastAddressList = null;
+ long lastDetectedTime = -1;
+
+ /**
+ * Fetches the currently detected IP address. If not detected yet a
detection is forced
+ * @param preferedAddress An address that for some reason is prefered
above others. Might be null
+ * @return Detected ip address
+ */
+ public InetAddress getAddress(String preferedAddress) {
+ return getAddress(0, preferedAddress);
+ }
+
+ public InetAddress getAddress(InetAddress preferredAddress) {
+ checkpoint(preferredAddress);
+ return lastInetAddress;
+ }
+
+ /**
+ * Fetches the currently detected IP address. If not detected yet a
detection is forced
+ * @return Detected ip address
+ */
+ public InetAddress getAddress() {
+ return getAddress(0, null);
+ }
+
+ /**
+ * Get the IP address
+ * @param preferedAddress An address that for some reason is prefered
above others. Might be null
+ * @return Detected ip address
+ */
+ public InetAddress getAddress(long recheckTime, String preferedAddress)
{
+ if (lastInetAddress == null
+ || System.currentTimeMillis() > (lastDetectedTime +
recheckTime))
+ checkpoint(preferedAddress);
+ return lastInetAddress;
+ }
+
+ /**
+ * Get the IP address
+ * @return Detected ip address
+ */
+ public InetAddress getAddress(long recheckTime) {
+ return getAddress(recheckTime, null);
+ }
+
+ public void checkpoint() {
+ checkpoint((InetAddress)null);
+ }
+
+ boolean old = false;
+
+ protected synchronized void checkpoint(String preferredAddress) {
+ InetAddress preferredInetAddress = null;
+ try {
+ preferredInetAddress =
InetAddress.getByName(preferredAddress);
+ //It there was something preferred then convert it to a
proper class
+ } catch (UnknownHostException e) {
+ }
+ checkpoint(preferredInetAddress);
+ }
+
+ /**
+ * Execute a checkpoint - detect our internet IP address and log it
+ * @param preferedAddress An address that for some reason is prefered
above others. Might be null
+ */
+ protected synchronized void checkpoint(InetAddress preferedInetAddress)
{
+ boolean logDEBUG = Logger.shouldLog(Logger.DEBUG, this);
+ Vector addrs = new Vector();
+
+ Enumeration interfaces = null;
+ try {
+ interfaces =
java.net.NetworkInterface.getNetworkInterfaces();
+ } catch (NoClassDefFoundError e) {
+ addrs.add(oldDetect());
+ old = true;
+ } catch (SocketException e) {
+ Logger.error(
+ this,
+ "SocketException trying to detect
NetworkInterfaces",
+ e);
+ addrs.add(oldDetect());
+ old = true;
+ }
+
+ if (!old) {
+ while (interfaces.hasMoreElements()) {
+ java.net.NetworkInterface iface =
+ (java.net.NetworkInterface)
(interfaces.nextElement());
+ if (logDEBUG)
+ Logger.debug(
+ this,
+ "Scanning NetworkInterface " +
iface.getDisplayName());
+ Enumeration ee = iface.getInetAddresses();
+ while (ee.hasMoreElements()) {
+
+ InetAddress addr = (InetAddress)
(ee.nextElement());
+ addrs.add(addr);
+ if (logDEBUG)
+ Logger.debug(
+ this,
+ "Adding address "
+ + addr
+ + " from "
+ +
iface.getDisplayName());
+ }
+ if (logDEBUG)
+ Logger.debug(
+ this,
+ "Finished scanning interface "
+ iface.getDisplayName());
+ }
+ if (logDEBUG)
+ Logger.debug(
+ this,
+ "Finished scanning interfaces");
+ }
+
+ if (preferedInetAddress == null
+ && lastInetAddress != null
+ ? isInternetAddress(lastInetAddress)
+ : true) //If no specific other address is
preferred then we prefer to keep our old address
+ preferedInetAddress = lastInetAddress;
+
+ InetAddress oldAddress = lastInetAddress;
+ onGetAddresses(addrs, preferedInetAddress);
+ lastDetectedTime = System.currentTimeMillis();
+ if (oldAddress != null && lastInetAddress != null &&
+ !lastInetAddress.equals(oldAddress)) {
+ Logger.minor(
+ this,
+ "Public IP Address changed from "
+ + oldAddress.getHostAddress()
+ + " to "
+ + lastInetAddress.getHostAddress());
+ node.redetectAddress();
+ // We know it changed
+ }
+ }
+
+ protected InetAddress oldDetect() {
+ boolean shouldLog = Logger.shouldLog(Logger.DEBUG, this);
+ if (shouldLog)
+ Logger.debug(
+ this,
+ "Running old style detection code");
+ DatagramSocket ds = null;
+ try {
+ try {
+ ds = new DatagramSocket();
+ } catch (SocketException e) {
+ Logger.error(this, "SocketException", e);
+ return null;
+ }
+
+ // This does not transfer any data
+ // The ip is a.root-servers.net, 42 is DNS
+ try {
+ ds.connect(InetAddress.getByName("198.41.0.4"),
42);
+ } catch (UnknownHostException ex) {
+ Logger.error(this, "UnknownHostException", ex);
+ return null;
+ }
+ return ds.getLocalAddress();
+ } finally {
+ if (ds != null) {
+ ds.close();
+ }
+ }
+ }
+
+ /** Do something with the list of detected IP addresses.
+ * @param v Vector of InetAddresses
+ * @param preferedInetAddress An address that for some reason is
prefered above others. Might be null
+ */
+ protected void onGetAddresses(Vector v, InetAddress
preferedInetAddress) {
+ boolean logDEBUG = Logger.shouldLog(Logger.DEBUG, this);
+ if (logDEBUG)
+ Logger.debug(
+ this,
+ "onGetAddresses found " + v.size() + "
potential addresses)");
+ boolean detectedInetAddress = false;
+ InetAddress addrDetected = null;
+ if (v.size() == 0) {
+ Logger.error(this, "No addresses found!");
+ addrDetected = null;
+ } else {
+// InetAddress lastNonValidAddress = null;
+ for (int x = 0; x < v.size(); x++) {
+ if (v.elementAt(x) != null) {
+ InetAddress i = (InetAddress)
(v.elementAt(x));
+ if (logDEBUG)
+ Logger.debug(
+ this,
+ "Address " + x + ": " +
i);
+ if (isInternetAddress(i)) {
+ //Do not even consider this
address if it isn't globally addressable
+ if (logDEBUG)
+ Logger.debug(
+ this,
+ "Setting
default address to "
+ +
i.getHostAddress());
+
+ addrDetected = i;
+ //Use the last detected valid
IP as 'detected' IP
+ detectedInetAddress = true;
+ if (preferedInetAddress != null
+ && addrDetected.equals(
+
preferedInetAddress)) { //Prefer the specified address if it is still available
to us. Do not look for more ones
+ if (logDEBUG)
+ Logger.debug(
+ this,
+
"Detected address is the preferred address, setting final address to "
+
+ lastInetAddress.getHostAddress());
+ lastInetAddress =
addrDetected;
+ return;
+ }
+
+ }// else
+// lastNonValidAddress = i;
+ }
+ }
+ //If we are here we didn't manage to find a valid
globally addressable IP. Do the best of the situation, return the last valid
non-addressable IP
+ //This address will be used by the node if the user has
configured localIsOK.
+// if (lastInetAddress == null || (!detectedInetAddress))
+// lastInetAddress = lastNonValidAddress;
+ }
+ lastInetAddress = addrDetected;
+ // FIXME: add support for multihoming
+ }
+
+ protected boolean isInternetAddress(InetAddress addr) {
+ return IPUtil.checkAddress(addr);
+ }
+
+ public void run() {
+ while(true) {
+ try {
+ Thread.sleep(interval);
+ } catch (InterruptedException e) {
+ // Ignore
+ }
+ try {
+ checkpoint();
+ } catch (Throwable t) {
+ Logger.error(this, "Caught "+t, t);
+ }
+ }
+ }
+}
Added: trunk/freenet/src/freenet/transport/IPUtil.java
===================================================================
--- trunk/freenet/src/freenet/transport/IPUtil.java 2005-11-25 17:21:50 UTC
(rev 7602)
+++ trunk/freenet/src/freenet/transport/IPUtil.java 2005-11-25 18:03:07 UTC
(rev 7603)
@@ -0,0 +1,139 @@
+package freenet.transport;
+
+import java.net.InetAddress;
+import java.util.StringTokenizer;
+
+import freenet.support.Logger;
+
+public class IPUtil {
+
+ static final boolean strict = true;
+
+ /**
+ * Is this a valid address? Specifically, return false if it
+ * is in an RFC3330 reserved space.
+ */
+ public static boolean checkAddress(int[] i) {
+ // ip address (IPV6 is not supported by this transport)
+ boolean logDEBUG = Logger.shouldLog(Logger.DEBUG,IPUtil.class);
+ if(logDEBUG)
+ Logger.debug(IPUtil.class, "Checking "+i[0]+"."+i[1]+"."+i[2]+
+ "."+i[3]);
+ if (i.length != 4)
+ return false;
+
+ for (int j = 0 ; j < 4 ; j++)
+ if (i[j] < 0 || i[j] > 255)
+ return false;
+
+ if (i[0] == 10 || (i[0] == 172 && i[1] >= 16 && i[1] < 31)
+ || (i[0] == 192 && i[1] == 168)) // local network
+ return false;
+
+ if (i[0] == 169 && i[1] == 254)
+ return false; // link local
+
+ if (i[0] == 198 && (i[1] == 18 || i[1] == 19))
+ return false; // RFC2544
+
+ if (i[0] == 192 && i[1] == 0 && i[2] == 2)
+ return false; // test-net, see RFC3330
+
+ if (i[0] == 127) // loopback
+ return false;
+
+ if (i[0] == 0) // "this" net
+ return false;
+
+ if (i[0] >= 224 && i[0] < 240)
+ return false; // multicast
+
+ return true;
+ }
+
+ public static boolean checkAddress(InetAddress addr) {
+ if(Logger.shouldLog(Logger.DEBUG,IPUtil.class))
Logger.debug(IPUtil.class, "Checking "+addr);
+ int[] i = new int[4];
+ byte[] bytes = addr.getAddress();
+ if(bytes.length != 4) {
+ return false;
+ }
+ for(int x=0;x<4;x++) {
+ byte b = bytes[x];
+ int ii = b;
+ if(ii < 0) ii += 256;
+ i[x] = ii;
+ }
+ return checkAddress(i);
+ }
+
+ public static boolean checkAddress(byte[] b) {
+ int[] i = new int[4];
+ for(int x=0;x<4;x++) i[x] = b[x] & 0xff;
+ return checkAddress(i);
+ }
+
+ public static boolean checkAddress(String s) {
+ return checkAddress(s, false);
+ }
+
+ public static boolean checkAddress(String s, boolean noPort) {
+ boolean logDEBUG = Logger.shouldLog(Logger.DEBUG,IPUtil.class);
+ if(logDEBUG)
+ Logger.debug(IPUtil.class, "Checking "+s);
+ String a = s;
+ if(!noPort) {
+ StringTokenizer st = new StringTokenizer(s, ":");
+ if (st.countTokens() != 2)
+ return false;
+
+ a = st.nextToken();
+ try {
+ int p = Integer.parseInt(st.nextToken());
+ if (p < 0 || p >= (1 << 16))
+ return false;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+ if (!strict)
+ return true;
+
+ // strict check
+ if(logDEBUG)
+ Logger.debug(IPUtil.class, "Strict check");
+
+ StringTokenizer at = new StringTokenizer(a, ".");
+ int n = at.countTokens();
+
+ try {
+ int[] i = new int[4];
+ for (int j = 0 ; j < 4 ; j++) {
+ if (!at.hasMoreTokens()) {
+ if(logDEBUG)
+ Logger.debug(IPUtil.class, "Only "+j+" tokens.");
+ return false;
+ }
+ String tok = at.nextToken();
+ if(logDEBUG)
+ Logger.debug(IPUtil.class, "Trying to parseInt: "+tok);
+ i[j] = Integer.parseInt(tok);
+ }
+ return checkAddress(i);
+ } catch (NumberFormatException e) {
+ // dns address
+ if (n < 2) {
+ Logger.minor(IPUtil.class, a+": Not a DNS address, too short!");
+ return false;
+ }
+
+ if(logDEBUG)
+ Logger.debug(IPUtil.class, "Apparently valid DNS address: "+a);
+ return true;
+ // maybe we should actually look up the IP address here,
+ // but I'm concerned about revealing ourselves.
+ }
+ }
+
+
+}