TCP Hole Punch (NAT Traversal) Библиотека или что-то?

Я хочу сделать TCP Hole Punching (NAT Traversal) в C#. Это может быть сделано с сервером рандеву, если это необходимо. Я нашел http://sharpstunt.codeplex.com/ но не могу заставить это работать. В идеале мне нужен какой-то метод, который я даю в качестве параметра номер порта (int), который после вызова этого метода становится доступен ("Port Forwarded") в NAT. Также было бы хорошо, если бы метод просто возвращал какой-то номер порта, который затем доступен в NAT. Кто-нибудь делал это в C#? Можете ли вы дать мне рабочие примеры для sharpstunt или что-то еще?

6 ответов

Решение

В каждом сетевом сценарии пробивание дырок в TCP работает аналогично пробиванию дырок в UDP. Например, если два одноранговых узла A и B находятся за разными NAT, первый пакет SYN каждого однорангового узла, отправленный другому одноранговому узлу, открывает дыру, связанную с его общедоступным адресом в соответствующем NAT. Если первый SYN-пакет A для B достигает NAT B, прежде чем первый SYN-пакет B для A достигает NAT B, NAT B считает пакет SYN A незапрошенным и отбрасывает его. Однако впоследствии первый SYN-пакет B может успешно проходить через NAT A, поскольку NAT A распознает открытый адрес B в качестве пункта назначения исходящего сеанса, который инициировал A.

Так да. Это возможно для TCP дырокола. Я не понимаю, почему кто-то мог думать иначе.

Кроме того, не могли бы вы создать этот тип поведения вручную? Он не должен зависеть от какого-либо конкретного протокола, если шаги одинаковы для сбора всей необходимой информации.

В целом, перфорация TCP (3.2.1) происходит следующим образом:

Клиенты: A, B Сервер: S

• A использует свое соединение с S, чтобы запросить у S соединение с B. • S отвечает на A частными и общедоступными адресами B и одновременно отправляет адреса A на B.

• A и B асинхронно создают попытки исходящего соединения (отправляют пакеты SYN) на публичные и частные адреса друг друга с одного и того же порта, который они использовали для регистрации в S. В то же время они прослушивают попытки входящего соединения TCP на своих локальные порты TCP.

• A и B ждут ответа SYN-ACK на свои исходящие пакеты SYN или входящего запроса на соединение (пакет SYN). В случае сбоя соединения одноранговый узел может повторить попытку до максимального периода ожидания.

• После завершения процесса трехстороннего рукопожатия одноранговые узлы аутентифицируют друг друга. Если аутентификация не удалась, узлы закрывают это соединение и ждут, пока другое соединение не будет успешно аутентифицировано. Первое успешно аутентифицированное соединение будет использоваться для передачи данных TCP.

(Я знаю, что это не очень хороший ответ, но не было достаточно места для комментариев).

Вопрос довольно старый, но для тех, кто ищет решение, вы должны взглянуть на проект Open.NAT, он действительно прост в использовании и работает как с UPNP, так и с PMP NAT!

Допустим, вы хотите перенаправить внешний порт 1700 на локальный порт 1600, все, что вам нужно сделать, это:

var discoverer = new NatDiscoverer();
var device = await discoverer.DiscoverDeviceAsync();
await device.CreatePortMapAsync(new Mapping(Protocol.Tcp, 1600, 1700, "The mapping name"));

Вы также можете перечислить все существующие сопоставления, чтобы вы могли проверить, что ваш порт еще не используется.

var sb = new StringBuilder();
var ip = await device.GetExternalIPAsync();

sb.AppendFormat("\nAdded mapping: {0}:1700 -> 127.0.0.1:1600\n", ip);
sb.AppendFormat("\n+------+-------------------------------+--------------------------------+------------------------------------+-------------------------+");
sb.AppendFormat("\n| PROT | PUBLIC (Reacheable)           | PRIVATE (Your computer)        | Descriptopn                        |                         |");
sb.AppendFormat("\n+------+----------------------+--------+-----------------------+--------+------------------------------------+-------------------------+");
sb.AppendFormat("\n|      | IP Address           | Port   | IP Address            | Port   |                                    | Expires                 |");
sb.AppendFormat("\n+------+----------------------+--------+-----------------------+--------+------------------------------------+-------------------------+");
foreach (var mapping in await device.GetAllMappingsAsync())
{
    sb.AppendFormat("\n|  {5} | {0,-20} | {1,6} | {2,-21} | {3,6} | {4,-35}|{6,25}|",
        ip, mapping.PublicPort, mapping.PrivateIP, mapping.PrivatePort, mapping.Description, mapping.Protocol == Protocol.Tcp ? "TCP" : "UDP", mapping.Expiration.ToLocalTime());
}
sb.AppendFormat("\n+------+----------------------+--------+-----------------------+--------+------------------------------------+-------------------------+");
Console.WriteLine(sb.ToString());

На MSDN также есть запись в блоге о NAT Traversal: https://blogs.msdn.microsoft.com/ncl/2009/07/27/end-to-end-connectivity-with-nat-traversal/

Мы собрали библиотеку под названием IceLink, которая выполняет потоковую передачу P2P с использованием ICE/STUN/TURN с полным обходом NAT. Основанное на STUN перфорация работает для большинства маршрутизаторов для установления прямого соединения между узлами, а для "плохих" маршрутизаторов соединение возвращается к ретрансляции на основе TURN.

Похоже, вы перепутали TCP и UDP. TCP является протоколом, ориентированным на установление соединения, легко понимаемым брандмауэрами и маршрутизаторами и требующим одного инициатора (клиента) и одного прослушивателя (сервера). Если и клиент, и сервер находятся за брандмауэрами или NAT, вы не можете пробить дыру, не подключив их обоих к какому-либо прокси-серверу (который не защищен брандмауэром). Проблема в том, что тогда прокси будет отвечать за ретрансляцию всего своего трафика.

От вашего вопроса, кажется, что вы больше заинтересованы в пробивании дырок UDP, который использует тот факт, что UDP не имеет состояния и не ориентирован на соединение. Поэтому большинство брандмауэров, отслеживающих состояние, будут "делать правильные предположения" о потоке данных UDP и исходить из того, что трафик, выходящий из данного порта, будет получать ответы на тот же порт и автоматически направлять их обратно. Если при использовании некоторых внеканальных средств (таких как сервер TCP, который просто передает адреса, а не данные), оба узла могут передавать данные друг другу по одним и тем же портам, их соответствующие брандмауэры / маршрутизаторы NAT откроют дыры, позволяющие трафик в.

Что касается того, как это сделать, все зависит от того, как вы собираетесь получать IP-адреса пиров друг другу. Как только он у вас есть, просто начните передачу пакетов UDP по согласованному порту и дождитесь ответа.

http://sipsorcery.codeplex.com/ имеет работающий оглушающий сервер.

SipSorcery.core -> SipSorcery.Net -> Оглушение

Я не знаком с вашей темой, но я знаю P2PVPN с открытым исходным кодом, который использует lib для NAT. Вы можете проверить это здесь (www.SocialVPN.org).

Удачи.

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