แอป Android ไม่สามารถแก้ไขชื่อภายในได้ ขณะที่เบราว์เซอร์ของไคลเอนต์ VPN เองเข้าถึงได้ และบิลด์เดียวกันทำงานบนโทรศัพท์อีกเครื่องหนึ่ง URL ไม่ใช่ตัวแปร ตัวแปรคือเครือข่ายที่โปรเซสของแอปได้รับอนุญาตให้ใช้ในการแก้ไขชื่อ และ Android ไม่รับประกันว่า VPN ที่ใช้งานอยู่คือเครือข่ายที่ซ็อกเก็ตของคุณใช้ ทำการตรวจสอบเหล่านี้ตามลำดับและหยุดเมื่อภาพรวมของ resolver ไม่ตรงกับสมมติฐานของคุณ

ขั้นตอนที่ 1: พิสูจน์ว่าแอปอยู่บนเครือข่ายใด

อ่านมุมมองของแอปเอง ไม่ใช่แถบสถานะ จาก ConnectivityManager ดึงเครือข่ายที่ใช้งานอยู่ LinkProperties ของเครือข่ายนั้น รายการเซิร์ฟเวอร์ DNS และการตั้งค่า DNS ส่วนตัว หากรายการมี resolver ของ VPN แอปก็มีเส้นทางไปถึง หากมี resolver ของ Wi-Fi อุโมงค์ไม่ใช่เครือข่ายเริ่มต้นของโปรเซสนั้น

ไอคอน VPN บอกเพียงว่ามีอุโมงค์อยู่ ไม่ได้บอกว่าโปรเซสของแอปถูกผูกกับอุโมงค์นั้น และ Android ไม่ได้กำหนดเส้นทางการแก้ไขชื่อผ่านเครือข่ายที่ดูเหมือนใช้งานอยู่เสมอ แอป VPN ภายในเครื่องที่ส่งต่อไปยังอุปกรณ์อื่น เครือข่าย Wi-Fi ที่ไม่มีอินเทอร์เน็ต และบิลด์ของผู้ผลิต ล้วนทำให้แอปถาม resolver เริ่มต้นแทนเซิร์ฟเวอร์ของอุโมงค์ได้

ขั้นตอนที่ 2: ขอ transport ของ VPN และผูกโปรเซส

เมื่อแอปต้องใช้ resolver ของอุโมงค์ ให้ขอเครือข่ายที่มี transport ของ VPN และผูกโปรเซสใน callback เพื่อให้โค้ดไม่เดาว่าเครือข่ายจะปรากฏเมื่อใด:

val request = NetworkRequest.Builder()
    .addTransportType(NetworkCapabilities.TRANSPORT_VPN)
    .build()

connectivityManager.requestNetwork(request, object : NetworkCallback() {
    override fun onAvailable(network: Network) {
        val bound = connectivityManager.bindProcessToNetwork(network)
        Log.i(TAG, "bound to VPN network: " + bound)
    }
})

การเรียกนี้เปลี่ยนเครือข่ายเริ่มต้นของทั้งโปรเซส ดังนั้นทุกซ็อกเก็ตที่สร้างหลังจากนั้นจะใช้เครือข่ายนี้ ซ็อกเก็ตที่มีอยู่แล้วยังคงใช้เครือข่ายที่สร้างขึ้น จึงเป็นเหตุให้พูลการเชื่อมต่อที่เปิดก่อนการผูกยังแก้ไขชื่อผ่านเส้นทางเดิมได้ ค่าที่ส่งคืนเป็น boolean และผลลัพธ์ false หมายความว่าการผูกไม่ได้เกิดขึ้น ให้ลองใหม่ด้วยการหน่วงสั้น ๆ และบันทึกทั้งสองครั้ง

ขั้นตอนที่ 3: จำกัดการผูกให้อยู่ในขอบเขตที่จำเป็น

การผูกทั้งโปรเซสนั้นหยาบเกินไป เทเลเมทรี การตรวจสอบอัปเดต และ SDK ของบุคคลที่สามก็ย้ายไปยังอุโมงค์ด้วย และหากอุโมงค์ไม่มีอินเทอร์เน็ต สิ่งเหล่านี้ก็เริ่มล้มเหลว สำหรับคำขอเดียว ให้ใช้ socket factory ของเครือข่ายและคงค่าเริ่มต้นของอุปกรณ์ไว้สำหรับอย่างอื่น เลือกโมเดลอย่างตั้งใจ: การผูกแบบแคบต่อการเชื่อมต่อ หรือการผูกโปรเซสพร้อมการยกเลิกการผูกอย่างชัดเจนเมื่อ VPN หายไป

คุณสมบัติสองอย่างของ resolver สามารถเอาชนะการผูกได้โดยไม่เกิดข้อผิดพลาด DNS ส่วนตัวในโหมดเข้มงวดจะส่งคำถามไปยังเซิร์ฟเวอร์ DoT ที่ระบุชื่อแทน resolver ของเครือข่าย และแอปที่นำไคลเอนต์ DNS-over-HTTPS ของตัวเองมาจะข้าม resolver ของระบบทั้งหมด ตรวจสอบทั้งสองอย่างก่อนสรุปว่าการผูกล้มเหลว คำถามที่ไม่เคยไปถึงเซิร์ฟเวอร์ DNS ของ VPN จะไม่ปรากฏในบันทึกใด ๆ ฝั่งอุโมงค์

ขั้นตอนที่ 4: อย่าไว้วางใจข้อจำกัด CONNECTED

NetworkType.CONNECTED ใน WorkManager หมายความว่าเครือข่ายเชื่อมต่ออยู่ และ transport ของ VPN ทำให้เป็นไปตามเงื่อนไขแม้ลิงก์ Wi-Fi หรือเซลลูลาร์ที่อยู่ข้างใต้หายไป งานทำงาน ทุกคำขอล้มเหลว และนโยบายการลองใหม่เปลี่ยนให้เป็นพายุที่ดูเหมือนบั๊กของการจัดตาราง อุโมงค์คือเครือข่าย ข้อจำกัดนั้นไม่เคยเป็นการตรวจสอบอินเทอร์เน็ต

ตรวจสอบความสามารถที่งานต้องการจริง เช่น การเข้าถึงอินเทอร์เน็ตที่ผ่านการตรวจสอบ และรักษานโยบายการลองใหม่แบบจำกัดพร้อม backoff หากงานต้องการชื่อส่วนตัว ให้แก้ไขชื่อนั้นในเครือข่ายที่เลือกก่อนทำงาน และล้มเหลวอย่างรวดเร็วด้วยข้อผิดพลาดที่ชัดเจนแทนการลองคำขอที่ไม่สามารถสำเร็จได้

ขั้นตอนที่ 5: บันทึกหลักฐานและทดสอบช่วงเวอร์ชันซ้ำ

บันทึกประเภท transport ของเครือข่ายที่เลือก เซิร์ฟเวอร์ DNS จาก LinkProperties การผูกคืนค่า true หรือไม่ และความล้มเหลวที่แน่นอนของคำขอแรก จากนั้นเรียกใช้ชื่อส่วนตัวและชื่อสาธารณะภายใต้การผูกเดียวกัน คู่นี้แสดงว่าแอปใช้ resolver ของอุโมงค์หรือถอยกลับไปใช้ค่าเริ่มต้นของอุปกรณ์อย่างเงียบ ๆ และนั่นคือความแตกต่างที่ผู้ใช้สัมผัสได้

ทำซ้ำบนเวอร์ชัน Android เก่าที่สุดที่คุณรองรับและบนรีลีสปัจจุบันหนึ่งรายการ พฤติกรรมของ resolver ที่ทำให้เส้นทางเริ่มต้นดูถูกต้องคือจุดที่อุปกรณ์และเวอร์ชันแตกต่างกัน และบิลด์ที่ผ่านเฉพาะบนอุปกรณ์ทดสอบใหม่ล่าสุดยังไม่ได้รับการตรวจสอบสำหรับช่วงที่คุณจัดส่ง adb shell dumpsys connectivity เป็นวิธีที่รวดเร็วในการยืนยันว่าอุปกรณ์รายงานเครือข่ายและความสามารถใดขณะที่คุณจำลองความล้มเหลว

บทความที่เกี่ยวข้อง