简体   繁体   English

在Java中编写TCP代理(用于http,smtp或类似协议)可用于非SSL,但不适用于SSL

[英]Writing a tcp proxy (for http, smtp or similar) in java works non-ssl but doesn't work ssl

i'm trying to write a proxy for simple services like http and smtp using java. 我正在尝试使用Java为简单服务(如http和smtp)编写代理。 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");
    }
}

nb 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. nb天真的信任管理器接受我的邮件服务器使用的自签名证书的所有证书,这仅用于个人/我自己的教育用途,因此我完全不必担心安全性。

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. 对于非ssl连接,它似乎可以正常工作-我已经测试了esmtp,它创建了一个连接并交换问候和其他内容,但是我的服务器不支持对非ssl连接的身份验证,所以我无法测试任何消息的发送。

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. 我还测试了非ssl http连接-它可以处理正常-尽管我认为线程不喜欢很好地处理图像,因为只有一些想象可以通过。

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. 我怀疑我在其中做了一些不太出色的代码,但此刻我正试图使其在ssl上工作,以便我能理解。

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. 当在ssl模式下使用它时,我已经知道ProxyWorker线程进入了while真正的循环,但随后一直循环。 so for esmtp while it waits for the greeting i get no output at all, and when using http i see the get request from firefox, but again nothing from the server. 因此,对于esmtp,它在等待问候语时根本没有任何输出,而使用http时,我看到了来自firefox的get请求,但仍然没有来自服务器的任何请求。

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. 如果要编写完全透明的代理,则完全不需要考虑SSL。 Just copy bytes. 只需复制字节。

If you're writing an application proxy such as HTTP you have to deal with the setup command. 如果要编写HTTP之类的应用程序代理,则必须处理setup命令。 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. 例如,一个HTTP代理将收到一个HTTP CONNECT命令,该命令告诉它要连接的内容,并且在开始双向铲除字节之前,必须以明文形式以适当的HTTP响应进行应答。

In either case there is no need to implement SSL in the proxy at all. 无论哪种情况,都完全不需要在代理中实现SSL。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM