Подтвердить что ты не робот

Перфорирование отверстий TCP

Я пытаюсь реализовать перфорирование отверстий TCP с помощью сокета Windows с помощью инструментальной цепочки mingw. Я думаю, что этот процесс прав, но дыра, похоже, не воспринимается. Я использовал этот в качестве справочника.

  • A и B подключиться к серверу S
  • S отправляет на A, B маршрутизатор IP + порт, к которому он привык подключаться к S
  • S делает то же самое для B
  • A запустите 2 потока:
    • Один поток пытается подключиться к маршрутизатору B с информацией, отправленной S
    • Другой поток ожидает входящего соединения на том же порту, который используется для подключения к его маршрутизатору, когда он подключен к S
  • B делает то же самое

У меня нет проблем в коде, который я думаю с тех пор:

  • A и B получают друг друга ip и порт для использования
  • Они оба слушают порт, который они использовали для подключения к своему маршрутизатору, когда они связались с сервером.
  • Они оба подключаются к правильному ip и порту, но получают тайм-аут (ошибка кода 10060)

Я что-то упустил?

EDIT:. С помощью обработчика процессов я вижу, что одному из клиентов удалось установить соединение с одноранговым узлом. Но коллега не считает, что соединение должно быть сделано.

Вот что я захватил с Wireshark. Для примера, сервер S и клиент A находятся на одном ПК. Сервер S прослушивает определенный порт (8060), перенаправленный на этот компьютер. B по-прежнему пытается подключиться по правильному IP-адресу, поскольку видит, что общий адрес A, отправленный S, localhost и, следовательно, использует публичный IP S. (Я заменил публичные IP-адреса заполнителями)

wireshark

EDIT 2: Я думаю, что путаница связана с тем, что как входящие, так и исходящие данные запроса соединения передаются на одном и том же порту. Который, кажется, испортил состояние соединения, потому что мы не знаем, какой сокет получит данные из порта. Если я укажу msdn:

Параметр сокета SO_REUSEADDR позволяет сокету принудительно связываться с порт, используемый другим сокетом. Второй сокет вызывает setsockopt с параметр optname установлен на SO_REUSEADDR и набор параметров optval до логического значения TRUE перед вызовом bind на том же порту, что и оригинальный гнездо. Как только второй сокет успешно связан, поведение для всех сокетов, связанных с этим портом, является неопределенным.

Но разговор по тому же порту требуется методом TCP Hole Punching, чтобы открыть отверстия!

4b9b3361

Ответ 1

Начало 2 потока:
    Один поток пытается подключиться к маршрутизатору B с информацией, отправленной S
    Другой поток ожидает входящего соединения на том же порту, который используется для подключения к его маршрутизатору, когда он подключен к S

Вы не можете сделать это с помощью двух потоков, так как это всего лишь одна операция. Каждое TCP-соединение, выполняющее исходящее соединение, также ожидает входящего соединения. Вы просто вызываете "connect", и вы отправляете исходящие SYN для соединения и ожидания входящих SYN для соединения.

Однако вам может потребоваться закрыть соединение с сервером. Вероятно, ваша платформа не позволяет вам устанавливать TCP-соединение из порта, если у вас уже установлено соединение с тем же портом. Так же, как вы начинаете перфорирование отверстий TCP, закройте соединение с сервером. Привяжите новый TCP-сокет к тому же порту и вызовите connect.

Ответ 2

Простое решение для перехода на NAT-маршрутизаторы - это сделать ваш трафик, следуя протоколу, что ваш NAT уже имеет алгоритм пересылки, например FTP.

Ответ 3

  • Использовать Wireshark для проверки запроса соединения tcp (трехсторонний процесс Handhsake) идет правильно.

  • Убедитесь, что поток Listener имеет функцию select() для демпплексирования дескриптора.

  • sockPeerConect (сокет, используемый для подключения другого однорангового узла) - это FD_SET() в потоке прослушивателя.

  • Убедитесь, что вы проверяете

     int Listener Thread()
     {
       while(true)
       {
           FD_SET(sockPeerConn);
           FD_SET(sockServerConn);
           FD_SET(nConnectedSock );
          if (FD_ISSET(sockPeerConect)
          {
            /// and calling accept() in side the
            nConnectedSock = accept( ....);
    
           }
           if (FD_ISSET(sockServerConn)
           {
            /// receive data from Server
            recv(sockServerConn );
    
           }
           if (FD_ISSET(nConnectedSock )
           {
            /// Receive data from Other Peer
             recv(nConnectedSock );
    
           }
    
       }
      }
    

5. Убедитесь, что вы одновременно начинаете одноранговое соединение A с B и B с A.
6. Запустите тему прослушивателя перед подключением к серверу и одноранговому узлу и получите один поток прослушивателя для приема сервера и клиента.