tcpdump를 사용하여 IPv6 패킷에서 HTTP 메서드 필터링

tcpdump를 사용하여 IPv6 패킷에서 HTTP 메서드 필터링

트래픽을 캡처하기 위해 "tcpdump"를 사용하고 있으며 HTTP 메서드로 필터링하고 싶습니다. IPv4 패킷이 있는 경우 다음을 사용합니다. tcpdump -s 0 -A 'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420'HTTP GET 패킷을 필터링합니다.

안타깝게도 이 tcp[]필터는 IPv6 패킷에서는 작동하지 않습니다. 문서에 따르면

같은 전송 계층 헤더에 대한 산술 표현식은 tcp[0]IPv6 패킷에 대해 작동하지 않습니다.

그래서 tcpdump를 사용하여 IPv6 트래픽에 대해 HTTP 메서드만 필터링하는 다른 방법을 찾고 있습니다.

솔루션 검색을 시도했지만 필터링된 모든 트래픽을 pcap 파일에 직접 출력하려고 하기 때문에 내 요구에 적합하지 않은 grep 사용이 포함된 것 같습니다.

답변1

tcpdump버전 4.99.x 기준 IPv6 의 제한 사항

IPv4의 경우 패킷에서 페이로드 오프셋을 얻으려면 다음을 사용하여 페이로드 오프셋을 어느 정도 계산할 수 있습니다.IPv4의 IHL+ TCP의 데이터 오프셋IPv4 옵션과 TCP 옵션도 고려합니다. 이것은 포함하기에 충분히 간단합니다.tcpdumpBPF 바이트코드 필터를 생성할 때 직접적으로(예를 들어 일부 BPF 문서를 사용할 수 있음)거기).

대신 IPv6의 경우 고정 헤더와 상위 헤더 사이에 확장 헤더의 가변(0~9 사이) 개수가 있을 수 있습니다. 이는 특정 경우에 대한 추가 특성이 없거나 잘못된 형식의 패킷에 대한 보호를 시도하지 않는다는 가정 하에 패킷에서 페이로드 오프셋을 찾기 위해 가능한 10가지 경우(0, 1, 2, ... 9 확장 헤더)에 대한 코드를 포함한다는 의미입니다. (오탐 일치로 이어질 수 있음): 복잡성과 그러한 헤더를 무시하는 결함 있는 구현을 제공하려는 의지가 없기 때문에 이것이 구현되지 않았다고 가정할 수 있습니다.

ip6 and tcp dst port 80아래 생성된 BPF 코드에서 볼 수 있듯이 확장 헤더를 고려하지 않는 것과 같은 간단한 테스트도 있습니다 .

$ tcpdump --version 
tcpdump version 4.99.3
libpcap version 1.10.3 (with TPACKET_V3)
OpenSSL 3.0.9 30 May 2023
$ tcpdump -y EN10MB -d ip6 and tcp dst port 80
(000) ldh      [12]
(001) jeq      #0x86dd          jt 2    jf 7
(002) ldb      [20]
(003) jeq      #0x6             jt 4    jf 7
(004) ldh      [56]
(005) jeq      #0x50            jt 6    jf 7
(006) ret      #262144
(007) ret      #0

그래서 교통 체증을 놓칠 수 있습니다.

tcpdump 4.99.x부터 IPv6 확장 헤더를 적절하게 처리하는 유일한 위치는 매뉴얼 페이지 끝에 문서화되어 있는 것으로 보입니다.

ip6 proto헤더 체인을 추적해야 하지만 지금은 그렇지 않습니다. ip6 protochain이 동작을 위해 제공됩니다.

실제로 현재 tcpdump 4.99.x는 ip6 and tcp다음과 같습니다 ip6 proto 6(동일한 바이트코드를 생성함).

$ tcpdump -y EN10MB -d ip6 and tcp
(000) ldh      [12]
(001) jeq      #0x86dd          jt 2    jf 8
(002) ldb      [20]
(003) jeq      #0x6             jt 7    jf 4
(004) jeq      #0x2c            jt 5    jf 8
(005) ldb      [54]
(006) jeq      #0x6             jt 7    jf 8
(007) ret      #262144
(008) ret      #0

while은 ip6 protochain 6좀 더 철저한 검사를 수행하며 TCP와 같은 상위 계층(최종 전송 헤더)과 관련된 모든 테스트에서 예상되는 것입니다.

$ tcpdump -y EN10MB -d ip6 protochain 6
(000) ldh      [12]
(001) jeq      #0x86dd          jt 2    jf 35
(002) ldb      [20]
(003) ldx      #0x28
(004) jeq      #0x6             jt 32   jf 5
(005) jeq      #0x3b            jt 32   jf 6
(006) jeq      #0x0             jt 10   jf 7
(007) jeq      #0x3c            jt 10   jf 8
(008) jeq      #0x2b            jt 10   jf 9
(009) jeq      #0x2c            jt 10   jf 19
(010) ldb      [x + 14]
(011) st       M[0]
(012) ldb      [x + 15]
(013) add      #1
(014) mul      #8
(015) add      x
(016) tax      
(017) ld       M[0]
(018) ja       4
(019) jeq      #0x33            jt 20   jf 32
(020) txa      
(021) ldb      [x + 14]
(022) st       M[0]
(023) txa      
(024) add      #1
(025) tax      
(026) ldb      [x + 14]
(027) add      #2
(028) mul      #4
(029) tax      
(030) ld       M[0]
(031) ja       4
(032) add      #0
(033) jeq      #0x6             jt 34   jf 35
(034) ret      #262144
(035) ret      #0

위의 4개 테스트에서는 jt 10) (10(018) ja 4특정 IPv6 확장 헤더 중 4개를 반복하여 건너뛰고 IPSec AH를 처리합니다 (19). (31)다른 곳에서 이러한 코드를 생성하는 방법을 모르겠습니다.tcpdump언어(직접적으로 말하는 것보다BPF암호). ip6 protochain 6 and ip6 and tcp dst port 80방금 얻은 TCP 헤더를 활용하는 대신 처음부터 다시 시작하거나 더 나쁜 경우를 사용합니다 .

동일한 종류의 문제가 Linux용 다양한 네트워크 시설 및 도구에 설명되어 있습니다. 예:tc u32말한다:

icmp_code VAL_MASK_8

icmp 또는 ipv6-icmp의 다음 헤더 프로토콜을 가정하고 유형 또는 코드 필드 값을 일치시킵니다.코드에서 가정한 것처럼 이는 위험합니다.IPv4의 최소 헤더 크기 및IPv6용 확장 헤더 부족.

이 모든 것은 특히 HTTP의 경우 연결이 재사용될 때 다음 HTTP 쿼리가 패킷 경계의 시작 부분에 있지 않을 수도 있고 쿼리가 아닌 데이터로 포함된 쿼리가 해당 데이터가 일치할 경우 일치할 수도 있다는 점조차 고려하지 않습니다. 패킷 경계의 시작 부분에 나타납니다.

tcpdump버전 4.99.x를 사용하여 0 확장 헤더 사례를 테스트합니다.

다음은 0개의 확장 헤더를 사용한 테스트입니다. 즉, 동일한 수준에서tcpdump현재는 최소한의 확인만 수행하고 있습니다.

tcpdump -n -s 0 -A 'ip6[6] == 6 and ( ip6[4:2] - ((ip6[52] & 0xf0) >> 2) >= 4 ) and ip6[40 + ((ip6[52] & 0xf0) >> 2) :4] == 0x47455420'

다음과 같이 문서화할 수 있습니다(TCP 헤더가 항상 위치 40에서 시작하는 0 확장 헤더의 경우에만 해당).

  • 다음 헤더는 TCP입니다

    ip6[6] == 6
    
  • IPv6페이로드 길이:

    ip6[4:2]
    
  • TCP데이터 오프셋(고정 IPv6 크기 40 + 12 = 52)(바이트를 얻기 위한 적절한 조정)

    (ip6[52] & 0xf0) >> 2
    
  • TCP 페이로드 길이 = IPv6 페이로드 길이 - TCP 데이터 오프셋

  • 최소 "GET" 길이에 대해 최소 4바이트의 TCP 페이로드가 있는지 테스트합니다.

    ip6[4:2] - ((ip6[52] & 0xf0) >> 2)  >= 4
    
  • ASCII/UTF-8로 인코딩된 4바이트 문자열 "GET"은 4바이트 값 0x47455420으로 표시될 수 있습니다.

  • TCP 페이로드 오프셋은 IPv6 고정 헤더 길이(40) + TCP 데이터 오프셋입니다.

    40 + ((ip6[52] & 0xf0) >> 2)
    
  • IPv6 고정 헤더 길이(40) + 데이터 오프셋에서 시작하는 첫 번째 4바이트 단어가 문자열 "GET "의 값과 같은지 테스트합니다.

    ip6[40 + ((ip6[52] & 0xf0) >> 2) :4] = 0x47455420
    

nftablesLinux 커널 >= 5.15.54 +tcpdump

나는 다음을 사용하여 간단한 대체 Linux 전용 방법을 제안합니다.nftables그리고 충분한 최신 커널이 필요합니다(Linux 커널 버전>= 5.15.54백포트됨5.16) 게다가nftables>= 1.0.1지원하기 위해@ih(내부 헤더/페이로드) 원시 페이로드@th, 단지 (전송 헤더) 가 아닌nftables@th유용한 방식 으로 임의 처리를 수행하기에는 그 자체가 너무 제한적입니다 .

IPv6 확장 헤더를 포함하여 IPv6 데이터그램이 이미 구문 분석되었으며 @th 및 @in 포인터를 이미 사용할 수 있습니다.nftables: 모든 케이스를 가져오기 위해 추가 처리가 필요하지 않습니다. 나는 의지한다nftables실제 TCP 페이로드 크기를 계산할 필요 없이 패킷이 너무 짧은지 확인하는 데 실패합니다.tcpdump그리고 BPF,nftables뺄셈을 할 수 없어서 크기를 제대로 확인할 방법이 없습니다.)

그만큼nftables아래 예는 OP의 정확한 예를 모방하려고 시도하지만 일부 조정 없이는 항상 모든 세부 사항을 모방할 수는 없습니다. 방향이나 포트가 없으며 NAT 이전에 들어오는 패킷과 NAT 이후에 나가는 패킷을 캡처합니다(따라서 후크와 우선 순위가 선택됨). 선택한 패킷이 최종적으로에 보냈습니다nflog시설:

두 번째 호출 형식(만약nflog_group지정됨), Linux 커널은 패킷을 nfnetlink_log로 전달하고 nfnetlink_log는 netlink 소켓을 통해 지정된 그룹으로 로그를 보냅니다. 하나의 사용자 공간 프로세스는 로그를 수신하기 위해 그룹에 가입할 수 있습니다 [...]

table ip6 special_log
delete table ip6 special_log

table ip6 special_log {
        chain log_to_nflog {
                log group 4242
        }

        chain ih_filter {
                meta l4proto tcp @ih,0,32 0x47455420 counter jump log_to_nflog
        }

        chain c_ingress {
                type filter hook prerouting priority -150; policy accept;
                jump ih_filter
        }
        chain c_egress {
                type filter hook postrouting priority 150; policy accept;
                jump ih_filter
        }
}

리눅스에서는nflog기능은 의사 인터페이스로 사용 가능합니다(libpcap그리고)tcpdump:

# tcpdump -D |grep nflog
12.nflog (Linux netfilter log (NFLOG) interface) [none]

에 의해 선택된 패킷nftables따라서 다음과 같이 표시될 수 있습니다(동일한 NFLOG 그룹 재사용: 4242).

tcpdump -n -s 0 -A -i nflog:4242

주의 사항: 직접 캡처보다 대기 시간이 더 길어집니다.

참고: 올바른 취급nftables확장 헤더가 있는 사례는 실제로 UDP(TCP가 아님)와 조각난 패킷(조각 헤더) TCP보다 UDP로 조각난 패킷을 생성하는 것이 훨씬 쉽고 확장 헤더를 어딘가에 가질 수 있는 다른 방법을 찾지 못했기 때문에 socat(시작을 방지하기 위해 별도의 네트워크 네임스페이스에서 ) 사용했습니다 .nf_defrag_ipv6

관련 정보