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 <droden at gmail.com>
+ * @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 <droden at gmail.com>
+ * @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 <droden at gmail.com>
+ * @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