diff --git a/dist/proxy.jar b/dist/proxy.jar old mode 100755 new mode 100644 index 8ac8f86..5966dd0 Binary files a/dist/proxy.jar and b/dist/proxy.jar differ diff --git a/src/com/meituan/tools/proxy/Accept2Thread.java b/src/com/meituan/tools/proxy/Accept2Thread.java new file mode 100644 index 0000000..04bbc98 --- /dev/null +++ b/src/com/meituan/tools/proxy/Accept2Thread.java @@ -0,0 +1,20 @@ +package com.meituan.tools.proxy; + +import java.net.ServerSocket; + +/** + * Created by 张小美 on 2021/12/11. + * Copyright 2002-2016 + */ +class Accept2Thread extends AcceptThread { + + public Accept2Thread(JavaHttpProxy parent) { + super(parent); + } + + @Override + protected ServerSocket getServer() { + return parent.sslServerSocket; + } + +} diff --git a/src/com/meituan/tools/proxy/AcceptThread.java b/src/com/meituan/tools/proxy/AcceptThread.java index 5235e10..1b718dd 100644 --- a/src/com/meituan/tools/proxy/AcceptThread.java +++ b/src/com/meituan/tools/proxy/AcceptThread.java @@ -15,12 +15,16 @@ public AcceptThread(JavaHttpProxy parent) { this.parent=parent; } + protected ServerSocket getServer() { + return parent.serverSocket; + } + @Override public Object call() throws Exception { - ServerSocket serverSocket=parent.serverSocket; + ServerSocket serverSocket=getServer(); while(serverSocket.isBound()) { Socket socket=serverSocket.accept(); - logger.debug("connection from %s",socket.getRemoteSocketAddress()); + logger.debug("connection from %s (%d)",socket.getRemoteSocketAddress(),socket.getLocalPort()); Executors.getInstance().submitCommon(new ProcessThread(parent,socket)); } return this; diff --git a/src/com/meituan/tools/proxy/JavaHttpProxy.java b/src/com/meituan/tools/proxy/JavaHttpProxy.java index ebfbbd3..02b4ca6 100644 --- a/src/com/meituan/tools/proxy/JavaHttpProxy.java +++ b/src/com/meituan/tools/proxy/JavaHttpProxy.java @@ -5,16 +5,17 @@ import com.meituan.tools.proxy.interceptors.GZIPInterceptor; import com.meituan.tools.proxy.interceptors.LogRequestInterceptor; -import java.io.Closeable; -import java.io.File; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.ServerSocket; -import java.net.SocketAddress; +import javax.net.ssl.*; +import java.io.*; +import java.net.*; +import java.security.KeyStore; +import java.security.cert.*; public class JavaHttpProxy implements Closeable { - ServerSocket serverSocket; + ServerSocket serverSocket; + SSLServerSocket sslServerSocket; + boolean enableHttps; public JavaHttpProxy(String host, int port,RequestInterceptor interceptor) throws IOException { this.interceptor=interceptor; @@ -25,17 +26,94 @@ public JavaHttpProxy(String host, int port,RequestInterceptor interceptor) throw SocketAddress address=new InetSocketAddress(host,port); serverSocket.bind(address); } + this.enableHttps=Boolean.parseBoolean(System.getProperty("JavaHttpsProxy")); + } + + private SSLContext createSSLContext(){ + try{ + KeyStore keyStore = KeyStore.getInstance("JKS"); + String name=this.getClass().getName(); + name=name.substring(0,name.lastIndexOf('.')).replace('.','/')+"/key/test.keystore"; + try(InputStream input=this.getClass().getClassLoader().getResourceAsStream(name)) { + keyStore.load(input, "123456".toCharArray()); + } + + // Create key manager + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509"); + keyManagerFactory.init(keyStore, "123456".toCharArray()); + KeyManager[] km = keyManagerFactory.getKeyManagers(); + + // Create trust manager + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509"); + trustManagerFactory.init(keyStore); + TrustManager[] tm = trustManagerFactory.getTrustManagers(); + + X509TrustManager tm1=new X509TrustManager() { + @Override + public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + + } + + @Override + public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { + + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; + } + }; + tm=new TrustManager[]{tm1}; + + // Initialize SSLContext + SSLContext sslContext = SSLContext.getInstance("TLSv1"); + sslContext.init(km, tm, null); + + return sslContext; + } catch (Exception ex){ + ex.printStackTrace(); + throw new RuntimeException(ex); + } + } + + protected void initHttps(String host, int port) throws Exception { + if(this.enableHttps) { + SSLContext sslContext = this.createSSLContext(); + + SSLServerSocketFactory sslServerSocketFactory = sslContext.getServerSocketFactory(); + SSLServerSocket sslServerSocket; + if (host == null || host.length() < 1 || "null".equalsIgnoreCase(host)) { + sslServerSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket(port + 1); + } else { + sslServerSocket = (SSLServerSocket) sslServerSocketFactory.createServerSocket(port + 1, 0, Inet4Address.getByName(host)); + } + sslServerSocket.setEnabledCipherSuites(sslServerSocketFactory.getSupportedCipherSuites()); + this.sslServerSocket = sslServerSocket; + } } public void start() { Executors.getInstance().submitCommon(new AcceptThread(this)); + if(this.enableHttps && sslServerSocket!=null) { + Executors.getInstance().submitCommon(new Accept2Thread(this)); + } } @Override public void close() throws IOException { - serverSocket.close(); - if(interceptor!=null) { - interceptor.close(); + try { + try { + serverSocket.close(); + } finally { + if (sslServerSocket != null) { + sslServerSocket.close(); + } + } + } finally { + if(interceptor!=null) { + interceptor.close(); + } } } @@ -58,7 +136,10 @@ public static void main(String[] args) throws Exception { return; } RequestInterceptor interceptor=new ComboInterceptor(new GZIPInterceptor(),new LogRequestInterceptor(new File(args[2]))); - try (JavaHttpProxy proxy=new JavaHttpProxy(args[0],Integer.parseInt(args[1]),interceptor)) { + final String host = args[0]; + final int port = Integer.parseInt(args[1]); + try (JavaHttpProxy proxy=new JavaHttpProxy(host, port,interceptor)) { + proxy.initHttps(host,port); proxy.start(); if(args.length>3) { while(args[3]!=null) { diff --git a/src/com/meituan/tools/proxy/ProxyThread.java b/src/com/meituan/tools/proxy/ProxyThread.java index caf88c0..a096611 100644 --- a/src/com/meituan/tools/proxy/ProxyThread.java +++ b/src/com/meituan/tools/proxy/ProxyThread.java @@ -2,6 +2,7 @@ import com.meituan.service.GarUtils; +import javax.net.ssl.*; import java.io.*; import java.net.Socket; import java.util.*; @@ -201,7 +202,14 @@ protected void sendRequest() throws IOException { try { String encoding = HeaderEncoding; close(); - socket = new Socket(uriToks[1].toString(), ((Number) uriToks[2]).intValue()); + if(this.parent.socket instanceof SSLSocket) { + SSLSocketFactory socketFactory = (SSLSocketFactory) + SSLSocketFactory.getDefault(); + socket=socketFactory.createSocket(uriToks[1].toString(), ((Number) uriToks[2]).intValue()); + ((SSLSocket)socket).setEnabledCipherSuites(socketFactory.getSupportedCipherSuites()); + } else { + socket = new Socket(uriToks[1].toString(), ((Number) uriToks[2]).intValue()); + } DataOutputStream output = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream())); sendRequestHeaders(output, encoding); diff --git a/src/com/meituan/tools/proxy/key/test.keystore b/src/com/meituan/tools/proxy/key/test.keystore new file mode 100644 index 0000000..0ce24cd Binary files /dev/null and b/src/com/meituan/tools/proxy/key/test.keystore differ