ตัวกรองแพ็คเก็ต Android

Android Packet Filter (APF) ช่วยให้เฟรมเวิร์กควบคุมตรรกะการกรองแพ็กเก็ตฮาร์ดแวร์ในขณะรันไทม์ ซึ่งช่วยให้ระบบประหยัดพลังงานโดยการปล่อยแพ็กเก็ตลงในฮาร์ดแวร์ ในขณะเดียวกันก็อนุญาตให้เฟรมเวิร์ก Android เปลี่ยนกฎการกรองขณะรันไทม์ตามเงื่อนไขของเครือข่าย

ภาพรวมของ APF

APF ประกอบด้วยสององค์ประกอบหลัก:

  • ล่าม APF ทำงานบนฮาร์ดแวร์เครือข่าย (โดยทั่วไปคือชิปเซ็ต Wi-Fi) ตัวแปล APF รันรหัสไบต์ APF บนแพ็กเก็ตที่ได้รับจากฮาร์ดแวร์ และตัดสินใจว่าจะยอมรับหรือปล่อยแพ็กเก็ตเหล่านั้น
  • รหัสการสร้างโปรแกรม APF ทำงานบน CPU หลัก รหัสสร้างและอัปเดตโปรแกรม APF ตามสถานะเครือข่ายและอุปกรณ์

วิธี Wi-Fi HAL อนุญาตให้เฟรมเวิร์ก Android ติดตั้งรหัสไบต์ของโปรแกรม APF และอ่านตัวนับปัจจุบัน โมดูล Network Stack Mainline สามารถอัปเดตรหัสไบต์ของโปรแกรม APF ได้ตลอดเวลาในขณะที่ APF กำลังทำงานอยู่

มีการนำตัวกรอง APF หลายตัวไปใช้ ตัวอย่างเช่น APF มีตัวกรองเพื่อทิ้งอีเทอร์ไทป์ที่ไม่ได้รับอนุญาต กรองแพ็กเก็ตโฆษณาเราเตอร์ IPv6 (RA) กรองมัลติคาสต์และการรับส่งข้อมูลการออกอากาศ หากไม่มีการล็อคมัลติคาสต์ ปล่อยแพ็กเก็ต DHCP สำหรับโฮสต์อื่น และวางโปรโตคอลการแก้ไขที่อยู่ที่ไม่พึงประสงค์ (ARP) และ (การค้นพบเพื่อนบ้าน) แพ็กเก็ต ND รายการตัวกรองทั้งหมดถูกกำหนดไว้ใน ApfFilter

เนื่องจากโค้ดการสร้างโปรแกรม APF เป็นส่วนหนึ่งของโมดูล Network Stack จึงสามารถอัปเดตตรรกะการกรองได้ และสามารถเพิ่มตัวกรองใหม่ได้ ผ่านการอัพเดต Mainline ทุกเดือน

การบูรณาการ APF

APF API ถูกกำหนดไว้ใน apf_interpreter.h รหัสเฟิร์มแวร์ Wi-Fi เรียก int accept_packet() เพื่อตรวจสอบว่าแพ็กเก็ตควรถูกทิ้ง (ค่าส่งคืนเป็นศูนย์) หรือส่งผ่าน (ค่าส่งคืนที่ไม่ใช่ศูนย์) คำสั่ง APF มีความยาวผันแปรได้ แต่ละคำสั่งมีความยาวอย่างน้อยหนึ่งไบต์ รหัสคำสั่ง APF ถูกกำหนดไว้ใน apf.h

APF อาศัยหน่วยความจำเฉพาะ หน่วยความจำใช้สำหรับทั้งโปรแกรม APF เองและสำหรับการจัดเก็บข้อมูล และหน่วยความจำจะต้องไม่ถูกล้างหรือเขียนโดยชิปเซ็ต ยกเว้นผ่านวิธี APF HAL รหัสไบต์ APF ใช้ที่จัดเก็บข้อมูลเพื่อจัดเก็บตัวนับสำหรับแพ็กเก็ตที่ยอมรับและปล่อย ขอบเขตข้อมูลสามารถอ่านได้จากเฟรมเวิร์ก Android จำนวนหน่วยความจำขั้นต่ำที่ใช้ได้กับ APF ต้องเป็น 1024 ไบต์

ดีบัก APF

หากต้องการตรวจสอบว่า APF เปิดใช้งานบนอุปกรณ์หรือไม่ ให้แสดงโปรแกรมปัจจุบัน และแสดงตัวนับปัจจุบัน ให้รันคำสั่ง adb shell dumpsys network_stack ต่อไปนี้เป็นตัวอย่างของคำสั่งนี้:

adb shell dumpsys network_stack
......
IpClient.wlan0 APF dump:
    Capabilities: ApfCapabilities{version: 4, maxSize: 4096, format: 1}
......
    Last program:
      6bfcb03a01b8120c6b9494026506006b907c025e88a27c025988a47c025488b87c024f88cd7c024a88e17c024588e384004408066a0e6bdca4022b000600010800060412147a1e016bd884021f00021a1c6b8c7c021c0000686bd4a402080006ffffffffffff6a266bbca402010004c0a801eb6bf87401f6120c84005f08000a17821f1112149c00181fffab0d2a108211446a3239a20506c2fc393057dd6bf47401cb0a1e52f06bac7c01c600e06bb41a1e7e000001b9ffffffff6bb07e000001aec0a801ff6be868a4019a0006ffffffffffff6bb874019b6bf07401907c001386dd686bd0a4017d0006ffffffffffff6bc874017e0a147a0e3a6b980a267c017000ff6be07401650a366ba87c016200858219886a26a2050fff02000000000000000000000000006ba4740146aa0e84013700e6aa0f8c0130006068a4011b000f33330000000184c9b26aed4c86dd606a12a2f02600b03afffe8000000000000086c9b2fffe6aed4cff02000000000000000000000000000186006a3aa2e9024000123c92e4606a3ea2d70800000000000000006a56a2ce04030440c01a5a92c9601a5e92c4606a62a2bb04000000006a66a2a6102401fa00049c048400000000000000006a76a29d04030440c01a7a9298601a7e9293606c0082a28904000000006c0086a27310fdfd9ed67950000400000000000000006c0096a2690418033c001a9a9264606c009ea24e102401fa00049c048000000000000000006c00aea24404180330001ab2923f606c00b6a22910fdfd9ed67950000000000000000000006c00c6a21f04190300001aca921a606c00cea20410fdfd9ed67950000400000000000000016bc472086be4b03a01b87206b03a01b87201
    APF packet counters:
      TOTAL_PACKETS: 469
      PASSED_DHCP: 4
      PASSED_IPV4: 65
      PASSED_IPV6_NON_ICMP: 64
      PASSED_IPV4_UNICAST: 64
      PASSED_IPV6_ICMP: 223
      PASSED_IPV6_UNICAST_NON_ICMP: 6
      PASSED_ARP_UNICAST_REPLY: 4
      PASSED_NON_IP_UNICAST: 1
      DROPPED_RA: 4
      DROPPED_IPV4_BROADCAST_ADDR: 7
      DROPPED_IPV4_BROADCAST_NET: 27

เอาต์พุตสำหรับตัวอย่างนี้ คำสั่ง adb shell dumpsys network_stack มีดังต่อไปนี้:

  • ApfCapabilities{version: 4, maxSize: 4096, format: 1} : หมายความว่าชิป Wi-Fi รองรับ APF (เวอร์ชัน 4)
  • Last program : ส่วนนี้เป็นไบนารีของโปรแกรม APF ที่ติดตั้งล่าสุดในรูปแบบสตริงเลขฐานสิบหก
  • APF packet counters : ส่วนนี้จะแสดงจำนวนแพ็กเก็ตที่ส่งผ่านหรือทิ้งโดย APF และเหตุผลเฉพาะ

หากต้องการถอดรหัสและแยกส่วนโค้ดเป็นภาษาแอสเซมเบลอร์ที่มนุษย์อ่านได้ ให้ใช้เครื่องมือ apf_disassembler หากต้องการคอมไพล์ไบนารีที่ปฏิบัติการได้ ให้รันคำสั่ง m apf_disassembler ต่อไปนี้เป็นตัวอย่างวิธีการใช้เครื่องมือ apf_disassembler

echo "6bfcb03a01b8120c6b949401e906006b907c01e288a27c01dd88a47c01d888b87c01d388cd7c01ce88e17c01c988e384004008066a0e6bdca401af000600010800060412147a1e016bd88401a300021a1c6b8c7c01a00000686bd4a4018c0006ffffffffffff1a266bc07c018900006bf874017e120c84005408000a17821f1112149c00181fffab0d2a108211446a3239a205065a56483ac3146bf47401530a1e52f06bac7c014e00e06bb41a1e7e00000141ffffffff6be868a4012d0006ffffffffffff6bb874012e6bf07401237c001386dd686bd0a401100006ffffffffffff6bc87401110a147a0d3a6b980a267c010300ff6be072f90a366ba87af8858218886a26a2040fff02000000000000000000000000006ba472ddaa0e82d0aeaa0f8c00c9025868a2b60f5a56483ac3140c8126f3895186dd606a12a28b2600783afffe8000000000000002005efffe00026fff02000000000000000000000000000186006a3aa284024000123c94007d02586a3ea2700800000000000000006a56a26704190500001a5a94006002586a5ea23b2020014860486000000000000000006464200148604860000000000000000000646a7ea23204030440c01a8294002b02581a8694002402586c008aa21a04000000006c008ea204102a0079e10abcf60500000000000000006bc472086be4b03a01b87206b03a01b87201" | out/host/linux-x86/bin/apf_disassembler
       0: li    r1, -4
       2: lddw  r0, [r1+0]
       3: add   r0, 1
       5: stdw  r0, [r1+0]
       6: ldh   r0, [12]
       8: li    r1, -108
      10: jlt   r0, 0x600, 504
      15: li    r1, -112
      17: jeq   r0, 0x88a2, 504
      22: jeq   r0, 0x88a4, 504
      27: jeq   r0, 0x88b8, 504
      32: jeq   r0, 0x88cd, 504
      37: jeq   r0, 0x88e1, 504
      42: jeq   r0, 0x88e3, 504
      47: jne   r0, 0x806, 116
......

หากต้องการตรวจสอบผลลัพธ์ APF แบบออฟไลน์ ให้ใช้เครื่องมือ apf_run หากต้องการคอมไพล์ไบนารีที่ปฏิบัติการได้ ให้รันคำสั่ง m apf_run ต่อไปนี้เป็นตัวอย่างวิธีการตรวจสอบกับแพ็กเก็ตเดียวโดยใช้คำสั่ง apf_run

หากต้องการจัดเตรียมการนำเสนอสตริงไบนารีฐานสิบหกของแพ็กเก็ตดิบ ให้ใช้ตัวเลือก --packet หากต้องการระบุสตริงไบนารี่ฐานสิบหกของขอบเขตข้อมูล ซึ่งใช้ในการจัดเก็บตัว นับ APF ให้ใช้ --data option เนื่องจากตัวนับแต่ละตัวมีความยาว 4 ไบต์ ขอบเขตข้อมูลจึงต้องยาวเพียงพอเพื่อให้แน่ใจว่าไม่มีบัฟเฟอร์ล้นเกิดขึ้น

out/host/linux-x86/bin/apf_run --program 6bfcb03a01b8120c6b9494010c06006b907c010588a27c010088a47c00fb88b87c00f688cd7c00f188e17c00ec88e384003908066a0e6bdca2d40600010800060412147a18016bd882ca021a1c6b8c7ac900686bd4a2b706ffffffffffff6a266bbca2b204c0a814656bf872a8120c84005808000a17821e1112149c00171fffab0d2a108210446a3239a204064651dbcc88ff6bf4727e0a1e52f06bac7a7be06bb41a1e7e0000006effffffff6bb07e00000063c0a814ff6be868a25106ffffffffffff6bb872536bf072497c001086dd686bd0a23806ffffffffffff6bc8723a0a147a0b3a6b980a267a2eff6be072240a366ba87a23858218886a26a2040fff02000000000000000000000000006ba472086be4b03a01b87206b03a01b87201 --packet 5ebcd79a8f0dc244efaab81408060001080006040002c244efaab814c0a8ca1e5ebcd79a8f0d --data 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Packet passed
Data: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000001

หากต้องการตรวจสอบผลลัพธ์ APF กับไฟล์ pcap ที่ถ่ายโดย tcpdump ให้ใช้คำสั่ง apf_run ดังต่อไปนี้:

out/host/linux-x86/bin/apf_run --program 6bfcb03a01b8120c6b989401df06006b947c01d888a27c01d388a47c01ce88b87c01c988cd7c01c488e17c01bf88e384004408066a0e6bdca401a5000600010800060412147a1e016bd884019900021a1c6b907c01960000686bd4a401820006ffffffffffff6a266bc0a4017b0004c0a82b056bf874017084005f08000a17821f1112149c00181fffab0d2a108211446a3239a20506fabe589435936bf47401470a1e52f06bb07c014200e06bb81a1e7e00000135ffffffff6bb47e0000012ac0a82bff6be868a401160006ffffffffffff6bbc7401176bf074010c7c001086dd686bd0a2fb06ffffffffffff6bcc72fd0a147a0b3a6b9c0a267af1ff6be072e70a366bac7ae6858218886a26a2040fff02000000000000000000000000006ba872cbaa0e82be8eaa0f8c00b7025868a2a40ffabe5894359352a9874d08aa86dd606a12a2792600583afffe80000000000000f7d4e8ccd81ddb43fe80000000000000f8be58fffe94359386006a3aa272024108123c94006b02586a3ea25e0800000000000000006a56a25504030440c01a5a94004e02581a5e94004702586a62a23e04000000006a66a229102409891f9a26ae6d00000000000000006a76a22004190300001a7a94001902586a7ea204102409891f9a26ae6dba98e781ca9ef9ba6bc872086be4b03a01b87206b03a01b87201 --pcap apf.pcap --data 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
37 packets dropped
1733 packets passed
Data: 00000000000000000000000000000000000000000200000005000000000000000000000002000000000000001b000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000689000000000000003c00000000000000000000000000000000000006ea