Technika "hole punching"

0

Cześć, chciałbym skomunikować w Qt dwa klienty między sobą za pomocą gniazd UDP. Jak to bywa, większość komputerów jest za NATem. Do ustanowienia połączenia zamierzam użyć pośredniczącego serwera. Czytałem o technice "hole punching". Rozumiem, że dzięki tej technice, żaden z klientów nie musi nasłuchiwać na jakiś portach, dzięki czemu firewall nie poprosi nas o zgodę na otwarcie portów. Nie wiem jak to zaimplementować i czy będzie to możliwe z poziomu funkcji dostępnych w Qt czy trzeba skorzystać z funkcji niższego poziomu. Mógłbym prosić o wskazówki?

1

Technicznie rzecz ujmując UDP nie nasłuchuje na portach i nie wspiera listen(2), bo jest bezpołączeniowy, a adres (w tym numer portu) można przypisać wywołaniem bind(2) lub np. wysyłając datagram.

Główna trudność sprowadza się do przewidywania numerów portów po translacji. Generalna zasada jest taka, że proste NATy starają się zachować oryginalny numer portu, natomiast w rozwiązaniach klasy CGN mogą być przydzielane małe bloki numerów portów (np. 16) z których następnie są przydzielane konkretne numery portów, a jak się skończą, to przydzielany jest nowy blok, być może nawet z innym "publicznym" adresem IP.

Co do Qt, to ja bym to jednak robił na surowych socketach.

PS. Hole punching jest możliwy także dla TCP i innych protokołów :)

0
Alley Cat napisał(a):

Co do Qt, to ja bym to jednak robił na surowych socketach.

o ile zna język C i umie zaimplementować raw socketa - a jest to bardzo duża dawka wiedzy

co do Qt i protokołu UDP to dość łatwo to zrobić używając klasy QUdpSocket

  1. Tworzy się socket

wysyłanie

  1. wywołuje się funkcję writeDatagram

odbieranie

  1. wywołuje się funkcję readDatagram

to tak ogólnie

ale można też zrobić sobie swój datagram za pomocą klasy QNetworkDatagram

2

Tyle, że to co napisałeś dotyczy implementacji UDP, a główną trudnością w przypadku opisywanym przez OP będzie przewidzenie adresów (wraz z numerami portów) pod które należy wysyłać datagramy.

Generalnie z uwagi na mnogość różnych (mis)konfiguracji może się to nie udać.

0
Alley Cat napisał(a):

Tyle, że to co napisałeś dotyczy implementacji UDP, a główną trudnością w przypadku opisywanym przez OP będzie przewidzenie adresów (wraz z numerami portów) pod które należy wysyłać datagramy.

Generalnie z uwagi na mnogość różnych (mis)konfiguracji może się to nie udać.

nic nie musi przewidywać, w sumie to zależy co chce zrobić ? Ale na 100% będzie musiał sobie zarezerwować do tego celu jeden numer portu. Co do reszty to:

  1. Jeżeli będzie chciał się skomunikować z komputerem 1:1 to wystarczy, że wpisze jego adres IP i port który sobie zarezerwuje
  2. Jeżeli będzie chciał wysłać na adres rozgłoszeniowy tj. 255.255.255.255 - to no problem, może taki wpisać lub może użyć QHostAddress::Broadcast
  3. Co do NAT-a to mam ten sam problem co on :/
2
zkubinski napisał(a):

nic nie musi przewidywać, w sumie to zależy co chce zrobić ?

Jeśli nic nie musi przewidywać, to co byś zrobił chcąc wysłać datagram w takiej sytuacji:

  1. Komputer A ma przypisany adres IP 192.168.1.100 i jest za podwójnym NATem (router SOHO w domu + CGNAT operatora).
  2. Komputer B ma przypisany adres IP 192.168.1.100 i jest za podwójnym NATem (router SOHO w domu + CGNAT operatora).
  3. Chcesz wysłać datagram z komputera A do komputera B.

Na jaki adres powinien wysłać swój datagram komputer A, żeby dotarł do komputera B?

Zauważ, że oba komputery mają identyczną adresację.

0

Od siebie dodam link do jednego ze swoich projektów w Qt. Jest to wielofunkcyjny program, ale ma też możliwość komunikacji po TCP i UDP (przesyłanie obrazu w czasie rzeczywistym). W interfejsie programu jest możliwość testowania komunikacji poprzez zdefiniowane komunikaty tekstowe (one-way test to test komunikatu w jedną stronę, a two-way test to test żądania i odpowiedzi), procedurę ustanawiania takiego połączenia opisałem w rozdziale "Establishing UDP connection". Same gniazda zaimplementowałem w tym nagłówku i w tym pliku. Wykorzystałem to, co oferuje Qt, bez problemu działa na Linux i Windows (testowałem wariant, że jeden komputer był na Linux i drugi na Windows).

Przy komunikacji sieciowej zdarza się, że kilka komunikatów zostanie połączonych w jeden komunikat, a jeden komunikat zostanie podzielony na kilka komunikatów. Ten problem tez jest odpowiednio obsłużony poprzez sprawdzanie wielkości całego komunikatu.

0
Alley Cat napisał(a):
zkubinski napisał(a):

nic nie musi przewidywać, w sumie to zależy co chce zrobić ?

Jeśli nic nie musi przewidywać, to co byś zrobił chcąc wysłać datagram w takiej sytuacji:

  1. Komputer A ma przypisany adres IP 192.168.1.100 i jest za podwójnym NATem (router SOHO w domu + CGNAT operatora).
  2. Komputer B ma przypisany adres IP 192.168.1.100 i jest za podwójnym NATem (router SOHO w domu + CGNAT operatora).
  3. Chcesz wysłać datagram z komputera A do komputera B.

Na jaki adres powinien wysłać swój datagram komputer A, żeby dotarł do komputera B?

Zauważ, że oba komputery mają identyczną adresację.

ZTCW, przede wszystkim musi istnieć serwer, do którego oba komputery mają bezpośredni dostęp. Serwer nasłuchuje i odbiera komunikat od jednego i drugiego komputera (protokół UDP), sam komunikat jednoznacznie wskazuje, który komputer jest który, serwer również odczytuje adres źródłowy komunikatu. Potem serwer do każdego komputera wysyła informację o widzianym przez niego adresie IP drugiego komputera. Od tego momentu wszystkie routery są "przygotowane" i komputery mogą komunikować się ze sobą posługując się adresami otrzymanymi od serwera.

W moim programie LivePic, o którym wspomniałem, bez problemu zrealizowałem dwustronną komunikację pomiędzy dwiema stronami, z których jedna strona była za NAT. Teoretycznie da się zrobić komunikację w sytuacji, w której obie strony są za NAT, ale w praktyce nie mam możliwości zrobić takiej próby.

0
andrzejlisek napisał(a):

W moim programie LivePic, o którym wspomniałem, bez problemu zrealizowałem dwustronną komunikację pomiędzy dwiema stronami, z których jedna strona była za NAT. Teoretycznie da się zrobić komunikację w sytuacji, w której obie strony są za NAT, ale w praktyce nie mam możliwości zrobić takiej próby.

można to zrobić ale pod warunkiem jak masz całkiem niezłe zasoby sprzętowe - czyli stawiasz kilka wirtualnych maszyn z linuchem na pokładzie i robisz na każdej maszynie z linuchem ip forwarding - to tak na pierwszy rzut oka co mi wpadło do głowy ale nie dam gwarancji czy dobrze mówię bo bardzo dawno tym się nie bawiłem

0
andrzejlisek napisał(a):

ZTCW, przede wszystkim musi istnieć serwer, do którego oba komputery mają bezpośredni dostęp. Serwer nasłuchuje i odbiera komunikat od jednego i drugiego komputera (protokół UDP), sam komunikat jednoznacznie wskazuje, który komputer jest który, serwer również odczytuje adres źródłowy komunikatu. Potem serwer do każdego komputera wysyła informację o widzianym przez niego adresie IP drugiego komputera. Od tego momentu wszystkie routery są "przygotowane" i komputery mogą komunikować się ze sobą posługując się adresami otrzymanymi od serwera.

To nie jest takie proste jak Ci się wydaje.

  1. Komputer A ma przypisany adres IP 192.168.1.100 i jest za podwójnym NATem (router SOHO w domu + CGNAT operatora).
  2. Komputer B ma przypisany adres IP 192.168.1.100 i jest za podwójnym NATem (router SOHO w domu + CGNAT operatora).
  3. Pakiety z komputera A docierają do serwera z adresem źródłowym 192.0.2.1.
  4. Pakiety z komputera B docierają do serwera z adresem źródłowym 192.0.2.1.
  5. Chcesz wysłać datagram z komputera A do komputera B.

Na jaki adres powinien wysłać swój datagram komputer A, żeby dotarł do komputera B?

Zauważ, że oba komputery mają identyczną adresację.

W moim programie LivePic, o którym wspomniałem, bez problemu zrealizowałem dwustronną komunikację pomiędzy dwiema stronami, z których jedna strona była za NAT. Teoretycznie da się zrobić komunikację w sytuacji, w której obie strony są za NAT, ale w praktyce nie mam możliwości zrobić takiej próby.

W przypadku, gdy tylko adresacja jednej strony podlega natowaniu, to zestawienie komunikacji jest banalne do zrealizowania.

zkubinski napisał(a):

można to zrobić ale pod warunkiem jak masz całkiem niezłe zasoby sprzętowe - czyli stawiasz kilka wirtualnych maszyn z linuchem na pokładzie i robisz na każdej maszynie z linuchem ip forwarding - to tak na pierwszy rzut oka co mi wpadło do głowy ale nie dam gwarancji czy dobrze mówię bo bardzo dawno tym się nie bawiłem

Kolega to chyba hole punching z DDoSem pomylił :(

0
Alley Cat napisał(a):

Na jaki adres powinien wysłać swój datagram komputer A, żeby dotarł do komputera B?

Zauważ, że oba komputery mają identyczną adresację.

Nie wiem, czy tak jest, ale moim zdaniem możliwe są dwa przypadki:

  1. Od strony serwera, pakiet z komputera A ma port 101, pakiet z komputera B ma port 102 (na takie porty komputery wysłały pakiet, żeby było jakieś rozróżnienie). Aby wysłać od A do B, to komputer A musi podać adres docelowy 192.0.2.1:102.
  2. Pakiety z obu komputerów mają ten sam adres źródłowy i ten sam numer portu. W takim przypadku wysłanie z A do B nie jest możliwe, albo możliwe jest pod warunkiem, że do serwera jako ostatni wysłał B. Sam nie wiem, co się stanie, gdyby to serwer wysłał pakiet na adres i port źródłowy, do którego komputera dotrze, bo nie można odróżnić komputerów A i B.

Na pewno musi to działać, bo na przykład na UDP działają wszystkie programy do wideokonferencji pracujące w architekturze P2P. Podobnie, jak popularne niegdyś programy P2P, przy czym w tym przypadku używa się protokołu TCP, jednak pakiety tak samo mają tylko adres IP i port źródłowy i docelowy.

0
Alley Cat napisał(a):

W przypadku, gdy tylko adresacja jednej strony podlega natowaniu, to zestawienie komunikacji jest banalne do zrealizowania.

Załóżmy, że istnieje komputer C, który nie jest za NAT, komputery A i B mają do niego bezpośredni dostęp. Jak sam stwierdzasz, w takim przypadku można zestawić połączenie UDP A<->C i B<->C. W UDP nie ma logicznego połączenia, wysyła się tylko poszczególne pakiety. W takim razie, jeżeli komputer C potrafi skutecznie wysłać pakiet i do A i do B (pytanie czy jest to możliwe w przypadku, gdy A i B mają taki sam adres od strony C), to z tego wynika, że komputery A i B również mogą się wzajemnie komunikować, o ile ich pakiet wyjdzie poza NAT, czyli do tej sieci, w której jest komputer C.

0
andrzejlisek napisał(a):
Alley Cat napisał(a):

Na jaki adres powinien wysłać swój datagram komputer A, żeby dotarł do komputera B?

Zauważ, że oba komputery mają identyczną adresację.

Nie wiem, czy tak jest, ale moim zdaniem możliwe są dwa przypadki:

  1. Od strony serwera, pakiet z komputera A ma port 101, pakiet z komputera B ma port 102 (na takie porty komputery wysłały pakiet, żeby było jakieś rozróżnienie). Aby wysłać od A do B, to komputer A musi podać adres docelowy 192.0.2.1:102.

A skąd CGNAT za którym jest komputer B ma wiedzieć, że pakiety wysłane z komputera A na adres 192.0.2.1:102 ma kierować do komputera B?

  1. Pakiety z obu komputerów mają ten sam adres źródłowy i ten sam numer portu. W takim przypadku wysłanie z A do B nie jest możliwe, albo możliwe jest pod warunkiem, że do serwera jako ostatni wysłał B. Sam nie wiem, co się stanie, gdyby to serwer wysłał pakiet na adres i port źródłowy, do którego komputera dotrze, bo nie można odróżnić komputerów A i B.

Na pewno musi to działać, bo na przykład na UDP działają wszystkie programy do wideokonferencji pracujące w architekturze P2P. Podobnie, jak popularne niegdyś programy P2P, przy czym w tym przypadku używa się protokołu TCP, jednak pakiety tak samo mają tylko adres IP i port źródłowy i docelowy.

To nie jest takie proste, że wystarczy wysyłać pakiety na adres:port, który wcześniej widział jakiś serwer.

1 użytkowników online, w tym zalogowanych: 0, gości: 1