beginnings of outproxy configuration and routing
This commit is contained in:
@ -7,6 +7,12 @@
|
|||||||
package net.i2p.i2ptunnel.socks;
|
package net.i2p.i2ptunnel.socks;
|
||||||
|
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
import net.i2p.client.streaming.I2PSocket;
|
import net.i2p.client.streaming.I2PSocket;
|
||||||
import net.i2p.data.Destination;
|
import net.i2p.data.Destination;
|
||||||
@ -20,7 +26,7 @@ import net.i2p.util.Log;
|
|||||||
public class I2PSOCKSTunnel extends I2PTunnelClientBase {
|
public class I2PSOCKSTunnel extends I2PTunnelClientBase {
|
||||||
|
|
||||||
private static final Log _log = new Log(I2PSOCKSTunnel.class);
|
private static final Log _log = new Log(I2PSOCKSTunnel.class);
|
||||||
|
private HashMap<String, List<String>> proxies = null; // port# + "" or "default" -> hostname list
|
||||||
protected Destination outProxyDest = null;
|
protected Destination outProxyDest = null;
|
||||||
|
|
||||||
//public I2PSOCKSTunnel(int localPort, Logging l, boolean ownDest) {
|
//public I2PSOCKSTunnel(int localPort, Logging l, boolean ownDest) {
|
||||||
@ -36,7 +42,7 @@ public class I2PSOCKSTunnel extends I2PTunnelClientBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setName(getLocalPort() + " -> SOCKSTunnel");
|
setName(getLocalPort() + " -> SOCKSTunnel");
|
||||||
|
parseOptions();
|
||||||
startRunning();
|
startRunning();
|
||||||
|
|
||||||
notifyEvent("openSOCKSTunnelResult", "ok");
|
notifyEvent("openSOCKSTunnelResult", "ok");
|
||||||
@ -53,4 +59,42 @@ public class I2PSOCKSTunnel extends I2PTunnelClientBase {
|
|||||||
closeSocket(s);
|
closeSocket(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final String PROP_PROXY = "i2ptunnel.socks.proxy.";
|
||||||
|
private void parseOptions() {
|
||||||
|
Properties opts = getTunnel().getClientOptions();
|
||||||
|
proxies = new HashMap(0);
|
||||||
|
for (Map.Entry e : opts.entrySet()) {
|
||||||
|
String prop = (String)e.getKey();
|
||||||
|
if ((!prop.startsWith(PROP_PROXY)) || prop.length() <= PROP_PROXY.length())
|
||||||
|
continue;
|
||||||
|
String port = prop.substring(PROP_PROXY.length());
|
||||||
|
List proxyList = new ArrayList(1);
|
||||||
|
StringTokenizer tok = new StringTokenizer((String)e.getValue(), ", \t");
|
||||||
|
while (tok.hasMoreTokens()) {
|
||||||
|
String proxy = tok.nextToken().trim();
|
||||||
|
if (proxy.endsWith(".i2p"))
|
||||||
|
proxyList.add(proxy);
|
||||||
|
else
|
||||||
|
_log.error("Non-i2p SOCKS outproxy: " + proxy);
|
||||||
|
}
|
||||||
|
proxies.put(port, proxyList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashMap<String, List<String>> getProxyMap() {
|
||||||
|
return proxies;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getProxies(int port) {
|
||||||
|
List<String> rv = proxies.get(port + "");
|
||||||
|
if (rv == null)
|
||||||
|
rv = getDefaultProxies();
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getDefaultProxies() {
|
||||||
|
return proxies.get("default");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,9 @@ import java.io.IOException;
|
|||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.i2p.I2PAppContext;
|
||||||
import net.i2p.I2PException;
|
import net.i2p.I2PException;
|
||||||
import net.i2p.client.streaming.I2PSocket;
|
import net.i2p.client.streaming.I2PSocket;
|
||||||
import net.i2p.data.DataFormatException;
|
import net.i2p.data.DataFormatException;
|
||||||
@ -33,7 +35,6 @@ public class SOCKS5Server extends SOCKSServer {
|
|||||||
private static final int SOCKS_VERSION_5 = 0x05;
|
private static final int SOCKS_VERSION_5 = 0x05;
|
||||||
|
|
||||||
private Socket clientSock = null;
|
private Socket clientSock = null;
|
||||||
|
|
||||||
private boolean setupCompleted = false;
|
private boolean setupCompleted = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -274,6 +275,13 @@ public class SOCKS5Server extends SOCKSServer {
|
|||||||
throw new SOCKSException("BUG! See the logs!");
|
throw new SOCKSException("BUG! See the logs!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DataOutputStream out; // for errors
|
||||||
|
try {
|
||||||
|
out = new DataOutputStream(clientSock.getOutputStream());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new SOCKSException("Connection error (" + e.getMessage() + ")");
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: here we should read our config file, select an
|
// FIXME: here we should read our config file, select an
|
||||||
// outproxy, and instantiate the proper socket class that
|
// outproxy, and instantiate the proper socket class that
|
||||||
// handles the outproxy itself (SOCKS4a, SOCKS5, HTTP CONNECT...).
|
// handles the outproxy itself (SOCKS4a, SOCKS5, HTTP CONNECT...).
|
||||||
@ -285,24 +293,64 @@ public class SOCKS5Server extends SOCKSServer {
|
|||||||
// Let's not due a new Dest for every request, huh?
|
// Let's not due a new Dest for every request, huh?
|
||||||
//I2PSocketManager sm = I2PSocketManagerFactory.createManager();
|
//I2PSocketManager sm = I2PSocketManagerFactory.createManager();
|
||||||
//destSock = sm.connect(I2PTunnel.destFromName(connHostName), null);
|
//destSock = sm.connect(I2PTunnel.destFromName(connHostName), null);
|
||||||
// TODO get the streaming lib options in there
|
|
||||||
destSock = t.createI2PSocket(I2PTunnel.destFromName(connHostName));
|
destSock = t.createI2PSocket(I2PTunnel.destFromName(connHostName));
|
||||||
confirmConnection();
|
} else if ("localhost".equals(connHostName) || "127.0.0.1".equals(connHostName)) {
|
||||||
_log.debug("connection confirmed - exchanging data...");
|
String err = "No localhost accesses allowed through the Socks Proxy";
|
||||||
|
_log.error(err);
|
||||||
|
try {
|
||||||
|
sendRequestReply(Reply.CONNECTION_NOT_ALLOWED_BY_RULESET, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
|
||||||
|
} catch (IOException ioe) {}
|
||||||
|
throw new SOCKSException(err);
|
||||||
|
} else if (connPort == 80) {
|
||||||
|
// rewrite GET line to include hostname??? or add Host: line???
|
||||||
|
// or forward to local eepProxy (but that's a Socket not an I2PSocket)
|
||||||
|
// use eepProxy configured outproxies?
|
||||||
|
String err = "No handler for HTTP outproxy implemented";
|
||||||
|
_log.error(err);
|
||||||
|
try {
|
||||||
|
sendRequestReply(Reply.CONNECTION_NOT_ALLOWED_BY_RULESET, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
|
||||||
|
} catch (IOException ioe) {}
|
||||||
|
throw new SOCKSException(err);
|
||||||
} else {
|
} else {
|
||||||
// if (connPort == 80) ...
|
List<String> proxies = t.getProxies(connPort);
|
||||||
_log.error("We don't support outproxies (yet)");
|
if (proxies == null || proxies.size() <= 0) {
|
||||||
throw new SOCKSException("Ouproxies not supported (yet)");
|
String err = "No outproxy configured for port " + connPort + " and no default configured either";
|
||||||
|
_log.error(err);
|
||||||
|
try {
|
||||||
|
sendRequestReply(Reply.CONNECTION_NOT_ALLOWED_BY_RULESET, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
|
||||||
|
} catch (IOException ioe) {}
|
||||||
|
throw new SOCKSException(err);
|
||||||
|
}
|
||||||
|
int p = I2PAppContext.getGlobalContext().random().nextInt(proxies.size());
|
||||||
|
String proxy = proxies.get(p);
|
||||||
|
_log.debug("connecting to port " + connPort + " proxy " + proxy + " for " + connHostName + "...");
|
||||||
|
// this isn't going to work, these need to be socks outproxies so we need
|
||||||
|
// to do a socks session to them?
|
||||||
|
destSock = t.createI2PSocket(I2PTunnel.destFromName(proxy));
|
||||||
}
|
}
|
||||||
|
confirmConnection();
|
||||||
|
_log.debug("connection confirmed - exchanging data...");
|
||||||
} catch (DataFormatException e) {
|
} catch (DataFormatException e) {
|
||||||
|
try {
|
||||||
|
sendRequestReply(Reply.HOST_UNREACHABLE, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
|
||||||
|
} catch (IOException ioe) {}
|
||||||
throw new SOCKSException("Error in destination format");
|
throw new SOCKSException("Error in destination format");
|
||||||
} catch (SocketException e) {
|
} catch (SocketException e) {
|
||||||
|
try {
|
||||||
|
sendRequestReply(Reply.HOST_UNREACHABLE, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
|
||||||
|
} catch (IOException ioe) {}
|
||||||
throw new SOCKSException("Error connecting ("
|
throw new SOCKSException("Error connecting ("
|
||||||
+ e.getMessage() + ")");
|
+ e.getMessage() + ")");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
try {
|
||||||
|
sendRequestReply(Reply.HOST_UNREACHABLE, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
|
||||||
|
} catch (IOException ioe) {}
|
||||||
throw new SOCKSException("Error connecting ("
|
throw new SOCKSException("Error connecting ("
|
||||||
+ e.getMessage() + ")");
|
+ e.getMessage() + ")");
|
||||||
} catch (I2PException e) {
|
} catch (I2PException e) {
|
||||||
|
try {
|
||||||
|
sendRequestReply(Reply.HOST_UNREACHABLE, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out);
|
||||||
|
} catch (IOException ioe) {}
|
||||||
throw new SOCKSException("Error connecting ("
|
throw new SOCKSException("Error connecting ("
|
||||||
+ e.getMessage() + ")");
|
+ e.getMessage() + ")");
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user