Служба VPN: невозможно прочитать данные из туннеля сокета - PullRequest
0 голосов
/ 15 апреля 2020

Я пытаюсь создать приложение VPN android с использованием VPNService для какого-либо поставщика услуг VPN. При попытке чтения данных столкнулся с проблемой ниже:

Не удалось прочитать данные с адреса сокета "xxx.xxx.xxx.xx". Может кто-нибудь помочь мне понять, что я здесь пропустил?

//Able to establish an Inteface like below
ParcelFileDescriptor mInterface = builder
.addAddress("10.50.0.3", 32)
.addDnsServer("8.8.8.8")
.addRoute("0.0.0.0", 0)
.establish();

// Создан туннель, как показано ниже (я полагаю, это равноправно)

DatagramChannel tunnel = DatagramChannel.open();
tunnel.connect(new InetSocketAddress("3.101.128.28", 443));
tunnel.configureBlocking(false);
protect(tunnel.socket());

Кроме того, попытался записать общий ключ publi c в пакеты для отправки в туннель, как показано ниже, но это тоже не помогло работа.

ByteBuffer packet = ByteBuffer.allocate(1024);
packet.put((byte) 0).put("PrtBg/5jooxYciQgi1XCzyXXXXXXXIzqmKQRtPSc=".getBytes()).flip();
packet.position(0);
tunnel.write(packet);

Тем не менее, чтение данных из туннеля всегда возвращает ноль.

int length = tunnel.read(packet);

Ниже приведен класс обслуживания Complete:

public class MyVPNService extends VpnService {

    private Thread mThread;
    private ParcelFileDescriptor mInterface;
    Builder builder = new Builder();

    private static final int MAX_PACKET_SIZE = Short.MAX_VALUE;
    private static final long RECEIVE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(20);
    private static final long IDLE_INTERVAL_MS = TimeUnit.MILLISECONDS.toMillis(100);
    private static final long KEEPALIVE_INTERVAL_MS = TimeUnit.SECONDS.toMillis(15);

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // Start a new session by creating a new thread.
        mThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {

                    // -----------------Interface----------------

                    //Configure the TUN and get the interface.
                    mInterface = builder
                            .addAddress("10.50.0.3", 32)
                            .addDnsServer("8.8.8.8")
                            .addRoute("0.0.0.0", 0)
                            .establish();

                    //b. Packets to be sent are queued in this input stream.
                    FileInputStream in = new FileInputStream(
                            mInterface.getFileDescriptor());
                    //b. Packets received need to be written to this output stream.
                    FileOutputStream out = new FileOutputStream(
                            mInterface.getFileDescriptor());


                    //-------------------Peer-----------------------

                    //c. The UDP channel can be used to pass/get ip package to/from server
                    DatagramChannel tunnel = DatagramChannel.open();

                    tunnel.connect(new InetSocketAddress("3.101.128.28", 443));

                    // For simplicity, we use the same thread for both reading and
                    // writing. Here we put the tunnel into non-blocking mode.
                    tunnel.configureBlocking(false);

                    //Protect this socket, so package send by it will not be feedback to the vpn service.
                    protect(tunnel.socket());

                    //Allocate the buffer for a single packet.
                    ByteBuffer packet = ByteBuffer.allocate(MAX_PACKET_SIZE);

                    packet.put((byte) 0).put("PrtBg/5jooxYciQgi1XCzyGhhZtQejcjIzqmKQRtPSc=".getBytes()).flip();
                    packet.position(0);

                    //Timeouts:
                    // - when data has not been sent in a while, send empty keepalive messages.
                    // - when data has not been received in a while, assume the connection is broken.
                    long lastSendTime = System.currentTimeMillis();
                    long lastReceiveTime = System.currentTimeMillis();
                    // We keep forwarding packets till something goes wrong.
                    while (true) {
                        // Assume that we did not make any progress in this iteration.
                        boolean idle = true;
                        // Read the outgoing packet from the input stream.
                        int length = in.read(packet.array());
                        if (length > 0) {
                            // Write the outgoing packet to the tunnel.
                            packet.limit(length);
                            tunnel.write(packet);
                            packet.clear();
                            // There might be more outgoing packets.
                            idle = false;
                            lastReceiveTime = System.currentTimeMillis();
                        }
                        // Read the incoming packet from the tunnel.
                        **length = tunnel.read(packet); // This length is always zero**
                        if (length > 0) {
                            // Ignore control messages, which start with zero.
                            if (packet.get(0) != 0) {
                                // Write the incoming packet to the output stream.
                                out.write(packet.array(), 0, length);
                            }
                            packet.clear();
                            // There might be more incoming packets.
                            idle = false;
                            lastSendTime = System.currentTimeMillis();
                        }
                        // If we are idle or waiting for the network, sleep for a
                        // fraction of time to avoid busy looping.
                        if (idle) {
                            Thread.sleep(IDLE_INTERVAL_MS);
                            final long timeNow = System.currentTimeMillis();
                            if (lastSendTime + KEEPALIVE_INTERVAL_MS <= timeNow) {
                                // We are receiving for a long time but not sending.
                                // Send empty control messages.
                                packet.put((byte) 0).limit(1);
                                for (int i = 0; i < 3; ++i) {
                                    packet.position(0);
                                    tunnel.write(packet);
                                }
                                packet.clear();
                                lastSendTime = timeNow;
                            } else if (lastReceiveTime + RECEIVE_TIMEOUT_MS <= timeNow) {
                                // We are sending for a long time but not receiving.
                                throw new IllegalStateException("Timed out");
                            }
                        }
                    }

                } catch (Exception e) {
                    // Catch any exception
                    e.printStackTrace();
                    System.out.println(">>Rock Exception ::" + e.getMessage());
                } finally {
                    try {
                        if (mInterface != null) {
                            mInterface.close();
                            mInterface = null;
                        }
                    } catch (Exception e) {
                        System.out.println(">>Rock Exception22 ::" + e.getMessage());
                    }
                }
            }

        }, "MyVpnRunnable");

        //start the service
        mThread.start();
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        System.out.println(">>Rock onDestroy ::");
        // TODO Auto-generated method stub
        if (mThread != null) {
            mThread.interrupt();
        }
        super.onDestroy();
    }

}
...