Filtre de paquets Android

Android Packet Filter (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 les 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.

Aperçu de l'APF

L'APF se compose de deux éléments principaux :

  • L' interpréteur APF fonctionne 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 APF 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 Wi-Fi HAL permettent au framework Android d'installer le bytecode du programme APF et de lire les compteurs actuels. Le module Network Stack Mainline peut mettre à jour le bytecode du programme APF à tout moment pendant l'exécution d'APF.

Plusieurs filtres APF sont implémentés. Par exemple, APF inclut des filtres pour supprimer les types Ethernet non autorisés, filtrer les paquets de publicité de routeur IPv6 (RA), filtrer le trafic de multidiffusion et de diffusion si le verrouillage de multidiffusion n'est pas maintenu, supprimer les paquets DHCP pour d'autres hôtes et supprimer le protocole de résolution d'adresse (ARP) non sollicité. et (découverte de voisin) les paquets ND. 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 Network Stack, la logique de filtrage peut être mise à jour et de nouveaux filtres peuvent être ajoutés via des mises à jour mensuelles de Mainline.

Intégration 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 abandonné (valeur de retour nulle) ou transmis (valeur de retour différente de zéro). Les instructions APF sont de longueur variable. Chaque instruction fait au moins un octet. Les codes d'instructions APF sont définis dans apf.h .

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

Déboguer l'APF

Pour vérifier si APF est activé sur l'appareil, afficher le programme en cours et afficher 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 comprend les éléments suivants :

  • ApfCapabilities{version: 4, maxSize: 4096, format: 1} : Cela signifie que les puces Wi-Fi prennent en charge APF (version 4).
  • Last program : Cette section est le dernier binaire du programme APF installé au format chaîne hexadécimale.
  • APF packet counters : cette section montre combien de paquets sont transmis ou abandonnés par APF et les raisons spécifiques.

Pour décoder et désassembler le code dans un langage assembleur lisible par l'homme, 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 ligne, utilisez l'outil apf_run . Pour compiler le binaire exécutable, exécutez la commande m apf_run . Ce qui suit est un exemple de la façon de vérifier 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, utilisée pour stocker le compteur APF , utilisez l' --data option . Étant donné que chaque compteur fait 4 octets de long, les régions de données doivent être suffisamment longues pour garantir 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 vérifier les résultats APF par rapport au fichier pcap récupéré 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