การระบุที่มา VPN บน Android: getConnectionOwnerUid กับ /proc/net
Android 10 ซ่อน /proc/net จากแอป VPN ยังได้รับแพ็กเก็ต แต่การระบุที่มาจะย้ายไปที่ getConnectionOwnerUid พร้อมกฎ tuple และสิทธิ์ของตัวเอง
บน Android 10 และใหม่กว่า แอปที่เปิด /proc/net/tcp จะได้รับการปฏิเสธการเข้าถึงแทนตาราง socket อินเทอร์เฟซ VPN ไม่สนใจ เพราะแพ็กเก็ตยังมาถึงอยู่ เนื่องจากการอุโมงค์เป็นการตัดสินใจเรื่องเส้นทาง ไม่ใช่สิทธิ์ของไฟล์ สิ่งที่เปลี่ยนไปคือคำตอบของคำถามที่แคบลง: “แอปใดเป็นเจ้าของการเชื่อมต่อนี้?” ตัวแทนคือ ConnectivityManager.getConnectionOwnerUid, คำค้นต่อการเชื่อมต่อที่รองรับ และการเลือกระหว่างนิสัยเดิมกับ API ใหม่ขึ้นอยู่กับว่างานใดในสามอย่างที่คุณมีจริง: การรับแพ็กเก็ต การระบุที่มาของโฟลว์ หรือการรวมปริมาณการใช้งาน
สองวิธีในการตอบคำถามเรื่องเจ้าของ
ก่อน API 29 กระบวนการที่ได้รับสิทธิ์พิเศษหรือ root สามารถอ่านตาราง socket ของเคอร์เนล จับคู่สี่ส่วน และรู้ UID ของเจ้าของได้ นั่นให้บัญชีทั้งอุปกรณ์ในไฟล์เดียว ตั้งแต่ API 29 มุมมองระบบไฟล์ถูกจำกัด และเส้นทางที่รองรับคือคำค้นต่อการเชื่อมต่อด้วยโปรโตคอล ที่อยู่ภายใน และที่อยู่ระยะไกล
| Question | Legacy socket tables | getConnectionOwnerUid |
|---|---|---|
| Who owns this flow? | Scan and match the tuple | Ask once per tuple |
| Device-wide inventory? | Yes, when readable | No, one flow at a time |
| Historical usage? | No | No; that is NetworkStatsManager |
| Works without root? | No on modern releases | Yes, for authorized callers |
การเปรียบเทียบไม่ใช่ “เก่ากับใหม่” แต่เป็นสามงานที่แตกต่างกัน ซึ่งเคยได้รับการตอบสนองจากไฟล์ที่อ่านได้ไฟล์เดียว และตอนนี้ได้รับการตอบสนองจากอินเทอร์เฟซสามแบบที่มีสัญญาสามแบบ
ที่อยู่ภายในคือปลายทางของแอป
ลายเซ็นของเมธอดรับโปรโตคอล ที่อยู่ socket ภายใน และที่อยู่ socket ระยะไกล “ภายใน” หมายถึงฝั่งแอปในการเชื่อมต่อ ไม่ใช่ปลายทางที่บังเอิญเป็นแหล่งของแพ็กเก็ตในขณะที่คุณตรวจสอบ แพ็กเก็ตที่เดินทางจากเซิร์ฟเวอร์ระยะไกลกลับมาที่แอปมีแหล่งและปลายทางสลับกันเมื่อเทียบกับคำจำกัดความนั้น
ConnectivityManager cm = getSystemService(ConnectivityManager.class);
int uid = cm.getConnectionOwnerUid(
OsConstants.IPPROTO_TCP, appLocalAddress, appRemoteAddress);ข้อผิดพลาดเรื่องทิศทางนี้เป็นสาเหตุที่พบบ่อยที่สุดที่คำค้นที่ทำงานได้ให้คำตอบผิด หรือไม่ให้เลย บันทึกทั้งสองปลายก่อนเรียก และยืนยันคู่กับการเชื่อมต่อที่แอปเปิดจริง ครอบครัวที่อยู่ก็สำคัญ ที่อยู่ที่แมปผ่าน IPv4 และที่อยู่ IPv6 แบบเนทีฟเป็น tuple ที่ต่างกัน รวมถึงโฟลว์ TCP และ UDP บนพอร์ตเดียวกัน
การอนุญาตและผลลัพธ์ที่ไม่ทราบเป็นส่วนหนึ่งของสัญญา
คำค้นจำกัดเฉพาะผู้เรียกที่ได้รับอนุญาต รวมถึงแอป VPN ที่ใช้งานอยู่สำหรับผู้ใช้ที่เกี่ยวข้อง แอปตรวจสอบที่ไม่เกี่ยวข้องไม่สามารถถือว่าสามารถแจกแจงการเชื่อมต่อของโปรไฟล์อื่นได้ และการเรียกที่ไม่ได้รับอนุญาตอาจโยนข้อยกเว้นด้านความปลอดภัยแทนที่จะคืนข้อผิดพลาดที่เป็นมิตร จัดการทั้งสองผลลัพธ์อย่างชัดเจน
เจ้าของที่หายไปไม่ใช่ชื่อแพ็กเกจ โฟลว์อาจปิดไประหว่างแพ็กเก็ตกับคำค้น tuple อาจไม่สมบูรณ์ หรือผู้เรียกอาจไม่ได้รับอนุญาตให้รู้ การแคชคำตอบที่สำเร็จครั้งแรกแล้วนำกลับมาใช้ใหม่ภายหลังจะระบุการเชื่อมต่อใหม่ให้แอปเก่า ซึ่งแย่กว่าการรายงานว่าไม่ทราบ
เมื่อการระบุที่มาล้มเหลว ทราฟฟิกยังต้องมีการตัดสินใจ: บล็อกในที่ที่นโยบายกำหนด อนุญาตเฉพาะขอบเขตที่คุณเข้าใจ หรือเปิดเผยช่องว่าง ส่วนสำรองนั้นเป็นของการออกแบบ ไม่ใช่ความคิดเห็น
การบัญชีเป็นอีกคำถามหนึ่ง
NetworkStatsManager รายงานการใช้งานภายใต้กฎการเข้าถึงของตัวเอง มันบอกได้ว่า UID หนึ่งถ่ายโอนเท่าใดในช่วงเวลาหนึ่ง แต่บอกเจ้าของแพ็กเก็ตที่มีชีวิตตามอำเภอใจไม่ได้ ความสามารถของเครือข่ายอธิบายคุณสมบัติของเครือข่าย ไม่ใช่ไดเรกทอรีของ socket การผสมทั้งสามจะสร้างแดชบอร์ดที่ดูสอดคล้องแต่ไม่ใช่
สำหรับกรณีง่าย ๆ ในการตัดสินว่าแอปใดใช้การอุโมงค์ รายการแอปที่อนุญาตและไม่อนุญาตที่รองรับของ Android ได้แสดงนโยบายอยู่แล้วโดยไม่ต้องดึงข้อมูลใด ๆ เก็บการระบุที่มาต่อโฟลว์ไว้สำหรับกรณีที่ต้องการจริง ๆ และกันงบประมาณสำหรับการนำไปใช้ที่ดูแลรักษาซึ่งจัดการทิศทาง สิทธิ์ และสถานะที่ไม่ทราบร่วมกัน
เลือกเครื่องมือตามงาน แล้วทดสอบขอบ
หากข้อกำหนดคือการเลือกอุโมงค์ ให้ใช้รายการของแพลตฟอร์ม หากเป็นการระบุที่มาแบบสด ให้ใช้คำค้นหาเจ้าของและถือทุก tuple ที่ตอบไม่ได้ว่าไม่ทราบ หากเป็นยอดรวมย้อนหลัง ให้ใช้ stats API จากนั้นทดสอบสามขอบที่ทำให้การนำไปใช้แบบง่าย ๆ พัง: แพ็กเก็ตที่สวนทาง โฟลว์ที่ปิดก่อนคุณถาม และผู้เรียกที่ไม่ใช่ VPN ที่ใช้งานอยู่
ไม่มีสิ่งใดในนี้ที่ต้องปิด SELinux ทำ root โทรศัพท์ หรือทำให้ตารางเคอร์เนลอ่านได้ทั่วโลก ข้อจำกัดคือประเด็น: แพลตฟอร์มย้ายการระบุที่มาไปไว้หลังสัญญา เพื่อให้คำตอบมีให้กับองค์ประกอบที่ต้องการอย่างชอบธรรมเท่านั้น และไม่มีให้ใครอื่น