Androidi VpnService'il pole välistusmarsruuti ja ükski API lugemine ei tekita seda. Builder.addRoute() lisab tunnelile alati ainult sihtkohti, seega LAN-segmendi lokaalsena hoidmine tähendab, et see segment ei jõua kunagi marsruutide loendisse. Selle asemel lisate segmendi komplementi, väljendatuna tavaliste prefiksitena. Töö on aritmeetika ja see ebaõnnestub mõnes etteaimatavas kohas.

Käige allolevad kontrollid järjekorras läbi. Igaüks eeldab, et eelmine pidas, seega peatuge esimesel ebaõnnestumisel, selle asemel et sümptomeid allpool lappida.

Alustage sellest, mida tunnel väidab

0.0.0.0/0 edastamine addRoute()-le ütleb Androidile, et iga IPv4-sihtkoht kuulub tunnelisse. Sellepärast näivad paljud kliendid jagatud tunneldamiseks võimetud: nad nõuavad kogu aadressiruumi ja püüavad siis sellest lahutada. Miski ehitajas ei lahuta. Konkreetsem marsruut võrgule, mille tahtsite lokaalseks jätta, teeb vastupidist sellele, mida inimesed ootavad, sest pikim sobiv prefiks võidab ja see võrk maandub tunnelis.

Marsruutide loend on kogu poliitika. Selle taga pole sihtkohapõhist vetot ja Builderi viide ei loetle ühtegi meetodit, mis selle annaks.

Genereerige komplement prefiksiaritmeetikast

Välistatud prefiksi komplement on selle õdede-vendade hulk teel aadressipuu juureni. Iga pikkuse puhul 1-st kuni välistatud pikkuseni võtke selle pikkusega plokk, mis sisaldab teie prefiksit, pöörake bitt vahetult prefiksi all ja väljastage tulemus. See kõlab abstraktselt, kuni te seda käivitate.

10.0.0.0/8 välistamine annab kaheksa marsruuti: 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. Ükski neist ei sisalda 10.0.0.0/8 ja koos katavad need kõik muu.

Kaheksa rida genereerivad selle loendi iga prefiksi jaoks:

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

Marsruutide arv võrdub prefiksi pikkusega ja see on arv, mida jälgida. Üks /21 välistus maksab 21 marsruuti ja jääb loetavaks. Kümme välistust võib maksta paar sada, mis tavaliselt tähendab, et muuta tuleb võrgu disaini, mitte generaatorit.

Kontrollige aadressiperekonda ja tunneli ulatust

IPv4 marsruudid ei tee IPv6 jaoks midagi. Kui tunnel nõuab IPv6 aadressi, vajab IPv6 LAN-prefiks oma komplementi, genereerituna sama aritmeetikaga üle 128 biti. Levinud põhjus, miks välistus paberil töötab, samal ajal kui kohalik seade jääb kättesaamatuks, on see: hostini jõuti IPv6 kaudu ja välja oli lõigatud ainult IPv4. Kontrollige mõlemat perekonda, enne kui järeldate, et matemaatika on vale.

Ulatuse on kontrolli teine pool. Android jälgib marsruutimist võrgu ja rakenduse kaupa, seega sama prefiks võib ühe rakenduse jaoks minna läbi tunneli ja teise jaoks otse, sõltuvalt sellest, kuidas VPN on deklareeritud.

Pange DNS-i ja rakendusepõhised reeglid sinna, kuhu need kuuluvad

Marsruudi välistused ei muuda resolverit. Kohalikule hostinimele võib endiselt vastata tunneli DNS-server, samal ajal kui selle aadress on marsruuditud lokaalselt, ja lahknevus ilmneb nimena, mis laheneb millekski, mida LAN ei ulata. Määrake resolveri poliitika teadlikult, otsingudomeeni või jagatud DNS-i reegliga. Ärge eeldage, et marsruudid otsustasid selle teie eest.

addDisallowedApplication() hoiab ühe rakenduse tunnelist väljas; see ei hoia sihtkohta väljas nende rakenduste jaoks, mis jäävad sisse. protect() laseb teie avatud socketil tunnelist mööda minna ja nii väldib tunnel omaenda transporthõive. Kumbki ei asenda komplementi.

Kontrollige otsinguga, mitte oma loendiga

Kui tunnel on üleval, küsige seadmelt, kuhu aadress tegelikult läheb, selle asemel et oma koostatud loendit uuesti lugeda. Buildil, mis tarnib iproute2, nimetab adb shell ip route get 10.1.2.3 liidese, mille kernel valis. Käivitage sama käsk avaliku aadressi jaoks ja kinnitage, et see nimetab tunnelit.

Veel kaks kontrolli sulgevad ringi. Esmalt lahendage kohalik nimi, seejärel käivitage adb shell ip route get lahendatud aadressil ja nõudke liidest, mis pole tunnel, sest edukas adb shell ping -c 1 host.lan tõestab kättesaadavust, mitte teed. Korrake aadressiperekonna testi IPv6 üle, kui tunnel seda nõuab. Testige API tasemel, mida tarnite, sest viis, kuidas VPN-võrke marsruutimistabelile eksponeeritakse, on väljaannete vahel muutunud. Marsruutide loend, mis näeb paberil õige välja, ja otsing, mis valib vale liidese, on erinevad vead ning ainult teine jõuab kasutajateni.

Kui välistusloend kasvab edasi, lõpetage marsruutide genereerimine ja nummerdage kaugvõrk ümber või kitsendage tunnelit. Generaator on puuduva API jaoks mõeldud mööramine, mitte disainitööriist.

Seotud artiklid