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