Author: bombe
Date: 2006-04-27 22:36:25 +0000 (Thu, 27 Apr 2006)
New Revision: 8594

Added:
   trunk/freenet/src/freenet/io/Inet4AddressMatcher.java
   trunk/freenet/src/freenet/io/Inet4AddressMatcherTest.java
   trunk/freenet/src/freenet/io/NetworkInterface.java
Modified:
   trunk/freenet/src/freenet/clients/http/SimpleToadletServer.java
   trunk/freenet/src/freenet/node/TextModeClientInterfaceServer.java
   trunk/freenet/src/freenet/node/fcp/FCPServer.java
Log:
exchange server sockets with network interface that allows multiple bind 
addresses and ip address level filter

Modified: trunk/freenet/src/freenet/clients/http/SimpleToadletServer.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/SimpleToadletServer.java     
2006-04-27 22:15:13 UTC (rev 8593)
+++ trunk/freenet/src/freenet/clients/http/SimpleToadletServer.java     
2006-04-27 22:36:25 UTC (rev 8594)
@@ -3,7 +3,6 @@
 import java.io.File;
 import java.io.IOException;
 import java.net.InetAddress;
-import java.net.ServerSocket;
 import java.net.Socket;
 import java.net.SocketException;
 import java.net.SocketTimeoutException;
@@ -17,6 +16,7 @@
 import freenet.config.StringCallback;
 import freenet.config.SubConfig;
 import freenet.crypt.DummyRandomSource;
+import freenet.io.NetworkInterface;
 import freenet.node.Node;
 import freenet.support.BucketFactory;
 import freenet.support.FileLoggerHook;
@@ -38,8 +38,9 @@

        final int port;
        final String bindTo;
+       String allowedHosts;
        final BucketFactory bf;
-       private final ServerSocket sock;
+       final NetworkInterface networkInterface;
        private final LinkedList toadlets;
        private String cssName;
        private Thread myThread;
@@ -71,6 +72,21 @@
                }
        }

+       class FproxyAllowedHostsCallback implements StringCallback {
+       
+               public String get() {
+                       return allowedHosts;
+               }
+               
+               public void set(String allowedHosts) {
+                       if (!allowedHosts.equals(get())) {
+                               networkInterface.setAllowedHosts(allowedHosts);
+                               SimpleToadletServer.this.allowedHosts = 
allowedHosts;
+                       }
+               }
+               
+       }
+       
        class FproxyCSSNameCallback implements StringCallback {

                public String get() {
@@ -122,12 +138,15 @@
                                new FproxyPortCallback());
                fproxyConfig.register("bindTo", "127.0.0.1", 2, true, "IP 
address to bind to", "IP address to bind to",
                                new FproxyBindtoCallback());
+               fproxyConfig.register("allowedHosts", "127.0.0.1", 2, true, 
"Allowed hosts", "Hostnames or IP addresses that are allowed to connect to 
Fproxy",
+                               new FproxyAllowedHostsCallback());
                fproxyConfig.register("css", "clean", 1, true, "CSS Name", 
"Name of the CSS Fproxy should use",
                                new FproxyCSSNameCallback());

                this.bf = node.tempBucketFactory;
                port = fproxyConfig.getInt("port");
                bindTo = fproxyConfig.getString("bindTo");
+               allowedHosts = fproxyConfig.getString("allowedHosts");
                cssName = fproxyConfig.getString("css");
                if(cssName.indexOf(':') != -1 || cssName.indexOf('/') != -1)
                        throw new InvalidConfigValueException("CSS name must 
not contain slashes or colons!");
@@ -137,9 +156,9 @@

                if(!enabled) {
                        Logger.normal(node, "Not starting Fproxy as it's 
disabled");
-                       this.sock = null;
+                       this.networkInterface = null;
                } else {
-                       this.sock = new ServerSocket(port, 0, 
InetAddress.getByName(this.bindTo));
+                       this.networkInterface = new NetworkInterface(port, 
this.bindTo, this.allowedHosts);

                        myThread = new Thread(this, "SimpleToadletServer");
                        myThread.setDaemon(true);
@@ -149,11 +168,12 @@
                }
        }

-       public SimpleToadletServer(int i, String newbindTo, BucketFactory bf, 
String cssName) throws IOException {
+       public SimpleToadletServer(int i, String newbindTo, String 
allowedHosts, BucketFactory bf, String cssName) throws IOException {
                this.port = i;
                this.bindTo = newbindTo;
+               this.allowedHosts = allowedHosts;
                this.bf = bf;
-               this.sock = new ServerSocket(port, 0, 
InetAddress.getByName(this.bindTo));
+               this.networkInterface = new NetworkInterface(port, this.bindTo, 
this.allowedHosts);
                toadlets = new LinkedList();
                this.cssName = cssName;
                Thread t = new Thread(this, "SimpleToadletServer");
@@ -190,7 +210,7 @@
         Logger.globalSetThreshold(Logger.MINOR);
         Logger.globalAddHook(logger);
         logger.start();
-               SimpleToadletServer server = new SimpleToadletServer(1111, 
"127.0.0.1", new TempBucketFactory(new FilenameGenerator(new 
DummyRandomSource(), true, new File("temp-test"), "test-temp-")), "aqua");
+               SimpleToadletServer server = new SimpleToadletServer(1111, 
"127.0.0.1", "127.0.0.1", new TempBucketFactory(new FilenameGenerator(new 
DummyRandomSource(), true, new File("temp-test"), "test-temp-")), "aqua");
                server.register(new TrivialToadlet(null), "", true);
                System.out.println("Bound to port 1111.");
                while(true) {
@@ -204,7 +224,7 @@

        public void run() {
                try {
-                       sock.setSoTimeout(500);
+                       networkInterface.setSoTimeout(500);
                } catch (SocketException e1) {
                        Logger.error(this, "Could not set so-timeout to 500ms; 
on-the-fly disabling of the interface will not work");
                }
@@ -213,7 +233,7 @@
                                if(myThread == null) return;
                        }
                        try {
-                               Socket conn = sock.accept();
+                               Socket conn = networkInterface.accept();
                                Logger.minor(this, "Accepted connection");
                                new SocketHandler(conn);
                        } catch (SocketTimeoutException e) {


Property changes on: 
trunk/freenet/src/freenet/clients/http/SimpleToadletServer.java
___________________________________________________________________
Name: svn:keywords
   + Id

Added: trunk/freenet/src/freenet/io/Inet4AddressMatcher.java
===================================================================
--- trunk/freenet/src/freenet/io/Inet4AddressMatcher.java       2006-04-27 
22:15:13 UTC (rev 8593)
+++ trunk/freenet/src/freenet/io/Inet4AddressMatcher.java       2006-04-27 
22:36:25 UTC (rev 8594)
@@ -0,0 +1,122 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package freenet.io;
+
+import java.net.Inet4Address;
+import java.util.StringTokenizer;
+
+/**
+ * Matcher for IPv4 network addresses. It works like the regex matcher in
+ * {@link java.util.regex.Matcher}, i.e. you create a new Inet4AddressMatcher
+ * with the IP address pattern and can then match IP addresses to it. The
+ * Inet4AddressMatcher can match the following kinds of IP addresses or address
+ * ranges:
+ * <ul>
+ * <li>IP address only (<code>192.168.1.2</code>)</li>
+ * <li>IP address and network mask 
(<code>192.168.1.2/255.255.255.0</code>)</li>
+ * <li>IP address and network mask bits (<code>192.168.1.2/24</code>)</li>
+ * </ul>
+ * 
+ * @author David Roden &lt;droden at gmail.com&gt;
+ * @version $Id$
+ */
+public class Inet4AddressMatcher {
+
+       /** The address of this matcher */
+       private int address;
+
+       /** The network mask of this matcher */
+       private int networkMask;
+
+       /**
+        * Creates a new address matcher that matches InetAddress objects to the
+        * address specification given by <code>cidrHostname</code>.
+        * 
+        * @param cidrHostname
+        *            The address range this matcher matches
+        */
+       public Inet4AddressMatcher(String cidrHostname) {
+               int slashPosition = cidrHostname.indexOf('/');
+               if (slashPosition == -1) {
+                       address = convertToBytes(cidrHostname);
+                       networkMask = 0xffffffff;
+               } else {
+                       address = convertToBytes(cidrHostname.substring(0, 
slashPosition));
+                       String maskPart = cidrHostname.substring(slashPosition 
+ 1);
+                       if (maskPart.indexOf('.') == -1) {
+                               networkMask = 0xffffffff << (32 - 
Integer.parseInt(maskPart));
+                               if (Integer.parseInt(maskPart) == 0) {
+                                       networkMask = 0;
+                               }
+                       } else {
+                               networkMask = convertToBytes(maskPart);
+                       }
+               }
+       }
+
+       /**
+        * Converts a dotted IP address (a.b.c.d) to a 32-bit value. The first 
octet
+        * will be in bits 24 to 31, the second in bits 16 to 23, the third in 
bits
+        * 8 to 15, and the fourth in bits 0 to 7.
+        * 
+        * @param address
+        *            The address to convert
+        * @return The IP address as 32-bit value
+        * @throws NumberFormatException
+        *             if a part of the string can not be parsed using
+        *             {@link Integer#parseInt(java.lang.String)}
+        * @throws java.util.NoSuchElementException
+        *             if <code>address</code> contains less than 3 dots
+        */
+       public static int convertToBytes(String address) {
+               StringTokenizer addressTokens = new StringTokenizer(address, 
".");
+               int bytes = Integer.parseInt(addressTokens.nextToken()) << 24 | 
Integer.parseInt(addressTokens.nextToken()) << 16 | 
Integer.parseInt(addressTokens.nextToken()) << 8 | 
Integer.parseInt(addressTokens.nextToken());
+               return bytes;
+       }
+
+       /**
+        * Checks whether the given address matches this matcher's address.
+        * 
+        * @param inetAddress
+        *            The address to match to this matcher
+        * @return <code>true</code> if <code>inetAddress</code> matches the
+        *         specification of this matcher, <code>false</code> otherwise
+        */
+       public boolean matches(Inet4Address inetAddress) {
+               int matchAddress = convertToBytes(inetAddress.getHostAddress());
+               return (matchAddress & networkMask) == (address & networkMask);
+       }
+
+       /**
+        * Shortcut method for creating a new Inet4AddressMatcher and matching
+        * <code>address</code> to it.
+        * 
+        * @param cidrHostname
+        *            The host specification to match
+        * @param address
+        *            The address to match
+        * @return <code>true</code> if <code>address</code> matches the
+        *         specification in <code>cidrHostname</code>, 
<code>false</code>
+        *         otherwise
+        * @see #Inet4AddressMatcher(String)
+        * @see #matches(Inet4Address)
+        */
+       public static boolean matches(String cidrHostname, Inet4Address 
address) {
+               return new Inet4AddressMatcher(cidrHostname).matches(address);
+       }
+
+}


Property changes on: trunk/freenet/src/freenet/io/Inet4AddressMatcher.java
___________________________________________________________________
Name: svn:keywords
   + Id

Added: trunk/freenet/src/freenet/io/Inet4AddressMatcherTest.java
===================================================================
--- trunk/freenet/src/freenet/io/Inet4AddressMatcherTest.java   2006-04-27 
22:15:13 UTC (rev 8593)
+++ trunk/freenet/src/freenet/io/Inet4AddressMatcherTest.java   2006-04-27 
22:36:25 UTC (rev 8594)
@@ -0,0 +1,74 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package freenet.io;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+
+import freenet.io.Inet4AddressMatcher;
+
+import junit.framework.TestCase;
+
+/**
+ * @author David Roden &lt;droden at gmail.com&gt;
+ * @version $Id$
+ */
+public class Inet4AddressMatcherTest extends TestCase {
+
+       public void test() throws Exception {
+               Inet4AddressMatcher matcher = new 
Inet4AddressMatcher("192.168.1.2");
+               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.1.1")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.1.2")));
+               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("127.0.0.1")));
+               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("0.0.0.0")));
+               
+               matcher = new Inet4AddressMatcher("192.168.1.2/8");
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.1.1")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.1.2")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.2.1")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.16.81.1")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.255.255.255")));
+               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("172.16.1.1")));
+               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("127.0.0.1")));
+               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("0.0.0.0")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.0.0.0")));
+
+               /* some fancy matching */
+               matcher = new Inet4AddressMatcher("192.168.1.1/255.0.255.0");
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.1.1")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.16.1.1")));
+               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.2.1")));
+               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("192.16.2.1")));
+               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("127.0.0.1")));
+               
+               matcher = new Inet4AddressMatcher("127.0.0.1/8");
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("127.0.0.1")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("127.23.42.64")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("127.0.0.0")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("127.255.255.255")));
+               assertEquals(false, matcher.matches((Inet4Address) 
InetAddress.getByName("28.0.0.1")));
+
+               matcher = new Inet4AddressMatcher("0.0.0.0/0");
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("127.0.0.1")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.1.1")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("192.168.2.1")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("172.16.42.23")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("10.0.0.1")));
+               assertEquals(true, matcher.matches((Inet4Address) 
InetAddress.getByName("224.0.0.1")));
+       }
+
+}


Property changes on: trunk/freenet/src/freenet/io/Inet4AddressMatcherTest.java
___________________________________________________________________
Name: svn:keywords
   + Id

Added: trunk/freenet/src/freenet/io/NetworkInterface.java
===================================================================
--- trunk/freenet/src/freenet/io/NetworkInterface.java  2006-04-27 22:15:13 UTC 
(rev 8593)
+++ trunk/freenet/src/freenet/io/NetworkInterface.java  2006-04-27 22:36:25 UTC 
(rev 8594)
@@ -0,0 +1,189 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+package freenet.io;
+
+import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import freenet.support.Logger;
+
+/**
+ * @author David Roden &lt;droden at gmail.com&gt;
+ * @version $Id$
+ */
+public class NetworkInterface {
+
+       protected final Object syncObject = new Object();
+       private final List/* <Acceptor> */acceptors = new ArrayList();
+       protected final List/* <String> */allowedHosts = new ArrayList();
+       protected final Map/* <String, Inet4AddressMatcher> */addressMatchers = 
new HashMap();
+       protected final List/* <Socket> */acceptedSockets = new ArrayList();
+       private int timeout = 0;
+
+       /**
+        * Creates a new network interface that can bind to several addresses 
and
+        * allows connection filtering on IP address level.
+        * 
+        * @param bindTo
+        *            A comma-separated list of addresses to bind to
+        * @param allowedHosts
+        *            A comma-separated list of allowed addresses
+        */
+       public NetworkInterface(int port, String bindTo, String allowedHosts) 
throws IOException {
+               StringTokenizer bindToTokens = new StringTokenizer(bindTo, ",");
+               List bindToTokenList = new ArrayList();
+               while (bindToTokens.hasMoreTokens()) {
+                       bindToTokenList.add(bindToTokens.nextToken().trim());
+               }
+               for (int serverSocketIndex = 0; serverSocketIndex < 
bindToTokenList.size(); serverSocketIndex++) {
+                       ServerSocket serverSocket = new ServerSocket();
+                       serverSocket.bind(new InetSocketAddress((String) 
bindToTokenList.get(serverSocketIndex), port));
+                       Acceptor acceptor = new Acceptor(serverSocket);
+                       acceptors.add(acceptor);
+                       new Thread(acceptor).start();
+               }
+               setAllowedHosts(allowedHosts);
+       }
+
+       public void setAllowedHosts(String allowedHosts) {
+               StringTokenizer allowedHostsTokens = new 
StringTokenizer(allowedHosts, ",");
+               synchronized (syncObject) {
+                       this.allowedHosts.clear();
+                       this.addressMatchers.clear();
+                       while (allowedHostsTokens.hasMoreTokens()) {
+                               String allowedHost = 
allowedHostsTokens.nextToken().trim();
+                               this.allowedHosts.add(allowedHost);
+                               if (allowedHost.equals("*")) {
+                                       addressMatchers.put("*", new 
Inet4AddressMatcher("0.0.0.0/0"));
+                               } else if 
(!Character.isLetter(allowedHost.charAt(0))) {
+                                       addressMatchers.put(allowedHost, new 
Inet4AddressMatcher(allowedHost));
+                               }
+                       }
+               }
+       }
+
+       public void setSoTimeout(int timeout) throws SocketException {
+               Iterator acceptors = this.acceptors.iterator();
+               while (acceptors.hasNext()) {
+                       ((Acceptor) acceptors.next()).setSoTimeout(timeout);
+               }
+       }
+
+       public Socket accept() throws SocketTimeoutException {
+               synchronized (syncObject) {
+                       while (acceptedSockets.size() == 0) {
+                               try {
+                                       syncObject.wait(timeout);
+                               } catch (InterruptedException ie1) {
+                               }
+                               if ((timeout > 0) && (acceptedSockets.size() == 
0)) {
+                                       throw new SocketTimeoutException();
+                               }
+                       }
+                       return (Socket) acceptedSockets.remove(0);
+               }
+       }
+
+       public void close() throws IOException {
+               IOException exception = null;
+               Iterator acceptors = this.acceptors.iterator();
+               while (acceptors.hasNext()) {
+                       Acceptor acceptor = (Acceptor) acceptors.next();
+                       try {
+                               acceptor.close();
+                       } catch (IOException ioe1) {
+                               exception = ioe1;
+                       }
+               }
+               if (exception != null) {
+                       throw (exception);
+               }
+       }
+
+       private class Acceptor implements Runnable {
+
+               private final ServerSocket serverSocket;
+               private boolean closed = false;
+
+               public Acceptor(ServerSocket serverSocket) {
+                       this.serverSocket = serverSocket;
+               }
+
+               public void setSoTimeout(int timeout) throws SocketException {
+                       serverSocket.setSoTimeout(timeout);
+               }
+
+               public void close() throws IOException {
+                       closed = true;
+                       serverSocket.close();
+               }
+
+               public void run() {
+                       while (!closed) {
+                               try {
+                                       Socket clientSocket = 
serverSocket.accept();
+                                       InetAddress clientAddress = 
clientSocket.getInetAddress();
+                                       String clientHostName = 
clientAddress.getHostName();
+
+                                       /* check if the ip address is allowed */
+                                       boolean addressMatched = false;
+                                       synchronized (syncObject) {
+                                               Iterator hosts = 
allowedHosts.iterator();
+                                               while (!addressMatched && 
hosts.hasNext()) {
+                                                       String host = (String) 
hosts.next();
+                                                       Inet4AddressMatcher 
matcher = (Inet4AddressMatcher) addressMatchers.get(host);
+                                                       if (matcher != null) {
+                                                               addressMatched 
= matcher.matches((Inet4Address) clientAddress);
+                                                       } else {
+                                                               addressMatched 
= clientHostName.equalsIgnoreCase(host);
+                                                       }
+                                               }
+                                       }
+
+                                       if (addressMatched) {
+                                               synchronized (syncObject) {
+                                                       
acceptedSockets.add(clientSocket);
+                                                       syncObject.notify();
+                                               }
+                                       } else {
+                                               try {
+                                                       clientSocket.close();
+                                               } catch (IOException ioe1) {
+                                               }
+                                               Logger.normal(Acceptor.class, 
"Denied connection to " + clientHostName);
+                                       }
+                               } catch (SocketTimeoutException ste1) {
+                               } catch (IOException ioe1) {
+                               }
+                       }
+               }
+
+       }
+
+}


Property changes on: trunk/freenet/src/freenet/io/NetworkInterface.java
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: trunk/freenet/src/freenet/node/TextModeClientInterfaceServer.java
===================================================================
--- trunk/freenet/src/freenet/node/TextModeClientInterfaceServer.java   
2006-04-27 22:15:13 UTC (rev 8593)
+++ trunk/freenet/src/freenet/node/TextModeClientInterfaceServer.java   
2006-04-27 22:36:25 UTC (rev 8594)
@@ -5,7 +5,6 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.InetAddress;
-import java.net.ServerSocket;
 import java.net.Socket;
 import java.net.SocketException;
 import java.net.SocketTimeoutException;
@@ -19,6 +18,7 @@
 import freenet.config.StringCallback;
 import freenet.config.SubConfig;
 import freenet.crypt.RandomSource;
+import freenet.io.NetworkInterface;
 import freenet.support.Logger;

 public class TextModeClientInterfaceServer implements Runnable {
@@ -30,15 +30,18 @@
     final File downloadsDir;
     int port;
     final String bindTo;
+    String allowedHosts;
     boolean isEnabled;
+    NetworkInterface networkInterface;

-    TextModeClientInterfaceServer(Node n, int port, String bindTo) {
+    TextModeClientInterfaceServer(Node n, int port, String bindTo, String 
allowedHosts) {
         this.n = n;
         this.r = n.random;
         streams = new Hashtable();
         this.downloadsDir = n.downloadDir;
         this.port=port;
         this.bindTo=bindTo;
+        this.allowedHosts = allowedHosts;
         this.isEnabled=true;
         n.setTMCI(this);
         new Thread(this, "Text mode client interface").start();
@@ -51,6 +54,8 @@
                                new TMCIEnabledCallback(node));
                TMCIConfig.register("bindTo", "127.0.0.1", 2, true, "IP address 
to bind to", "IP address to bind to",
                                new TMCIBindtoCallback(node));
+               TMCIConfig.register("allowedHosts", "127.0.0.1", 2, true, 
"Allowed hosts", "Hostnames or IP addresses that are allowed to connect to the 
TMCI",
+                               new TMCIAllowedHostsCallback(node));
                TMCIConfig.register("port", 2323, 1, true, "Testnet port", 
"Testnet port number",
                        new TCMIPortNumberCallback(node));
                TMCIConfig.register("directEnabled", false, 1, true, "Enable on 
stdout/stdin?", "Enable text mode client interface on standard input/output? 
(.enabled refers to providing a telnet-style server, this runs it over a 
socket)",
@@ -59,10 +64,11 @@
                boolean TMCIEnabled = TMCIConfig.getBoolean("enabled");
                int port =  TMCIConfig.getInt("port");
                String bind_ip = TMCIConfig.getString("bindTo");
+               String allowedHosts = TMCIConfig.getString("allowedHosts");
                boolean direct = TMCIConfig.getBoolean("directEnabled");

                if(TMCIEnabled){
-                       new TextModeClientInterfaceServer(node, port, bind_ip);
+                       new TextModeClientInterfaceServer(node, port, bind_ip, 
allowedHosts);
                        Logger.normal(node, "TMCI started on 
"+bind_ip+":"+port);
                        System.out.println("TMCI started on "+bind_ip+":"+port);
                }
@@ -142,7 +148,31 @@
                throw new InvalidConfigValueException("Cannot be updated on the 
fly");
        }
     }
+    
+    static class TMCIAllowedHostsCallback implements StringCallback {

+       private final Node node;
+       
+       public TMCIAllowedHostsCallback(Node node) {
+               this.node = node;
+       }
+       
+               public String get() {
+                       if (node.getTextModeClientInterface() != null) {
+                               return 
node.getTextModeClientInterface().allowedHosts;
+                       }
+                       return "127.0.0.1";
+               }
+
+               public void set(String val) {
+                       if (!val.equals(get())) {
+                               
node.getTextModeClientInterface().networkInterface.setAllowedHosts(val);
+                               node.getTextModeClientInterface().allowedHosts 
= val;
+                       }
+               }
+       
+    }
+
     static class TCMIPortNumberCallback implements IntCallback{

        final Node node;
@@ -172,16 +202,15 @@
        while(true) {
                int curPort = port;
                String bindTo = this.bindTo;
-               ServerSocket server;
                try {
-                       server = new ServerSocket(curPort, 0, 
InetAddress.getByName(bindTo));
+                       networkInterface = new NetworkInterface(curPort, 
bindTo, allowedHosts);
                } catch (IOException e) {
                        Logger.error(this, "Could not bind to TMCI port: 
"+bindTo+":"+port);
                        System.exit(-1);
                        return;
                }
                try {
-                       server.setSoTimeout(1000);
+                       networkInterface.setSoTimeout(1000);
                } catch (SocketException e1) {
                        Logger.error(this, "Could not set timeout: "+e1, e1);
                        System.err.println("Could not start TMCI: "+e1);
@@ -193,7 +222,7 @@
                                if(port != curPort) break;
                                if(!(this.bindTo.equals(bindTo))) break;
                        try {
-                               Socket s = server.accept();
+                               Socket s = networkInterface.accept();
                                InputStream in = s.getInputStream();
                                OutputStream out = s.getOutputStream();

@@ -215,7 +244,7 @@
                        }
                }
                try{
-                       server.close();
+                       networkInterface.close();
                }catch (IOException e){
                        Logger.error(this, "Error shuting down TMCI", e);
                }


Property changes on: 
trunk/freenet/src/freenet/node/TextModeClientInterfaceServer.java
___________________________________________________________________
Name: svn:keywords
   + Id

Modified: trunk/freenet/src/freenet/node/fcp/FCPServer.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/FCPServer.java   2006-04-27 22:15:13 UTC 
(rev 8593)
+++ trunk/freenet/src/freenet/node/fcp/FCPServer.java   2006-04-27 22:36:25 UTC 
(rev 8594)
@@ -13,7 +13,6 @@
 import java.io.OutputStreamWriter;
 import java.net.BindException;
 import java.net.InetAddress;
-import java.net.ServerSocket;
 import java.net.Socket;
 import java.util.Iterator;
 import java.util.Vector;
@@ -29,6 +28,7 @@
 import freenet.config.LongCallback;
 import freenet.config.StringCallback;
 import freenet.config.SubConfig;
+import freenet.io.NetworkInterface;
 import freenet.node.Node;
 import freenet.support.Logger;

@@ -37,11 +37,12 @@
  */
 public class FCPServer implements Runnable {

-       final ServerSocket sock;
+       final NetworkInterface networkInterface;
        final Node node;
        final int port;
        final boolean enabled;
        final String bindTo;
+       String allowedHosts;
        final WeakHashMap clientsByName;
        final FCPClient globalClient;
        private boolean enablePersistentDownloads;
@@ -68,8 +69,9 @@
                persister = null;
        }

-       public FCPServer(String ipToBindTo, int port, Node node, boolean 
persistentDownloadsEnabled, String persistentDownloadsDir, long 
persistenceInterval, boolean isEnabled) throws IOException, 
InvalidConfigValueException {
+       public FCPServer(String ipToBindTo, String allowedHosts, int port, Node 
node, boolean persistentDownloadsEnabled, String persistentDownloadsDir, long 
persistenceInterval, boolean isEnabled) throws IOException, 
InvalidConfigValueException {
                this.bindTo = ipToBindTo;
+               this.allowedHosts = allowedHosts;
                this.persistenceInterval = persistenceInterval;
                this.port = port;
                this.enabled = isEnabled;
@@ -97,23 +99,23 @@
                        }

                        Logger.normal(this, "Starting FCP server on 
"+bindTo+":"+port+".");
-                       ServerSocket tempsock = null;
+                       NetworkInterface networkInterface = null;
                        try {
-                               tempsock = new ServerSocket(port, 0, 
InetAddress.getByName(bindTo));
+                               networkInterface = new NetworkInterface(port, 
bindTo, allowedHosts);
                        } catch (BindException be) {
                                Logger.error(this, "Couldn't bind to FCP Port 
"+port+". FCP Server not started.");
                        }

-                       this.sock = tempsock;
+                       this.networkInterface = networkInterface;

-                       if (this.sock != null) {
+                       if (this.networkInterface != null) {
                                Thread t = new Thread(this, "FCP server");
                                t.setDaemon(true);
                                t.start();
                        }
                } else {
                        Logger.normal(this, "Not starting FCP server as it's 
disabled");
-                       this.sock = null;
+                       this.networkInterface = null;
                        this.node = null;
                        this.clientsByName = null;
                        this.globalClient = null;
@@ -136,7 +138,7 @@

        private void realRun() throws IOException {
                // Accept a connection
-               Socket s = sock.accept();
+               Socket s = networkInterface.accept();
                new FCPConnectionHandler(s, this);
        }

@@ -195,12 +197,33 @@

 //TODO: Allow it
                public void set(String val) throws InvalidConfigValueException {
-                       if(val.equals(get())) {
+                       if(!val.equals(get())) {
                                throw new InvalidConfigValueException("Cannot 
change the ip address the server is binded to on the fly");
                        }
                }
        }
+       
+       static class FCPAllowedHostsCallback implements StringCallback {

+               private final Node node;
+               
+               public FCPAllowedHostsCallback(Node node) {
+                       this.node = node;
+               }
+               
+               public String get() {
+                       return node.getFCPServer().allowedHosts;
+               }
+
+               public void set(String val) {
+                       if (!val.equals(get())) {
+                               
node.getFCPServer().networkInterface.setAllowedHosts(val);
+                               node.getFCPServer().allowedHosts = val;
+                       }
+               }
+               
+       }
+
        static class PersistentDownloadsEnabledCallback implements 
BooleanCallback {

                FCPServer server;
@@ -256,6 +279,7 @@
                fcpConfig.register("port", 9481 /* anagram of 1984, and 1000 up 
from old number */,
                                2, true, "FCP port number", "FCP port number", 
new FCPPortNumberCallback(node));
                fcpConfig.register("bindTo", "127.0.0.1", 2, true, "Ip address 
to bind to", "Ip address to bind the FCP server to", new 
FCPBindtoCallback(node));
+               fcpConfig.register("allowedHosts", "127.0.0.1", 2, true, 
"Allowed hosts", "Hostnames or IP addresses that are allowed to connect to the 
FCP server", new FCPAllowedHostsCallback(node));
                PersistentDownloadsEnabledCallback cb1;
                PersistentDownloadsFileCallback cb2;
                PersistentDownloadsIntervalCallback cb3;
@@ -274,7 +298,7 @@

                FCPServer fcp;

-               fcp = new FCPServer(fcpConfig.getString("bindTo"), 
fcpConfig.getInt("port"), node, persistentDownloadsEnabled, 
persistentDownloadsDir, persistentDownloadsInterval, 
fcpConfig.getBoolean("enabled"));
+               fcp = new FCPServer(fcpConfig.getString("bindTo"), 
fcpConfig.getString("allowedHosts"), fcpConfig.getInt("port"), node, 
persistentDownloadsEnabled, persistentDownloadsDir, 
persistentDownloadsInterval, fcpConfig.getBoolean("enabled"));
                node.setFCPServer(fcp); 

                if(fcp != null) {


Property changes on: trunk/freenet/src/freenet/node/fcp/FCPServer.java
___________________________________________________________________
Name: svn:keywords
   + Id


Reply via email to