diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java
index 966a9bee7..389f0eb99 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java
@@ -105,7 +105,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
"the following Destination:
")
.getBytes();
*****/
- private final static byte[] _ERR_NO_OUTPROXY =
+ private final static byte[] ERR_NO_OUTPROXY =
("HTTP/1.1 503 Service Unavailable\r\n" +
"Content-Type: text/html; charset=iso-8859-1\r\n" +
"Cache-control: no-cache\r\n" +
@@ -113,6 +113,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
"
I2P ERROR: No outproxy found
" +
"Your request was for a site outside of I2P, but you have no " +
"HTTP outproxy configured. Please configure an outproxy in I2PTunnel").getBytes();
+
private final static byte[] ERR_AHELPER_CONFLICT =
("HTTP/1.1 409 Conflict\r\n" +
"Content-Type: text/html; charset=iso-8859-1\r\n" +
@@ -127,6 +128,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
"and either discarding the addresshelper link, " +
"discarding the host entry from your host database, " +
"or naming one of them differently.
").getBytes();
+
private final static byte[] ERR_AHELPER_NOTFOUND =
("HTTP/1.1 404 Not Found\r\n" +
"Content-Type: text/html; charset=iso-8859-1\r\n" +
@@ -136,6 +138,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
"The helper key you put for i2paddresshelper= is not resolvable. " +
"It seems to be garbage data, or a mistyped b32. Check your URL " +
"to try and fix the helper key to be either a b32 or a base64.").getBytes();
+
private final static byte[] ERR_AHELPER_NEW =
("HTTP/1.1 409 New Address\r\n" +
"Content-Type: text/html; charset=iso-8859-1\r\n" +
@@ -146,6 +149,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
"You may either save the destination for this host name to your address book, or remember it only until your router restarts. " +
"If you save it to your address book, you will not see this message again. " +
"If you do not wish to visit this host, click the \"back\" button on your browser.").getBytes();
+
private final static byte[] ERR_BAD_PROTOCOL =
("HTTP/1.1 403 Bad Protocol\r\n" +
"Content-Type: text/html; charset=iso-8859-1\r\n" +
@@ -154,6 +158,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
"
I2P ERROR: NON-HTTP PROTOCOL
" +
"The request uses a bad protocol. " +
"The I2P HTTP Proxy supports HTTP and HTTPS requests only. Other protocols such as FTP are not allowed. ").getBytes();
+
private final static byte[] ERR_BAD_URI =
("HTTP/1.1 403 Bad URI\r\n" +
"Content-Type: text/html; charset=iso-8859-1\r\n" +
@@ -162,6 +167,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
"
I2P ERROR: INVALID REQUEST URI
" +
"The request URI is invalid, and probably contains illegal characters. " +
"If you clicked e.g. a forum link, check the end of the URI for any characters the browser has mistakenly added on. ").getBytes();
+
private final static byte[] ERR_LOCALHOST =
("HTTP/1.1 403 Access Denied\r\n" +
"Content-Type: text/html; charset=iso-8859-1\r\n" +
@@ -170,6 +176,15 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
"
I2P ERROR: REQUEST DENIED
" +
"Your browser is misconfigured. Do not use the proxy to access the router console or other localhost destinations. ").getBytes();
+ private final static byte[] ERR_INTERNAL_SSL =
+ ("HTTP/1.1 403 SSL Rejected\r\n" +
+ "Content-Type: text/html; charset=iso-8859-1\r\n" +
+ "Cache-control: no-cache\r\n" +
+ "\r\n" +
+ "
I2P ERROR: SSL to I2P address rejected
" +
+ "SSL for to .i2p addresses denied by configuration." +
+ "You may change the configuration in I2PTunnel").getBytes();
+
/**
* This constructor always starts the tunnel (ignoring the i2cp.delayOpen option).
* It is used to add a client to an existing socket manager.
@@ -317,6 +332,10 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
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";
+ /** @since 0.9.14 */
+ public static final String PROP_INTERNAL_SSL = "i2ptunnel.httpclient.allowInternalSSL";
protected void clientConnectionRun(Socket s) {
OutputStream out = null;
@@ -728,7 +747,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
_log.warn(getPrefix(requestId) + "Host wants to be outproxied, but we dont have any!");
}
l.log("No outproxy found for the request.");
- out.write(getErrorPage("noproxy", _ERR_NO_OUTPROXY));
+ out.write(getErrorPage("noproxy", ERR_NO_OUTPROXY));
writeFooter(out);
reader.drain();
s.close();
@@ -800,8 +819,10 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
} else if(lowercaseLine.startsWith("accept")) {
// strip the accept-blah headers, as they vary dramatically from
// browser to browser
- line = null;
- continue;
+ if(!Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_ACCEPT))) {
+ line = null;
+ continue;
+ }
} else if (lowercaseLine.startsWith("referer: ")) {
// save for address helper form below
referer = line.substring(9);
@@ -850,7 +871,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
// according to rfc2616 s14.3, this *should* force identity, even if
// an explicit q=0 for gzip doesn't. tested against orion.i2p, and it
// seems to work.
- newRequest.append("Accept-Encoding: \r\n");
+ if(!Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_ACCEPT)))
+ newRequest.append("Accept-Encoding: \r\n");
if (!usingInternalOutproxy)
newRequest.append("X-Accept-Encoding: x-i2p-gzip;q=1.0, identity;q=0.5, deflate;q=0, gzip;q=0, *;q=0\r\n");
}
@@ -1002,12 +1024,14 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
}
byte[] header;
String jumpServers = null;
+ String extraMessage = null;
if(usingWWWProxy) {
header = getErrorPage("dnfp", ERR_DESTINATION_UNKNOWN);
} else if(ahelperPresent) {
header = getErrorPage("dnfb", ERR_DESTINATION_UNKNOWN);
} else if(destination.length() == 60 && destination.toLowerCase(Locale.US).endsWith(".b32.i2p")) {
header = getErrorPage("nols", ERR_DESTINATION_UNKNOWN);
+ extraMessage = _("Destination lease set not found");
} else {
header = getErrorPage("dnfh", ERR_DESTINATION_UNKNOWN);
jumpServers = getTunnel().getClientOptions().getProperty(PROP_JUMP_SERVERS);
@@ -1015,11 +1039,21 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
jumpServers = DEFAULT_JUMP_SERVERS;
}
}
- writeErrorMessage(header, out, targetRequest, usingWWWProxy, destination, jumpServers);
+ writeErrorMessage(header, extraMessage, out, targetRequest, usingWWWProxy, destination, jumpServers);
s.close();
return;
}
+ if (method.toUpperCase(Locale.US).equals("CONNECT") &&
+ !usingWWWProxy &&
+ !Boolean.parseBoolean(getTunnel().getClientOptions().getProperty(PROP_INTERNAL_SSL))) {
+ writeErrorMessage(ERR_INTERNAL_SSL, out, targetRequest, false, destination);
+ s.close();
+ if (_log.shouldLog(Log.WARN))
+ _log.warn("SSL to i2p destinations denied by configuration: " + targetRequest);
+ return;
+ }
+
// Address helper response form
// This will only load once - the second time it won't be "new"
// Don't do this for eepget, which uses a user-agent of "Wget"
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java
index 14a886ad3..b00611311 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java
@@ -549,8 +549,11 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
_requestId = id;
}
+ /**
+ * @param ex may be null
+ */
public void onFail(Exception ex) {
- Throwable cause = ex.getCause();
+ Throwable cause = ex != null ? ex.getCause() : null;
if (cause != null && cause instanceof I2PSocketException) {
I2PSocketException ise = (I2PSocketException) cause;
handleI2PSocketException(ise, _out, _target, _usingProxy, _wwwProxy);
@@ -562,6 +565,7 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
}
/**
+ * @param ex may be null
* @since 0.9.14 moved from subclasses
*/
protected void handleClientException(Exception ex, OutputStream out, String targetRequest,
@@ -582,13 +586,14 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
* Generate an error page based on the status code
* in our custom exception.
*
+ * @param ise may be null
* @since 0.9.14
*/
protected void handleI2PSocketException(I2PSocketException ise, OutputStream out, String targetRequest,
boolean usingWWWProxy, String wwwProxy) {
if (out == null)
return;
- int status = ise.getStatus();
+ int status = ise != null ? ise.getStatus() : -1;
String error;
//TODO MessageStatusMessage.STATUS_SEND_FAILURE_UNSUPPORTED_ENCRYPTION
if (status == MessageStatusMessage.STATUS_SEND_FAILURE_NO_LEASESET) {
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java
index 057c6acaa..d4bd1d455 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java
@@ -134,7 +134,7 @@ public class I2PTunnelRunner extends I2PAppThread implements I2PSocket.SocketErr
*/
public I2PTunnelRunner(Socket s, I2PSocket i2ps, Object slock, byte[] initialI2PData,
byte[] initialSocketData, List sockList, Runnable onTimeout) {
- this(s, i2ps, slock, initialI2PData, null, sockList, onTimeout, null, true);
+ this(s, i2ps, slock, initialI2PData, initialSocketData, sockList, onTimeout, null, true);
}
/**
@@ -150,7 +150,7 @@ public class I2PTunnelRunner extends I2PAppThread implements I2PSocket.SocketErr
*/
public I2PTunnelRunner(Socket s, I2PSocket i2ps, Object slock, byte[] initialI2PData,
byte[] initialSocketData, List sockList, FailCallback onFail) {
- this(s, i2ps, slock, initialI2PData, null, sockList, null, onFail, false);
+ this(s, i2ps, slock, initialI2PData, initialSocketData, sockList, null, onFail, false);
}
/**
diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java
index 1abc56c98..12fded0d8 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java
@@ -238,7 +238,27 @@ public class EditBean extends IndexBean {
public boolean getDelayOpen(int tunnel) {
return getBooleanProperty(tunnel, "i2cp.delayOpen");
}
-
+
+ /** @since 0.9.14 */
+ public boolean getAllowUserAgent(int tunnel) {
+ return getBooleanProperty(tunnel, I2PTunnelHTTPClient.PROP_USER_AGENT);
+ }
+
+ /** @since 0.9.14 */
+ public boolean getAllowReferer(int tunnel) {
+ return getBooleanProperty(tunnel, I2PTunnelHTTPClient.PROP_REFERER);
+ }
+
+ /** @since 0.9.14 */
+ public boolean getAllowAccept(int tunnel) {
+ return getBooleanProperty(tunnel, I2PTunnelHTTPClient.PROP_ACCEPT);
+ }
+
+ /** @since 0.9.14 */
+ public boolean getAllowInternalSSL(int tunnel) {
+ return getBooleanProperty(tunnel, I2PTunnelHTTPClient.PROP_INTERNAL_SSL);
+ }
+
/** all proxy auth @since 0.8.2 */
public boolean getProxyAuth(int tunnel) {
return getProperty(tunnel, I2PTunnelHTTPClientBase.PROP_AUTH, "false") != "false";
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 cb1b25ae7..0e5ff09f7 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java
@@ -892,6 +892,26 @@ public class IndexBean {
}
}
+ /** @since 0.9.14 */
+ public void setAllowUserAgent(String moo) {
+ _booleanOptions.add(I2PTunnelHTTPClient.PROP_USER_AGENT);
+ }
+
+ /** @since 0.9.14 */
+ public void setAllowReferer(String moo) {
+ _booleanOptions.add(I2PTunnelHTTPClient.PROP_REFERER);
+ }
+
+ /** @since 0.9.14 */
+ public void setAllowAccept(String moo) {
+ _booleanOptions.add(I2PTunnelHTTPClient.PROP_ACCEPT);
+ }
+
+ /** @since 0.9.14 */
+ public void setAllowInternalSSL(String moo) {
+ _booleanOptions.add(I2PTunnelHTTPClient.PROP_INTERNAL_SSL);
+ }
+
/** all proxy auth @since 0.8.2 */
public void setProxyAuth(String s) {
if (s != null)
@@ -1269,7 +1289,11 @@ public class IndexBean {
};
private static final String _booleanProxyOpts[] = {
I2PTunnelHTTPClientBase.PROP_OUTPROXY_AUTH,
- I2PTunnelHTTPClient.PROP_USE_OUTPROXY_PLUGIN
+ I2PTunnelHTTPClient.PROP_USE_OUTPROXY_PLUGIN,
+ I2PTunnelHTTPClient.PROP_USER_AGENT,
+ I2PTunnelHTTPClient.PROP_REFERER,
+ I2PTunnelHTTPClient.PROP_ACCEPT,
+ I2PTunnelHTTPClient.PROP_INTERNAL_SSL
};
private static final String _booleanServerOpts[] = {
"i2cp.reduceOnIdle", "i2cp.encryptLeaseSet", PROP_ENABLE_ACCESS_LIST, PROP_ENABLE_BLACKLIST,
diff --git a/apps/i2ptunnel/jsp/editClient.jsp b/apps/i2ptunnel/jsp/editClient.jsp
index 739b9f5f4..1762da29a 100644
--- a/apps/i2ptunnel/jsp/editClient.jsp
+++ b/apps/i2ptunnel/jsp/editClient.jsp
@@ -448,6 +448,40 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
<% } %>
+
+ <% if ("httpclient".equals(tunnelType)) { %>
+
+
+
+
+
+ class="tickbox" />
+
+
+
+
+
+
+ class="tickbox" />
+
+
+
+
+
+
+ class="tickbox" />
+
+
+
+
+
+
+ class="tickbox" />
+
+
+
+
+ <% } // if httpclient %>
<% if (true /* editBean.isAdvanced() */ ) { %>