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(); } }