2015-10-15 37 views
1

我正在編寫自己的代理服務器。我有最簡單的實現。第一代碼段是設置服務器監聽端口8080(其上的請求將通過WiFi設置重定向):適用於Android的SSL代理服務器SSL

public class MyProxyServer { 

private ServerSocket proxyServer; 

public void init() throws Exception { 
    proxyServer = new ServerSocket(8080); 

    new Thread(new Runnable() { 
     @Override 
     public void run() { 
      while (true) { 
       try { 
        Socket proxySocket = proxyServer.accept(); 
        ProxyConnectionHandler proxyConnectionHandler = new ProxyConnectionHandler(proxySocket); 
        new Thread(proxyConnectionHandler).start(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 

      } 
     } 
    }).start(); 
} 

}

二是通過插座傳遞請求和響應數據:

public class ProxyConnectionHandler implements Runnable { 

private static final int BUFFER_SIZE = 8192; 

Socket mProxySocket; 
Socket mOutsideSocket; 

public ProxyConnectionHandler(Socket proxySocket) { 
    mProxySocket = proxySocket; 
} 

@Override 
public void run() { 
    try { 
     long startTimestamp = System.currentTimeMillis(); 

     InputStream proxyInputStream = mProxySocket.getInputStream(); 


     byte[] bytes = new byte[BUFFER_SIZE]; 
     int bytesRead = proxyInputStream.read(bytes, 0, BUFFER_SIZE); 
     String request = new String(bytes); 

     Log.d("ACHTUNG", "Request: " + request); 

     String host = extractHost(request); 

     int port = request.startsWith("CONNECT") ? 443 : 80; 
     mOutsideSocket = new Socket(host, port); 
     OutputStream outsideOutputStream = mOutsideSocket.getOutputStream(); 
     outsideOutputStream.write(bytes, 0, bytesRead); 
     outsideOutputStream.flush(); 

     InputStream outsideSocketInputStream = mOutsideSocket.getInputStream(); 
     OutputStream proxyOutputStream = mProxySocket.getOutputStream(); 
     byte[] responseArray = new byte[BUFFER_SIZE]; 

     do 
     { 
      bytesRead = outsideSocketInputStream.read(responseArray, 0, BUFFER_SIZE); 
      if (bytesRead > 0) 
      { 
       proxyOutputStream.write(responseArray, 0, bytesRead); 
       String response = new String(bytes, 0, bytesRead); 
       Log.d("ACHTUNG", "Response: " + response); 
      } 
     } while (bytesRead > 0); 

     proxyOutputStream.flush(); 
     mOutsideSocket.close(); 
     mProxySocket.close(); 

     Log.d("ACHTUNG", "Cycle: " + (System.currentTimeMillis() - startTimestamp)); 

    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

private String extractHost(String request) { 
    int hStart = request.indexOf("Host: ") + 6; 
    int hEnd = request.indexOf('\n', hStart); 
    return request.substring(hStart, hEnd - 1); 
} 

}

當我進入瀏覽器時,它對HTTP頁面起作用,但對HTTPS不起作用。還有更多東西需要處理SSL。我不想讀取SSL軟件包,我只是想通過它們。怎麼做 ?

+0

在瀏覽器中,我得到: ERR_TUNNEL_CONNECTION_FAILED –

回答

1

我找到了解決方案。

如果客戶端的SSL請求被修改爲HTTP「CONNECT」方法。但是,這種要求不能去外面server.The代理服務器必須向客戶端響應:

"HTTP/1.1 200 Connection established\r\n\r\n" 

下一步是讓客戶端和服務器之間的雙向套接字連接。它應該看起來像這樣:

public class Https443RequestHandler implements RequestHandler { 

    private static final int BUFFER_SIZE = 8192; 
    private static final String CRLF = "\r\n"; 

    Socket mProxySocket; 
    Socket mOutsideSocket; 

    public Https443RequestHandler(Socket proxySocket) { 
     this.mProxySocket = proxySocket; 
    } 

    @Override 
    public void handle(String request) throws Exception { 
     byte[] bytes = request.getBytes(); 
     int bytesRead = bytes.length; 

     String host = extractHost(request); 
     int port = 443; 

     mOutsideSocket = new Socket(); 
     mOutsideSocket.setKeepAlive(true); 
     mOutsideSocket.connect(new InetSocketAddress(host, port)); 

     OutputStream proxyOutputStream = mProxySocket.getOutputStream(); 
     proxyOutputStream.write(("HTTP/1.1 200 Connection established" + CRLF + CRLF).getBytes()); 
     proxyOutputStream.flush(); 

     DirectionalConnectionHandler client = new DirectionalConnectionHandler(mProxySocket, mOutsideSocket); 
     client.start(); 
     DirectionalConnectionHandler server = new DirectionalConnectionHandler(mOutsideSocket, mProxySocket); 
     server.start(); 

     client.join(); 
     server.join(); 

     mOutsideSocket.close(); 
     mProxySocket.close(); 
    } 

    private String extractHost(String request) { 
     int hStart = request.indexOf("Host: ") + 6; 
     int hEnd = request.indexOf('\n', hStart); 
     return request.substring(hStart, hEnd - 1); 
    } 
} 

public class DirectionalConnectionHandler extends Thread 
{ 
    private final InputStream in; 
    private final OutputStream out; 

    DirectionalConnectionHandler(final Socket sin, final Socket sout) throws IOException 
    { 
     in = sin.getInputStream(); 
     out = sout.getOutputStream(); 
    } 

    @Override 
    public void run() 
    { 
     final byte[] buf = new byte[4096]; 
     int count; 

     try 
    { 
     while ((count = in.read(buf, 0, buf.length)) != -1) 
     { 
      String stream = new String(buf); 
      out.write(buf, 0, count); 
     } 
     out.flush(); 
    } 
    catch (final IOException e) 
    { 
     // Just swallow as we can't recover from this 
    } 
} 

}