Filtre de paquets Android

Le filtre de paquets Android (APF) permet au framework de contrôler la logique de filtrage des paquets matériels au moment de l'exécution. Cela permet au système d'économiser de l'énergie en supprimant des paquets dans le matériel, tout en permettant au framework Android de modifier les règles de filtrage au moment de l'exécution en fonction des conditions du réseau.

Présentation de l'outil APF

Il se compose de deux éléments principaux:

  • L'interpréteur APR s'exécute sur du matériel réseau (généralement, le chipset Wi-Fi). L'interpréteur APF exécute le bytecode APF sur les paquets reçus par le matériel et décide de les accepter ou de les supprimer.
  • Le code de génération du programme AAP s'exécute sur le processeur principal. Le code crée et met à jour les programmes APF en fonction de l'état du réseau et de l'appareil.

Les méthodes HAL Wi-Fi permettent au framework Android d'installer le bytecode du programme APF et de lire les compteurs actuels. Le module principal de la pile réseau peut mettre à jour le bytecode du programme APF à tout moment pendant son exécution.

Plusieurs filtres APF sont implémentés. Par exemple, APF inclut des filtres pour supprimer les éthertypes non autorisés, filtrer les paquets d'annonces de routeur IPv6 (RA), filtrer le trafic de multidiffusion et de diffusion si le verrouillage multicast n'est pas respecté, supprimer les paquets DHCP d'autres hôtes, et supprimer les paquets ND (protocole de résolution d'adresses non sollicités) et (détection des voisins). La liste complète des filtres est définie dans ApfFilter.

Étant donné que le code de génération du programme APF fait partie du module de pile réseau, la logique de filtrage peut être mise à jour et de nouveaux filtres peuvent être ajoutés via des mises à jour Mainline mensuelles.

Intégration de la fonctionnalité APF

L'API APF est définie dans apf_interpreter.h. Le code du micrologiciel Wi-Fi appelle int accept_packet() pour déterminer si le paquet doit être supprimé (valeur renvoyée nulle) ou transmis (valeur de retour différente de zéro). Les instructions APF sont de longueur variable. La longueur de chaque instruction est d'au moins un octet. Les codes d'instructions APF sont définis dans apf.h.

L'APF repose sur une mémoire dédiée. La mémoire est utilisée pour le programme APF lui-même et pour le stockage des données. Elle ne doit pas être effacée ni écrite par le chipset, sauf via les méthodes APF HAL. Le bytecode APF utilise le stockage de données pour stocker des compteurs pour les paquets acceptés et supprimés. La région des données peut être lue à partir du framework Android. La quantité minimale de mémoire disponible pour l'APF doit être de 1 024 octets.

Déboguer APF

Pour vérifier si l'APF est activé sur l'appareil, afficher le programme en cours, ainsi que les compteurs actuels, exécutez la commande adb shell dumpsys network_stack. Voici un exemple de cette commande:

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

Le résultat de cet exemple de commande adb shell dumpsys network_stack inclut les éléments suivants:

  • ApfCapabilities{version: 4, maxSize: 4096, format: 1}: cela signifie que les puces Wi-Fi sont compatibles avec le protocole APF (version 4).
  • Last program: cette section correspond au dernier fichier binaire du programme APF installé au format de chaîne hexadécimale.
  • APF packet counters: cette section indique le nombre de paquets transmis ou supprimés par la règle APF et les motifs spécifiques.

Pour décoder et désassembler le code dans un langage assembleur lisible par l'humain, utilisez l'outil apf_disassembler. Pour compiler le binaire exécutable, exécutez la commande m apf_disassembler. Voici un exemple d'utilisation de l'outil 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
......

Pour vérifier les résultats APF hors connexion, utilisez l'outil apf_run. Pour compiler le binaire exécutable, exécutez la commande m apf_run. Voici un exemple de vérification par rapport à un seul paquet à l'aide de la commande apf_run.

Pour fournir la présentation de la chaîne binaire hexadécimale du paquet brut, utilisez l'option --packet. Pour fournir la chaîne binaire hexadécimale de la région de données, qui permet de stocker le compteur APR, utilisez --data option. Étant donné que chaque compteur compte 4 octets, les régions de données doivent être suffisamment longues pour qu'aucun débordement de tampon ne se produise.

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

Pour comparer les résultats APF au fichier pcap pris par tcpdump, utilisez la commande apf_run comme suit:

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