package org.littleshoot.proxy.mitm;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpObject;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import java.io.File;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import org.apache.log4j.xml.DOMConfigurator;
import org.littleshoot.proxy.DefaultHostResolver;
import org.littleshoot.proxy.HostResolver;
import org.littleshoot.proxy.HttpFilters;
import org.littleshoot.proxy.HttpFiltersAdapter;
import org.littleshoot.proxy.HttpFiltersSource;
import org.littleshoot.proxy.HttpFiltersSourceAdapter;
import org.littleshoot.proxy.HttpProxyServerBootstrap;
import org.littleshoot.proxy.MitmManager;
import org.littleshoot.proxy.impl.DefaultHttpProxyServer;
import org.littleshoot.proxy.impl.ProxyUtils;
import de.ganskef.test.IProxy;
import de.ganskef.test.Server;
public class LittleProxyMitmProxy extends de.ganskef.test.Proxy implements
IProxy {
private boolean connectionLimited;
private final MitmManager mitmManager;
public LittleProxyMitmProxy(int proxyPort) throws RootCertificateException {
this(proxyPort, new CertificateSniffingMitmManager());
}
public LittleProxyMitmProxy(int proxyPort, MitmManager mitmManager) {
super(proxyPort);
this.mitmManager = mitmManager;
}
@Override
public LittleProxyMitmProxy start() {
return (LittleProxyMitmProxy) super.start();
}
protected HttpProxyServerBootstrap bootstrap() {
HttpFiltersSource filtersSource = new HttpFiltersSourceAdapter() {
@Override
public HttpFilters filterRequest(HttpRequest originalRequest,
ChannelHandlerContext ctx) {
// The connect request must bypass the filter! Otherwise the
// handshake will fail.
//
if (ProxyUtils.isCONNECT(originalRequest)) {
return new HttpFiltersAdapter(originalRequest);
}
return new HttpFiltersAdapter(originalRequest) {
/**
* This filter delivers special responses if connection
* limited
*/
@Override
public HttpResponse clientToProxyRequest(
HttpObject httpObject) {
if (isConnectionLimited()) {
return createOfflineResponse();
} else {
return super.clientToProxyRequest(httpObject);
}
}
/**
* This proxy expect aggregated chunks only, with https too
*/
@Override
public HttpObject proxyToClientResponse(
HttpObject httpObject) {
if (httpObject instanceof FullHttpResponse) {
return super.proxyToClientResponse(httpObject);
} else {
throw new IllegalStateException(
"Response is not been aggregated");
}
}
};
}
/** This proxy must aggregate chunks */
@Override
public int getMaximumResponseBufferSizeInBytes() {
return 10 * 1024 * 1024;
}
};
HostResolver serverResolver = new DefaultHostResolver() {
/** This proxy uses unresolved adresses while offline */
@Override
public InetSocketAddress resolve(String host, int port)
throws UnknownHostException {
if (isConnectionLimited()) {
return new InetSocketAddress(host, port);
}
return super.resolve(host, port);
}
};
return DefaultHttpProxyServer
.bootstrap()
.withFiltersSource(filtersSource)
.withPort(getProxyPort())
.withServerResolver(serverResolver)
.withManInTheMiddle(mitmManager);
}
public boolean isConnectionLimited() {
return connectionLimited;
}
public void setConnectionLimited() {
connectionLimited = true;
}
public void setConnectionUnlimited() {
connectionLimited = false;
}
private HttpResponse createOfflineResponse() {
ByteBuf buffer = Unpooled.wrappedBuffer("Offline response".getBytes());
HttpResponse response = new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buffer);
HttpHeaders.setContentLength(response, buffer.readableBytes());
HttpHeaders.setHeader(response, HttpHeaders.Names.CONTENT_TYPE,
"text/html");
return response;
}
public static void main(final String... args) throws Exception {
File log4jConfigurationFile = new File("src/test/resources/log4j.xml");
if (log4jConfigurationFile.exists()) {
DOMConfigurator.configureAndWatch(
log4jConfigurationFile.getAbsolutePath(), 15);
}
new LittleProxyMitmProxy(9090).start();
Server.waitUntilInterupted();
}
}