forked from I2P_Developers/i2p.i2p

to avoid conflict in applications linking to apache jars As requested by 'mesh' project Remove with-libhttpclient-java build option No known external uses other than obsolete i2pcontrol plugin
130 lines
3.9 KiB
Java
130 lines
3.9 KiB
Java
package net.i2p.i2pcontrol;
|
|
|
|
import java.io.IOException;
|
|
import java.util.HashSet;
|
|
import java.util.Set;
|
|
|
|
import javax.servlet.ServletException;
|
|
import javax.servlet.http.HttpServletRequest;
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
|
import net.i2p.I2PAppContext;
|
|
import net.i2p.data.DataHelper;
|
|
import net.i2p.util.Log;
|
|
|
|
import net.i2p.apache.http.conn.util.InetAddressUtils;
|
|
|
|
import org.eclipse.jetty.server.Request;
|
|
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
|
|
|
/**
|
|
* Block certain Host headers to prevent DNS rebinding attacks.
|
|
*
|
|
* This Handler wraps the ContextHandlerCollection, which handles
|
|
* all the webapps (not just routerconsole).
|
|
* Therefore, this protects all the webapps.
|
|
*
|
|
* This class is NOT used for the webapp or the bare ServerSocket implementation.
|
|
*
|
|
* @since 0.12 copied from routerconsole
|
|
*/
|
|
public class HostCheckHandler extends HandlerWrapper
|
|
{
|
|
private final I2PAppContext _context;
|
|
private final Set<String> _listenHosts;
|
|
|
|
/**
|
|
* MUST call setListenHosts() afterwards.
|
|
*/
|
|
public HostCheckHandler(I2PAppContext ctx) {
|
|
super();
|
|
_context = ctx;
|
|
_listenHosts = new HashSet<String>(8);
|
|
}
|
|
|
|
/**
|
|
* Set the legal hosts.
|
|
* Not synched. Call this BEFORE starting.
|
|
* If empty, all are allowed.
|
|
*
|
|
* @param hosts contains hostnames or IPs. But we allow all IPs anyway.
|
|
*/
|
|
public void setListenHosts(Set<String> hosts) {
|
|
_listenHosts.clear();
|
|
_listenHosts.addAll(hosts);
|
|
}
|
|
|
|
/**
|
|
* Block by Host header, pass everything else to the delegate.
|
|
*/
|
|
public void handle(String pathInContext,
|
|
Request baseRequest,
|
|
HttpServletRequest httpRequest,
|
|
HttpServletResponse httpResponse)
|
|
throws IOException, ServletException
|
|
{
|
|
|
|
String host = httpRequest.getHeader("Host");
|
|
if (!allowHost(host)) {
|
|
Log log = _context.logManager().getLog(HostCheckHandler.class);
|
|
host = DataHelper.stripHTML(getHost(host));
|
|
String s = "Console request denied.\n" +
|
|
" To allow access using the hostname \"" + host + "\", add the line \"" +
|
|
I2PControlController.PROP_ALLOWED_HOSTS + '=' + host +
|
|
"\" to I2PControl.conf and restart.";
|
|
log.logAlways(Log.WARN, s);
|
|
httpResponse.sendError(403, s);
|
|
return;
|
|
}
|
|
|
|
super.handle(pathInContext, baseRequest, httpRequest, httpResponse);
|
|
}
|
|
|
|
/**
|
|
* Should we allow a request with this Host header?
|
|
*
|
|
* ref: https://en.wikipedia.org/wiki/DNS_rebinding
|
|
*
|
|
* @param host the HTTP Host header, null ok
|
|
* @return true if OK
|
|
*/
|
|
private boolean allowHost(String host) {
|
|
if (host == null)
|
|
return true;
|
|
// common cases
|
|
if (host.equals("127.0.0.1:7650") ||
|
|
host.equals("localhost:7650"))
|
|
return true;
|
|
// all allowed?
|
|
if (_listenHosts.isEmpty())
|
|
return true;
|
|
host = getHost(host);
|
|
if (_listenHosts.contains(host))
|
|
return true;
|
|
// allow all IP addresses
|
|
if (InetAddressUtils.isIPv4Address(host) || InetAddressUtils.isIPv6Address(host))
|
|
return true;
|
|
//System.out.println(host + " not found in " + s);
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Strip [] and port from a host header
|
|
*
|
|
* @param host the HTTP Host header non-null
|
|
*/
|
|
private static String getHost(String host) {
|
|
if (host.startsWith("[")) {
|
|
host = host.substring(1);
|
|
int brack = host.indexOf(']');
|
|
if (brack >= 0)
|
|
host = host.substring(0, brack);
|
|
} else {
|
|
int colon = host.indexOf(':');
|
|
if (colon >= 0)
|
|
host = host.substring(0, colon);
|
|
}
|
|
return host;
|
|
}
|
|
}
|