Kā izslēgt apakštīklu no Android VPN tuneļa
VpnService nevar izslēgt maršrutu, tāpēc jūs pievienojat papildinājumu: astoņus ģenerētus prefiksus /8, kā arī IPv6, DNS un meklēšanas pārbaudes, kas noķer pārējo.
Android VpnService nav izslēgšanas maršruta, un nekāds API lasīšanas apjoms to neizveidos. Builder.addRoute() vienmēr pievieno tikai galamērķus tunelim, tāpēc LAN segmenta saglabāšana lokāli nozīmē, ka šis segments nekad neiekļūst maršrutu sarakstā. Tā vietā jūs pievienojat segmenta papildinājumu, kas izteikts ar parastiem prefiksiem. Darbs ir aritmētika, un tas neizdodas dažās paredzamās vietās.
Veiciet zemāk esošās pārbaudes secīgi. Katra pieņem, ka iepriekšējā izturēja, tāpēc apstājieties pie pirmās neveiksmes, nevis lāpiet simptomus tālāk.
Sāciet ar to, ko tunelis apgalvo
0.0.0.0/0 nodošana addRoute() liek Android saprast, ka katrs IPv4 galamērķis pieder tunelim. Tāpēc tik daudzi klienti šķiet nespējīgi veikt sadalīto tuneļošanu: tie pieprasa visu adrešu telpu un pēc tam mēģina no tās atņemt. Būvētājā nekas neatņem. Konkrētāks maršruts tīklam, kuru gribējāt saglabāt lokālu, dara pretējo gaidītajam, jo uzvar garākais atbilstošais prefikss un šis tīkls nonāk tuneļa iekšpusē.
Maršrutu saraksts ir visa politika. Aiz tā nav veto katram galamērķim, un Builder atsauce neuzskaita nevienu metodi, kas to nodrošinātu.
Ģenerējiet papildinājumu no prefiksu aritmētikas
Izslēgtā prefiksa papildinājums ir tā brāļu un māsu kopa ceļā uz adrešu koka sakni. Katram garumam no 1 līdz izslēgtajam garumam paņemiet tā garuma bloku, kas satur jūsu prefiksu, apgrieziet bitu tieši zem prefiksa un izvadiet rezultātu. Tas skan abstrakti, līdz to palaižat.
Izslēdzot 10.0.0.0/8, iegūst astoņus maršrutus: 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. Neviens no tiem nesatur 10.0.0.0/8, un kopā tie nosedz visu pārējo.
Astoņas rindas ģenerē šo sarakstu jebkuram prefiksam:
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))
Maršrutu skaits ir vienāds ar prefiksa garumu, un tas ir skaitlis, kas jāuzrauga. Viens /21 izslēgums izmaksā 21 maršrutu un paliek lasāms. Desmit izslēgumi var izmaksāt vairākus simtus, kas parasti nozīmē, ka jāmaina tīkla dizains, nevis ģenerators.
Pārbaudiet adrešu saimi un tuneļa apjomu
IPv4 maršruti neko nedara IPv6. Ja tunelis pieprasa IPv6 adresi, IPv6 LAN prefiksam vajag savu papildinājumu, kas ģenerēts ar to pašu aritmētiku 128 bitu ietvaros. Biežs iemesls, kāpēc izslēgums darbojas uz papīra, bet lokālā ierīce paliek nesasniedzama, ir šis: uz resursdatoru nokļuva pa IPv6, un izgriezts bija tikai IPv4. Pārbaudiet abas saimes, pirms secināt, ka matemātika ir nepareiza.
Apjoms ir pārbaudes otrā puse. Android izseko maršrutēšanu pa tīkliem un pa lietotnēm, tāpēc viens prefikss var iet caur tuneli vienai lietotnei un būt tiešs citai atkarībā no tā, kā VPN tika deklarēts.
Novietojiet DNS un pēc lietotnes noteikumus tur, kur tie pieder
Maršrutu izslēgumi nemaina risinātāju. Lokāls resursdatora nosaukums joprojām var tikt atbildēts no tuneļa DNS servera, kamēr tā adrese tiek maršrutēta lokāli, un neatbilstība izpaužas kā nosaukums, kas atrisinās uz kaut ko, ko LAN nevar sasniegt. Iestatiet risinātāja politiku apzināti, ar meklēšanas domēnu vai sadalītā DNS noteikumu. Neuzskatiet, ka maršruti to izlēma jūsu vietā.
addDisallowedApplication() patur vienu lietotni ārpus tuneļa; tas nepatur galamērķi ārpusē tām lietotnēm, kas paliek iekšā. protect() ļauj jūsu atvērtajai ligzdai apiet tuneli, un tā tunelis izvairās no sava transporta pārtveršanas. Neviens no tiem neaizstāj papildinājumu.
Pārbaudiet ar meklēšanu, nevis ar savu sarakstu
Kad tunelis ir pacelts, pajautājiet ierīcei, kur adrese patiešām iet, nevis lasiet savu būvēto sarakstu vēlreiz. Būvējumā, kas nodrošina iproute2, adb shell ip route get 10.1.2.3 nosauc saskarni, kuru izvēlējās kodols. Palaidiet to pašu komandu publiskai adresei un apstipriniet, ka tā nosauc tuneli.
Vēl divas pārbaudes aizver ciklu. Vispirms atrisiniet lokālu nosaukumu, pēc tam palaidiet adb shell ip route get atrisinātajai adresei un pieprasiet saskarni, kas nav tunelis, jo veiksmīgs adb shell ping -c 1 host.lan pierāda sasniedzamību, nevis ceļu. Atkārtojiet adrešu saimes testu IPv6 ietvaros, ja tunelis to pieprasa. Pārbaudiet tajā API līmenī, kuru piegādājat, jo tas, kā VPN tīkli tiek pakļauti maršrutēšanas tabulai, ir mainījies starp laidieniem. Maršrutu saraksts, kas uz papīra izskatās pareizs, un meklēšana, kas izvēlas nepareizo saskarni, ir dažādas kļūdas, un tikai otrā sasniedz lietotājus.
Ja izslēgumu saraksts turpina augt, pārtrauciet ģenerēt maršrutus un pārnumurējiet attālo tīklu vai tā vietā sašauriniet tuneli. Ģenerators ir apvedceļš trūkstošajam API, nevis dizaina rīks.