วิธีแยกเครือข่ายย่อยออกจากอุโมงค์ VPN ของ Android
VpnService แยกเส้นทางออกไม่ได้ คุณจึงเพิ่มส่วนเติมเต็ม: คำนำหน้าแปดค่าที่สร้างขึ้นสำหรับ /8 พร้อมการตรวจ IPv6, DNS และการค้นหาที่จับส่วนที่เหลือ
VpnService ของ Android ไม่มีเส้นทางสำหรับแยกออก และการอ่าน API เท่าไรก็ไม่ทำให้เกิดเส้นทางนั้น Builder.addRoute() เพิ่มปลายทางเข้าไปในอุโมงค์เท่านั้น การเก็บเซกเมนต์ LAN ไว้ในเครื่องจึงหมายความว่าเซกเมนต์นั้นไม่เคยเข้าสู่รายการเส้นทางเลย สิ่งที่คุณเพิ่มแทนคือส่วนเติมเต็มของเซกเมนต์ เขียนเป็นคำนำหน้าปกติ งานนี้คือเลขคณิต และมันล้มเหลวในไม่กี่จุดที่คาดเดาได้
ไล่ตรวจตามลำดับด้านล่าง แต่ละข้อถือว่าข้อก่อนหน้าผ่านแล้ว จึงหยุดที่ความล้มเหลวแรกแทนที่จะปะอาการที่อยู่ล่างลงไป
เริ่มจากสิ่งที่อุโมงค์อ้างสิทธิ์
การส่ง 0.0.0.0/0 ให้ addRoute() บอก Android ว่าทุกปลายทาง IPv4 เป็นของอุโมงค์ นี่คือเหตุที่ไคลเอนต์จำนวนมากดูทำ tunneling แบบแยกส่วนไม่ได้ พวกมันอ้างสิทธิ์พื้นที่แอดเดรสทั้งหมดแล้วจึงพยายามลบออกจากพื้นที่นั้น ไม่มีอะไรในตัวสร้างที่ลบออก เส้นทางที่เจาะจงกว่าสำหรับเครือข่ายที่คุณอยากเก็บไว้ในเครื่องกลับทำตรงข้ามกับที่คนคาด เพราะคำนำหน้าที่ตรงกันยาวที่สุดชนะและเครือข่ายนั้นไปอยู่ในอุโมงค์
รายการเส้นทางคือทั้งหมดของนโยบาย ไม่มีสิทธิ์ยับยั้งรายปลายทางอยู่ข้างหลัง และ เอกสารอ้างอิง Builder ไม่ได้ระบุเมธอดใดที่จะให้สิ่งนั้น
สร้างส่วนเติมเต็มจากเลขคณิตของคำนำหน้า
ส่วนเติมเต็มของคำนำหน้าที่ถูกแยกออกคือเซตของพี่น้องของมันบนเส้นทางไปยังรากของต้นไม้แอดเดรส สำหรับแต่ละความยาวตั้งแต่ 1 ไปจนถึงความยาวที่ถูกแยกออก ให้เอาบล็อกที่มีความยาวนั้นซึ่งมีคำนำหน้าของคุณ พลิกบิตที่อยู่ใต้คำนำหน้าโดยตรง แล้วส่งผลลัพธ์ออกมา ฟังดูเป็นนามธรรมจนกว่าคุณจะรันมัน
การแยก 10.0.0.0/8 ออกได้แปดเส้นทาง: 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 ไม่มีเส้นใดมี 10.0.0.0/8 และเมื่อรวมกันก็ครอบคลุมทุกอย่างที่เหลือ
แปดบรรทัดสร้างรายการนั้นสำหรับคำนำหน้าใดก็ได้
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))
จำนวนเส้นทางเท่ากับความยาวของคำนำหน้า และนั่นคือตัวเลขที่ต้องจับตา การแยก /21 หนึ่งครั้งใช้ 21 เส้นทางและยังอ่านได้ การแยกสิบครั้งอาจใช้หลายร้อย ซึ่งปกติหมายความว่าต้องเปลี่ยนการออกแบบเครือข่าย ไม่ใช่ตัวสร้าง
ตรวจตระกูลแอดเดรสและขอบเขตของอุโมงค์
เส้นทาง IPv4 ไม่มีผลกับ IPv6 หากอุโมงค์อ้างสิทธิ์แอดเดรส IPv6 คำนำหน้า LAN ของ IPv6 ต้องมีส่วนเติมเต็มของตัวเอง สร้างด้วยเลขคณิตเดียวกันบน 128 บิต สาเหตุทั่วไปที่การแยกออกทำงานบนกระดาษแต่เครื่องในเครื่องยังเข้าถึงไม่ได้คือ อุโมงค์เข้าถึงโฮสต์ผ่าน IPv6 และถูกตัดออกเฉพาะ IPv4 ตรวจทั้งสองตระกูลก่อนสรุปว่าเลขคณิตผิด
ขอบเขตคืออีกครึ่งหนึ่งของการตรวจ Android ติดตามเส้นทางตามเครือข่ายและตามแอป คำนำหน้าเดียวกันจึงอาจผ่านอุโมงค์สำหรับแอปหนึ่งและตรงสำหรับอีกแอป ขึ้นกับว่าประกาศ VPN ไว้อย่างไร
วางกฎ DNS และกฎรายแอปให้ถูกที่
การแยกเส้นทางไม่เปลี่ยนตัวแก้ไขชื่อ ชื่อโฮสต์ในเครื่องยังตอบได้โดยเซิร์ฟเวอร์ DNS ของอุโมงค์ในขณะที่แอดเดรสถูกส่งเส้นทางในเครื่อง และความไม่ลงรอยปรากฏเป็นชื่อที่แปลงไปยังสิ่งที่ LAN เข้าไม่ถึง ตั้งนโยบายตัวแก้ไขชื่ออย่างตั้งใจ ด้วยโดเมนค้นหาหรือกฎ split-DNS อย่าสันนิษฐานว่าเส้นทางตัดสินใจให้คุณแล้ว
addDisallowedApplication() กันแอปหนึ่งออกจากอุโมงค์ แต่ไม่ได้กันปลายทางออกให้แอปที่ยังอยู่ข้างใน protect() ปล่อยให้ซ็อกเก็ตที่คุณเปิดข้ามอุโมงค์ได้ และนั่นคือวิธีที่อุโมงค์หลีกเลี่ยงการดักการรับส่งของตัวเอง ทั้งสองไม่ได้แทนส่วนเติมเต็ม
ตรวจด้วยการค้นหา ไม่ใช่ด้วยรายการของคุณเอง
เมื่ออุโมงค์ขึ้นแล้ว ให้ถามเครื่องว่าแอดเดรสไปที่ใดจริง ๆ แทนที่จะอ่านรายการที่คุณสร้างซ้ำ บนบิลด์ที่มาพร้อม iproute2 adb shell ip route get 10.1.2.3 ระบุอินเทอร์เฟซที่เคอร์เนลเลือก รันคำสั่งเดียวกันกับแอดเดรสสาธารณะและยืนยันว่ามันระบุอุโมงค์
อีกสองการตรวจก็ปิดวงจร แก้ชื่อในเครื่องก่อน จากนั้นรัน adb shell ip route get บนแอดเดรสที่แก้แล้วและเรียกร้องอินเทอร์เฟซที่ไม่ใช่อุโมงค์ เพราะ adb shell ping -c 1 host.lan ที่สำเร็จพิสูจน์การเข้าถึง ไม่ใช่เส้นทาง ทำการทดสอบตระกูลแอดเดรสซ้ำบน IPv6 หากอุโมงค์อ้างสิทธิ์หนึ่งค่า ทดสอบที่ระดับ API ที่คุณส่งออก เพราะวิธีที่เครือข่าย VPN ถูกเปิดให้ตารางเส้นทางเปลี่ยนไประหว่างรีลีส รายการเส้นทางที่ดูถูกบนกระดาษกับการค้นหาที่เลือกอินเทอร์เฟซผิดเป็นบั๊กคนละแบบ และมีเพียงอย่างหลังที่ถึงผู้ใช้
หากรายการแยกออกยังโตต่อไป ให้หยุดสร้างเส้นทางและเปลี่ยนเลขเครือข่ายระยะไกลหรือ บีบอุโมงค์ให้แคบลง แทน ตัวสร้างเป็นทางอ้อมสำหรับ API ที่หายไป ไม่ใช่เครื่องมือออกแบบ