5

I want to use android's VpnService to capture packets filter them based off IP address. I can get the packets from the "tun" interface just fine but after that i'm not sure how to forward them to their original destination. Based off of the comments from this answer it seems like i just need to:

  1. Create a new socket to the destination IP address and port
  2. Trim the IP and TCP header to send only the data
  3. Re-attach the IP and TCP header when i get a response
  4. Send the complete packet to the output stream

I have tried to send the data like this:

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());

The methods getTCPHeader(ByteArray packet) and getIpHeader(ByteArray packet) simply splits the packet into two ByteArray's as follows:

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};
}

Now to get a response from the server, i am using the following code:

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();
}

This code seems to work either EXTREMELY slowly, or not at all. Sometimes if i go to www.google.com it will load slowly but most of the time it doesn't. Also some times i am getting the following error on the line int responseLength = socketInputStream.read(serverResponse.array());

java.net.SocketException: recvfrom failed: ECONNRESET (Connection reset by peer)

What is causing this error, and how can i properly forward these packets to the appropriate destination? Any help is greatly appreciated!

Community
  • 1
  • 1
TychoTheTaco
  • 664
  • 1
  • 7
  • 28

1 Answers1

0

What is causing this error?

recvfrom failed exception means that Server has closed the client socket but client was still reading input data (in your case serverResponse.array(). For details, see this.

how can i properly forward these packets to the appropriate destination?

There is a sample-code from google-sources here that forwards available packets. Please go through the code and the relevant comments. According to google-sources:

This application consists of an Android client and a sample implementation of a server. It performs IP over UDP and is capable of doing seamless handover between different networks as long as it receives the same VPN parameters.It shows how to build a VPN client using the VpnService class introduced in API level 14.

The sample code of the server-side implementation is Linux-specific and is available in the server directory. To run the server or port it to another platform, please see comments in the code for the details.

one more helpful app link here

Community
  • 1
  • 1
rupinderjeet
  • 2,984
  • 30
  • 54
  • I have already looked at the toyVpn example from google, but that one uses a separate VPN server. I am trying to implement all of this on the phone itself with no connection to another server. – TychoTheTaco Jun 11 '16 at 16:50
  • the linux-specific server-side implementation is what you have to go through. Go to Server directory as mentioned. Your phone itself is also based on linux. – rupinderjeet Jun 14 '16 at 14:00