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


Reply via email to