2009-10-24 18 views
46

Aktualnie pracuję nad aplikacją gniazda UDP i muszę wbudować obsługę tak, aby połączenia IPV4 i IPV6 mogły wysyłać pakiety na serwer.Jak obsługiwać połączenia IPv4 i IPv6?

Miałem nadzieję, że ktoś może mi pomóc i wskazać mi właściwy kierunek; większość dokumentacji, którą znalazłem, nie była kompletna. Pomocne byłoby również wskazanie różnic między gniazdami Winsock i BSD.

Z góry dziękuję!

Odpowiedz

72

Najlepszym rozwiązaniem jest utworzenie gniazda serwera IPv6, które może również akceptować połączenia IPv4. Aby to zrobić, utwórz zwykłe gniazdo IPv6, zmień off z opcją gniazda IPV6_V6ONLY, połącz ją z "dowolnym" adresem i zacznij odbierać. Adresy IPv4 będą prezentowane jako adresy IPv6 w formacie IPv4-mapped.

Główna różnica między systemami to, czy IPV6_V6ONLY jest a) dostępna, oraz b) domyślnie włączona lub wyłączona. Domyślnie jest on wyłączony w systemie Linux (tzn. Zezwalając na używanie gniazd z dwoma stosami bez setsockopt) i jest włączony na większości innych systemów.

Ponadto stos IPv6 w systemie Windows XP nie obsługuje tej opcji. W takich przypadkach należy utworzyć dwa oddzielne gniazda serwera i umieścić je w selekcji lub w wielu wątkach.

+1

Dzięki za te informacje, dokładnie to, czego szukałem. – Charles

+7

Powiedzenie, że IPV6_V6ONLY jest domyślnie wyłączone w systemie Linux, jest nieprawidłowe: zależy to od systemu operacyjnego, a nie tylko od jądra. Na przykład w systemie Debian GNU/Linux domyślnie została domyślnie włączona. – bortzmeyer

+1

System operacyjny również domyślnie go wyłącza, ale najlepiej jest zawsze ustawić go jawnie. Lokalny sysadmin mógł mimo wszystko go zmienić. –

6

Interfejs API gniazda jest zarządzany przez specyfikacje RFC IETF i powinien być taki sam na wszystkich platformach, w tym w systemie Windows WRT IPv6.

Dla aplikacji IPv4/IPv6 jest to ALL około getaddrinfo() i getnameinfo(). getaddrinfo jest geniuszem - sprawdza DNS, nazwy portów i możliwości klienta, aby rozwiązać odwieczne pytanie "czy mogę używać IPv4, IPv6 lub obu, aby dotrzeć do określonego miejsca docelowego?" Lub jeśli wybierasz trasę z dwoma stosami i chce, aby zwrócił adresy IPv6 odwzorowane w IPv4, to też to zrobi.

Zapewnia bezpośredni sockaddr * struktury, które mogą być podłączone do bind(), recvfrom(), sendto() i rodziny adresów dla socket() ... W wielu przypadkach oznacza to nie bałagan sockaddr_in(6) struktur wypełnić i czynienia.

Dla implementacji UDP byłbym ostrożny przy ustawianiu gniazd z dwoma stosami lub, bardziej ogólnie, dla wszystkich interfejsów (INADDR_ANY). Klasyczny problem polega na tym, że gdy adresy nie są zablokowane (patrz bind()) dla konkretnych interfejsów, a system ma wiele żądań interfejsów, odpowiedzi mogą być przesyłane z różnych adresów dla komputerów z wieloma adresami w oparciu o kaprysy tabeli routingu systemu operacyjnego, mylące zastosowanie protokoły - w szczególności wszelkie systemy z wymogami uwierzytelniania.

W przypadku implementacji UDP, w których nie występuje problem, lub w przypadku protokołu TCP, gniazda z dwoma stosami mogą zaoszczędzić dużo czasu, gdy IPv * włącza system. Trzeba być ostrożnym, aby nie polegać wyłącznie na dual-stacku, gdzie nie jest to absolutnie konieczne, ponieważ nie ma niedoborów rozsądnych platform (Old Linux, BSD, Windows 2003) wdrożonych ze stosami IPv6, które nie są w stanie obsługiwać podwójnych stosów.

2

Dokumenty RFC tak naprawdę nie określają istnienia opcji gniazda IPV6_V6ONLY, ale jeśli są nieobecne, specyfikacje RFC są dość jasne, że implementacja powinna wyglądać tak, jakby ta opcja była FAŁSZ.

Gdy opcja jest obecna, argumentowałabym, że powinna ona mieć wartość FALSE, ale z przyczyn zgodnych z rozumieniem implementacje BSD i Windows są domyślnie PRAWDA. Istnieje dziwne twierdzenie, że jest to problem związany z bezpieczeństwem, ponieważ nieświadomy programista IPv6 mógł wiązać myślenie, że był wiążący tylko z IN6ADDR_ANY tylko dla IPv6 i przypadkowo akceptował połączenie IPv4, co powodowało problem z bezpieczeństwem. Sądzę, że jest to zarówno naciągany, jak i absurdalny dodatek do niespodzianki dla każdego, kto oczekuje wdrożenia zgodnego z RFC.

W przypadku systemu Windows brak zgodności zwykle nie jest zaskoczeniem. W przypadku BSD jest to w najlepszym wypadku niefortunne.

+3

Standard interfejsu API IPv6, RFC 3493, opisuje IPV6_V6ONLY w sekcji 5.3, jeśli chcesz przeczytać wszystkie szczegóły. – bortzmeyer

3

Grałem z tym pod Windows i wygląda na to, że jest tam problem z zabezpieczeniami, jeśli podłączysz się do adresu pętli zwrotnej, wtedy gniazdo IPv6 jest poprawnie powiązane z [:: 1], ale zmapowane gniazdo IPv4 jest powiązane z INADDR_ANY, więc twoja aplikacja (podobno) bezpieczna tylko lokalnie jest wystawiona na działanie świata.