IPIP w WireGuardzie: te dodatkowe 20 bajtów, których nikt nie uwzględnił w budżecie
IPIP kosztuje 20 bajtów więcej wewnątrz WireGuarda. Zrób budżet na właściwej warstwie, zanim obwinisz fragmentację za zatrzymany transfer na żywym tunelu.
Małe pingi przechodzą przez tunel cały dzień, pojawia się baner SSH, a potem sesja zamarza w chwili, gdy zaczyna się transfer pliku. Ten wzorzec wskazuje na budżet bajtów liczony na niewłaściwej warstwie, gdzie tunel zewnętrzny został zwymiarowany pod własny narzut, a nikt nie odjął wewnętrznego. Zagnieżdżony pakiet IPIP jest dla WireGuarda po prostu kolejnym pakietem IP, i właśnie dlatego zużywa bajty, których nigdy nie zarezerwowałeś. Poprawka jest arytmetyką i mieści się w trzech poleceniach oraz jednej tabeli.
Objaw, który to zdradza
Problemy z fragmentacją ogłaszają się rozmiarem, nigdy adresami. Twój peer odpowiada przez godzinę na ping o rozmiarze 56 bajtów, a potem milknie przy 1400 bajtach, podczas gdy tunel pozostaje podniesiony i żadna trasa się nie zmieniła. Uścisk dłoni się mieści, pierwsze pełne okno TCP nie, a transfer zatrzymuje się kilka sekund po tym, jak wyglądał zdrowo.
Zmierz sufit, zanim cokolwiek edytujesz, bo niezmierzony sufit to ten, którego będziesz gonić dwa razy. Wyślij jedną sondę poniżej podejrzanego rozmiaru z ustawionym bitem do-not-fragment, ping -M do -s 1000 10.9.0.2, a potem powtórz ją przy rozmiarze, o którym już wiesz, że jest za duży. Kiedy odwrócenie podąża za rozmiarem ładunku, a cel pozostaje niezmieniony, routing robi swoje i w budżecie brakuje jednego nagłówka.
Policz każdy nagłówek raz, na właściwej warstwie
Zacznij od najmniejszego MTU na ścieżce, a nie od interfejsu tunelu, bo ściana znajduje się powyżej obu końców. WireGuard wydaje 60 bajtów na zewnętrzny transport IPv4: 20 na IP, 8 na UDP i 32 na własny nagłówek, a 80 bajtów, gdy ten transport to IPv6. wg0 o rozmiarze 1420 bajtów zachowuje 20 bajtów zapasu poniżej 1440, które ścieżka 1500 bajtów naprawdę może dostarczyć, i dlatego liczba skopiowana z wiki wciąż tu pasuje. Narysuj cały stos na diagramie, bo kto następny zmieni MTU, inaczej wybierze nową okrągłą liczbę i odziedziczy twój błąd.
| Layer | Bytes | Remaining |
|---|---|---|
| Path MTU on the wired link | none yet | 1500 |
| WireGuard outer: IP, UDP, WG header | 60 | 1440 |
| Slack kept for safety | 20 | 1420 (wg0) |
| IPIP header inside the tunnel | 20 | 1400 (ipip0) |
| Original IPv4 and TCP headers | 40 | 1360 payload |
Piąty wiersz to miejsce, w którym budżety się psują, bo 1400 bajtów, które niesie zagnieżdżony interfejs, zawiera już własne 40 bajtów nagłówków oryginalnego pakietu. Do procesu czytającego plik dociera tylko 1360 z tych bajtów. Traktuj 1400 jako ładunek aplikacji, do czego zaprasza każdy diagram bez tej kolumny, a wewnętrzne urządzenie kończy o 40 bajtów zbyt hojnie wobec ściany, która się nie przesunęła.
Ustaw oba MTU osobno
Nośnik i zagnieżdżone urządzenie to osobne obiekty, więc każde potrzebuje własnej wartości. Zastosuj je w tej kolejności, bo zagnieżdżone urządzenie niczego nie dziedziczy po nośniku:
ip link set wg0 mtu 1420
ip tunnel add ipip0 mode ipip remote 203.0.113.9 local 198.51.100.4
ip link set ipip0 mtu 1400
Zasada warta zapamiętania: wewnętrzne MTU = zewnętrzne MTU - 20, gdy pakiet niesiony przez tunel IPIP jest IPv4, i - 40, gdy tylko którakolwiek strona wewnętrznego pakietu jest IPv6, bo zagnieżdżony nagłówek rośnie z 20 bajtów do 40. Nic innego nie należy do tego odejmowania. Narzut WireGuarda został już wydany, gdy wybrałeś 1420, a naliczanie go dwa razy daje tunel, który działa doskonale i pozostaje wolny, dopóki nikt go nie mierzy. Wdrożenie, w którym oba urządzenia noszą okrągłe 1400, jest odciskiem palca właśnie tego błędu.
IPv6 po którejkolwiek stronie zagnieżdżonego pakietu unieważnia każdą liczbę powyżej, więc przelicz ponownie, zamiast kopiować liczbę z podobnej strony. Odejmowane nagłówki mają po 40 bajtów, gdy tylko IPv6 pojawi się na zewnętrznej ścieżce lub w oryginalnym datagramie, a liczba ładunku spada dokładnie o tyle.
Reguła firewalla, której prawdopodobnie nie potrzebujesz
Między dwoma peerami WireGuarda jedyną rzeczą na drucie jest UDP, więc reguła przychodząca dla protokołu 4, numeru, który RFC 2003 przypisuje enkapsulacji IPv4-w-IPv4, ani nie tworzy zagnieżdżonej ścieżki, ani nie utrzymuje jej przy życiu. Nagłówek IPIP żyje wewnątrz zaszyfrowanego ładunku, gdzie żaden firewall brzegowy go nie widzi. Otwarcie protokołu 4 i tak nic nie kupuje poza jedną dodatkową dozwoloną drogą do hosta.
Polityka, która wymienia źródła i cele oryginalnego pakietu, należy po dekapulacji, na interfejsach tunelu i w tabeli routingu. Umieść ją tam, a reguła brzegowa może pozostać zamknięta.
Co WireGuard faktycznie waliduje
AllowedIPs ocenia źródło pakietu, który niesie WireGuard, a niesie on pakiet enkapsulowany w IPIP. Dozwolone źródło IPIP jest akceptowane nawet wtedy, gdy wewnętrzny nagłówek wskazuje hosta, do którego wolisz nie routować. Oryginalne źródło nie jest więc tym, co peer sprawdził za ciebie, a ta wewnętrzna para adresów wymaga własnego egzekwowania po dekapulacji.
Otoczka dostarcza strukturę routingu, a nie drugą warstwę kryptografii. Nazywanie IPIP dodatkową ochroną wewnątrz WireGuarda opisuje inny projekt.
Weryfikuj drabiną, a nie jednym pingiem
Sprawdź rozmiary obejmujące obliczoną granicę, a potem potwierdź, co jądro sądzi o obu urządzeniach. Gdy 1360 bajtów ładunku plus 40 bajtów nagłówków daje 1400, pierwsze echo poniżej mieści się, a drugie siedzi jeden bajt za sufitem:
ping -M do -s 1372 10.9.0.2
ping -M do -s 1373 10.9.0.2
wg show wg0
ip -d link show ipip0
Czyste przejście pod sufitem i porażka przy pierwszym rozmiarze powyżej niego oznaczają, że arytmetyka trzyma się od początku do końca. Potem uruchom ponownie transfer, który pierwotnie się zatrzymał, bo syntetyczna sonda dowodzi budżetu i nic nie mówi o własnych rozmiarach zapisu nadawcy. Jeśli zagnieżdżona ścieżka nadal pęka przy rozmiarze, który udowodniłeś, że się mieści, sprawdź dekapulację i trasy drugiego końca, zanim odetniesz kolejne dziesięć bajtów od MTU.