מסנן חבילת Android

מסנן Android Packet (APF) מאפשר ללוגיקת סינון חבילות החומרה של framework במהלך זמן ריצה. כך המערכת יכולה לחסוך בצריכת החשמל על ידי שחרור חבילות בחומרה, והמסגרת של Android יכולה לשנות את כללי הסינון בזמן הריצה בהתאם לתנאי הרשת.

סקירה כללית של APF

APF מורכב משני חלקים עיקריים:

  • התרגום ב-APF פועל בחומרה של הרשת (בדרך כלל ערכת השבבים ל-Wi-Fi). המתרגם של APF מריץ בייטקוד של APF על חבילות שהחומרה מקבלת, ומחליטים אם לקבל או להסיר אותן.
  • קוד הגנרציה של תוכנית APF פועל במעבד הראשי. הקוד יוצר ומעדכן תוכניות APF בהתאם למצב הרשת והמכשיר.

שיטות HAL ב-Wi-Fi מאפשרות ל-framework של Android להתקין את הבייטקוד של תוכנית APF ולקרוא את המוניים הנוכחיים. המודול של Network Stack Mainline יכול לעדכן את הבייטקוד של תוכנית APF בכל שלב בזמן ש-APF פועל.

הוטמעו כמה מסנני APF. לדוגמה, APF כולל מסננים להסרת חבילות ethertype לא מותרות, סינון חבילות פרסום בנתב IPv6 (RA), סינון של תעבורת נתונים בשידורים מרובים (multicast) ותעבורת נתונים אם נעילת השידור הרחב לא מוחזקת, שחרור חבילות 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 עצמה וגם לאחסון נתונים, ואי אפשר לנקות או לכתוב את הזיכרון באמצעות ערכת השבבים, אלא באמצעות methods של APF HAL. הבייטקוד של APF משתמש באחסון הנתונים כדי לאחסן מונה של חבילות שאושרו ונשלחו. אפשר לקרוא את אזור הנתונים מה-framework של Android. נפח הזיכרון המינימלי שזמין ל-APF הוא 1,024 בייטים.

ניפוי באגים ב-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