Таны апп VpnService.prepare-г дуудаж, null авч, туннель барьж, тодорхойлогч хүчинтэй харагдана, гэвч серверт юу ч хүрэхгүй. Эсвэл prepare Intent буцааж, хэрэглэгч зөвшөөрсөн ч establish бүтэлгүйтсээр байна. Хоёр үр дүн ихэвчлэн нэг утгатай: өөр апп энэ хэрэглэгчийн VPN интерфейсийг аль хэдийн эзэмшиж байгаа бөгөөд таны protect дуудлагууд таны туннель ашиглаж чадахгүй сокетуудыг тэмдэглэж байна. Доорх шалгалтуудыг дарааллаар гүйцэтгээд эхний бүтэлгүйтсэн дээр зогсоно уу, учир нь дараагийн алхам өмнөхийг засахгүй.

protect-д хүрэхийн өмнө VPN байрлалыг шалгана уу

Android хэрэглэгч бүрт яг нэг идэвхтэй VPN интерфейс өгдөг. Энэ нь платформын дүрэм, таны апп шаардаж болох зөвшөөрөл биш, тиймээс хоёулаа туннель болохыг хүсдэг хоёр клиент зэрэг оршин тогтнохгүй.

Өөр апп-д тохируулсан үргэлж асаалттай VPN бол хамгийн хэцүү тохиолдол, учир нь систем тэр аппыг холбоотой байлгаж, эзэмшилтийг үгүйсгэдэг. AdGuard мэтийн траффик шүүлтүүр, корпорацийн клиент эсвэл хэрэглэгчийн VPN нь хэрэглэгч суулгасан гэдгээ мартсан байхад байрлалыг эзэлж чадна. Хэрэглэгчээс Тохиргоог нээж VPN-ийн доор жагсаасан бичлэгийг уншихыг хүс; тэнд байгаа нэр нь таны өрсөлдөж буй эзэн юм. Тэр бичлэг салгагдах эсвэл үргэлж асаалттай тохиргоо арилаагүй л бол таны VpnService интерфейс болж чадахгүй.

Алхам 1: prepare юу буцааж байгааг уншина уу

VpnService.prepare нэг асуултад хариулна: энэ апп VPN болж чадах уу? Зөвшөөрөл аль хэдийн байвал null, хэрэглэгч одоо ч зөвшөөрөх шаардлагатай бол Intent буцаана, үүнийг startActivityForResult-оор ажиллуулах ёстой. null буцаалтыг үргэлжлүүлэх зөвшөөрөл гэж үзээрэй, establish амжилттай болно гэсэн нотолгоо биш.

Intent intent = VpnService.prepare(context);
if (intent != null) {
    startActivityForResult(intent, REQUEST_VPN);
}

Intent зам буцаж, хэрэглэгч татгалзсан бол prepare дараагийн оролдлогод дахин Intent буцаана. Циклд дахин оролдохын оронд үр дүнгийн кодыг бүртгээрэй, учир нь татгалзсан зөвшөөрөл бол хэрэглэгчийн шийдвэр, түр зуурын алдаа биш.

Алхам 2: интерфейс таны апп-д харьяалагдахыг баталгаажуулна уу

establish-ийн дараа авсан ParcelFileDescriptor бол таны эзэмшлийн нотолгоо бөгөөд сокет ажлын өмнө шалгах нь зүйтэй. null эсвэл аль хэдийн хаагдсан тодорхойлогч нь үл хамаарах зүйл гараагүй ч интерфейс хэзээ ч үүсээгүй гэсэн үг. builder-ийн интерфейсийн нэрийг системийн идэвхтэй VPN-д мэдээлсэн нэртэй харьцуул, туршилтын төхөөрөмж дээр dumpsys ашиглан. Хэрэв тэд ялгаатай бол таны барьсан туннель траффик дамжуулж буй туннель биш.

adb shell dumpsys connectivity

Мөн адил зөрүү холбогдсон дүрс тасарсан траффикийг тайлбарлана. Систем өөр аппын туннелийг харуулж, таны код өөрийн эзэмшилгүй интерфейсийн тодорхойлогчийг барьж байна.

Алхам 3: connect-ийн өмнө protect-г дуудна уу

Интерфейс үүссэний дараа таны аппын нээдэг сокетууд анхдагчаар туннель руу чиглэнэ. Гадаад тээвэр энэ дүрмийг дагаж чадахгүй, эс бөгөөс багцлагдсан пакет интерфейс руу буцаж эргэх тул VpnService protect сокетыг VPN-г тойрч, доорх сүлжээг ашиглах гэж тэмдэглэнэ. Дуудлага boolean буцаах бөгөөд түүнийг үл тоомсорлох нь эрүүл харагдах боловч юу ч дамжуулахгүй сокет руу хүрэх зам юм.

protect-г connect эсвэл bind-ийн өмнө дуудаж, хэзээ ч дараа нь дуудаж болохгүй. Хамгаалалт нь сокетыг холбох эсвэл бэхлэхээс өмнө байх ёстой, учир нь холбогдсон сокет аль хэдийн замаа сонгосон бөгөөд дараагийн protect түүнийг найдвартай зөөдөггүй. Хэрэв protect false буцаавал зогсож, эзэмшлийг дахин шалгана уу: интерфейс таны апп-д харьяалагдахгүй үед бүтэлгүйтдэг бөгөөд энэ нь яг өөр VPN үлдээдэг байдал юм. false буцаалт нь Алхам 1 руу буцах дохио, ижил сокетыг дахин оролдох дохио биш.

DatagramSocket socket = new DatagramSocket();
if (!vpnService.protect(socket)) {
    return;
}
socket.connect(serverAddress, serverPort);

Алхам 4: сокет эвгүй үед процессыг холбоно уу

Зарим тээвэр нэг сокет биш: номын сан хэдийг нээж болно, эсвэл туслах процесс дахь холболт бүр ижил гарах хаалгыг ашиглаасай гэж хүсч болно. ConnectivityManager.bindProcessToNetwork процессыг сонгосон сүлжээнд холбодог, хуучин setProcessDefaultNetwork ч энэ ажлыг хийж байсан, түүнийг хуучирсан гэж зарлахаас өмнө. Доорх холболтыг NET_CAPABILITY_NOT_VPN-ээр хүс, ингэснээр холболт таны туннелийн доорх сүлжээг сонгох бөгөөд туннелийг өөрөө биш.

NetworkRequest request = new NetworkRequest.Builder()
    .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
    .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
    .build();

Процесс холбох нь хоёр дахь VPN биш. Энэ нь тэр процессод гарах хаалга сонгодог бөгөөд таны тээвэрт ашигтай, хоёр туннелийг зэрэг ажиллуулахад ашиггүй.

Кодын замыг биш, хэрэглэгчийн төхөөрөмжийг засаарай

Хоёр апп VPN байрлалыг хуваалцахыг зөвшөөрдөг API байхгүй тул засвар нь төхөөрөмжийн байдалд хамаарна. Хэрэглэгчид хоёр тодорхой зам санал болго: өөр аппын холболтыг салгах эсвэл үргэлж асаалттайг арилгаж таны prepare эзэмшилтийг авч чадах, эсвэл тэр аппын апп тус бүрийн тохиргоог нээж таны аппыг түүний туннелээс хасах. Хасалт нь бусад бүх зүйлд шүүлтүүрийг ажиллуулж, таны аппад энгийн холболтыг ашиглах боломж өгдөг бөгөөд энэ нь ихэвчлэн хэрэглэгчийн үнэхээр хүсдэг үр дүн юм.

Хоёр замыг дэмжлэгийн баримт бичигт бичээрэй, учир нь хэрэглэгчид аль апп VPN-г эзэмшиж байгааг ховор мэддэг. Тэднээс Тохиргооноос идэвхтэй VPN-ийн нэрийг, логоос prepare, establish, protect-ийн үр дүнг илгээхийг хүс, нэг минутын дотор аль алхам бүтэлгүйтсэнийг хэлж чадна. Дараа нь бодит траффикоор баталгаажуул: нэр хайлт, TCP холболт, туннелээр нэг хүсэлт, зөвхөн холбогдсон дүрс биш. Хүчинтэй тодорхойлогч, ногоон заагч нь хамгийн сайндаа эзэмшлийг нотолдог, тээвэр чиглүүлэлтийн дүрмийг даван туулсан гэдгийг хэзээ ч биш.

Хэрэв дөрвөн шалгалт бүгд давж, траффик гэсэн ч үхэж байвал эзэмшил таны асуудал байхаа болино. Чиглүүлэлт, серверийн хүртээмж рүү шилжиж, VPN апп суулгаагүй төхөөрөмжөөс ижил итгэмжлэлийг шалга.

Холбоотой нийтлэлүүд