From 0bc6c23ac90644f151bf8a3e241492eba2d7f8bc Mon Sep 17 00:00:00 2001 From: zzz <zzz@mail.i2p> Date: Mon, 6 Jan 2014 13:57:45 +0000 Subject: [PATCH] Remove outproxy hook in context, use ClientAppManager: - Add clientAppManager() to I2PAppContext so it can be used there - Add routerAppManager() to RouterContext for convenience inside router Start of SSL support in I2PTunnelHTTPClient - Add initialSocketData support back to I2PTunnelOutproxyRunner - Works for orchid (and in-net?) - TODO Doesn't work for in-net proxy - Need separate config for SSL proxy --- .../i2p/i2ptunnel/I2PTunnelConnectClient.java | 2 +- .../i2p/i2ptunnel/I2PTunnelHTTPClient.java | 86 ++++++++++++++----- .../i2ptunnel/I2PTunnelOutproxyRunner.java | 11 ++- .../i2p/router/web/ConfigClientsHandler.java | 2 +- .../i2p/router/web/ConfigClientsHelper.java | 2 +- apps/routerconsole/jsp/debug.jsp | 2 +- core/java/src/net/i2p/I2PAppContext.java | 37 ++------ .../net/i2p/{outproxy => app}/Outproxy.java | 4 +- .../src/net/i2p/router/RouterContext.java | 14 ++- .../i2p/router/startup/LoadClientAppsJob.java | 4 +- 10 files changed, 103 insertions(+), 61 deletions(-) rename core/java/src/net/i2p/{outproxy => app}/Outproxy.java (74%) diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java index 95221c4771..d56d0787cb 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java @@ -90,7 +90,7 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R "Your browser is misconfigured. Do not use the proxy to access the router console or other localhost destinations.<BR>") .getBytes(); - private final static byte[] SUCCESS_RESPONSE = + final static byte[] SUCCESS_RESPONSE = ("HTTP/1.1 200 Connection Established\r\n"+ "Proxy-agent: I2P\r\n"+ "\r\n") diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java index 05a41860a6..65af721594 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java @@ -18,6 +18,9 @@ import java.util.concurrent.ConcurrentHashMap; import net.i2p.I2PAppContext; import net.i2p.I2PException; +import net.i2p.app.ClientApp; +import net.i2p.app.ClientAppManager; +import net.i2p.app.Outproxy; import net.i2p.client.I2PSession; import net.i2p.client.streaming.I2PSocket; import net.i2p.client.streaming.I2PSocketManager; @@ -29,7 +32,6 @@ import net.i2p.data.DataHelper; import net.i2p.data.Destination; import net.i2p.data.Hash; import net.i2p.i2ptunnel.localServer.LocalHTTPServer; -import net.i2p.outproxy.Outproxy; import net.i2p.util.EventDispatcher; import net.i2p.util.Log; import net.i2p.util.PortMapper; @@ -416,6 +418,14 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn ****/ } + method = params[0]; + if (method.toUpperCase(Locale.US).equals("CONNECT")) { + // this makes things easier later, by spoofing a + // protocol so the URI parser find the host and port + // FIXME breaks in-net outproxy + request = "https://" + request + '/'; + } + // Now use the Java URI parser // This will be the incoming URI but will then get modified // to be the outgoing URI (with http:// if going to outproxy, otherwise without) @@ -447,13 +457,13 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn s.close(); return; } - method = params[0]; + String protocolVersion = params[2]; protocol = requestURI.getScheme(); host = requestURI.getHost(); if(protocol == null || host == null) { - _log.warn("Null protocol or host: " + request); + _log.warn("Null protocol or host: " + request + ' ' + protocol + ' ' + host); method = null; break; } @@ -531,6 +541,9 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn break; } ******/ + } else if ("https".equals(protocol) || + method.toUpperCase(Locale.US).equals("CONNECT")) { + remotePort = 443; } else { remotePort = 80; } @@ -681,18 +694,28 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn s.close(); return; } else if(host.contains(".") || host.startsWith("[")) { - if (Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_OUTPROXY)) && - (outproxy = _context.outproxy()) != null) { - int rPort = requestURI.getPort(); - if (rPort > 0) - remotePort = rPort; - else - remotePort = 80; - usingOutproxy = true; - targetRequest = requestURI.toASCIIString(); - if(_log.shouldLog(Log.DEBUG)) - _log.debug(getPrefix(requestId) + " [" + host + "]: outproxy!"); - } else { + if (Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_OUTPROXY))) { + ClientAppManager mgr = _context.clientAppManager(); + if (mgr != null) { + ClientApp op = mgr.getRegisteredApp(Outproxy.NAME); + if (op != null) { + outproxy = (Outproxy) op; + int rPort = requestURI.getPort(); + if (rPort > 0) + remotePort = rPort; + else if ("https".equals(protocol) || + method.toUpperCase(Locale.US).equals("CONNECT")) + remotePort = 443; + else + remotePort = 80; + usingOutproxy = true; + targetRequest = requestURI.toASCIIString(); + if(_log.shouldLog(Log.DEBUG)) + _log.debug(getPrefix(requestId) + " [" + host + "]: outproxy!"); + } + } + } + if (!usingOutproxy) { if(port >= 0) { host = host + ':' + port; } @@ -917,9 +940,17 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn // no destination, going to outproxy plugin if (usingOutproxy) { Socket outSocket = outproxy.connect(host, remotePort); - byte[] data = newRequest.toString().getBytes("ISO-8859-1"); Runnable onTimeout = new OnTimeout(s, s.getOutputStream(), targetRequest, usingWWWProxy, currentProxy, requestId); - new I2PTunnelOutproxyRunner(s, outSocket, sockLock, data, onTimeout); + byte[] data; + byte[] response; + if (method.toUpperCase(Locale.US).equals("CONNECT")) { + data = null; + response = I2PTunnelConnectClient.SUCCESS_RESPONSE; + } else { + data = newRequest.toString().getBytes("ISO-8859-1"); + response = null; + } + new I2PTunnelOutproxyRunner(s, outSocket, sockLock, data, response, onTimeout); return; } @@ -1025,9 +1056,22 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn if (remotePort > 0) sktOpts.setPort(remotePort); I2PSocket i2ps = createI2PSocket(clientDest, sktOpts); - byte[] data = newRequest.toString().getBytes("ISO-8859-1"); Runnable onTimeout = new OnTimeout(s, s.getOutputStream(), targetRequest, usingWWWProxy, currentProxy, requestId); - new I2PTunnelHTTPClientRunner(s, i2ps, sockLock, data, mySockets, onTimeout); + if (method.toUpperCase(Locale.US).equals("CONNECT")) { + byte[] data; + byte[] response; + if (usingWWWProxy) { + data = newRequest.toString().getBytes("ISO-8859-1"); + response = null; + } else { + data = null; + response = I2PTunnelConnectClient.SUCCESS_RESPONSE; + } + new I2PTunnelRunner(s, i2ps, sockLock, data, response, mySockets, onTimeout); + } else { + byte[] data = newRequest.toString().getBytes("ISO-8859-1"); + new I2PTunnelHTTPClientRunner(s, i2ps, sockLock, data, mySockets, onTimeout); + } } catch (SocketException ex) { if (_log.shouldLog(Log.INFO)) { _log.info(getPrefix(requestId) + "Error trying to connect", ex); @@ -1310,8 +1354,10 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn } } ****/ - return protocol.toLowerCase(Locale.US).equals("http"); + String lc = protocol.toLowerCase(Locale.US); + return lc.equals("http") || lc.equals("https"); } + private final static byte[] ERR_HELPER_DISABLED = ("HTTP/1.1 403 Disabled\r\n" + "Content-Type: text/plain\r\n" + diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelOutproxyRunner.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelOutproxyRunner.java index daea6bd4f7..a399a6ed0a 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelOutproxyRunner.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelOutproxyRunner.java @@ -48,6 +48,7 @@ public class I2PTunnelOutproxyRunner extends I2PAppThread { private final Object slock, finishLock = new Object(); volatile boolean finished = false; private final byte[] initialI2PData; + private final byte[] initialSocketData; /** when the last data was sent/received (or -1 if never) */ private long lastActivityOn; /** when the runner started up */ @@ -68,11 +69,12 @@ public class I2PTunnelOutproxyRunner extends I2PAppThread { it will be run before closing s. */ public I2PTunnelOutproxyRunner(Socket s, Socket i2ps, Object slock, byte[] initialI2PData, - Runnable onTimeout) { + byte[] initialSocketData, Runnable onTimeout) { this.s = s; this.i2ps = i2ps; this.slock = slock; this.initialI2PData = initialI2PData; + this.initialSocketData = initialSocketData; this.onTimeout = onTimeout; lastActivityOn = -1; startedOn = Clock.getInstance().now(); @@ -130,9 +132,14 @@ public class I2PTunnelOutproxyRunner extends I2PAppThread { i2pout.write(initialI2PData); i2pout.flush(); } + if (initialSocketData != null) { + // this does not increment totalReceived + out.write(initialSocketData); + } if (_log.shouldLog(Log.DEBUG)) _log.debug("Initial data " + (initialI2PData != null ? initialI2PData.length : 0) - + " written to the outproxy, starting forwarders"); + + " written to the outproxy, " + (initialSocketData != null ? initialSocketData.length : 0) + + " written to the socket, starting forwarders"); if (!(s instanceof InternalSocket)) in = new BufferedInputStream(in, 2*NETWORK_BUFFER_SIZE); Thread t1 = new StreamForwarder(in, i2pout, true); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHandler.java index 695f9aeb09..b5f1e1c51f 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHandler.java @@ -235,7 +235,7 @@ public class ConfigClientsHandler extends FormHandler { return; } ClientAppConfig ca = clients.get(i); - ClientApp clientApp = _context.clientAppManager().getClientApp(ca.className, LoadClientAppsJob.parseArgs(ca.args)); + ClientApp clientApp = _context.routerAppManager().getClientApp(ca.className, LoadClientAppsJob.parseArgs(ca.args)); if (clientApp != null && clientApp.getState() == ClientAppState.RUNNING) { try { // todo parseArgs(ca.stopArgs) ? diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHelper.java index 9ae98ce991..3197dec5d9 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHelper.java @@ -103,7 +103,7 @@ public class ConfigClientsHelper extends HelperBase { showStart = false; showStop = false; } else { - ClientApp clientApp = _context.clientAppManager().getClientApp(ca.className, LoadClientAppsJob.parseArgs(ca.args)); + ClientApp clientApp = _context.routerAppManager().getClientApp(ca.className, LoadClientAppsJob.parseArgs(ca.args)); showStart = clientApp == null; showStop = clientApp != null && clientApp.getState() == ClientAppState.RUNNING; } diff --git a/apps/routerconsole/jsp/debug.jsp b/apps/routerconsole/jsp/debug.jsp index 93b9b58c07..f36e9f31ff 100644 --- a/apps/routerconsole/jsp/debug.jsp +++ b/apps/routerconsole/jsp/debug.jsp @@ -35,7 +35,7 @@ /* * Print out the status for the AppManager */ - ctx.clientAppManager().renderStatusHTML(out); + ctx.routerAppManager().renderStatusHTML(out); /* * Print out the status for all the SessionKeyManagers diff --git a/core/java/src/net/i2p/I2PAppContext.java b/core/java/src/net/i2p/I2PAppContext.java index 9aaf4c3b27..665b54feb9 100644 --- a/core/java/src/net/i2p/I2PAppContext.java +++ b/core/java/src/net/i2p/I2PAppContext.java @@ -7,6 +7,7 @@ import java.util.Properties; import java.util.Random; import java.util.Set; +import net.i2p.app.ClientAppManager; import net.i2p.client.naming.NamingService; import net.i2p.crypto.AESEngine; import net.i2p.crypto.CryptixAESEngine; @@ -1028,37 +1029,11 @@ public class I2PAppContext { } /** - * A local outproxy - * @return The outproxy if it is registered, else null - * @since 0.9.11 + * The RouterAppManager in RouterContext, null always in I2PAppContext + * @return null always + * @since 0.9.11, in RouterContext since 0.9.4 */ - public Outproxy outproxy() { - return _outproxy; - } - - /** - * Register as the outproxy. For now, only one. - * @throws IllegalStateException if one was already registered - * @since 0.9.11 - */ - public void registerOutproxy(Outproxy oproxy) { - synchronized(_lock21) { - if (_outproxy != null) - throw new IllegalStateException(); - _outproxy = oproxy; - } - } - - /** - * Unregister the outproxy. - * @throws IllegalStateException if it was not registered - * @since 0.9.11 - */ - public void unregisterOutproxy(Outproxy oproxy) { - synchronized(_lock21) { - if (_outproxy != oproxy) - throw new IllegalStateException(); - _outproxy = null; - } + public ClientAppManager clientAppManager() { + return null; } } diff --git a/core/java/src/net/i2p/outproxy/Outproxy.java b/core/java/src/net/i2p/app/Outproxy.java similarity index 74% rename from core/java/src/net/i2p/outproxy/Outproxy.java rename to core/java/src/net/i2p/app/Outproxy.java index a18066acdd..9238cd37d8 100644 --- a/core/java/src/net/i2p/outproxy/Outproxy.java +++ b/core/java/src/net/i2p/app/Outproxy.java @@ -1,4 +1,4 @@ -package net.i2p.outproxy; +package net.i2p.app; import java.io.IOException; import java.net.Socket; @@ -9,6 +9,8 @@ import java.net.Socket; */ public interface Outproxy { + public static final String NAME = "outproxy"; + /** * */ diff --git a/router/java/src/net/i2p/router/RouterContext.java b/router/java/src/net/i2p/router/RouterContext.java index 6af37e54fa..ba837ccf2d 100644 --- a/router/java/src/net/i2p/router/RouterContext.java +++ b/router/java/src/net/i2p/router/RouterContext.java @@ -8,6 +8,7 @@ import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArrayList; import net.i2p.I2PAppContext; +import net.i2p.app.ClientAppManager; import net.i2p.data.Hash; import net.i2p.data.RouterInfo; import net.i2p.internal.InternalClientManager; @@ -586,7 +587,18 @@ public class RouterContext extends I2PAppContext { * @return the manager * @since 0.9.4 */ - public RouterAppManager clientAppManager() { + @Override + public ClientAppManager clientAppManager() { + return _appManager; + } + + /** + * The RouterAppManager. + * For convenience, same as clientAppManager(), no cast required + * @return the manager + * @since 0.9.11 + */ + public RouterAppManager routerAppManager() { return _appManager; } } diff --git a/router/java/src/net/i2p/router/startup/LoadClientAppsJob.java b/router/java/src/net/i2p/router/startup/LoadClientAppsJob.java index 2cd538fe16..27242397e8 100644 --- a/router/java/src/net/i2p/router/startup/LoadClientAppsJob.java +++ b/router/java/src/net/i2p/router/startup/LoadClientAppsJob.java @@ -267,13 +267,13 @@ public class LoadClientAppsJob extends JobImpl { Class<?> cls = Class.forName(_className, true, _cl); if (isRouterApp(cls)) { Constructor<?> con = cls.getConstructor(RouterContext.class, ClientAppManager.class, String[].class); - RouterAppManager mgr = _ctx.clientAppManager(); + RouterAppManager mgr = _ctx.routerAppManager(); Object[] conArgs = new Object[] {_ctx, _ctx.clientAppManager(), _args}; RouterApp app = (RouterApp) con.newInstance(conArgs); mgr.addAndStart(app, _args); } else if (isClientApp(cls)) { Constructor<?> con = cls.getConstructor(I2PAppContext.class, ClientAppManager.class, String[].class); - RouterAppManager mgr = _ctx.clientAppManager(); + RouterAppManager mgr = _ctx.routerAppManager(); Object[] conArgs = new Object[] {_ctx, _ctx.clientAppManager(), _args}; ClientApp app = (ClientApp) con.newInstance(conArgs); mgr.addAndStart(app, _args); -- GitLab