From aab8b10adf095241f1df8c061a9878980ece1028 Mon Sep 17 00:00:00 2001 From: zzz <zzz@mail.i2p> Date: Thu, 20 Feb 2014 14:07:02 +0000 Subject: [PATCH] * i2ptunnel: Add inproxy block option to HTTP server --- .../i2p/i2ptunnel/I2PTunnelHTTPServer.java | 45 +++++++++++++++++-- .../src/net/i2p/i2ptunnel/web/IndexBean.java | 18 +++++++- apps/i2ptunnel/jsp/editServer.jsp | 17 ++++++- 3 files changed, 74 insertions(+), 6 deletions(-) diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java index 4e96b6a5cb..49137a1d8f 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java @@ -48,6 +48,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { public static final String OPT_POST_TOTAL_BAN_TIME = "postTotalBanTime"; public static final String OPT_POST_MAX = "maxPosts"; public static final String OPT_POST_TOTAL_MAX = "maxTotalPosts"; + public static final String OPT_REJECT_INPROXY = "rejectInproxy"; public static final int DEFAULT_POST_WINDOW = 5*60; public static final int DEFAULT_POST_BAN_TIME = 30*60; public static final int DEFAULT_POST_TOTAL_BAN_TIME = 10*60; @@ -95,6 +96,19 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { "</body></html>") .getBytes(); + private final static byte[] ERR_INPROXY = + ("HTTP/1.1 403 Denied\r\n"+ + "Content-Type: text/html; charset=iso-8859-1\r\n"+ + "Cache-control: no-cache\r\n"+ + "Connection: close\r\n"+ + "Proxy-Connection: close\r\n"+ + "\r\n"+ + "<html><head><title>403 Denied</title></head>\n"+ + "<body><h2>403 Denied</h2>\n" + + "<p>Inproxy access denied. You must run <a href=\"https://geti2p.net/\">I2P</a> to access this site.</p>\n" + + "</body></html>") + .getBytes(); + public I2PTunnelHTTPServer(InetAddress host, int port, String privData, String spoofHost, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) { super(host, port, privData, l, notifyThis, tunnel); setupI2PTunnelHTTPServer(spoofHost); @@ -198,6 +212,24 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { CLIENT_SKIPHEADERS, getTunnel().getContext()); long afterHeaders = getTunnel().getContext().clock().now(); + Properties opts = getTunnel().getClientOptions(); + if (Boolean.parseBoolean(opts.getProperty(OPT_REJECT_INPROXY)) && + (headers.containsKey("X-Forwarded-For") || + headers.containsKey("X-Forwarded-Server") || + headers.containsKey("X-Forwarded-Host"))) { + if (_log.shouldLog(Log.WARN)) + _log.warn("Refusing inproxy access: " + peerHash.toBase64()); + try { + // Send a 403, so the user doesn't get an HTTP Proxy error message + // and blame his router or the network. + socket.getOutputStream().write(ERR_INPROXY); + } catch (IOException ioe) {} + try { + socket.close(); + } catch (IOException ioe) {} + return; + } + if (_postThrottler != null && command.length() >= 5 && command.substring(0, 5).toUpperCase(Locale.US).equals("POST ")) { @@ -221,7 +253,6 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { addEntry(headers, DEST64_HEADER, socket.getPeerDestination().toBase64()); // Port-specific spoofhost - Properties opts = getTunnel().getClientOptions(); String spoofHost; int ourPort = socket.getLocalPort(); if (ourPort != 80 && ourPort > 0 && ourPort <= 65535 && opts != null) { @@ -668,15 +699,21 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { else value = ""; - if ("accept-encoding".equals(name.toLowerCase(Locale.US))) + String lcName = name.toLowerCase(Locale.US); + if ("accept-encoding".equals(lcName)) name = "Accept-encoding"; - else if ("x-accept-encoding".equals(name.toLowerCase(Locale.US))) + else if ("x-accept-encoding".equals(lcName)) name = "X-Accept-encoding"; + else if ("x-forwarded-for".equals(lcName)) + name = "X-Forwarded-For"; + else if ("x-forwarded-server".equals(lcName)) + name = "X-Forwarded-Server"; + else if ("x-forwarded-host".equals(lcName)) + name = "X-Forwarded-Host"; // For incoming, we remove certain headers to prevent spoofing. // For outgoing, we remove certain headers to improve anonymity. boolean skip = false; - String lcName = name.toLowerCase(Locale.US); for (String skipHeader: skipHeaders) { if (skipHeader.toLowerCase(Locale.US).equals(lcName)) { skip = true; 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 9b9ad31ad4..d69080592c 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java @@ -808,6 +808,21 @@ public class IndexBean { return false; } + /** @since 0.9.12 */ + public void setRejectInproxy(String moo) { + _booleanOptions.add(I2PTunnelHTTPServer.OPT_REJECT_INPROXY); + } + + /** @since 0.9.12 */ + public boolean isRejectInproxy(int tunnel) { + TunnelController tun = getController(tunnel); + if (tun != null) { + Properties opts = tun.getClientOptionProps(); + return Boolean.parseBoolean(opts.getProperty(I2PTunnelHTTPServer.OPT_REJECT_INPROXY)); + } + return false; + } + protected static final String PROP_ENABLE_ACCESS_LIST = "i2cp.enableAccessList"; protected static final String PROP_ENABLE_BLACKLIST = "i2cp.enableBlackList"; @@ -1243,7 +1258,8 @@ public class IndexBean { }; private static final String _booleanServerOpts[] = { "i2cp.reduceOnIdle", "i2cp.encryptLeaseSet", PROP_ENABLE_ACCESS_LIST, PROP_ENABLE_BLACKLIST, - I2PTunnelServer.PROP_USE_SSL + I2PTunnelServer.PROP_USE_SSL, + I2PTunnelHTTPServer.OPT_REJECT_INPROXY }; private static final String _otherClientOpts[] = { "i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.closeIdleTime", diff --git a/apps/i2ptunnel/jsp/editServer.jsp b/apps/i2ptunnel/jsp/editServer.jsp index 978afd63ac..1a109b22d9 100644 --- a/apps/i2ptunnel/jsp/editServer.jsp +++ b/apps/i2ptunnel/jsp/editServer.jsp @@ -381,7 +381,22 @@ input.default { width: 1px; height: 1px; visibility: hidden; } <textarea rows="2" style="height: 8em;" cols="60" id="hostField" name="accessList" title="Access List" wrap="off" spellcheck="false"><%=editBean.getAccessList(curTunnel)%></textarea> </div> - <div class="subdivider"> + <% if (("httpserver".equals(tunnelType)) || ("httpbidirserver".equals(tunnelType))) { + %><div class="rowItem"> + <div id="optionsField" class="rowItem"> + <label> + <%=intl._("Block Access via Inproxies")%>: + </label> + </div> + <div id="portField" class="rowItem"> + <label for="access" accesskey="d"> + <%=intl._("Enable")%>: + </label> + <input value="1" type="checkbox" id="startOnLoad" name="rejectInproxy" title="Deny inproxy access when enabled"<%=(editBean.isRejectInproxy(curTunnel) ? " checked=\"checked\"" : "")%> class="tickbox" /> + </div> + </div> + <% } // httpserver + %><div class="subdivider"> <hr /> </div> -- GitLab