Az Android VpnService-ének nincs kizárási útvonala, és az API olvasása semmilyen mennyiségben nem hoz létre egyet. A Builder.addRoute() mindig csak célpontokat ad az alagúthoz, ezért egy LAN-szegmens helyben tartása azt jelenti, hogy az a szegmens soha nem kerül be az útvonallistába. Amit helyette hozzáadsz, az a szegmens komplementere, közönséges előtagokkal kifejezve. A munka aritmetika, és néhány kiszámítható helyen elbukik.

Az alábbi ellenőrzéseket sorrendben hajtsd végre. Mindegyik feltételezi, hogy az előző tartotta magát, ezért az első hibánál állj meg, ahelyett hogy lejjebb foltoznád a tüneteket.

Kezdd azzal, amit az alagút állít

A 0.0.0.0/0 átadása a addRoute()-nek azt mondja az Androidnak, hogy minden IPv4-cél az alagúthoz tartozik. Ezért tűnik olyan sok kliens képtelennek az osztott alagutazásra: igénylik a teljes címteret, majd megpróbálnak belőle kivonni. A szerkesztőben semmi nem von ki. Egy konkrétabb útvonal ahhoz a hálózathoz, amelyet helyben akartál tartani, az elvárttal ellentétes hatást ad, mert a leghosszabb egyező előtag nyer, és az a hálózat az alagút belsejébe kerül.

Az útvonallista maga a teljes szabályzat. Nincs mögötte célonkénti vétó, és a Builder-referencia nem sorol fel olyan metódust, amely ilyet biztosítana.

Állítsd elő a komplementert előtag-aritmetikával

Egy kizárt előtag komplementere a testvéreinek halmaza a címfa gyökeréhez vezető úton. Minden hosszra 1-től a kizárt hosszig vedd az adott hosszúságú blokkot, amely tartalmazza az előtagodat, fordítsd meg az előtag alatti bitet, és add ki az eredményt. Addig tűnik elvontnak, amíg le nem futtatod.

A 10.0.0.0/8 kizárása nyolc útvonalat ad: 128.0.0.0/1, 64.0.0.0/2, 32.0.0.0/3, 16.0.0.0/4, 0.0.0.0/5, 12.0.0.0/6, 8.0.0.0/7, 11.0.0.0/8. Egyik sem tartalmazza a 10.0.0.0/8-t, és együtt minden mást lefednek.

Nyolc sor állítja elő ezt a listát bármely előtaghoz:

import ipaddress
def complement(addr, length):
    base = int(ipaddress.IPv4Address(addr))
    out = []
    for k in range(1, length + 1):
        block = base & (0xFFFFFFFF << (32 - k))
        sibling = block ^ (1 << (32 - k))
        out.append(f"{ipaddress.IPv4Address(sibling)}/{k}")
    return out
print(complement("10.0.0.0", 8))

Az útvonalak száma megegyezik az előtag hosszával, és ez az a szám, amelyet figyelni kell. Egyetlen /21 kizárás 21 útvonalba kerül, és olvasható marad. Tíz kizárás néhány százba kerülhet, ami általában azt jelenti, hogy a hálózati tervet kell megváltoztatni, nem a generátort.

Ellenőrizd a címcsaládot és az alagút hatókörét

Az IPv4-útvonalak semmit nem tesznek az IPv6-ért. Ha az alagút IPv6-címet igényel, az IPv6 LAN-előtagnak saját komplementerre van szüksége, ugyanazzal az aritmetikával 128 bit felett előállítva. Gyakori oka annak, hogy a kizárás papíron működik, miközben a helyi eszköz elérhetetlen marad, ez: a hosztot IPv6-on keresztül érték el, és csak az IPv4-et vágták ki. Ellenőrizd mindkét családot, mielőtt arra jutsz, hogy a matematika hibás.

A hatókör az ellenőrzés másik fele. Az Android hálózatonként és alkalmazásonként követi az útválasztást, ezért ugyanaz az előtag az egyik alkalmazásnak alagúton mehet, a másiknak közvetlenül, attól függően, hogyan lett a VPN deklarálva.

Tedd a DNS- és alkalmazásonkénti szabályokat oda, ahová tartoznak

Az útvonalkizárások nem változtatják meg a feloldót. Egy helyi hosztnevet továbbra is az alagút DNS-kiszolgálója válaszolhat meg, miközben a címe helyben útválasztódik, és az eltérés úgy jelenik meg, mint egy név, amely olyasmire oldódik fel, amit a LAN nem tud elérni. Állítsd be a feloldó szabályzatát szándékosan, keresési domainnel vagy osztott DNS-szabállyal. Ne feltételezd, hogy az útvonalak döntöttek helyetted.

A addDisallowedApplication() egy alkalmazást kint tart az alagútból; nem tart kint egy célpontot a bent maradó alkalmazások számára. A protect() engedi, hogy a megnyitott socket megkerülje az alagutat, és így az alagút elkerüli a saját forgalmának elkapását. Egyik sem helyettesíti a komplementert.

Kereséssel ellenőrizz, ne a saját listáddal

Amikor az alagút feláll, kérdezd meg az eszközt, hová megy valójában egy cím, ahelyett hogy újraolvasnád az általad épített listát. Egy iproute2-t szállító builden a adb shell ip route get 10.1.2.3 megnevezi a kernel által választott interfészt. Futtasd ugyanezt a parancsot egy nyilvános címre, és igazold, hogy az alagutat nevezi meg.

Két további ellenőrzés zárja a kört. Először oldj fel egy helyi nevet, majd futtasd a adb shell ip route get-et a feloldott címen, és követelj olyan interfészt, amely nem az alagút, mert egy sikeres adb shell ping -c 1 host.lan elérhetőséget bizonyít, nem az útvonalat. Ismételd meg a címcsalád-tesztet IPv6 felett, ha az alagút ilyet igényel. A szállított API-szinten tesztelj, mert az, ahogyan a VPN-hálózatok a forgalomirányítási táblához kerülnek, kiadások között változott. Egy papíron jónak tűnő útvonallista és egy rossz interfészt választó keresés különböző hibák, és csak a második ér el a felhasználókhoz.

Ha a kizárási lista tovább nő, hagyd abba az útvonalak generálását, és számozd újra a távoli hálózatot, vagy szűkítsd az alagutat helyette. A generátor a hiányzó API kerülőútja, nem tervezőeszköz.

Kapcsolódó cikkek