VpnService v Androidu nemá vylučovací trasu a žádné čtení API ji nevytvoří. Builder.addRoute() vždy jen přidává cíle do tunelu, takže ponechání segmentu LAN lokálně znamená, že se tento segment vůbec nedostane do seznamu tras. Místo toho přidáte doplněk segmentu vyjádřený běžnými prefixy. Práce je aritmetika a selhává na několika předvídatelných místech.

Projděte níže uvedené kontroly v pořadí. Každá předpokládá, že předchozí prošla, takže se zastavte u prvního selhání místo záplatování příznaků níže.

Začněte tím, co tunel tvrdí

Předání 0.0.0.0/0 do addRoute() říká Androidu, že každý cíl IPv4 patří tunelu. Proto tolik klientů vypadá neschopně pro rozdělené tunelování: nárokují si celý adresní prostor a pak se z něj snaží odečítat. Nic v konstruktéru neodečítá. Konkrétnější trasa pro síť, kterou jste chtěli ponechat lokální, dělá opak očekávání, protože nejdelší odpovídající prefix vyhrává a tato síť skončí uvnitř tunelu.

Seznam tras je celá politika. Není za ním žádné veto na cíl a reference Builder neuvádí metodu, která by ho poskytla.

Vygenerujte doplněk z aritmetiky prefixů

Doplněk vyloučeného prefixu je množina jeho sourozenců na cestě ke kořeni stromu adres. Pro každou délku od 1 do vyloučené délky vezměte blok této délky obsahující váš prefix, otočte bit bezprostředně pod prefixem a vypište výsledek. Zní to abstraktně, dokud to nespustíte.

Vyloučení 10.0.0.0/8 dává osm tras: 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. Žádná z nich neobsahuje 10.0.0.0/8 a společně pokrývají vše ostatní.

Osm řádků generuje tento seznam pro jakýkoli prefix:

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))

Počet tras se rovná délce prefixu a to je číslo, které je třeba sledovat. Jedno vyloučení /21 stojí 21 tras a zůstává čitelné. Deset vyloučení může stát několik stovek, což obvykle znamená, že změnu potřebuje návrh sítě, ne generátor.

Zkontrolujte rodinu adres a rozsah tunelu

Trasy IPv4 nedělají pro IPv6 nic. Pokud tunel nárokuje adresu IPv6, lokální prefix IPv6 potřebuje vlastní doplněk vygenerovaný stejnou aritmetikou nad 128 bity. Častou příčinou, že vyloučení funguje na papíře, zatímco lokální zařízení zůstává nedostupné, je toto: hostitel byl dosažen přes IPv6 a vyříznuto bylo jen IPv4. Zkontrolujte obě rodiny, než uzavřete, že matematika je špatná.

Rozsah je druhá polovina kontroly. Android sleduje směrování po síti a po aplikaci, takže stejný prefix může jít tunelem pro jednu aplikaci a přímo pro jinou podle toho, jak je VPN deklarována.

Umístěte pravidla DNS a pro aplikace tam, kam patří

Vyloučení tras nemění resolver. Lokální název hostitele může stále odpovídat DNS server tunelu, zatímco jeho adresa se směruje lokálně, a nesoulad se projeví jako název, který se překládá na něco, co LAN nedosáhne. Nastavte politiku resolveru záměrně, s vyhledávací doménou nebo pravidlem rozděleného DNS. Nepředpokládejte, že to za vás rozhodly trasy.

addDisallowedApplication() drží jednu aplikaci mimo tunel; nedrží cíl mimo pro aplikace, které zůstávají uvnitř. protect() umožňuje socketu, který otevřete, obejít tunel, a tak se tunel vyhýbá zachycení vlastního transportu. Ani jedno nenahrazuje doplněk.

Ověřujte vyhledáním, ne vlastním seznamem

Když tunel běží, zeptejte se zařízení, kam adresa skutečně jde, místo abyste znovu četli seznam, který jste sestavili. Na buildu, který dodává iproute2, adb shell ip route get 10.1.2.3 pojmenuje rozhraní, které jádro vybralo. Spusťte stejný příkaz pro veřejnou adresu a potvrďte, že pojmenuje tunel.

Dvě další kontroly uzavírají smyčku. Nejprve přeložte lokální název, pak spusťte adb shell ip route get na přeložené adrese a požadujte rozhraní, které není tunel, protože úspěšný adb shell ping -c 1 host.lan dokazuje dosažitelnost, ne cestu. Zopakujte test rodiny adres přes IPv6, pokud tunel nějakou nárokuje. Testujte na úrovni API, kterou dodáváte, protože způsob, jakým se sítě VPN vystavují směrovací tabulce, se mezi verzemi měnil. Seznam tras, který na papíře vypadá správně, a vyhledání, které vybere špatné rozhraní, jsou různé chyby a jen ta druhá se dostane k uživatelům.

Pokud seznam vyloučení dál roste, přestaňte generovat trasy a přečíslujte vzdálenou síť nebo zúžte tunel. Generátor je obejití chybějícího API, ne návrhový nástroj.

Související články