Walang ruta ng pagbubukod ang VpnService ng Android, at walang dami ng pagbasa ng API ang makakagawa nito. Lagi lamang nagdaragdag ng mga destinasyon sa tunnel ang Builder.addRoute(), kaya ang pagpapanatiling lokal ng isang segment ng LAN ay nangangahulugang hindi kailanman pumapasok ang segment na iyon sa listahan ng ruta. Ang idinadagdag mo sa halip ay ang komplemento ng segment, na ipinapahayag bilang ordinaryong prefix. Ang gawain ay aritmetika, at nabibigo ito sa ilang mahuhulaang lugar.

Daanan ang mga pagsusuri sa ibaba nang sunod-sunod. Ipinapalagay ng bawat isa na nanindigan ang nauna, kaya huminto sa unang pagkabigo sa halip na tapalan ang mga sintomas sa ibaba.

Magsimula sa inaangkin ng tunnel

Ang pagpasa ng 0.0.0.0/0 sa addRoute() ay nagsasabi sa Android na ang bawat destinasyong IPv4 ay kabilang sa tunnel. Ito ang dahilan kung bakit napakaraming kliyente ang mukhang walang kakayahan sa split tunneling: inaangkin nila ang buong espasyo ng address at pagkatapos ay sinusubukang bawasan iyon. Walang binabawas sa loob ng builder. Ang isang mas tiyak na ruta para sa network na gusto mong panatilihing lokal ay gumagawa ng kabaligtaran ng inaasahan, dahil ang pinakamahabang tumutugmang prefix ang nananalo at napupunta ang network na iyon sa loob ng tunnel.

Ang listahan ng ruta ang buong patakaran. Walang veto kada destinasyon sa likod nito, at ang sanggunian ng Builder ay hindi naglilista ng anumang paraan na magbibigay nito.

Bumuo ng komplemento mula sa aritmetika ng prefix

Ang komplemento ng ibinukod na prefix ay ang set ng mga kapatid nito sa landas patungo sa ugat ng puno ng address. Para sa bawat haba mula 1 hanggang sa ibinukod na haba, kunin ang bloke ng haba na iyon na naglalaman ng iyong prefix, baliktarin ang bit sa ilalim mismo ng prefix, at ilabas ang resulta. Parang abstrakto ito hanggang patakbuhin mo.

Ang pagbubukod sa 10.0.0.0/8 ay nagbubunga ng walong ruta: 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. Wala sa mga ito ang naglalaman ng 10.0.0.0/8, at magkasama nilang sinasaklaw ang lahat ng iba pa.

Walong linya ang bumubuo ng listahang iyon para sa anumang 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))

Ang bilang ng ruta ay katumbas ng haba ng prefix, at iyon ang bilang na dapat bantayan. Ang isang pagbubukod na /21 ay gumagastos ng 21 ruta at nananatiling nababasa. Ang sampung pagbubukod ay maaaring gumastos ng ilang daan, na karaniwang nangangahulugang ang disenyo ng network ang kailangang baguhin, hindi ang generator.

Suriin ang pamilya ng address at ang saklaw ng tunnel

Walang ginagawa ang mga rutang IPv4 para sa IPv6. Kung inaangkin ng tunnel ang isang address na IPv6, kailangan ng prefix ng LAN na IPv6 ang sarili nitong komplemento, na nabuo gamit ang parehong aritmetika sa 128 bit. Isang karaniwang dahilan kung bakit gumagana ang pagbubukod sa papel habang nananatiling hindi maabot ang lokal na aparato ay ito: naabot ang host sa pamamagitan ng IPv6, at IPv4 lamang ang naitaboy. Suriin ang dalawang pamilya bago magpasya na mali ang matematika.

Ang saklaw ang kabilang kalahati ng pagsusuri. Sinusubaybayan ng Android ang routing kada network at kada app, kaya ang parehong prefix ay maaaring dumaan sa tunnel para sa isang app at maging direkta para sa iba depende sa kung paano idineklara ang VPN.

Ilagay ang mga patakaran sa DNS at kada app sa tamang lugar

Hindi binabago ng mga pagbubukod sa ruta ang resolver. Ang isang lokal na hostname ay maaari pa ring sagutin ng DNS server ng tunnel habang ang address nito ay niruruta nang lokal, at ang hindi pagtutugma ay lumilitaw bilang pangalang niresolba sa isang bagay na hindi maabot ng LAN. Itakda ang patakaran ng resolver nang sadya, gamit ang isang search domain o isang split-DNS na patakaran. Huwag ipagpalagay na ang mga ruta ang nagpasya nito para sa iyo.

addDisallowedApplication() pinapanatili ang isang app sa labas ng tunnel; hindi nito pinapanatili ang isang destinasyon sa labas para sa mga app na nananatili sa loob. Hinahayaan ng protect() ang isang socket na binuksan mo na laktawan ang tunnel, at ganoon iniiwasan ng tunnel na hulihin ang sarili nitong transport. Wala sa dalawa ang pumapalit sa komplemento.

I-verify gamit ang isang paghahanap, hindi gamit ang sarili mong listahan

Kapag nakataas na ang tunnel, tanungin ang aparato kung saan talaga pumupunta ang isang address sa halip na basahin muli ang listahang binuo mo. Sa isang build na may iproute2, pinapangalanan ng adb shell ip route get 10.1.2.3 ang interface na pinili ng kernel. Patakbuhin ang parehong utos para sa isang pampublikong address at kumpirmahing pinapangalanan nito ang tunnel.

Dalawang pagsusuri pa ang nagsasara ng loop. Resolbahin muna ang isang lokal na pangalan, pagkatapos patakbuhin ang adb shell ip route get sa naresolbang address at hilingin ang interface na hindi ang tunnel, dahil ang matagumpay na adb shell ping -c 1 host.lan ay nagpapatunay ng maabot, hindi ang landas. Ulitin ang pagsusuri ng pamilya ng address sa IPv6 kung may inaangkin ang tunnel. Subukan sa antas ng API na ipinapadala mo, dahil nagbago ang paraan ng paglalantad ng mga network ng VPN sa talahanayan ng routing sa pagitan ng mga release. Ang listahan ng rutang mukhang tama sa papel at ang paghahanap na pumipili ng maling interface ay magkaibang bug, at ang pangalawa lamang ang nakakarating sa mga gumagamit.

Kung patuloy na lumalaki ang listahan ng pagbubukod, itigil ang pagbuo ng mga ruta at muling bilangin ang malayong network o paliitin ang tunnel sa halip. Ang generator ay isang paraan sa paligid ng nawawalang API, hindi isang kasangkapan sa disenyo.

Kaugnay na mga artikulo