
我正在使用“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 方法。
我嘗試尋找解決方案,但似乎它們包含 grep 的用法,這不適合我的需求,因為我想將所有過濾後的流量直接輸出到 pcap 文件
答案1
tcpdump
從版本 4.99.x 開始,IPv6的限制
對於 IPv4,要取得封包中的有效負載偏移量,只需使用以下方法或多或少計算有效負載偏移量:IPv4 的國際人道法+ TCP的資料偏移量也考慮 IPv4 選項和 TCP 選項。這很簡單,可以包含在tcp轉儲直接在產生 BPF 字節碼過濾器時直接產生(例如一些可用的 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
whileip6 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
循環 4 個特定的 IPv6 擴充標頭以跳過它們,同時(19)
處理(31)
IPSec AH。我不知道如何在其他地方產生這樣的程式碼tcp轉儲語言(而不是直接的帶通濾波器代碼)。使用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 個擴充標頭的測試,即處於同一級別tcp轉儲目前是這樣,只需完成最少的驗證:
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'
可以這樣記錄(仍然僅適用於 0 擴展標頭情況,其中 TCP 標頭始終從位置 40 開始):
下一個標頭是 TCP
ip6[6] == 6
IPv6有效負載長度:
ip6[4:2]
傳輸控制協定資料偏移量(固定 IPv6 的大小為 40 + 12 = 52)(並進行適當調整以取得位元組)
(ip6[52] & 0xf0) >> 2
TCP 負載長度 = IPv6 負載長度 - TCP 資料偏移量
測試至少有 4 個位元組的 TCP 有效負載,至少具有“GET”的長度
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 +tcp轉儲
我提出了一種簡單的僅適用於 Linux 的替代方法,使用nftables並且需要足夠新的核心(Linux 核心版本>= 5.15.54向後移植自5.16) 也nftables>= 1.0.1支援@ih
(內部標頭/有效負載)原始有效負載,而不僅僅是@th
(傳輸頭),因為nftables@th
它本身太有限,無法以有用的方式進行任意處理。
IPv6 資料封包已解析,包括任何 IPv6 擴充標頭,@th 和 @in 指標已可用於nftables:無需進一步處理即可取得所有案例。我依靠nftables如果封包太短,則檢查失敗,而無需計算實際的 TCP 有效負載大小(與tcp轉儲和帶通濾波器,nftables無法進行減法,因此無法正確檢查大小)。
這nftables下面的例子試圖模仿OP的精確例子,但如果不進行一些調整,就不能總是在所有細節上。無方向或端口,捕獲 NAT 之前的傳入資料包和 NAT 之後的傳出資料包(因此選擇了掛鉤和優先權)。最終選定的資料包發送到網誌設施:
在第二種調用形式中(如果nflog_組指定),Linux 核心會將資料包傳遞給 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
}
}
在 Linux 上,網誌設施可作為(libpcap和)tcp轉儲:
# 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)和分段資料包(由片段頭)使用socat
(在單獨的網路命名空間中以防止nf_defrag_ipv6
啟動),因為使用 UDP 生成分段資料包比使用 TCP 更容易,而且我沒有找到其他方法在某處擁有擴展標頭。