Нет подтверждения от клиента в дыроколе TCP

Я реализовал TCP дырокол в C#. Я получаю то, что клиенты посылают друг другу сообщения SYN, но они отбрасываются на противоположных маршрутизаторах. Сценарий выглядит примерно так: Клиент:A-------- Маршрутизатор:A-------- Сервер -------- Маршрутизатор:B-------- Клиент: B

Если клиент: A отправляет пакет SYN клиенту:B, он отбрасывается на маршрутизаторе:B, что является очевидным поведением NAT. Но, согласно сценариям дырокола, теперь, если клиент: B отправляет SYN клиенту:A, он должен проходить через NAT на маршрутизаторе:A. Вот в моём случае роутер: А тоже отбрасывает этот пакет. В netstat он показывает соединение с B как SYN_SENT, и через пару секунд я получаю сообщение типа "Клиент не отвечает. Ошибка подключения"

Согласно моим исследованиям, причиной падения может быть тихое падение или активное отклонение. Если это бесшумное отбрасывание, то дыра должна быть пробита, и SYN от B должен быть передан через NAT в A. И если это активное отклонение, маршрутизатор: A получит уведомление от маршрутизатора: B о сбрасывании и A закроется дыра.

Проблема в том, что я не получаю никаких уведомлений в A. (проверено через журнал роутера). Я также попытался использовать уже реализованный пример TCP-дырки, полученный по https://github.com/jasonpang/tcp-holepunching

Но я получаю аналогичные результаты. Помогите мне найти решение для этого. Я также сомневаюсь в тайм-ауте для пробитых отверстий на маршрутизаторах.

пространство имен HolePunching {открытый класс HolePunchingClient {private Socket _clientSocket;

    private Socket _serverSocket;
    private Socket _connectSocket;
    //private Socket _serverSocket;

    private Socket _holePunchedSocket;

    public HolePunchingClient (IPEndPoint localEndPoint)
    {
        /*For the moment, only TCP Hole Punching is supported*/
        _clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        _clientSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        _clientSocket.Bind(localEndPoint);

        //_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        //_serverSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        //_serverSocket.Bind(localEndPoint);
    }

    private void ProcessClientRequest (object sender, DoWorkEventArgs eventArgs)
    {
        try
        {
            IPEndPoint iep = (IPEndPoint)eventArgs.Argument;
            _connectSocket.Connect(iep);
            Console.WriteLine("Connected correctly with: " + iep);
            _serverSocket.Close();
            _holePunchedSocket = _connectSocket;
            Console.WriteLine("\n\n\nException check clientRequest\n\n\n");
        }
        catch (Exception e)
        {
            Console.WriteLine("In ProcessClientRequest: " + e.Message);
            return;
        }
    }

    private void ProcessServerRequest (object sender, DoWorkEventArgs eventArgs)
    {
        try
        {
            _serverSocket.Listen(10);
            Socket s = _serverSocket.Accept();
            Console.WriteLine("Received connection from: " + s.RemoteEndPoint);
            _holePunchedSocket = s;
            Console.WriteLine("\n\n\nException check serverRequest\n\n\n");
        }
        catch (Exception e)
        {
            Console.WriteLine("In ProcessServerRequest: " + e.Message);
            return;
        }
    }

    private void ProcessRequest (object sender, DoWorkEventArgs eventArgs)
    {
        while (true)
        {
            byte[] bytes = new byte[2048];
            _clientSocket.Receive(bytes);

            MessageType messageType = (MessageType) bytes[0];
            Console.WriteLine("MessageType received: " + messageType);

            switch (messageType)
            {
                case MessageType.ConnectClient:
                    byte[] byteAddress = new byte[4];
                    byte[] bytePort = new byte[2];
                    Buffer.BlockCopy(bytes, 1, byteAddress, 0, 4);
                    Buffer.BlockCopy(bytes, 5, bytePort, 0, 2);
                    IPEndPoint remoteEndPoint = new IPEndPoint(new IPAddress(byteAddress), BitConverter.ToUInt16(bytePort, 0));
                    Console.WriteLine("HP will be done towards this address: " + remoteEndPoint);

                    _connectSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    _connectSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
                    _connectSocket.Bind(_clientSocket.LocalEndPoint);

                    _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    _serverSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
                    _serverSocket.Bind(_clientSocket.LocalEndPoint);

                    BackgroundWorker bwClient = new BackgroundWorker();
                    bwClient.DoWork += ProcessClientRequest;

                    BackgroundWorker bwServer = new BackgroundWorker();
                    bwServer.DoWork += ProcessServerRequest;

                    bwClient.RunWorkerAsync(remoteEndPoint);
                    bwServer.RunWorkerAsync();

                    break;
            }
        }
    }

    public void Connect (IPEndPoint serverEndPoint)
    {
        _clientSocket.Connect(serverEndPoint);
        _clientSocket.Send(BitConverter.GetBytes((byte)MessageType.Register));

        BackgroundWorker bw = new BackgroundWorker();
        bw.DoWork += ProcessRequest;
        bw.RunWorkerAsync();
    }

    public Socket HolePunch (IPAddress otherAddress)
    {
        byte[] bytes = new byte[5];
        Buffer.BlockCopy(BitConverter.GetBytes((byte)MessageType.RequestClient), 0, bytes, 0, 1);
        Buffer.BlockCopy(otherAddress.GetAddressBytes(), 0, bytes, 1, 4);

        _clientSocket.Send(bytes);

        while (_holePunchedSocket == null)
        {
            System.Threading.Thread.Sleep(1500);
        }

        return _holePunchedSocket;
    }
}

}

Это код клиента, который я взял по ссылке выше. При подключении к клиенту B/A появляется сообщение об исключении "Нет ответа от другого клиента. Ошибка подключения".

оба клиента A и B запускают одинаковые копии этой программы. Любой из них отправит запрос серверу на соединение с другим клиентом. Сервер отправит комбинацию IP-портов обоим. и код клиента будет продолжен, посылая друг другу запрос на соединение (который в итоге истекает)

0 ответов

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