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
This commit is contained in:
zzz
2014-01-06 13:57:45 +00:00
parent 0fae0640d6
commit 0bc6c23ac9
10 changed files with 103 additions and 61 deletions

View File

@ -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")

View File

@ -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" +

View File

@ -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);

View File

@ -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) ?

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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";
/**
*
*/

View File

@ -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;
}
}

View File

@ -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);