From e5d76a5a77bab200f4eb4ef9b7ccd412610e851e Mon Sep 17 00:00:00 2001 From: zzz <zzz@mail.i2p> Date: Fri, 23 Jan 2009 19:17:27 +0000 Subject: [PATCH] beginnings of outproxy configuration and routing --- .../i2p/i2ptunnel/socks/I2PSOCKSTunnel.java | 48 +++++++++++++- .../net/i2p/i2ptunnel/socks/SOCKS5Server.java | 62 ++++++++++++++++--- 2 files changed, 101 insertions(+), 9 deletions(-) diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSTunnel.java index 627cd0616f..be398f770e 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSTunnel.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSTunnel.java @@ -7,6 +7,12 @@ package net.i2p.i2ptunnel.socks; 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.data.Destination; @@ -20,7 +26,7 @@ import net.i2p.util.Log; public class I2PSOCKSTunnel extends I2PTunnelClientBase { 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; //public I2PSOCKSTunnel(int localPort, Logging l, boolean ownDest) { @@ -36,7 +42,7 @@ public class I2PSOCKSTunnel extends I2PTunnelClientBase { } setName(getLocalPort() + " -> SOCKSTunnel"); - + parseOptions(); startRunning(); notifyEvent("openSOCKSTunnelResult", "ok"); @@ -53,4 +59,42 @@ public class I2PSOCKSTunnel extends I2PTunnelClientBase { 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"); + } + } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS5Server.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS5Server.java index fea3285a65..252d4e1aa8 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS5Server.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKS5Server.java @@ -13,7 +13,9 @@ import java.io.IOException; import java.net.InetAddress; import java.net.Socket; import java.net.SocketException; +import java.util.List; +import net.i2p.I2PAppContext; import net.i2p.I2PException; import net.i2p.client.streaming.I2PSocket; import net.i2p.data.DataFormatException; @@ -33,7 +35,6 @@ public class SOCKS5Server extends SOCKSServer { private static final int SOCKS_VERSION_5 = 0x05; private Socket clientSock = null; - private boolean setupCompleted = false; /** @@ -274,6 +275,13 @@ public class SOCKS5Server extends SOCKSServer { 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 // outproxy, and instantiate the proper socket class that // 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? //I2PSocketManager sm = I2PSocketManagerFactory.createManager(); //destSock = sm.connect(I2PTunnel.destFromName(connHostName), null); - // TODO get the streaming lib options in there destSock = t.createI2PSocket(I2PTunnel.destFromName(connHostName)); - confirmConnection(); - _log.debug("connection confirmed - exchanging data..."); + } else if ("localhost".equals(connHostName) || "127.0.0.1".equals(connHostName)) { + 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 { - // if (connPort == 80) ... - _log.error("We don't support outproxies (yet)"); - throw new SOCKSException("Ouproxies not supported (yet)"); + List<String> proxies = t.getProxies(connPort); + if (proxies == null || proxies.size() <= 0) { + 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) { + try { + sendRequestReply(Reply.HOST_UNREACHABLE, AddressType.DOMAINNAME, null, "0.0.0.0", 0, out); + } catch (IOException ioe) {} throw new SOCKSException("Error in destination format"); } 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 (" + e.getMessage() + ")"); } 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 (" + e.getMessage() + ")"); } 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 (" + e.getMessage() + ")"); } -- GitLab