i'm trying to write a proxy for simple services like http and smtp using java. so far i've got this:
class Main {
public static final int listenPort = 465, // port to listen on
remotePort = 465; // port to connect to
public static final String remoteH = "";// my mail server hostname here
public static void main(String[] args) {
ExecutorService tm = Executors.newCachedThreadPool();
try {
ServerSocket ss = new ServerSocket(listenPort);
while (true) {
try {
Socket client = ss.accept();
tm.submit(new ProxyWorker(client));
} catch (Exception e) {
System.out.println("error " + e);
}
}
} catch (Exception e) {
System.out.println("error " + e);
}
}
}
class ProxyWorker implements Runnable {
Socket client, server;
OutputStream serverOut = null, clientOut = null;
InputStream serverIn = null, clientIn = null;
private static SSLSocketFactory sslSocketFactory;
/**
* Returns a SSL Factory instance that accepts all server certificates.
* <pre>SSLSocket sock =
* (SSLSocket) getSocketFactory.createSocket ( host, 443 ); </pre>
* @return An SSL-specific socket factory.
**/
public static final SSLSocketFactory getSocketFactory() {
if (sslSocketFactory == null) {
try {
TrustManager[] tm = new TrustManager[]{new NaiveTrustManager()};
SSLContext context = SSLContext.getInstance("SSL");
context.init(new KeyManager[0], tm, new SecureRandom());
sslSocketFactory = (SSLSocketFactory) context.getSocketFactory();
} catch (KeyManagementException e) {
System.err.println("No SSL algorithm support: " + e.getMessage());
} catch (NoSuchAlgorithmException e) {
System.err.println("Exception when setting up the Naive key management.");
}
}
return sslSocketFactory;
}
ProxyWorker(Socket c) {
client = c;
try {
try {
server = (SSLSocket) getSocketFactory().createSocket(Main.remoteH, Main.remotePort);
((SSLSocket)server).startHandshake();
serverOut = server.getOutputStream();
serverIn = server.getInputStream();
} catch (Exception e) {
System.err.println("SSL FAIL!\n" + e.toString());
server = new Socket(Main.remoteH, Main.remotePort);
serverOut = server.getOutputStream();
serverIn = server.getInputStream();
}
clientOut = client.getOutputStream();
clientIn = client.getInputStream();
} catch (Exception e) {
System.out.println("error\n" + e.toString());
System.exit(0);
}
}
public void run() {
System.out.println("listening runner activated");
try {
byte[] b = new byte[0];
BufferedOutputStream bos = new BufferedOutputStream(System.out);
while (true) {
int clientReady = clientIn.available();
while (clientReady > 0) {
b = new byte[clientReady];
clientIn.read(b, 0, clientReady);
serverOut.write(b);
bos.write(b);
bos.flush();
clientReady = clientIn.available();
}
Thread.sleep(100);
int serverReady = serverIn.available();
while (serverReady > 0) {
b = new byte[serverReady];
serverIn.read(b, 0, serverReady);
clientOut.write(b);
bos.write(b);
bos.flush();
serverReady = serverIn.available();
}
if(server.isClosed()||client.isClosed()){
break;
}
}
} catch (NullPointerException e) {
System.err.println("NPE:\n"+e.getMessage());
System.err.println(e.toString());
e.printStackTrace();
} catch (Exception e) {
System.out.println(e);
} finally {
try {
server.close();
client.close();
} catch (IOException ex) {
System.out.println("could not close sockets");
}
}
System.out.println("Thread Exiting Now");
}
}
n.b. the naive trust manager accepts all certs cos my mailserver is using a self signed cert and this is only for personal/my own educational use so i'm not worrying about security at all.
it seems to be working ~ok for non ssl connections - i have tested esmtp which creates a connection and exchanges greetings and stuff, but my server doesn't support authentication over non ssl connections, so i can't test sending of any messages.
i've also tested for non ssl http connections - which it can handle ok - though i think the threads don't like handling images very well as only some immages get through.
i suspect i've done some not too wonderful code in there, but at the moment i'm trying to get it to work on ssl so i can understand it.
when using it in ssl mode i have worked out that the ProxyWorker thread gets to the while true loop, but then just keeps looping. so for esmtp while it waits for the greeting i get no output at all, a开发者_如何学Cnd when using http i see the get request from firefox, but again nothing from the server.
Any pointers/things i do wrong/recommended reading would be appreciated
If you're writing a fully transparent proxy you don't need to consider SSL at all. Just copy bytes.
If you're writing an application proxy such as HTTP you have to deal with the setup command. For example, an HTTP proxy will receive an HTTP CONNECT command, which tells it what to connect to, and must reply with an appropriate HTTP response, in plaintext, before it starts shovelling bytes in both directions.
In either case there is no need to implement SSL in the proxy at all.
精彩评论