Java UDP hole punching example-łączenie przez firewall

Powiedzmy, że mam dwa komputery.

Znają się na publicznych i prywatnych IP za pośrednictwem ice4j.

Jeden klient nasłuchuje, a drugi wysyła ciąg znaków.

Chciałbym to zobaczyć poprzez dziurkowanie w UPD:

Let A be the client requesting the connection

Let B be the client that is responding to the request

Let S be the ice4j STUN server that they contact to initiate the connection
--
A sends a connection request to S

S responds with B's IP and port info, and sends A's IP and port info to B

A sends a UDP packet to B, which B's router firewall drops but it still
punches a hole in A's own firewall where B can connect

B sends a UDP packet to A, that both punches a hole in their own firewall,
and reaches A through the hole that they punched in their own firewall

A and B can now communicate through their established connection without 
the help of S

Czy ktos moze zamiescic pseudo przyklady jak zrobic dziurkowanie przez symetryczny NAT? Zakładając, że będzie serwer s, który pomoże odgadnąć numery portów i nawiązać połączenie między Klientem A i B.

Byłoby miło, gdybyś również uwzględnił podwójny NAT.

Uwaga:

Możesz użyć STUN, aby odkryć IP i Port, ale musisz napisać własny kod, który wyśle IP: Port do twojego serwera za pomocą techniki keepalive.

Gdy jeden klient zidentyfikuje drugiego za pomocą unikalnego identyfikatora na serwerze, zostanie on dostarczony z IP klienta drugiego: informacja o porcie UDP dziurkuje dane, które musi wysłać i odebrać.

Mała aktualizacja:

Jest biblioteka to pokazuje się na horyzoncie dla Javy sprawdź to:
https://github.com/htwg/UCE#readme

Author: MatBanik, 2012-03-11

4 answers

Ten przykład jest w C#, a nie w Javie, ale pojęcia NAT traversal są agnostyczne.

Zobacz bibliotekę sieciową Michaela Lidgrena, która ma wbudowany NAT traversal.

Link: http://code.google.com/p/lidgren-network-gen3 / Specyficzny plik C# obsługujący Nat: http://code.google.com/p/lidgren-network-gen3/source/browse/trunk/Lidgren.Network/NetNatIntroduction.cs

Proces, który opublikowałeś, jest prawidłowy. Będzie działać, bo tylko 3 z 4 typĂłw urzÄ ... dzeĹ " nat (mĂłwiÄ ™ ogăłlnie, poniewaĹź zachowanie NAT nie jest tak naprawdÄ ™ standaryzowane): Full-Cone NATs, Restricted-Cone NATs i Port-Restricted-Cone NATs. NAT traversal nie będzie działać z symetrycznymi Nat, które znajdują się głównie w sieciach korporacyjnych w celu zwiększenia bezpieczeństwa. JeĹ "li jedna strona uĹźywa symetrycznego NAT, a druga nie, moĹźliwe jest przeĹ' Ä ... czenie NAT, ale wymaga to wiÄ ™ cej domysĺ ' Ăłw. Symetrycznego nat do symetrycznego NAT jest niezwykle trudne- możesz przeczytać artykuł o tym tutaj .

Ale tak naprawdę, proces, który opisałeś działa dokładnie. Zaimplementowałem go dla mojego własnego programu do zdalnego udostępniania ekranu (również w C#, niestety). Upewnij się tylko, że została wyłączona Zapora systemu Windows (jeśli używasz systemu Windows) i zapory innych firm. Ale tak, mogę z radością potwierdzić, że to zadziała.

Wyjaśnienie procesu Trawersacji NAT

Piszę tę aktualizację, aby wyjaśnić proces trawersowania NAT dla Ciebie i przyszłych czytelników. Mam nadzieję, że może to być jasne podsumowanie historii i procesu.

Niektóre źródła odniesienia: http://think-like-a-computer.com/2011/09/16/types-of-nat / i http://en.wikipedia.org/wiki/Network_address_translation, http://en.wikipedia.org/wiki/IPv4, http://en.wikipedia.org/wiki/IPv4_address_exhaustion .

Adresy IPv4, z możliwością unikalnej nazwy w przybliżeniu Skończyły się 4,3 miliarda komputerów. Inteligentni ludzie przewidzieli ten problem, a między innymi wynaleźli routery do walki z wyczerpaniem adresu IPv4, przypisując sieci komputerów podłączonych do siebie 1 wspólny adres IP.

Istnieją IP sieci LAN. I jeszcze Wan IPs. Lan IPs to adresy IP sieci lokalnej, które jednoznacznie identyfikują komputery w sieci lokalnej, np. komputery stacjonarne, laptopy, drukarki i smartfony podłączone do domowego routera. Wan IPs jednoznacznie identyfikuje Komputery poza siecią lokalną w sieci rozległej-potocznie rozumianej jako Internet. Więc te routery przypisać grupę komputerów 1 WAN IP. Każdy komputer nadal ma swój własny LAN IP. Adresy IP sieci LAN są tym, co widzisz po wpisaniu ipconfig w wierszu polecenia i pobraniu IPv4 Address . . . . . . . . 192.168.1.101. Adresy IP WAN są tym, co widzisz, gdy łączysz się z cmyip.com i otrzymujesz 128.120.196.204.

Tak jak widmo radiowe jest wykupione , tak całe zakresy IP są wykupione i zarezerwowane przez Agencje i organizacje, oraz numery portów . Krótka wiadomość jest taka, że nie mamy więcej adresów IPv4 do oszczędzania.

Co to ma wspólnego z NAT traversal? Cóż, odkąd wynaleziono routery, połączenia bezpośrednie ([73]}łączność end-to-end ) były nieco ... niemożliwe, bez kilku hacków. Jeśli posiadasz sieć 2 komputerów (komputer A i komputer B), oba współdzielące adres IP WAN 128.120.196.204, do którego komputera następuje połączenie? Mówię o zewnętrznym komputer (powiedzmy google.com) inicjowanie połączenia z 128.120.196.204. Odpowiedź brzmi: nikt nie wie , podobnie jak router, dlatego Router zrywa połączenie. Jeśli komputer a zainicjuje połączenie z, powiedzmy, google.com, to jest inna historia. Router zapamiętuje, że komputer A Z LAN IP 192.168.1.101 zainicjował połączenie z 74.125.227.64 (google.com w związku z tym, że pakiet żądania komputera A opuszcza router, router w rzeczywistości zapisuje ponownie LAN IP 192.168.1.101 do adres IP WAN routera 128.120.196.204. Więc, kiedy google.com odbiera pakiet żądania komputera A, widzi adres IP nadawcy, który router przepisał ponownie, a nie IP LAN komputera A (google.com widzi 128.120.196.204 jako IP, na które należy odpowiedzieć). Kiedy google.com w końcu odpowiada, pakiet dociera do routera, router zapamiętuje (posiada tabelę Stanów), że oczekuje odpowiedzi od google.com i odpowiednio przekazuje pakiet do komputera A.

Innymi słowy, twój router nie ma problemu, gdy ty zainicjuj połączenie-twój router będzie pamiętał o przesłaniu odpowiadającego pakietu z powrotem do twojego komputera (przez cały proces opisany powyżej). Jednak gdy zewnętrzny serwer inicjuje połączenie z Tobą, router nie może wiedzieć, do którego komputera było przeznaczone połączenie, ponieważ komputer A i komputer B mają wspólny adres IP WAN 128.120.196.204 ... chyba, że istnieje jasna reguła nakazująca routerowi przesyłanie wszystkich pakietów pierwotnie udających się do portu docelowego X, teraz, aby przejść do komputera a, port docelowy Y. Jest to znane jako przekierowanie portów . Niestety, jeśli myślisz o wykorzystaniu przekierowania portów do aplikacji sieciowych, nie jest to praktyczne, ponieważ użytkownicy mogą nie rozumieć, jak je włączyć, i mogą być niechętni włączeniu go, jeśli uważają, że stanowi to zagrożenie bezpieczeństwa. UPnP to po prostu technologia, która pozwala programowo włączyć przekierowanie portów. Niestety, jeśli myślisz o użyciu UPnP aby przenieść swoje aplikacje sieciowe, nie jest to również praktyczne, ponieważ UPnP nie zawsze jest dostępny, a gdy jest, może nie być włączony domyślnie.

Więc jakie jest rozwiązanie? Rozwiązaniem jest albo proxy cały ruch na własnym komputerze (który starannie wstępnie skonfigurowany, aby był dostępny globalnie), lub wymyślić sposób na pokonanie systemu. Pierwsze rozwiązanie nazywa się (jak sądzę) TURN i magicznie rozwiązuje wszystkie problemy z łącznością w Cena dostarczenia farmy serwerów z dostępną przepustowością. Drugie rozwiązanie nazywa się NAT traversal i to właśnie będziemy badać dalej.

Wcześniej opisałem proces zewnętrznego serwera (powiedzmy google.com) inicjowanie połączenia z 128.120.196.204. Powiedziałem, że bez routera mającego określone zasady, aby zrozumieć, który komputer przekazać żądanie połączenia google, router po prostu upuści połączenie. Był to scenariusz uogólniony i nie jest dokładny ponieważ istnieją różne rodzaje natów. (Uwaga: router to rzeczywiste urządzenie fizyczne, które można upuścić na podłogę. Nat (ang. Network Address Translation) to proces programowy zaprogramowany do routera, który pomaga zapisywać adresy IPv4, takie jak drzewa). Tak więc, w zależności od jakiego NAT używa router, scenariusze połączeń są różne. Router może nawet łączyć procesy NAT.

Istnieją cztery typy Nat o standaryzowanym zachowaniu: Nat pełny-Stożek, Nat Ograniczony-Stożek, Naty stożkowe z ograniczeniem portów i Naty symetryczne. Oprócz tych typów, mogą istnieć inne typy Nat o niestandardowym zachowaniu, ale jest to rzadsze.

Uwaga: nie jestem zbyt zaznajomiony z NATs...it wydaje się, że istnieje wiele sposobów patrzenia na routery, a informacje w Internecie są bardzo rozłożone na ten temat. Klasyfikowanie natów według pełnych, ograniczonych i ograniczonych portów zostało nieco przestarzałe, mówi Wikipedia? Jest coś, co nazywa się statyczne i dynamiczne NATs...tylko kilka różnych pojęć, których nie mogę pogodzić. Niemniej jednak poniższy model pracował dla mojej własnej aplikacji. Możesz dowiedzieć się więcej o NATs, czytając linki poniżej i powyżej oraz w całym tym poście. Nie mogę pisać więcej o nich, ponieważ nie bardzo rozumiem o nich.

Mając nadzieję, że niektórzy Guru sieci poprawią / dodają dane wejściowe, abyśmy wszyscy mogli dowiedzieć się więcej o tym tajemniczym procesie.

Aby odpowiedzieć na twoje pytanie o pobieranie zewnętrznego IP i portu każdego klienta:

Nagłówki wszystkich pakietów UDP mają taką samą strukturę Z jednym źródłowym IP i jednym źródłowym portem. nagłówki pakietów UDP nie zawierają "wewnętrznego" i "zewnętrznego" adresu IP. Nagłówki pakietów UDP zawierają tylko jeden źródłowy adres IP. Jeśli chcesz uzyskać" wewnętrzny "i" zewnętrzny " adres IP źródła, musisz wysłać wewnętrzny adres IP źródła jako część ładunku. ale to nie brzmi jakbyś potrzebował wewnętrznego adresu IP i portu. Wygląda na to, że potrzebujesz tylko zewnętrznego adresu IP i portu, zgodnie z twoim pytaniem. Co oznacza, że Twoje rozwiązanie to po prostu odczytać źródłowy adres IP i port poza pakietem, jak pola, które są.

Dwa scenariusze poniżej (tak naprawdę nie wyjaśniają niczego innego):

Komunikacja LAN

Komputer A ma IP LAN 192.168.1.101. Komputer B posiada IP LAN 192.168.1.102. Komputer a wysyła pakiet, z portu 3000, do komputera B na porcie 6000. Źródłowy adres IP pakietu UDP to 192.168.1.101. I to będzie jedyne IP. "Zewnętrzna" nie ma tu żadnego kontekstu, ponieważ sieć jest wyłącznie siecią lokalną. W tym przykładzie sieć rozległa (taka jak Internet) nie istnieje. Jeśli chodzi o porty, ponieważ nie jestem pewien NATs, nie jestem pewien, czy port wpisany na pakiecie będzie wynosił 3000. UrzÄ ... dzenie NAT moĹźe ponownie zapisaÄ ‡ Port pakietu z 3000 do czegoĹ "przypadkowego, na przykĹ' ad 49826. Tak czy siak, ty powinieneś użyć dowolnego portu wpisanego na pakiecie do odpowiedzi - to jest to, czego powinieneś użyć do odpowiedzi. Tak więc w tym przykładzie komunikacji LAN, trzeba wysłać tylko jeden adres IP - LAN IP, ponieważ tylko to się liczy. Nie musisz się martwić o port - router zadba o to za Ciebie. Kiedy otrzymasz pakiet, zbierasz tylko IP i port po prostu odczytując go z pakietu.

Komunikacja WAN

Komputer A ma IP LAN, znowu, z 192.168.1.101. Komputer B ma IP LAN 192.168.1.102. Zarówno komputer A, jak i komputer B będą miały adres IP WAN 128.120.196.204. Serwer s to serwer, globalnie dostępny komputer na, powiedzmy, serwerze Amazon EC2, z IP WAN 1.1.1.1. Serwer S może mieć IP LAN, ale to nieistotne. Komputer B też jest nieistotny.

Komputer a wysyła pakiet z portu 3000 do serwera S. Po wyjściu z routera, źródłowy adres IP pakietu LAN z komputera A zostaje ponownie zapisany do IP WAN routera. Router ponownie zapisuje również port źródłowy od 300 do 32981. Co serwer widzi pod względem zewnętrznego IP i portu? Serwer s widzi 128.120.196.204 jako IP, a nie 192.168.1.101, a serwer s widzi 32981 jako port, a nie 3000. Chociaż nie są to oryginalne adresy IP i porty komputera a używane do wysyłania pakietu, są to poprawne adresy IP i porty, na które należy odpowiedzieć. Gdy otrzymasz pakiet, możesz znać tylko adres IP WAN i Port przepisany. Jeśli tego chcesz (prosiłeś o tylko zewnętrzny IP i port), wtedy jesteś ustawiony. W przeciwnym razie, jeśli chcesz również wewnętrzny adres IP nadawcy, musisz przesłać to jako normalne dane oddzielić od nagłówka.

Kod:

Jak napisano PowyĹźej (poniĹźej aby odpowiedzieÄ ‡ na twoje pytanie o zbieraniu zewnÄ ™ trznego IP), aby zebraÄ ‡ zewnÄ ™ trzny IP i Port kaĹźdego klienta, po prostu odczytasz je z pakietu. Każdy wysyłany datagram zawsze mA źródło IP i port źródłowy nadawcy; nie potrzebujesz nawet wymyślnego niestandardowego protokołu, ponieważ te dwa pola są zawsze włączone - każdy pojedynczy pakiet UDP musi z definicji mieć te dwa pola.

// Java language
// Buffer for receiving incoming data
byte[] inboundDatagramBuffer = new byte[1024];
DatagramPacket inboundDatagram = new DatagramPacket(inboundDatagramBuffer, inboundDatagramBuffer.length);
// Source IP address
InetAddress sourceAddress = inboundDatagram.getAddress();
// Source port
int sourcePort = inboundDatagram.getPort();
// Actually receive the datagram
socket.receive(inboundDatagram);

Ponieważ getAddress() i getPort() mogą zwracać port docelowy lub źródłowy, w zależności od tego, na maszynie klienckiej (wysyłającej) wywołaj setAddress() i setPort() do maszyny serwerowej (odbierającej), a na maszynie serwerowej (odbierającej) wywołaj setAddress() i setPort() z powrotem do klienta maszyna. Musi być na to sposób w receive(). Proszę rozwinąć, jeśli to (getAddress() i getPort() nie zwracają źródłowego IP i portu, którego oczekujesz)jest twoją faktyczną blokadą. Zakłada się, że serwer jest" standardowym " serwerem UDP(nie jest to serwer STUN).

Dalsza Aktualizacja:

Przeczytałem twój update o " jak używać STUN aby odebrać IP i port od jednego klienta i przekazać go drugiemu "? Serwer STUN nie jest przeznaczony do wymiany punktów końcowych lub wykonaj NAT traversal. Serwer STUN jest zaprojektowany tak, aby informował o Twoim publicznym IP, porcie publicznym i typie urządzenia NAT (niezależnie od tego, czy jest to Pełny Nat stożkowy, Ograniczony Nat stożkowy, czy Ograniczony Nat stożkowy). Serwer pośredniczący odpowiedzialny za wymianę punktów końcowych i przeprowadzanie rzeczywistego przejścia NAT nazwałbym "introducer". W moim osobistym projekcie , nie muszę używać STUN do wykonywania nat traversingu. Mój "introducer" (serwer pośredniczący, który wprowadza klientów A i B) to standardowy serwer nasłuchujący datagramów UDP. Ponieważ zarówno klienci A, jak i B rejestrują się u wprowadzającego, wprowadzający odczytuje ich publiczny adres IP oraz port i prywatny adres IP (w przypadku, gdy są w sieci LAN). Publiczny adres IP jest odczytywany z nagłówka datagramu, tak jak dla wszystkich standardowych datagramów UDP. Prywatny adres IP jest zapisywany jako część ładunku datagramowego, a wprowadzający odczytuje go jako część ładunku. Jeśli chodzi o użyteczność STUN, nie musisz polegać na STUN, aby uzyskać publiczne IP i publiczne port każdego klienta - każde podłączone gniazdo może Ci to powiedzieć. Powiedziałbym, że STUN jest użyteczny tylko do określenia jakiego typu urządzenia NAT znajduje się twój klient, aby wiedzieć, czy wykonać przemieszczenie NAT (jeśli typ urządzenia NAT jest typu Full-Cone, Restricted lub port-Restricted), czy też wykonać proxy all-out turn traffic (jeśli typ urządzenia NAT jest symetryczny).

Proszę rozwinąć swoją blokadę: jeśli chcesz porady na temat najlepszych praktyk projektowania protokołu komunikacyjnego aplikacji, i porady dotyczące czytania pól z otrzymanych wiadomości w sposób uporządkowany i systematyczny (na podstawie komentarza, który zamieściłeś poniżej), Czy mógłbyś podzielić się swoją obecną metodą?

 52
Author: Jason,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-29 12:04:20

Twoje pytanie jest naprawdę szerokie - nie mogę podać przykładu, ale poniższe linki mogą pomóc (specyfikacje, biblioteki, próbki itp.):

 10
Author: Yahia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-21 12:00:53

STUN działa w następujący sposób: twój Klient za firewallem łączy się z serwerem STUN poza firewallem. Serwer STUN sprawdza pakiet otrzymany od klienta i wysyła klientowi odpowiedź z powrotem zawierającą IP i port klienta, które pojawiają się na serwerze STUN.

W ten sposób klient za firewallem odkrywa swój własny zewnętrzny adres IP i port. Z tego co wiem serwer STUN normalnie nie przekazuje danych adresowych z jednego klienta do drugiego.

Zazwyczaj STUN jest używany do konfigurowania strumieni multimedialnych przez zapory sieciowe, gdy zapora sieciowa jest już otwarta na sygnalizację ruchu-np. w VoIP: klient kontaktuje się z serwerem STUN, aby odkryć swój zewnętrzny adres IP i port dla ruchu UDP, następnie wysyła swoje żądanie sygnalizacji (zaproszenie SIP lub cokolwiek innego) do innego klienta na dobrze znanym otwartym porcie - włączając w to informacje o jego zewnętrznym adresie UDP w ładunku (SDP lub cokolwiek innego). Więc generalnie jeden klient musi być osiągalny przez otwarty port dla sygnalizacja dla komunikacji peer-to-peer.

 6
Author: vladimir e.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-20 11:16:49

Twój problem nie jest związany z Javą. Jeśli wiesz, jak otworzyć połączenie UDP, to wystarczy. Przeczytaj treść poniższego linku . Nie bój się tytułu, dotyczy on również UDP. Reszta to tylko kodowanie w Javie.

P. S.: w Twoim scenariuszu brakuje kroku. Zarówno A, jak i B muszą mieć otwarte połączenie z S, ponieważ S musi powiedzieć B, że A próbuje do niego dotrzeć. Jeśli B nie ma otwartego połączenia z S, nie ma możliwości, aby A i B mogły zacząć się komunikować razem.

UPDATE

Odpowiedź Jasona zawiera błędy i dzikie spekulacje na temat NAT traversal. Należy przeczytać pracę wykonaną przez Saikat Guha (mpi-sws.org / ~ francis / imc05-tcpnat.pdf) aby naprawdę zrozumieć tę sprawę. Klasyfikacja stożkowa Wikipedii jest całkowicie przestarzała i wprowadzająca w błąd.

 6
Author: Jérôme Verstrynge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-21 23:39:41