title: Android VpnService forward packets
body: <p>I want to use android's <code>VpnService</code> to capture packets filter them based off IP address. I can get the packets from the &quot;tun&quot; interface just fine but after that i'm not sure how to forward them to their original destination. Based off of the comments from <a href="https://stackoverflow.com/a/17820461/4893507">this answer</a> it seems like i just need to:</p>
  <ol>
  <li>Create a new socket to the destination IP address and port</li>
  <li>Trim the IP and TCP header to send only the data</li>
  <li>Re-attach the IP and TCP header when i get a response</li>
  <li>Send the complete packet to the output stream</li>
  </ol>
  <p>I have tried to send the data like this:</p>
  <pre><code>Socket socket = new Socket();
  socket.bind(new InetSocketAddress(0));
  if (protect(socket)){
      Log.e(TAG, &quot;Socket protected&quot;);
  }else{
      Log.e(TAG, &quot;Socket NOT protected&quot;);
  }
  socket.connect(new InetSocketAddress(ipPacket.getDestinationIp(), ipPacket.getDstPort()));
  Log.e(TAG, &quot;Socket connected: &quot; + socket.isConnected());
  
  socket.getOutputStream().write(getTCPHeader(getIpHeader(packet)[1])[1].array());
  </code></pre>
  <p>The methods <code>getTCPHeader(ByteArray packet)</code> and <code>getIpHeader(ByteArray packet)</code> simply splits the packet into two <code>ByteArray</code>'s as follows:</p>
  <pre><code>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};
  }
  </code></pre>
  <p>Now to get a response from the server, i am using the following code:</p>
  <pre><code>ByteBuffer responsePacket = ByteBuffer.allocate(65535);
  InputStream socketInputStream = socket.getInputStream();
  try{
      int responseLength = socketInputStream.read(responsePacket.array());
      if (responseLength &gt; 20){
          Log.e(TAG, &quot;===Server Response===&quot;);
          Log.e(TAG, &quot;Length: &quot; + responseLength);
  
          ByteBuffer trimmedResponseData = ByteBuffer.allocate(responseLength);
          System.arraycopy(responseData.array(), 0, trimmedResponseData.array(), 0, responseLength);
  
          String resp = &quot;&quot;;
          for (int i = 0; i &lt; responseLength; i++){
              resp += String.valueOf(responseData.get(i) + &quot; &quot;);
          }
  
          Log.e(TAG, &quot;Response data: &quot; + 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(&quot;VPN&quot;, &quot;Final packet --&gt; Packet size: &quot; + finPack.getTotalLength() + &quot; from &quot; + finPack.getSourceIp() + &quot; src port: &quot; + finPack.getSrcPort() + &quot; going to &quot; + finPack.getDestinationIp() + &quot; dst port: &quot; + finPack.getDstPort());
  
          out.write(finalPacket.array());
      }
  }catch (Exception e){
      //Log.e(TAG, &quot;EXCEPTION: &quot; + e);
      e.printStackTrace();
  }
  </code></pre>
  <p>This code seems to work either EXTREMELY slowly, or not at all. Sometimes if i go to <code>www.google.com</code> it will load slowly but most of the time it doesn't. Also some times i am getting the following error on the line <code>int responseLength = socketInputStream.read(serverResponse.array());</code></p>
  <blockquote>
  <p>java.net.SocketException: recvfrom failed: ECONNRESET (Connection reset by peer)</p>
  </blockquote>
  <p>What is causing this error, and how can i properly forward these packets to the appropriate destination? Any help is greatly appreciated!</p>