/* I2PSOCKSTunnel is released under the terms of the GNU GPL, * with an additional exception. For further details, see the * licensing terms in I2PTunnel.java. * * Copyright (c) 2004 by human */ 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.client.streaming.I2PSocketOptions; import net.i2p.data.Destination; import net.i2p.i2ptunnel.I2PTunnel; import net.i2p.i2ptunnel.I2PTunnelClientBase; import net.i2p.i2ptunnel.I2PTunnelRunner; import net.i2p.i2ptunnel.Logging; import net.i2p.util.EventDispatcher; import net.i2p.util.Log; public class I2PSOCKSTunnel extends I2PTunnelClientBase { private HashMap<String, List<String>> proxies = null; // port# + "" or "default" -> hostname list //public I2PSOCKSTunnel(int localPort, Logging l, boolean ownDest) { // I2PSOCKSTunnel(localPort, l, ownDest, (EventDispatcher)null); //} /** * As of 0.9.20 this is fast, and does NOT connect the manager to the router, * or open the local socket. You MUST call startRunning() for that. * * @param pkf private key file name or null for transient key */ public I2PSOCKSTunnel(int localPort, Logging l, boolean ownDest, EventDispatcher notifyThis, I2PTunnel tunnel, String pkf) { super(localPort, ownDest, l, notifyThis, "SOCKS Proxy on " + tunnel.listenHost + ':' + localPort, tunnel, pkf); setName("SOCKS Proxy on " + tunnel.listenHost + ':' + localPort); parseOptions(); notifyEvent("openSOCKSTunnelResult", "ok"); } protected void clientConnectionRun(Socket s) { try { SOCKSServer serv = SOCKSServerFactory.createSOCKSServer(_context, s, getTunnel().getClientOptions()); Socket clientSock = serv.getClientSocket(); I2PSocket destSock = serv.getDestinationI2PSocket(this); Thread t = new I2PTunnelRunner(clientSock, destSock, sockLock, null, null, mySockets, (I2PTunnelRunner.FailCallback) null); // we are called from an unlimited thread pool, so run inline //t.start(); t.run(); } catch (SOCKSException e) { if (_log.shouldLog(Log.WARN)) _log.warn("Error from SOCKS connection", e); closeSocket(s); } } /** add "default" or port number */ public static final String PROP_PROXY_PREFIX = "i2ptunnel.socks.proxy."; public static final String DEFAULT = "default"; public static final String PROP_PROXY_DEFAULT = PROP_PROXY_PREFIX + DEFAULT; private void parseOptions() { Properties opts = getTunnel().getClientOptions(); proxies = new HashMap<String, List<String>>(1); for (Map.Entry<Object, Object> e : opts.entrySet()) { String prop = (String)e.getKey(); if ((!prop.startsWith(PROP_PROXY_PREFIX)) || prop.length() <= PROP_PROXY_PREFIX.length()) continue; String port = prop.substring(PROP_PROXY_PREFIX.length()); List<String> proxyList = new ArrayList<String>(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); } /** * Because getDefaultOptions() in super() is protected * @since 0.8.2 */ public I2PSocketOptions buildOptions(Properties overrides) { Properties defaultOpts = getTunnel().getClientOptions(); defaultOpts.putAll(overrides); // delayed start verifySocketManager(); I2PSocketOptions opts = sockMgr.buildOptions(defaultOpts); if (!defaultOpts.containsKey(I2PSocketOptions.PROP_CONNECT_TIMEOUT)) opts.setConnectTimeout(60 * 1000); return opts; } }