Filtro pacchetti Android

Il filtro pacchetti Android (APF) consente al framework di controllare la logica di filtro dei pacchetti hardware in fase di runtime. In questo modo il sistema risparmia energia rilasciando pacchetti nell'hardware, consentendo al framework Android di modificare le regole di filtro in fase di runtime in base alle condizioni della rete.

Panoramica APF

L'APF è costituito da due componenti principali:

  • L'interprete APF viene eseguito sull'hardware di rete (in genere il chipset Wi-Fi). L'interprete APF esegue il bytecode APF sui pacchetti ricevuti dall'hardware e decide se accettarli o meno.
  • Il codice di generazione del programma APF viene eseguito sulla CPU principale. Il codice crea e aggiorna i programmi APF in base allo stato della rete e del dispositivo.

I metodi HAL Wi-Fi consentono al framework Android di installare il bytecode del programma APF e di leggere i contatori correnti. Il modulo Mainline dello stack di rete può aggiornare il bytecode del programma APF in qualsiasi momento mentre l'APF è in esecuzione.

Sono stati implementati diversi filtri APF. Ad esempio, APF include filtri per eliminare ethertype non consentiti, filtrare pacchetti di annunci router IPv6 (RA), filtrare il traffico multicast e broadcast se il blocco multicast non viene trattenuto, eliminare i pacchetti DHCP per gli altri host e rimuovere i pacchetti ND (ARP) e (rilevamento dei vicini) per la risoluzione degli indirizzi non richiesti. L'elenco completo dei filtri è definito in ApfFilter.

Poiché il codice di generazione del programma APF fa parte del modulo dello stack di rete, la logica di filtro può essere aggiornata ed è possibile aggiungere nuovi filtri tramite aggiornamenti mensili di Mainline.

Integrazione APF

L'API APF è definita in apf_interpreter.h. Il codice firmware Wi-Fi chiama int accept_packet() per determinare se il pacchetto deve essere ignorato (valore restituito da zero) o passato (valore restituito diverso da zero). Le istruzioni APF hanno una lunghezza variabile. Ogni istruzione è lunga almeno un byte. I codici delle istruzioni APF sono definiti in apf.h.

L'APF si basa su una memoria dedicata. La memoria viene utilizzata sia per il programma APF stesso sia per l'archiviazione dei dati e non deve essere cancellata o scritta dal chipset, se non tramite i metodi APF HAL. Il bytecode APF utilizza l'archiviazione dei dati per archiviare i contatori dei pacchetti accettati e scartati. La regione di dati può essere letta dal framework Android. La quantità minima di memoria disponibile per APF deve essere 1024 byte.

APF debug

Per verificare se l'APF è abilitato sul dispositivo, visualizzare il programma corrente e i contatori attuali, esegui il comando adb shell dumpsys network_stack. Di seguito è riportato un esempio di questo comando:

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

L'output di questo comando adb shell dumpsys network_stack di esempio include il seguente:

  • ApfCapabilities{version: 4, maxSize: 4096, format: 1}: i chip Wi-Fi supportano APF (versione 4).
  • Last program: questa sezione è l'ultimo file binario del programma APF installato in formato di stringa esadecimale.
  • APF packet counters: questa sezione mostra quanti pacchetti vengono passati o eliminati dall'APF e i motivi specifici.

Per decodificare e disassemblare il codice in un linguaggio assemblatore leggibile da una persona, utilizza lo strumento apf_disassembler. Per compilare il programma binario eseguibile, esegui il comando m apf_disassembler. Di seguito è riportato un esempio di come utilizzare lo strumento 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
......

Per controllare i risultati della funzionalità APF offline, usa lo strumento apf_run. Per compilare il programma binario eseguibile, esegui il comando m apf_run. Di seguito è riportato un esempio di come eseguire il controllo a fronte di un singolo pacchetto utilizzando il comando apf_run.

Per fornire la presentazione in stringa binaria esadecimale del pacchetto non elaborato, utilizza l'opzione --packet. Per fornire la stringa binaria esadecimale della regione di dati, utilizzata per archiviare il contatore APF, utilizza --data option. Poiché ogni contatore ha una lunghezza di 4 byte, le regioni di dati devono essere sufficientemente lunghe da garantire che non si verifichi l'overflow del buffer.

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

Per verificare i risultati APF rispetto al file pcap preso da tcpdump, utilizza il comando apf_run come segue:

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