Trasa dodana do tabeli main w Androidzie wygląda poprawnie w każdym zestawieniu i mimo to nie przenosi ruchu. Powód jest taki, że tabela main jest tylko jedną z kilku opcji i nie jest pytana jako pierwsza. Usługa sieciowa Androida buduje reguły polityki, które wybierają tabelę routingu na podstawie informacji, których adres docelowy nie zawiera — uid aplikacji, znacznik na pakiecie, interfejs, na którym pakiet przyszedł — a wyszukanie trasy do celu odbywa się później, wewnątrz tabeli wybranej przez te reguły.

Trzy decyzje w ustalonej kolejności

Pakiet wychodzący podejmuje trzy odrębne decyzje. Po pierwsze, reguła polityki rozstrzyga, której tabeli routingu użyć. Po drugie, trasa w tej tabeli wyznacza następny skok i interfejs wyjściowy. Po trzecie, haki netfilter decydują, czy pakiet przetrwa, zostanie zmieniony czy przekierowany.

Kolejność ma znaczenie, bo każdy etap odpowiada tylko na własne pytanie. Reguła firewalla, która akceptuje pakiet, nie wybiera tabeli, a trasa dodana do tabeli, której nie wybiera żadna reguła, jest bezużyteczna. Duża część zamieszania wokół VPN-ów na Androidzie bierze się z naprawiania jednej z trzech rzeczy i braku widocznej zmiany, bo usterka była w innej.

StageSelectorWhat it cannot decide
Policy ruleuid range, mark, incoming interfaceWhich route exists inside the table
Route lookupDestination prefix, longest matchWhether the packet is allowed out
Netfilter hookChain position, match conditionsWhich table was selected

Znaczniki to upakowane pole, a nie etykieta, którą posiadasz

Android upakowuje kilka faktów w tę samą wartość znacznika: która sieć została wybrana, czy aplikacja jawnie wybrała sieć, czy gniazdo jest chronione przed VPN-em oraz bity związane z uprawnieniami. Nagłówek fwmark w AOSP definiuje ten układ dla bieżącego drzewa, a układ jest wewnętrznym szczegółem platformy, który zmienia się między wydaniami.

Dlatego na Androidzie niebezpieczne jest zapisanie całej wartości znacznika poleceniem iptables -j MARK --set-mark. To nie dodaje etykiety; to zastępuje wybór sieci, którego system już dokonał. Pakiet pasuje wtedy do innych reguł, co może wyglądać, jakby VPN zaczął działać albo jakby niezwiązana aplikacja straciła łączność, zależnie od tego, które bity nadpisano.

Jeśli musisz dotknąć znaczników, najpierw odczytaj bieżącą wartość i użyj maski, aby zmieniały się tylko te bity, które rozumiesz:

ip rule show
ip route show table all | head -40
ip route get 10.20.4.11

Znacznik połączenia jest osobnym obiektem od znacznika pakietu i żaden z nich nie jest trasą. Przywrócenie znacznika na pakietach odpowiedzi to inny krok niż wybór tabeli na wyjściu, dlatego jednostronne poprawki dają połączenia, które się otwierają, a potem zawieszają.

Kto jest właścicielem reguł i tabel

Usługa sieciowa Androida, netd, tworzy reguły i tabele dla poszczególnych sieci. AOSP RouteController jest miejscem, w którym te reguły są składane dla VPN-ów, sieci fizycznych i zakresów uid, a jego cykl życia jest związany ze zdarzeniami sieciowymi, a nie z plikiem konfiguracji.

Wynikają z tego dwie konsekwencje. Po pierwsze, priorytety i numery tabel, które znajdziesz na jednym urządzeniu, są wewnętrznymi szczegółami kompilacji, a nie interfejsem: identycznie wyglądające numery na innej wersji Androida mogą znaczyć zupełnie coś innego. Po drugie, stan jest odbudowywany przy zmianie sieci, więc reguła wstawiona dziś z powłoki root może zniknąć po następnym przełączeniu Wi-Fi.

To zniknięcie bywa zgłaszane jako ignorowanie trasy przez system. W rzeczywistości przestała istnieć reguła, która wybierała tabelę, a trasa wewnątrz tabeli jest teraz nieosiągalna z punktu widzenia pakietu. Sprawdzaj listę reguł, nie listę tras, gdy działająca konfiguracja przestaje działać po ponownym połączeniu.

Pytania o kolejność haków nie mają uniwersalnej odpowiedzi

Pytanie, czy iptables działa przed routingiem VPN, nie ma odpowiedzi bez wskazania ścieżki pakietu. Pakiet wygenerowany lokalnie przechodzi przez hak output, gdzie zmiana znacznika uruchamia ponowne sprawdzenie routingu — drugie wyszukanie, a nie wsteczna edycja pierwszego. Pakiet przychodzący od klienta po tetheringu przechodzi ścieżką prerouting i jest zamiast tego przekazywany dalej, a łańcuchy, które go widzą, są inne.

Ta sama reguła może więc być skuteczna dla ruchu aplikacji i niewidoczna dla ruchu tetheringu, a licznik, który pozostaje na zerze, mówi, którą ścieżką poszedł pakiet, a nie czy reguła jest błędna. Użyj liczników, aby ustalić ścieżkę, zanim zmienisz jakikolwiek warunek dopasowania.

To także etap, na którym błąd routingu polityki staje się trudny do zauważenia. Routing do tabeli, która istnieje, ale nie zawiera celu, daje sieć nieosiągalną, wyglądającą jak odrzucenie przez firewall, podczas gdy odrzucenie przez firewall daje przekroczenie czasu, które wygląda jak czarna dziura routingu.

Diagnozuj wewnątrz systemu albo zostaw go w spokoju

Przy autoryzowanym przeglądzie ustal cztery fakty, zanim czegokolwiek dotkniesz: uid i profil aplikacji, sieć wybraną dla niej przez Androida, czy VPN w ogóle obejmuje tę aplikację oraz czy problem występuje dla obu rodzin adresów. Wykluczenie pojedynczej aplikacji wyjaśnia bardzo wiele zgłoszeń typu VPN nie działa bez żadnej usterki routingu.

Potem odczytaj reguły, maski i tabele, które faktycznie obowiązują, i utrzymaj przełączenie sieci w oknie obserwacji. Jeśli zachowanie zmienia się przy ponownym połączeniu, patrzysz na zarządzany cykl życia, a nie na brakującą trasę.

W zwykłych wymaganiach używaj obsługiwanych mechanizmów: włączanie i wykluczanie poszczególnych aplikacji w aplikacji VPN oraz własnego wyboru sieci przez platformę dla wszystkiego, co wymaga określonej ścieżki. Jeśli uprzywilejowana integracja naprawdę musi współpracować z mechanizmem routingu, celuj w implementację dokładnie tej wersji Androida, którą obsługujesz, i utrzymuj jej cykl życia przez komponent, który nią zarządza. Wyczyszczenie łańcuchów platformy lub wstawienie reguły o wysokim priorytecie zamienia diagnozę w drugiego menedżera sieci, a telefon będzie się zachowywał odpowiednio.

Powiązane artykuły