diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java
index 37c906fbeb18d6f9847c72346b8236c273b9828d..de219ff39b36367c3707278299086294db81f22f 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java
@@ -14,6 +14,9 @@ import java.util.StringTokenizer;
 
 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.streaming.I2PSocket;
 import net.i2p.client.streaming.I2PSocketOptions;
 import net.i2p.data.Base64;
@@ -34,7 +37,7 @@ import net.i2p.util.PortMapper;
  *      example.com (sent to one of the configured proxies)
  *   )
  *
- *   (port and protocol are ignored for i2p destinations)
+ *   (protocol is ignored for i2p destinations)
  *   CONNECT host
  *   CONNECT host protocol
  *   CONNECT host:port
@@ -147,6 +150,9 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
         String targetRequest = null;
         boolean usingWWWProxy = false;
         String currentProxy = null;
+        // local outproxy plugin
+        boolean usingInternalOutproxy = false;
+        Outproxy outproxy = null;
         long requestId = __requestId.incrementAndGet();
         try {
             out = s.getOutputStream();
@@ -154,6 +160,7 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
             String line, method = null, host = null, destination = null, restofline = null;
             StringBuilder newRequest = new StringBuilder();
             String authorization = null;
+            int remotePort = 443;
             while (true) {
                 // Use this rather than BufferedReader because we can't have readahead,
                 // since we are passing the stream on to I2PTunnelRunner
@@ -172,8 +179,20 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
                     String request = line.substring(pos + 1);
 
                     pos = request.indexOf(':');
-                    if (pos == -1)
+                    if (pos == -1) {
                        pos = request.indexOf(' ');
+                    } else {
+                       int spos = request.indexOf(' ');
+                       if (spos > 0) {
+                           try {
+                               remotePort = Integer.parseInt(request.substring(pos + 1, spos));
+                           } catch (NumberFormatException nfe) {
+                               break;
+                           } catch (IndexOutOfBoundsException ioobe) {
+                               break;
+                           }
+                       }
+                    }
                     if (pos == -1) {
                         host = request;
                         restofline = "";
@@ -185,19 +204,36 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
                     if (host.toLowerCase(Locale.US).endsWith(".i2p")) {
                         // Destination gets the host name
                         destination = host;
-                    } else if (host.indexOf('.') != -1) {
-                        // The request must be forwarded to a outproxy
-                        currentProxy = selectProxy();
-                        if (currentProxy == null) {
-                            if (_log.shouldLog(Log.WARN))
-                                _log.warn(getPrefix(requestId) + "Host wants to be outproxied, but we dont have any!");
-                            writeErrorMessage(ERR_NO_OUTPROXY, out);
-                            s.close();
-                            return;
+                    } else if (host.contains(".") || host.startsWith("[")) {
+                        if (Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_USE_OUTPROXY_PLUGIN, "true"))) {
+                            ClientAppManager mgr = _context.clientAppManager();
+                            if (mgr != null) {
+                                ClientApp op = mgr.getRegisteredApp(Outproxy.NAME);
+                                if (op != null) {
+                                    outproxy = (Outproxy) op;
+                                    usingInternalOutproxy = true;
+                                    if (host.startsWith("[")) {
+                                        host = host.substring(1);
+                                        if (host.endsWith("]"))
+                                            host = host.substring(0, host.length() - 1);
+                                    }
+                                }
+                            }
                         }
-                        destination = currentProxy;
-                        usingWWWProxy = true;
-                        newRequest.append("CONNECT ").append(host).append(restofline).append("\r\n"); // HTTP spec
+                        if (!usingInternalOutproxy) {
+                            // The request must be forwarded to a outproxy
+                            currentProxy = selectProxy();
+                            if (currentProxy == null) {
+                                if (_log.shouldLog(Log.WARN))
+                                    _log.warn(getPrefix(requestId) + "Host wants to be outproxied, but we dont have any!");
+                                writeErrorMessage(ERR_NO_OUTPROXY, out);
+                                s.close();
+                                return;
+                            }
+                            destination = currentProxy;
+                            usingWWWProxy = true;
+                            newRequest.append("CONNECT ").append(host).append(restofline).append("\r\n"); // HTTP spec
+                         }
                     } else if (host.toLowerCase(Locale.US).equals("localhost")) {
                         writeErrorMessage(ERR_LOCALHOST, out);
                         s.close();
@@ -208,10 +244,12 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
                     targetRequest = host;
 
                     if (_log.shouldLog(Log.DEBUG)) {
-                        _log.debug(getPrefix(requestId) + "METHOD:" + method + ":");
-                        _log.debug(getPrefix(requestId) + "HOST  :" + host + ":");
-                        _log.debug(getPrefix(requestId) + "REST  :" + restofline + ":");
-                        _log.debug(getPrefix(requestId) + "DEST  :" + destination + ":");
+                        _log.debug(getPrefix(requestId) + "METHOD:" + method + ":\n" +
+                                   "HOST  :" + host + ":\n" +
+                                   "PORT  :" + remotePort + ":\n" +
+                                   "REST  :" + restofline + ":\n" +
+                                   "DEST  :" + destination + ":\n" +
+                                   "www proxy? " + usingWWWProxy + " internal proxy? " + usingInternalOutproxy);
                     }
                 } else if (line.toLowerCase(Locale.US).startsWith("proxy-authorization: ")) {
                     // strip Proxy-Authenticate from the response in HTTPResponseOutputStream
@@ -250,7 +288,24 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
                 }
             }
 
-            if (destination == null || method == null || !"CONNECT".equals(method.toUpperCase(Locale.US))) {
+            if (method == null || !"CONNECT".equals(method.toUpperCase(Locale.US))) {
+                writeErrorMessage(ERR_BAD_PROTOCOL, out);
+                s.close();
+                return;
+            }
+            
+            // no destination, going to outproxy plugin
+            if (usingInternalOutproxy) {
+                Socket outSocket = outproxy.connect(host, remotePort);
+                OnTimeout onTimeout = new OnTimeout(s, s.getOutputStream(), targetRequest, usingWWWProxy, currentProxy, requestId);
+                byte[] response = SUCCESS_RESPONSE.getBytes("UTF-8");
+                Thread t = new I2PTunnelOutproxyRunner(s, outSocket, sockLock, null, response, onTimeout);
+                // we are called from an unlimited thread pool, so run inline
+                t.run();
+                return;
+            }
+
+            if (destination == null) {
                 writeErrorMessage(ERR_BAD_PROTOCOL, out);
                 s.close();
                 return;
@@ -282,7 +337,10 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R
                 return;
             }
 
-            I2PSocket i2ps = createI2PSocket(clientDest, getDefaultOptions());
+            I2PSocketOptions sktOpts = getDefaultOptions();
+            if (!usingWWWProxy && remotePort > 0)
+                sktOpts.setPort(remotePort);
+            I2PSocket i2ps = createI2PSocket(clientDest, sktOpts);
             byte[] data = null;
             byte[] response = null;
             if (usingWWWProxy)
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java
index 6e40b9a5722b31c4739df7d295e3ca147711b533..4fe25039f8a8b462d230427ca3c9b5ace7ab01e7 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java
@@ -357,8 +357,6 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
     public static final String PROP_JUMP_SERVERS = "i2ptunnel.httpclient.jumpServers";
     public static final String PROP_DISABLE_HELPER = "i2ptunnel.httpclient.disableAddressHelper";
     /** @since 0.9.11 */
-    public static final String PROP_USE_OUTPROXY_PLUGIN = "i2ptunnel.useLocalOutproxy";
-    /** @since 0.9.11 */
     public static final String PROP_SSL_OUTPROXIES = "i2ptunnel.httpclient.SSLOutproxies";
     /** @since 0.9.14 */
     public static final String PROP_ACCEPT = "i2ptunnel.httpclient.sendAccept";
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java
index 354f5e816140f36e3ec7620115ab4148b90860c4..399269c5a9c0e2b19330c1c1d15225ad3115733d 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java
@@ -59,6 +59,8 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
     private static final int NONCE_BYTES = DataHelper.DATE_LENGTH + MD5_BYTES;
     private static final long MAX_NONCE_AGE = 60*60*1000L;
     private static final int MAX_NONCE_COUNT = 1024;
+    /** @since 0.9.11, moved to Base in 0.9.29 */
+    public static final String PROP_USE_OUTPROXY_PLUGIN = "i2ptunnel.useLocalOutproxy";
 
     private static final String ERR_AUTH1 =
             "HTTP/1.1 407 Proxy Authentication Required\r\n" +
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSServer.java
index b269b6798dcae875b36bbfad2e909dc5b47abce6..34f79567f5fbe31b2fa5ee50f2070d51fa976bb7 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSServer.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/SOCKSServer.java
@@ -14,7 +14,7 @@ import net.i2p.app.ClientApp;
 import net.i2p.app.ClientAppManager;
 import net.i2p.app.Outproxy;
 import net.i2p.client.streaming.I2PSocket;
-import net.i2p.i2ptunnel.I2PTunnelHTTPClient;
+import net.i2p.i2ptunnel.I2PTunnelHTTPClientBase;
 import net.i2p.util.Log;
 
 /**
@@ -89,7 +89,7 @@ abstract class SOCKSServer {
      *  @since 0.9.27
      */
     private boolean shouldUseOutproxyPlugin() {
-        return Boolean.parseBoolean(props.getProperty(I2PTunnelHTTPClient.PROP_USE_OUTPROXY_PLUGIN, "true"));
+        return Boolean.parseBoolean(props.getProperty(I2PTunnelHTTPClientBase.PROP_USE_OUTPROXY_PLUGIN, "true"));
     }
 
     /**
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/ui/GeneralHelper.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/ui/GeneralHelper.java
index 556982a43bf4be430bb2ebe4c7854dad7335d186..26f4265e023c16d7c1b86c58a5a6360965f3b966 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/ui/GeneralHelper.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/ui/GeneralHelper.java
@@ -579,7 +579,7 @@ public class GeneralHelper {
      *  Default true
      */
     public boolean getUseOutproxyPlugin(int tunnel) {
-        return getBooleanProperty(tunnel, I2PTunnelHTTPClient.PROP_USE_OUTPROXY_PLUGIN, true);
+        return getBooleanProperty(tunnel, I2PTunnelHTTPClientBase.PROP_USE_OUTPROXY_PLUGIN, true);
     }
 
     /** all of these are @since 0.8.3 */
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/ui/TunnelConfig.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/ui/TunnelConfig.java
index 0a007e37835534ca4fc181f3da3c8a37c5617b1c..6dd91cce3650c57ee1cedcce4fa46618b8d7691c 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/ui/TunnelConfig.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/ui/TunnelConfig.java
@@ -409,9 +409,9 @@ public class TunnelConfig {
 
     public void setUseOutproxyPlugin(boolean val) {
         if (val)
-            _booleanOptions.add(I2PTunnelHTTPClient.PROP_USE_OUTPROXY_PLUGIN);
+            _booleanOptions.add(I2PTunnelHTTPClientBase.PROP_USE_OUTPROXY_PLUGIN);
         else
-            _booleanOptions.remove(I2PTunnelHTTPClient.PROP_USE_OUTPROXY_PLUGIN);
+            _booleanOptions.remove(I2PTunnelHTTPClientBase.PROP_USE_OUTPROXY_PLUGIN);
     }
     
     /**
@@ -695,7 +695,7 @@ public class TunnelConfig {
         };
     private static final String _booleanProxyOpts[] = {
         I2PTunnelHTTPClientBase.PROP_OUTPROXY_AUTH,
-        I2PTunnelHTTPClient.PROP_USE_OUTPROXY_PLUGIN,
+        I2PTunnelHTTPClientBase.PROP_USE_OUTPROXY_PLUGIN,
         I2PTunnelHTTPClient.PROP_USER_AGENT,
         I2PTunnelHTTPClient.PROP_REFERER,
         I2PTunnelHTTPClient.PROP_ACCEPT,
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
index 15897cb618f78be766a5358f513d80b6ecae09db..fe1c30b17b865204fa7de73076e968820c2e6a97 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
@@ -499,7 +499,7 @@ public class IndexBean {
         if (tun != null) {
             if (TunnelController.TYPE_HTTP_CLIENT.equals(tun.getType())) {
                 Properties opts = tun.getClientOptionProps();
-                if (Boolean.parseBoolean(opts.getProperty(I2PTunnelHTTPClient.PROP_USE_OUTPROXY_PLUGIN, "true"))) {
+                if (Boolean.parseBoolean(opts.getProperty(I2PTunnelHTTPClientBase.PROP_USE_OUTPROXY_PLUGIN, "true"))) {
                     ClientAppManager mgr = _context.clientAppManager();
                     if (mgr != null)
                         return mgr.getRegisteredApp(Outproxy.NAME) != null;