/*
* This file is part of the OWASP Proxy, a free intercepting proxy library.
* Copyright (C) 2008-2010 Rogan Dawes <rogan@dawes.za.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to:
* The Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
package org.owasp.proxy;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.ProxySelector;
import java.net.SocketAddress;
import java.net.URI;
import java.security.GeneralSecurityException;
import java.security.Security;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Logger;
import javax.security.auth.x500.X500Principal;
import javax.sql.DataSource;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.owasp.proxy.daemon.LoopAvoidingTargetedConnectionHandler;
import org.owasp.proxy.daemon.Proxy;
import org.owasp.proxy.daemon.ServerGroup;
import org.owasp.proxy.daemon.TargetedConnectionHandler;
import org.owasp.proxy.http.MutableRequestHeader;
import org.owasp.proxy.http.MutableResponseHeader;
import org.owasp.proxy.http.RequestHeader;
import org.owasp.proxy.http.client.HttpClient;
import org.owasp.proxy.http.dao.JdbcMessageDAO;
import org.owasp.proxy.http.server.BufferedMessageInterceptor;
import org.owasp.proxy.http.server.BufferingHttpRequestHandler;
import org.owasp.proxy.http.server.ConversationServiceHttpRequestHandler;
import org.owasp.proxy.http.server.DefaultHttpRequestHandler;
import org.owasp.proxy.http.server.HttpProxyConnectionHandler;
import org.owasp.proxy.http.server.HttpRequestHandler;
import org.owasp.proxy.http.server.LoggingHttpRequestHandler;
import org.owasp.proxy.http.server.RecordingHttpRequestHandler;
import org.owasp.proxy.socks.SocksConnectionHandler;
import org.owasp.proxy.ssl.AutoGeneratingContextSelector;
import org.owasp.proxy.ssl.SSLConnectionHandler;
import org.owasp.proxy.ssl.SSLContextSelector;
import org.owasp.proxy.util.TextFormatter;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
public class Main {
private static Logger logger = Logger.getLogger("org.owasp.proxy");
/**
* Prints the usage of the program.
*/
private static void usage() {
System.err
.println("Usage: java -jar proxy.jar port [\"proxy instruction\"] [ <JDBC Driver> <JDBC URL> <username> <password> ]");
System.err.println("Where \'proxy instruction\' might look like:");
System.err
.println("'DIRECT' or 'PROXY server:port' or 'SOCKS server:port'");
System.err.println("and the JDBC connection details might look like:");
System.err
.println("org.h2.Driver jdbc:h2:mem:webscarab3;DB_CLOSE_DELAY=-1 sa \"\"");
}
/**
* Returns a proxy selector
*
* @param proxy
* @return
*/
private static ProxySelector getProxySelector(String proxy) {
final java.net.Proxy upstream;
if ("DIRECT".equals(proxy)) {
upstream = java.net.Proxy.NO_PROXY;
} else {
java.net.Proxy.Type type = null;
if (proxy.startsWith("PROXY ")) {
type = java.net.Proxy.Type.HTTP;
} else if (proxy.startsWith("SOCKS ")) {
type = java.net.Proxy.Type.SOCKS;
} else
throw new IllegalArgumentException("Unknown Proxy type: "
+ proxy);
proxy = proxy.substring(6); // "SOCKS " or "PROXY "
int c = proxy.indexOf(':');
if (c == -1)
throw new IllegalArgumentException("Illegal proxy address: "
+ proxy);
InetSocketAddress addr = new InetSocketAddress(proxy
.substring(0, c), Integer.parseInt(proxy.substring(c + 1)));
upstream = new java.net.Proxy(type, addr);
}
ProxySelector ps = new ProxySelector() {
@Override
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
logger.info("Proxy connection to " + uri + " via " + sa
+ " failed! " + ioe.getLocalizedMessage());
}
@Override
public List<java.net.Proxy> select(URI uri) {
return Arrays.asList(upstream);
}
};
return ps;
}
private static DataSource createDataSource(String driver, String url,
String username, String password) throws SQLException {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
private static SSLContextSelector getSSLContextSelector()
throws GeneralSecurityException, IOException {
File ks = new File("auto_generated_ca.p12");
String type = "PKCS12";
char[] password = "password".toCharArray();
String alias = "CA";
if (ks.exists()) {
try {
return new AutoGeneratingContextSelector(ks, type, password,
password, alias);
} catch (GeneralSecurityException e) {
System.err.println("Error loading CA keys from keystore: "
+ e.getLocalizedMessage());
} catch (IOException e) {
System.err.println("Error loading CA keys from keystore: "
+ e.getLocalizedMessage());
}
}
System.err.println("Generating a new CA");
X500Principal ca = new X500Principal("cn=OWASP Custom CA for Tank,ou=Tank Custom CA,o=Tank,l=Tank,st=Tank,c=Tank");
AutoGeneratingContextSelector ssl = new AutoGeneratingContextSelector(
ca);
try {
ssl.save(ks, type, password, password, alias);
} catch (GeneralSecurityException e) {
System.err.println("Error saving CA keys to keystore: "
+ e.getLocalizedMessage());
} catch (IOException e) {
System.err.println("Error saving CA keys to keystore: "
+ e.getLocalizedMessage());
}
FileWriter pem = null;
try {
pem = new FileWriter("auto_generated_ca.pem");
pem.write(ssl.getCACert());
} catch (IOException e) {
System.err.println("Error writing CA cert : "
+ e.getLocalizedMessage());
} finally {
if (pem != null)
pem.close();
}
return ssl;
}
public static void main(String[] args) throws Exception {
Security.addProvider(new BouncyCastleProvider()); // add
logger.setUseParentHandlers(false);
Handler ch = new ConsoleHandler();
ch.setFormatter(new TextFormatter());
logger.addHandler(ch);
if (args == null
|| (args.length != 1 && args.length != 2 && args.length != 5 && args.length != 6)) {
usage();
return;
}
InetSocketAddress listen;
try {
int port = Integer.parseInt(args[0]);
listen = new InetSocketAddress("localhost", port);
} catch (NumberFormatException nfe) {
usage();
return;
}
String proxy = "DIRECT";
if (args.length == 2 || args.length == 6) {
proxy = args[1];
}
DataSource dataSource = null;
if (args.length == 5) {
dataSource = createDataSource(args[1], args[2], args[3], args[4]);
} else if (args.length == 6) {
dataSource = createDataSource(args[2], args[3], args[4], args[5]);
}
final ProxySelector ps = getProxySelector(proxy);
DefaultHttpRequestHandler drh = new DefaultHttpRequestHandler() {
@Override
protected HttpClient createClient() {
HttpClient client = super.createClient();
client.setProxySelector(ps);
client.setSoTimeout(90000);
return client;
}
};
ServerGroup sg = new ServerGroup();
sg.addServer(listen);
drh.setServerGroup(sg);
HttpRequestHandler rh = drh;
rh = new LoggingHttpRequestHandler(rh);
if (dataSource != null) {
JdbcMessageDAO dao = new JdbcMessageDAO();
dao.setDataSource(dataSource);
dao.createTables();
rh = new RecordingHttpRequestHandler(dao, rh, 1024 * 1024);
rh = new ConversationServiceHttpRequestHandler("127.0.0.2", dao, rh);
}
BufferedMessageInterceptor bmi = new BufferedMessageInterceptor() {
@Override
public Action directResponse(RequestHeader request,
MutableResponseHeader response) {
// System.err.println(new String(request.getHeader())
// + "+++++++++++\n" + new String(response.getHeader())
// + "===========");
return Action.BUFFER;
}
@Override
public Action directRequest(MutableRequestHeader request) {
// System.err.println(new String(request.getHeader())
// + "===========");
return Action.BUFFER;
}
};
rh = new BufferingHttpRequestHandler(rh, bmi, 1024 * 1024);
HttpProxyConnectionHandler hpch = new HttpProxyConnectionHandler(rh);
SSLContextSelector cp = getSSLContextSelector();
TargetedConnectionHandler tch = new SSLConnectionHandler(cp, true, hpch);
tch = new LoopAvoidingTargetedConnectionHandler(sg, tch);
hpch.setConnectHandler(tch);
TargetedConnectionHandler socks = new SocksConnectionHandler(tch, true);
Proxy p = new Proxy(listen, socks, null);
p.setSocketTimeout(90000);
p.start();
System.out.println("Listener started on " + listen);
System.out.println("Press Enter to terminate");
new BufferedReader(new InputStreamReader(System.in)).readLine();
p.stop();
System.out.println("Terminated");
System.exit(0);
}
}