Android 패킷 필터

Android 패킷 필터(APF)를 사용하면 프레임워크에서 런타임에 하드웨어 패킷 필터링을 제어할 수 있습니다. 따라서 시스템이 하드웨어에서 패킷을 삭제하여 전원을 절약할 수 있으며 Android 프레임워크는 네트워크 조건에 따라 런타임에 필터링 규칙을 변경할 수 있습니다.

APF 개요

APF는 다음 두 가지 기본 요소로 구성됩니다.

  • APF 인터프리터: 네트워킹 하드웨어에서 실행됩니다(일반적으로 Wi-Fi 칩셋). APF 인터프리터는 하드웨어에서 수신한 패킷에서 APF 바이트 코드를 실행하고 이를 수락할지 삭제할지 결정합니다.
  • APF 프로그램 생성 코드: 메인 CPU에서 실행됩니다. 코드는 네트워크와 기기 상태에 따라 APF 프로그램을 만들고 업데이트합니다.

Wi-Fi HAL 메서드를 사용하면 Android 프레임워크에서 APF 프로그램 바이트 코드를 설치하고 현재 카운터를 읽을 수 있습니다. 네트워크 스택 메인라인 모듈은 APF가 실행되는 동안 언제든지 APF 프로그램 바이트 코드를 업데이트할 수 있습니다.

여러 APF 필터가 구현되었습니다. 예를 들어 APF는 허용되지 않은 ethertype을 삭제하고, IPv6 라우터 광고(RA) 패킷을 필터링하고, 멀티캐스트 잠금이 유지되지 않으면 멀티캐스트 및 브로드캐스트 트래픽을 필터링하고, 다른 호스트의 DHCP 패킷을 삭제하고, 요청하지 않은 주소 결정 프로토콜(ARP)과 (주변 검색) ND 패킷을 삭제하는 필터를 포함합니다. 전체 필터 목록은 ApfFilter에 정의되어 있습니다.

APF 프로그램 생성 코드는 네트워크 스택 모듈에 포함되어 있으므로 월간 메인라인 업데이트를 통해 필터링 로직을 업데이트할 수 있고 새 필터를 추가할 수 있습니다.

APF 통합

APF API는 apf_interpreter.h에 정의되어 있습니다. Wi-Fi 펌웨어 코드는 int accept_packet()을 호출하여 패킷을 삭제해야 하는지(반환값 0) 전달해야 하는지(반환값 0이 아님) 결정합니다. APF 명령은 가변 길이입니다. 각 명령은 최소 1바이트 길이입니다. 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: 이 섹션은 16진수 문자열 형식으로 설치된 최신 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 명령어를 사용하여 단일 패킷을 대상으로 확인하는 방법을 보여주는 예입니다.

원시 패킷의 16진수 바이너리 문자열 표시를 제공하려면 --packet 옵션을 사용하세요. APF 카운터를 저장하는 데 사용되는 데이터 리전의 16진수 바이너리 문자열을 제공하려면 --data option을 사용합니다. 각 카운터가 4바이트 길이이므로 데이터 리전은 버퍼 오버플로가 발생하지 않도록 충분히 길어야 합니다.

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

tcpdump에서 사용하는 pcap 파일을 대상으로 APF 결과를 확인하려면 다음과 같이 apf_run 명령어를 사용하세요.

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