Таны Android VpnService туннель трафик чиглүүлэхээ яагаад зогсоодог вэ
Үйлдвэрлэлд эвдэрдэг VpnService-ийн дөрвөн итгэл: нэг удаад нэг туннель, маршрутын хүрээ, апп тус бүрийн жагсаалт, унтраах дараалал, тус бүрд нь шалгалттай.
Android VpnService-ийн тухай дөрвөн таамаг надад нэг удаа долоо хоногийн ихэнх хэсгийг үрэгдүүлсэн бөгөөд тэдгээрийн нэг ч сүлжээний протоколын тухай байгаагүй. Апп холбогдсон гэж хэлсэн, түлхүүрийн дүрс төлөвийн мөрөнд сууж байсан бөгөөд трафик ердийн маршрутаар гарсаар байв. Би туннелийг өөрөө зогсоох хүртэл өөрийн гэж, нэмсэн маршрутууд маань авах маршрутууд гэж, stopSelf дуудвал интерфейс хамт бууна гэж байнга таамаглаж байсан. Үйлчилгээ яг баримтжуулсан шигээ ажиллаж байв. Эвдэрсэн хэсэг нь миний оюуны загвар байв.
Домог 1: туннель та түүнийг зогсоох хүртэл зогсохгүй
Android нэг удаад нэг VPN интерфейс барьдаг. Хоёр дахьыг суулгавал платформ үүнийг дараалалд оруулахгүй, харин таныхыг идэвхгүй болгож, таны үйлчилгээнд onRevoke() дуудна. Хэрэв таны код зөвхөн товч дарахад бүгдийг буулгадаг бол эзэмшил нь ард нь дескриптор болон уншигч урсгалыг үлдээж, дараагийн эхлэл хоёуланг нь өвлөнө.
VpnService-ийн лавлагаа апп аль хэдийн зөвшөөрөлтэй бол prepare() null буцааж, хэрэглэгч хараахан зөвшөөрөх шаардлагатай бол Intent буцаадаг гэдгийг тодорхой хэлдэг. Тэр зөвшөөрөл нь та санааны мэдэгдлийг startActivityForResult()-аар дамжуулж хүргэсэн тохиолдолд л ирнэ. Дамжуулалтыг алгасвал establish() null буцаана, үүнийг зөвшөөрлийн асуудал биш, чимээгүй бүтэлгүйтэл гэж уншина.
Always-on VPN таны хянадаггүй эзэмшигчийг нэмдэг. Систем ачаалсны дараа эсвэл ослын дараа туннелийг буцааж болох бөгөөд хэрэглэгчийн гараар эхлүүлсэн VPN аппыг түрүүлж гаргадаг. onRevoke()-г ердийн унтраахтайгаа ижил нөөцийг хаадаг байхаар бүтээж, үүнийг захын тохиолдол биш, үндсэн зогсоох зам гэж үзээрэй. Хэрэглэгчид VPN апп сольдог; таны код үүнийг давах ёстой.
Домог 2: addRoute яг таны жагсаасан зүйлийг барьдаг
Аль пакет таны дескрипторт хүрэхийг маршрутууд шийддэг, хүрээний алдаа нь трафикийн нэг хэсэг туннелээр явж, нөгөө хэсэг нь явахгүй уур хүргэм байдлыг үүсгэдэг. addRoute("0.0.0.0", 0) бүх IPv4-ийг авдаг, энэ нь одоо пакет бүр танд ирж, түүнийг цааш дамжуулах эсвэл хаях шаардлагатай гэсэн үг. Нэг хостод зориулсан /32 бараг юу ч авдаггүй, бусад бүх зүйл VPN тань хэзээ ч суулгагдаагүй мэт аашилна.
Гэр бүлүүдийг тусад нь тоолдог. Зөвхөн IPv4 маршрут нь IPv6-г үндсэн сүлжээнд үлдээдэг тул хос стектэй хост туннелийн дотор бүрэн холбогдсон мэт харагдаж байхдаа гадна талд нэр шийдэж, холбогдож чаддаг.
DNS мөн ижил логикийг баримталдаг. addDnsServer()-аар нэмсэн серверүүд туннелийн шийдэгчийг ашигладаг аппуудад очдог бол өөрийн шифрлэгдсэн DNS төгсгөлийн цэг эсвэл хост нэрэнд тохируулсан Private DNS-тэй апп тэдгээрийг бүрмөсөн үл тоомсорлодог. Нэрнүүд нэг аппд бүтэлгүйтэж, нөгөөд нь ажиллах үед нэг ч маршрут хүрэхээс өмнө шийдэгчийн замыг шалгаарай.
Домог 3: апп тус бүрийн дүрэм нь хоёр тийш эргүүлж болох унтраалга
addDisallowedApplication() ба addAllowedApplication() нь хоёр шүүлтүүр биш, хоёр горим юм. Бүтээгч нэг туннельд нэг загвар хүлээн авдаг тул гурван багцаас бусад бүхнийг хүсдэг апп хориглосон жагсаалтыг ашиглаж, зөвшөөрсөн жагсаалтыг хоосон үлдээдэг. Хоёулаа харилцан үл нийцэх бөгөөд хүмүүс үүнийг тохиргооны дэлгэц аль хэдийн хоёр унтраалгыг санал болгосны дараа ажиллах үед мэддэг.
Багцын харагдах байдал мөн хазаж байна. Android 11 ба түүнээс хойш та зөвхөн харж байгаа багцуудаа нэрлэж чадна, тиймээс таны аппд ажиллуулахыг зөвшөөрөөгүй асуулгаас бүтээсэн хасалтын жагсаалт бичлэгүүдийг чимээгүй алгасах болно. Жагсаалтад итгэхээсээ өмнө багц менежер бодитоор юу буцаадагтай харьцуулаарай.
Ажлын профайлууд үзэгчдийг дахин хуваадаг. Профайл дотор эхэлсэн туннель тэр профайл болон түүний аппуудыг хамардаг бол хувийн тал өөрийн холболтоо хадгалдаг. Энэ нь нэг удаа гаргадаг хүрээний шийдвэр бөгөөд түүний байр интерфейсэд, дэмжлэгийн тасалбарт биш.
Домог 4: stopSelf туннелийг дуусгадаг
Үгүй. Интерфейс establish()-ийн буцаадаг дескрипторт амьдардаг бөгөөд тэр дескриптор нээлттэй байхад үйлчилгээний объект үхэж болно. Эхлээд ParcelFileDescriptor-г хааж, лавлагааг тавьж, уншигч болон бичигч урсгуудыг нэгтгэх эсвэл таслах, дараа нь stopForeground(true) ба stopSelf()-г энэ дарааллаар дуудна.
Мартагдсан дескриптор нь үйлчилгээ өөрийн зогсоох хүсэлтээс амьд гарсан мэт харагдах нийтлэг шалтгаан бөгөөд өөрийг нь нэмсэн аппаас илүү урт насалсан хуучирсан маршрутыг тайлбарладаг.
Эсрэг алдаа мөн адил нийтлэг: уншигч урсгал уншилтын дунд байхад дескрипторийг хааж, дараа нь тэр урсгалыг хэн ч код бичээгүй үл хамаарах зүйлтэй ажиллахыг үлдээх. Унтраах дарааллыг нэг газар бариад хэрэглэгчийн үйлдэл болон onRevoke() хоёуланг нь тэнд дуудуулаарай.
Туннель үхсэн мэт харагдахад юу шалгах вэ
Туннель босохоос өмнө урт насалсан сокетуудыг protect()-оор хамгаалаарай. Үүнгүйгээр туннелийн өөрийн тээвэр дахин туннель рүү чиглэгдэж, холболт серверийн гэмтэлтэй яг ижил харагдах байдлаар гацана. Зөвхөн алсын сүлжээний цаана байдаг хаяг руу туршиж үзээрэй, кэш эсвэл суурь замаас хариулдаг нийтийн сайт руу биш.
establish()-ийн үр дүн, маршрутууд, хасагдсан багцууд болон унтраах шалтгааныг бүртгээрэй. Тэр дөрвөн мөр пакет барихгүйгээр зөвшөөрлийн асуудлыг хүрээний асуудал болон амьдралын мөчлөгийн асуудлаас ялгадаг.