Android VpnService пересылка пакетов

Я хочу использовать Android VpnService захватывать пакеты фильтровать их по IP-адресу. Я могу получить пакеты из интерфейса "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());

java.net. SocketException: recvfrom не удалось: ECONNRESET (соединение сбрасывается одноранговым узлом)

Что является причиной этой ошибки, и как я могу правильно переслать эти пакеты в соответствующий пункт назначения? Любая помощь очень ценится!

1 ответ

Что вызывает эту ошибку?

recvfrom failed исключение означает, что сервер закрыл клиентский сокет, но клиент все еще считывал входные данные (в вашем случае serverResponse.array(), Подробности смотрите в этом.

Как я могу правильно переслать эти пакеты в соответствующий пункт назначения?

Вот пример кода из google-sources, который пересылает доступные пакеты. Пожалуйста, просмотрите код и соответствующие комментарии. По данным гугл-источников:

Это приложение состоит из клиента Android и примера реализации сервера. Он выполняет IP через UDP и способен выполнять бесшовную передачу обслуживания между различными сетями, если он получает одни и те же параметры VPN. В нем показано, как создать клиент VPN с использованием класса VpnService, представленного на уровне API 14.

Пример кода реализации на стороне сервера специфичен для Linux и доступен в server каталог. Чтобы запустить сервер или перенести его на другую платформу, см. Подробности в комментариях в коде.

еще одна полезная ссылка на приложение здесь

Другие вопросы по тегам