簡體   English   中英

Android VpnService轉發數據包

[英]Android VpnService forward packets

我想使用Android的VpnService捕獲數據包,並根據IP地址VpnService進行過濾。 我可以從“ tun”接口獲取數據包,但是之后我不確定如何將其轉發到原始目的地。 基於此答案的評論,看來我只需要:

  1. 創建一個到目標IP地址和端口的新套接字
  2. 修剪IP和TCP標頭以僅發送數據
  3. 得到響應后重新附加IP和TCP標頭
  4. 將完整的數據包發送到輸出流

我試圖發送這樣的數據:

Socket socket = new Socket();
socket.bind(new InetSocketAddress(0));
if (protect(socket)){
    Log.e(TAG, "Socket protected");
}else{
    Log.e(TAG, "Socket NOT protected");
}
socket.connect(new InetSocketAddress(ipPacket.getDestinationIp(), ipPacket.getDstPort()));
Log.e(TAG, "Socket connected: " + socket.isConnected());

socket.getOutputStream().write(getTCPHeader(getIpHeader(packet)[1])[1].array());

方法getTCPHeader(ByteArray packet)getIpHeader(ByteArray packet)只是將數據包分成兩個ByteArray ,如下所示:

private ByteBuffer[] getIpHeader(ByteBuffer packet){
    packet.position(0);
    ByteBuffer ipHeader = ByteBuffer.allocate(20);
    ByteBuffer data = ByteBuffer.allocate(packet.limit() - 20);

    packet.get(ipHeader.array(), 0, 20);

    packet.get(data.array(), 0, packet.limit() - 20);

    return new ByteBuffer[]{ipHeader, data};
}

private ByteBuffer[] getTCPHeader(ByteBuffer packet){
    packet.position(20);
    ByteBuffer tcpHeader = ByteBuffer.allocate(20);
    ByteBuffer data = ByteBuffer.allocate(packet.limit() - 20);

    packet.get(tcpHeader.array(), 0, 20);

    packet.get(data.array(), 0, packet.limit() - 40);

    return new ByteBuffer[]{tcpHeader, data};
}

現在要從服務器獲得響應,我正在使用以下代碼:

ByteBuffer responsePacket = ByteBuffer.allocate(65535);
InputStream socketInputStream = socket.getInputStream();
try{
    int responseLength = socketInputStream.read(responsePacket.array());
    if (responseLength > 20){
        Log.e(TAG, "===Server Response===");
        Log.e(TAG, "Length: " + responseLength);

        ByteBuffer trimmedResponseData = ByteBuffer.allocate(responseLength);
        System.arraycopy(responseData.array(), 0, trimmedResponseData.array(), 0, responseLength);

        String resp = "";
        for (int i = 0; i < responseLength; i++){
            resp += String.valueOf(responseData.get(i) + " ");
        }

        Log.e(TAG, "Response data: " + resp);

        ByteBuffer finalPacket = ByteBuffer.allocate(40 + responseLength);
        ByteBuffer swappedIpHeader = swapSrcDstAddress(getIpHeader(packet)[0]);
        ByteBuffer swappedTcpHeader = swapTCPSrcDst(getTCPHeader(getIpHeader(packet)[1])[0]);

        finalPacket.put(swappedIpHeader.array());
        finalPacket.put(swappedTcpHeader.array());
        finalPacket.put(serverResponseData.array());

        Packet finPack = debugPacket(finalPacket);
        Log.e("VPN", "Final packet --> Packet size: " + finPack.getTotalLength() + " from " + finPack.getSourceIp() + " src port: " + finPack.getSrcPort() + " going to " + finPack.getDestinationIp() + " dst port: " + finPack.getDstPort());

        out.write(finalPacket.array());
    }
}catch (Exception e){
    //Log.e(TAG, "EXCEPTION: " + e);
    e.printStackTrace();
}

這段代碼似乎極慢地起作用,或者根本不起作用。 有時,如果我訪問www.google.com它加載速度會很慢,但大多數時候不會。 有時我在行int responseLength = socketInputStream.read(serverResponse.array());上遇到以下錯誤int responseLength = socketInputStream.read(serverResponse.array());

java.net.SocketException:recvfrom失敗:ECONNRESET(對等連接重置)

是什么導致此錯誤,如何將這些數據包正確轉發到適當的目的地? 任何幫助是極大的贊賞!

是什么導致此錯誤?

recvfrom failed異常表示服務器已關閉客戶端套接字,但客戶端仍在讀取輸入數據(在您的情況下為serverResponse.array() 。有關詳細信息, 請參見this)

我如何正確地將這些數據包轉發到適當的目的地?

有一個從谷歌來源的樣本代碼這里是可用的轉發數據包。 請仔細閱讀代碼和相關注釋。 根據google-sources:

該應用程序由一個Android客戶端和一個服務器示例實現組成。 它通過UDP執行IP,並且能夠在不同網絡之間進行無縫切換,只要它接收到相同的VPN參數即可。它展示了如何使用API​​級別14中引入的VpnService類來構建VPN客戶端。

服務器端實現的示例代碼特定於Linux,可在server目錄中找到。 要運行服務器或將其移植到另一個平台,請參閱代碼中的注釋以獲取詳細信息。

這里還有一個有用的應用程序鏈接

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM