Escribir en flujo de salida VpnService no proporciona ninguna respuesta

Mi aplicación implementa VpnService para interceptar tráfico de red y proporcionar respuestas personalizadas. El objetivo es manejar el tráfico a direcciones específicas y descartar otras solicitudes.

Actualmente tengo éxito en analizar las solicitudes entrantes y construir y enviar respuestas. El problema, sin embargo, es que estas respuestas no llegan como la respuesta real a la petición original; Las pruebas con una conexión de enchufe simplemente se agotan.

Para hacer esta distinción, actualmente estoy analizando los paquetes IP sin procesar del flujo de entrada de VpnService de la siguiente manera:

VpnService.Builder b = new VpnService.Builder(); b.addAddress("10.2.3.4", 28); b.addRoute("0.0.0.0", 0); b.setMtu(1500); ... ParcelFileDescriptor vpnInterface = b.establish(); final FileInputStream in = new FileInputStream( vpnInterface.getFileDescriptor()); final FileOutputStream out = new FileOutputStream( vpnInterface.getFileDescriptor()); // Allocate the buffer for a single packet. ByteBuffer packet = ByteBuffer.allocate(32767); // We keep forwarding packets till something goes wrong. try { while (vpnInterface != null && vpnInterface.getFileDescriptor() != null && vpnInterface.getFileDescriptor().valid()) { packet.clear(); SystemClock.sleep(10); // Read the outgoing packet from the input stream. final byte[] data = packet.array(); int length = in.read(data); if (length > 0) { packet.limit(length); /* 1. Parse the TCP/UDP header 2. Create an own socket with the same src/dest port/ip 3. Use protect() on this socket so it not routed over tun0 4. Send the packet body (excluding the header) 5. Obtain the response 6. Add the TCP header to the response and forward it */ final IpDatagram ip = IpDatagram.create(packet); ... } } 

IpDatagram es una clase a través de la cual create() analiza la matriz de bytes en una representación del paquete IP, que contiene el encabezado IP, las opciones y el cuerpo. Procedo a analizar la matriz de bytes del cuerpo de acuerdo con el tipo de protocolo. En este caso, sólo estoy interesado en IPv4 con una carga TCP-aquí también crear una representación de la cabecera TCP, las opciones y el cuerpo.

Después de obtener una instancia de IpDatagram, puedo determinar el IP de origen y destino (desde el encabezado IP) y el puerto (desde el encabezado TCP). También reconozco las banderas del TCP de la petición (tales como SYN, ACK y PSH) y el número de secuencia. En la aplicación:

Análisis del paquete TCP / IP entrante

Posteriormente construyo un nuevo IpDatagram como una respuesta, donde:

  • La IP de origen y de destino se invierte de la solicitud entrante;
  • Los puertos de origen y destino se invierten de la solicitud entrante;
  • El número de confirmación de TCP se establece en el número de secuencia de la solicitud entrante;
  • Una carga útil HTTP / 1.1 ficticia se proporciona como el cuerpo del TCP.

Convertir el IpDatagram resultante a un array de bytes y escribirlo en el flujo de salida del VpnServer:

 TcpDatagram tcp = new TcpDatagram(tcpHeader, tcpOptions, tcpBody); IpDatagram ip = new Ip4Datagram(ipHeader, ipOptions, tcp); out.write(ip.toBytes()); 

Mi aplicación muestra el datagrama saliente como debe ser, pero sin embargo, todas las conexiones aún están agotando el tiempo.

Respuesta de TCP / IP

Aquí hay una muestra de un paquete TCP / IP entrante en hexadecimal:

4500003c7de04000400605f10a0203044faa5a3bb9240050858bc52b00000000a00239089a570000020405b40402080a00bfb8cb0000000001030306

Y el resultante paquete TCP / IP saliente en hexadecimal:

450000bb30394000800613194faa5a3b0a0203040050b92400a00000858bc52b501820001fab0000485454502f312e3120323030204f4b0a446174653a205475652c203139204e6f7620323031332031323a32333a303320474d540a436f6e74656e742d547970653a20746578742f68746d6c0a436f6e74656e742d4c656e6774683a2031320a457870697265733a205475652c203139204e6f7620323031332031323a32333a303320474d540a0a48656c6c6f20776f726c6421

Sin embargo, una prueba sencilla simplemente se agota; Creo un nuevo zócalo y lo conecto al IP arriba, sin embargo la respuesta proporcionada arriba nunca llega.

¿Qué podría estar saliendo mal? ¿Hay alguna manera de solucionar por qué mi respuesta no está llegando?

Esta respuesta TCP / IP no contiene una suma de comprobación de encabezado TCP válida:

450000bb30394000800613194faa5a3b0a0203040050b92400a00000858bc52b50182000 1fab 0000485454502f312e3120323030204f4b0a446174653a205475652c203139204e6f7620323031332031323a32333a303320474d540a436f6e74656e742d547970653a20746578742f68746d6c0a436f6e74656e742d4c656e6774683a2031320a457870697265733a205475652c203139204e6f7620323031332031323a32333a303320474d540a0a48656c6c6f20776f726c6421

En términos más generales, el mecanismo de solicitud y respuesta es muy exigente. Esto es, por supuesto, el caso debido a la naturaleza misma de la creación de redes, y como el núcleo se encarga de asegurar que las respuestas son buenas ya qué puerto se debe enviar una respuesta, todo lo que no se calcula simplemente se descartará como paquete incorrecto . Esto también es cierto cuando responde desde el flujo de salida de VpnService, ya que está operando en la capa de red.

Para volver al caso específico anterior: el paquete IP es correcto (incluyendo la suma de comprobación) pero el paquete TCP no lo era. Necesita calcular la suma de comprobación de encabezado TCP no sólo en el paquete TCP, sino que prefiere el encabezado pseudo de la siguiente manera:

TCP pseudo-header http://www.tcpipguide.com/free/diagrams/tcppseudoheader.png

Deberá ser calculado sobre los siguientes bytes:

Suma de comprobación de cabecera TCP

  • Configurar VPN de forma programática en android
  • Conexión de Android OpenVPN
  • Cómo crear mediante programación una nueva interfaz VPN con Android 4.0?
  • ¿Cómo están creando nuevos perfiles de aplicaciones VPN existentes en Android 2.0 - 2.3?
  • ¿Cómo encontrar el estado de la conexión VPN a través de API de marco o cualquier otro método eficiente?
  • Android VpnService - ¿Cómo reenviar el tráfico interceptado de Internet?
  • Establecer una conexión VPN de forma programática en android 4.0
  • Desvío de paquetes VPN
  • Cómo conectarse a una VPN, que ya está configurada en un teléfono Android, mediante programación
  • Android VpnService, reenvío de paquetes
  • Cree una conexión VPN L2TP / IPSec mediante programación en Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.