Երբ էմուլյատորը չի հասնում այն build-սերվերին, որը հոսթի բրաուզերում բացվում է առանց խնդիրների, օգտակար հարցը VPN-ի աշխատելը չէ։ Հարցն այն է, թե երկու մեխանիզմներից որն է պակասում guest-ին։ Վիրտուալ սարքը գործարկում է իր ցանցային stack-ը էմուլյատորի NAT-ի հետևում, և նրա resolver-ների ցանկը boot-ի պահին վերցված պատճեն է, ուստի ավելի ուշ բարձրացած թունելը փոխում է հոսթի ուղին՝ չփոխելով այն, ինչ հարցնում է guest-ը։ Այս երկու շերտերի ընկալումը բացատրում է այս խնդրի գրեթե բոլոր տարբերակները։

Guest-ը առանձին stack է ֆիքսված NAT-ի հետևում

QEMU-ի user-mode ցանցը guest-ին տեղադրում է 10.0.2.15 հասցեում՝ 10.0.2.2 gateway-ով, և DNS ծառայությունը՝ 10.0.2.3-ից 10.0.2.6 հասցեներում։ Guest-ի ելքային տրաֆիկը չի forward-վում հոսթի kernel-ի կողմից. այն վերածվում է հոսթի կողմի socket-ների՝ մեկը յուրաքանչյուր guest-կապի համար, և այդ socket-ները դուրս են գալիս հոսթի հասցեային տարածքից։ Այդ պատճառով guest-կապը ժառանգում է հոսթի routing-ի որոշումը հենց ստեղծման պահին, և այդ պատճառով guest-ի route աղյուսակում չկա ձեր թունելին հղող գրառում։

Նույն մեխանիզմը guest-ին տալիս է օգտակար ելք։ 10.0.2.2-ը հոսթի loopback ինտերֆեյսի alias-ն է, ուստի նոութբուքի 127.0.0.1-ում լսող ծառայությունը հասանելի է guest-ից այդ հասցեով։ Ամեն ինչ, ինչ client-ը բացում է միայն loopback-ում, հասանելի է այդ ճանապարհով, և սա է հիմքը ստորև նկարագրված proxy կարգավորման։

Այն, ինչ guest-ը չի կարող անել, հոսթի ցանցը դիտարկելն է այնպես, ասես ինքը դրա namespace-ն է։ Չկա bridge, չկա ընդհանուր route աղյուսակ և չկա ժառանգված resolver. կա միայն NAT ծառայությունը, որն ընդունում է նրա packet-ները, և այն snapshot-ը, որը launcher-ը վերցրել է վիրտուալ սարքի մեկնարկի պահին։

DNS-ը snapshot է, ոչ կենդանի պատկեր

Մեկնարկին էմուլյատորը կարդում է հոսթի resolver-ների ցանկը և guest-ին տալիս է մինչև չորս սերվեր՝ 10.0.2.3-ից 10.0.2.6 հասցեներով։ Եթե այդ պահին թունելը իջեցված էր, snapshot-ը պարունակում է այն public resolver-ը, որն օգտագործում էր նոութբուքը, և guest-ը շարունակում է հարցնել նրան իր ողջ կյանքի ընթացքում։ Public անունները լուծվում են, ներքին անունները ձախողվում են, և բոլոր ախտանիշները մատնանշում են VPN-ին, մինչդեռ իրական հնացած արժեքը resolver-ների ցանկն է, որը գրավվել է թունելի բարձրանալուց մի քանի րոպե առաջ։

Հերթականության ուղղումը, հետևաբար, ժողովրդական բանահյուսություն չէ։ Նախ միացրեք թունելը, ապա վերագործարկեք էմուլյատորը, և նախընտրեք cold boot-ը snapshot-ի վերականգնման փոխարեն, քանի որ quick-boot պատկերը կարող է վերադառնալ ավելի վաղ պահված resolver-ի և route-ի վիճակով։ Եթե պետք է տեսնել, թե guest-ը ներկայում ինչ է օգտագործում, հարցրեք սարքին, ոչ թե հոսթին։

adb shell dumpsys connectivity | grep -i -A2 dns
adb shell ping -c 1 build.internal.example

Էմուլյատորը նաև ընդունում է բացահայտ resolver մեկնարկի ժամանակ, ինչը օգտակար է, երբ հստակ գիտեք, թե որ սերվերն օգտագործի guest-ը, և վտանգավոր է, երբ այդ սերվերը public է։

emulator -avd Pixel_API_34 -dns-server 203.0.113.53

Public resolver-ը ներքին zone-ի պատճեն չունի, ուստի մեկը ամրացնելը հերթականության խնդիրը վերածում է մշտական ձախողման։ Եթե profile-ը push է անում private DNS, թող թունելը տրամադրի այն և cold boot արեք guest-ին՝ հասցեն կոշտ գրելու փոխարեն։

Routing-ը հետևում է հոսթին կապի ստեղծման պահին

Քանի որ guest-կապերը դառնում են հոսթի socket-ներ, routing-ի որոշումը կայացվում է socket-ի ստեղծման պահին։ Թունելը հարցումից առաջ բարձրացված լինելը նշանակում է, որ հարցումը դուրս է գալիս թունելով՝ profile-ի route-ներին համապատասխան։ Split-tunnel profile-ը, որը տեղափոխում է միայն ընտրված prefix-ները, հանգիստ կթողնի ձեր private subnet-ը դրսում, ուստի հոսթի հասանելիությունը վարկած է guest-ի մասին, ոչ թե արդյունք։ Գոյություն ունեցող guest-կապերը պահում են այն ուղին, որով ստեղծվել են, այդ պատճառով վերամիացող client-ը միշտ չէ, որ շտկում է էմուլյատորում կախված ներբեռնումը։

Ստուգումը տեղ ունի հոսթի ինտերֆեյսում, ոչ թե guest-ի վիճակագրության մեջ։

sudo tcpdump -ni tun0 'host 203.0.113.10'

Եթե guest-ի հարցումը հայտնվում է թունելի ինտերֆեյսում, routing-ը աշխատում է, և խնդիրը դրա վերևում է։ Եթե այն հայտնվում է ֆիզիկական ինտերֆեյսում, profile-ը չի ծածկում այդ prefix-ը, և ոչ մի guest-կողմյան վերակարգավորում դա չի փոխի։

Երբ client-ը առաջարկում է միայն loopback proxy

Որոշ առևտրային client-ներ ընդհանրապես system tunnel չեն ստեղծում։ Նրանք բացում են HTTP կամ SOCKS listener 127.0.0.1-ում և սպասում, որ հավելվածները կօգտագործեն այն։ Guest-ը չի տեսնում այդ socket-ը ուղղակիորեն, բայց էմուլյատորին կարելի է ասել օգտագործել այն՝ կամ extended controls-ի միջոցով (Settings, ապա Proxy, manual mode, host 127.0.0.1 և client-ի տպած port-ը), կամ մեկնարկի ժամանակ։

emulator -avd Pixel_API_34 -http-proxy http://127.0.0.1:8080

Պատճենեք port-ը client-ի պատուհանից. գուշակված port-ը ձախողվում է լուռ և նման է կոտրված թունելի։ Նկատի ունեցեք, թե ինչ է դա ծածկում. HTTP proxy կարգավորումը հարգվում է proxy-ին գիտակից հավելվածների կողմից, իսկ raw socket-ները բացարձակ անտեսում են այն։ Եթե աշխատանքը native binary է, որը բացում է սեփական կապերը, proxy-ի ուղին համարժեք չէ թունելին, և համեմատությունը պետք է արվի բացահայտ։

Ապացուցեք արդյունքը guest-ի ներսից

Առանձնացրեք resolution-ը routing-ից՝ նույն սեսիայում երկու թեստով։ Անունը, որը ձախողվում է, մինչդեռ թվային հասցեն պատասխանում է, DNS snapshot-ի խնդիր է, և լուծումը հերթականությունն է կամ բացահայտ resolver-ը։ Երկուսի ձախողումը մատնանշում է routing-ը կամ policy-ն, և հաջորդ ստուգումն այն է, թե արդյոք հավելվածը աշխատում է work profile-ում՝ իր ցանցային սահմանափակումներով։

Վերջապես, իմացեք, թե որ guest-ի վրա եք թեստավորում։ Շատ հին էմուլյատոր պատկերներ թողարկվել են առանց tun աջակցության, որն անհրաժեշտ է guest-կողմյան VPN client-ին, ուստի ոչ մի profile այնտեղ չէր կարող աշխատել. ընթացիկ պատկերները ներառում են այն։ Client-ը, որը ձախողվում է ընթացիկ պատկերի վրա, client-ի կամ profile-ի խնդիր է, և հոսթի թունելի վերակառուցումը արդյունքը չի փոխի։

Առնչվող հոդվածներ