Add server option for unique local address per-client

as suggested in https://lists.torproject.org/pipermail/tor-dev/2014-March/006576.html
This commit is contained in:
zzz
2014-04-05 12:30:58 +00:00
parent 8d73b2e838
commit 44a5740a04
6 changed files with 67 additions and 12 deletions

View File

@@ -277,7 +277,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
setEntry(headers, "Accept-encoding", "");
socket.setReadTimeout(readTimeout);
Socket s = getSocket(socket.getLocalPort());
Socket s = getSocket(socket.getPeerDestination().calculateHash(), socket.getLocalPort());
long afterSocket = getTunnel().getContext().clock().now();
// instead of i2ptunnelrunner, use something that reads the HTTP
// request from the socket, modifies the headers, sends the request to the

View File

@@ -137,7 +137,7 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
buf.append("\r\n");
modifiedRegistration = buf.toString();
}
Socket s = getSocket(socket.getLocalPort());
Socket s = getSocket(socket.getPeerDestination().calculateHash(), socket.getLocalPort());
new I2PTunnelRunner(s, socket, slock, null, modifiedRegistration.getBytes(), null);
} catch (SocketException ex) {
try {

View File

@@ -11,6 +11,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
@@ -33,6 +34,7 @@ import net.i2p.client.streaming.I2PSocket;
import net.i2p.client.streaming.I2PSocketManager;
import net.i2p.client.streaming.I2PSocketManagerFactory;
import net.i2p.data.Base64;
import net.i2p.data.Hash;
import net.i2p.util.EventDispatcher;
import net.i2p.util.I2PAppThread;
import net.i2p.util.I2PSSLSocketFactory;
@@ -62,6 +64,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
private static final String PROP_USE_POOL = "i2ptunnel.usePool";
private static final boolean DEFAULT_USE_POOL = true;
public static final String PROP_USE_SSL = "useSSL";
public static final String PROP_UNIQUE_LOCAL = "enableUniqueLocal";
/** apparently unused */
protected static volatile long __serverId = 0;
/** max number of threads - this many slowlorisses will DOS this server, but too high could OOM the JVM */
@@ -518,7 +521,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
//threads.
try {
socket.setReadTimeout(readTimeout);
Socket s = getSocket(socket.getLocalPort());
Socket s = getSocket(socket.getPeerDestination().calculateHash(), socket.getLocalPort());
afterSocket = getTunnel().getContext().clock().now();
new I2PTunnelRunner(s, socket, slock, null, null);
@@ -543,9 +546,10 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
* To configure a specific host:port as the server for incoming port xx,
* set option targetForPort.xx=host:port
*
* @param from may be used to construct local address since 0.9.13
* @since 0.9.9
*/
protected Socket getSocket(int incomingPort) throws IOException {
protected Socket getSocket(Hash from, int incomingPort) throws IOException {
InetAddress host = remoteHost;
int port = remotePort;
if (incomingPort != 0 && !_socketMap.isEmpty()) {
@@ -557,16 +561,17 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
port = isa.getPort();
}
}
return getSocket(host, port);
return getSocket(from, host, port);
}
/**
* Get a regular or SSL socket depending on config.
* The SSL config applies to all hosts/ports.
*
* @param from may be used to construct local address since 0.9.13
* @since 0.9.9
*/
protected Socket getSocket(InetAddress remoteHost, int remotePort) throws IOException {
protected Socket getSocket(Hash from, InetAddress remoteHost, int remotePort) throws IOException {
String opt = getTunnel().getClientOptions().getProperty(PROP_USE_SSL);
if (Boolean.parseBoolean(opt)) {
synchronized(sslLock) {
@@ -582,9 +587,28 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
}
}
return _sslFactory.createSocket(remoteHost, remotePort);
} else {
// as suggested in https://lists.torproject.org/pipermail/tor-dev/2014-March/006576.html
boolean unique = Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_UNIQUE_LOCAL));
if (unique && remoteHost.isLoopbackAddress()) {
byte[] addr;
if (remoteHost instanceof Inet4Address) {
addr = new byte[4];
addr[0] = 127;
System.arraycopy(from.getData(), 0, addr, 1, 3);
} else {
addr = new byte[16];
addr[0] = (byte) 0xfd;
System.arraycopy(from.getData(), 0, addr, 1, 15);
}
InetAddress local = InetAddress.getByAddress(addr);
// Javadocs say local port of 0 allowed in Java 7.
// Not clear if supported in Java 6 or not.
return new Socket(remoteHost, remotePort, local, 0);
} else {
return new Socket(remoteHost, remotePort);
}
}
}
}

View File

@@ -25,6 +25,7 @@ import net.i2p.i2ptunnel.I2PTunnelHTTPClient;
import net.i2p.i2ptunnel.I2PTunnelHTTPClientBase;
import net.i2p.i2ptunnel.I2PTunnelHTTPServer;
import net.i2p.i2ptunnel.I2PTunnelIRCClient;
import net.i2p.i2ptunnel.I2PTunnelServer;
import net.i2p.i2ptunnel.TunnelController;
import net.i2p.i2ptunnel.TunnelControllerGroup;
import net.i2p.util.Addresses;
@@ -325,6 +326,11 @@ public class EditBean extends IndexBean {
return getProperty(tunnel, I2PTunnelHTTPServer.OPT_POST_TOTAL_BAN_TIME, I2PTunnelHTTPServer.DEFAULT_POST_TOTAL_BAN_TIME) / 60;
}
/** @since 0.9.13 */
public boolean getUniqueLocal(int tunnel) {
return getBooleanProperty(tunnel, I2PTunnelServer.PROP_UNIQUE_LOCAL);
}
private int getProperty(int tunnel, String prop, int def) {
TunnelController tun = getController(tunnel);
if (tun != null) {

View File

@@ -823,6 +823,11 @@ public class IndexBean {
return false;
}
/** @since 0.9.13 */
public void setUniqueLocal(String moo) {
_booleanOptions.add(I2PTunnelServer.PROP_UNIQUE_LOCAL);
}
protected static final String PROP_ENABLE_ACCESS_LIST = "i2cp.enableAccessList";
protected static final String PROP_ENABLE_BLACKLIST = "i2cp.enableBlackList";
@@ -1259,7 +1264,8 @@ public class IndexBean {
private static final String _booleanServerOpts[] = {
"i2cp.reduceOnIdle", "i2cp.encryptLeaseSet", PROP_ENABLE_ACCESS_LIST, PROP_ENABLE_BLACKLIST,
I2PTunnelServer.PROP_USE_SSL,
I2PTunnelHTTPServer.OPT_REJECT_INPROXY
I2PTunnelHTTPServer.OPT_REJECT_INPROXY,
I2PTunnelServer.PROP_UNIQUE_LOCAL
};
private static final String _otherClientOpts[] = {
"i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.closeIdleTime",

View File

@@ -206,9 +206,15 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
<%=intl._("Local destination")%>(<span class="accessKey">L</span>):
</label>
<textarea rows="1" style="height: 3em;" cols="60" readonly="readonly" id="localDestination" title="Read Only: Local Destination (if known)" wrap="off" spellcheck="false"><%=editBean.getDestinationBase64(curTunnel)%></textarea>
<% if (!"".equals(editBean.getDestinationBase64(curTunnel))) { %>
<a href="/susidns/addressbook.jsp?book=private&amp;hostname=<%=editBean.getTunnelName(curTunnel)%>&amp;destination=<%=editBean.getDestinationBase64(curTunnel)%>#add"><%=intl._("Add to local addressbook")%></a>
<% } %>
<% String b64 = editBean.getDestinationBase64(curTunnel);
if (!"".equals(b64)) {
String name = editBean.getSpoofedHost(curTunnel);
if (name == null || name.equals(""))
name = editBean.getTunnelName(curTunnel);
if (!"".equals(name)) { %>
<a href="/susidns/addressbook.jsp?book=private&amp;hostname=<%=name%>&amp;destination=<%=b64%>#add"><%=intl._("Add to local addressbook")%></a>
<% }
} %>
</div>
<% if (("httpserver".equals(tunnelType)) || ("httpbidirserver".equals(tunnelType))) {
@@ -396,7 +402,20 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
</div>
</div>
<% } // httpserver
%><div class="subdivider">
%><div class="rowItem">
<div id="optionsField" class="rowItem">
<label>
<%=intl._("Unique Local Address per Client")%>:
</label>
</div>
<div id="portField" class="rowItem">
<label for="access" accesskey="d">
<%=intl._("Enable")%>:
</label>
<input value="1" type="checkbox" id="startOnLoad" name="uniqueLocal" title="Use unique IP addresses for each connecting client (local non-SSL servers only)"<%=(editBean.getUniqueLocal(curTunnel) ? " checked=\"checked\"" : "")%> class="tickbox" />
</div>
</div>
<div class="subdivider">
<hr />
</div>