CaptureFilter の中身(BPF)
• Wireshark
Capture
-> Options
-> Capture Filter:(filter-expression)-> Capture Filter:(filter-expression)
-> Compile selected BPFs
Compile selected BPFs
This button allows you to compile the capture filter into BPF code
and pop up a window showing you the resulting pseudo code. This can
help in understanding the working of the capture filter you created.
The Compile Selected BPFs button leads you to Figure 4.5, "The
"Compile Results" dialog box".
CaptureFilter の中身(BPF)
• tcpdump/dumpcap
$ tcpdump -d (filter-expression)
$ dumpcap -d (filter-expression)
$ man tcpdump
-d Dump the compiled packet-matching code in a human readable
form to standard output and stop.
$ man dumpcap
-d Dump the code generated for the capture filter in a human-
readable form, and exit.
BPF/フィルタ無し
$ sudo tcpdump -d
(000) ret #65535
ret Returnret Return
65535[Byte] キャプチャする
(フレーム/パケット全体をキャプチャ)
(参考) tcpdump-4.0.0/interface.h
/*
* The default snapshot length. This value allows most printers to print
* useful information while keeping the amount of unwanted data down.
*/
#ifndef INET6
#define DEFAULT_SNAPLEN 68 /* ether + IPv4 + TCP + 14 */
#else
#define DEFAULT_SNAPLEN 96 /* ether + IPv6 + TCP + 22 */
#endif
(参考) tcpdump-4.1/netdissect.h
/*
* Maximum snapshot length. This should be enough to capture the full
* packet on most network interfaces.
*
* XXX - could it be larger? If so, should it? Some applications might
* use the snapshot length in a savefile header to control the size of
* the buffer they allocate, so a size of, say, 2^31-1 might not work
* well.
*/
#define MAXIMUM_SNAPLEN 65535
/*
* The default snapshot length is the maximum.
*/
#define DEFAULT_SNAPLEN MAXIMUM_SNAPLEN
(参考) libpcap-1.7.2/pcap-int.h
/*
* Maximum snapshot length.
*
* Somewhat arbitrary, but chosen to be:
*
* 1) big enough for maximum-size Linux loopback packets (65549)
* and some USB packets captured with USBPcap:
(snip)
* 2) small enough not to cause attempts to allocate huge amounts of
* memory; some applications might use the snapshot length in a
* savefile header to control the size of the buffer they allocate,
* so a size of, say, 2^31-1 might not work well.
*
* We don't enforce this in pcap_set_snaplen(), but we use it internally.
*/
#define MAXIMUM_SNAPLEN 262144
1.ip(IPv4)
$ sudo tcpdump -d ip
(000) ldh [12]
(001) jeq #0x800 jt 2 jf 3
(002) ret #65535
(003) ret #0
ldh Load Half Word (2Byte)
jeq Jump Equal (jt:Jump if True, jf:Jump if False)
(000) 12[Byte]ずれた後の 2[Byte]を読み込む(Etherヘッダの Type を読み込む)
(001) 0x800 なら (002)に/それ以外なら (003) に
(002) 65535[Byte]キャプチャ=全てキャプチャ
(003) 0[byte]キャプチャ=キャプチャしない
2.ip6(IPv6)
$ sudo tcpdump -d ip6
(000) ldh [12]
(001) jeq #0x86dd jt 2 jf 3
(002) ret #65535
(003) ret #0
ldh Load Half Word (2Byte)
jeq Jump Equal (jt:Jump if True, jf:Jump if False)
(000) 12[Byte]ずれた後の 2[Byte]を読み込む(Etherヘッダの Type を読み込む)
(001) 0x86dd なら (002)に/それ以外なら (003) に
(002) 65535[Byte]キャプチャ=全てキャプチャ
(003) 0[byte]キャプチャ=キャプチャしない
5.port 80(80番ポート)
$ sudo tcpdump -d port 80
(000) ldh [12]
(001) jeq #0x86dd jt 2 jf 10
(002) ldb [20]
(003) jeq #0x84 jt 6 jf 4
(004) jeq #0x6 jt 6 jf 5
(005) jeq #0x11 jt 6 jf 23
(006) ldh [54]
(007) jeq #0x50 jt 22 jf 8
(008) ldh [56]
(009) jeq #0x50 jt 22 jf 23
(010) jeq #0x800 jt 11 jf 23
(011) ldb [23]
…
5.port 80(80番ポート)
...
(012) jeq #0x84 jt 15 jf 13
(013) jeq #0x6 jt 15 jf 14
(014) jeq #0x11 jt 15 jf 23
(015) ldh [20]
(016) jset #0x1fff jt 23 jf 17
(017) ldxb 4*([14]&0xf)
(018) ldh [x + 14]
(019) jeq #0x50 jt 22 jf 20
(020) ldh [x + 16]
(021) jeq #0x50 jt 22 jf 23
(022) ret #65535
(023) ret #0
※ 長いので後回しに…
6.ip and port 80
$ sudo tcpdump -d ip and port 80
(000) ldh [12] # Type
(001) jeq #0x800 jt 2 jf 14 # IPv4
(002) ldb [23] # Protocol
(003) jeq #0x84 jt 6 jf 4 # SCTP
(004) jeq #0x6 jt 6 jf 5 # TCP
(005) jeq #0x11 jt 6 jf 14 # UDP
(006) ldh [20] # offset(IP Header)
(007) jset #0x1fff jt 14 jf 8 # IP Header Length
(008) ldxb 4*([14]&0xf) # TCP Header Length
(009) ldh [x + 14] # SrcPort
(010) jeq #0x50 jt 13 jf 11 # 0x50 = 80
(011) ldh [x + 16] # DstPort
(012) jeq #0x50 jt 13 jf 14 # 0x50 = 80
(013) ret #65535 # capture
(014) ret #0 # don't capture
6.ip and port 80
$ sudo tcpdump -d ip and port 80
(000) ldh [12] # Type
(001) jeq #0x800 jt 2 jf 14 # IPv4
(002) ldb [23] # Protocol
(003) jeq #0x84 jt 6 jf 4 # SCTP
(004) jeq #0x6 jt 6 jf 5 # TCP
IPヘッダ長を計算して x に代入
TCPヘッダ長を計算して x と足し算
→ TCPペイロードの先頭までの offset を計算(005) jeq #0x11 jt 6 jf 14 # UDP
(006) ldh [20] # offset(IP Header)
(007) jset #0x1fff jt 14 jf 8 # IP Header Length
(008) ldxb 4*([14]&0xf) # TCP Header Length
(009) ldh [x + 14] # SrcPort
(010) jeq #0x50 jt 13 jf 11 # 0x50 = 80
(011) ldh [x + 16] # DstPort
(012) jeq #0x50 jt 13 jf 14 # 0x50 = 80
(013) ret #65535 # capture
(014) ret #0 # don't capture
→ TCPペイロードの先頭までの offset を計算
(参考) IP Header
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| IHL |Type of Service| Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification |Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time to Live | Protocol | Header Checksum |
14+6[Byte]
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
https://www.ietf.org/rfc/rfc791.txt
14+9[Byte]
(参考) TCP Header
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |U|A|P|R|S|F| |
| Offset| Reserved |R|C|S|S|Y|I| Window |
| | |G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
5.port 80(80番ポート) again
$ sudo tcpdump -d port 80
(000) ldh [12] # Type
(001) jeq #0x86dd jt 2 jf 10 # IPv6
(002) ldb [20] # NextHeader(IPv6)
(003) jeq #0x84 jt 6 jf 4 # SCTP
(004) jeq #0x6 jt 6 jf 5 # TCP
(005) jeq #0x11 jt 6 jf 23 # UDP
(006) ldh [54] # SrcPort
(007) jeq #0x50 jt 22 jf 8 # 0x50=80
(008) ldh [56] # DstPort
(009) jeq #0x50 jt 22 jf 23 # 0x50=80
(010) jeq #0x800 jt 11 jf 23 # IPv4
(011) ldb [23] # Protocol(IPv4)
…
5.port 80(80番ポート) again
...
(012) jeq #0x84 jt 15 jf 13 # SCTP
(013) jeq #0x6 jt 15 jf 14 # TCP
(014) jeq #0x11 jt 15 jf 23 # UDP
(015) ldh [20] # flags + offset
(016) jset #0x1fff jt 23 jf 17 # offset
IPヘッダ長を計算して x に代入
TCPヘッダ長を計算して x と足し算
→ TCPペイロードの先頭までの offset を計算
(017) ldxb 4*([14]&0xf) # Length of IP Payload
(018) ldh [x + 14] # SrcPort
(019) jeq #0x50 jt 22 jf 20 # 0x50=80
(020) ldh [x + 16] # DstPort(SrcPort + 2)
(021) jeq #0x50 jt 22 jf 23 # 0x50=80
(022) ret #65535 # capture
(023) ret #0 # don't capture
巨大な(5000+行) CaptureFilter
• 5772行の BPF で tcpdump してみた
### compile(BPF を生成)
$ sudo tcpdump -d port 1 or port 2 or port 3 or … or port 1000 | wc -l$ sudo tcpdump -d port 1 or port 2 or port 3 or … or port 1000 | wc -l
5772
### tcpdump(パケットをキャプチャ)
$ sudo tcpdump -n port 1 or port 2 or port 3 or … or port 1000
(snip)
参考
The BSD Packet Filter:
A New Architecture for User-level Packet Capture
http://www.tcpdump.org/papers/bpf-usenix93.pdf
Linux Socket Filtering aka Berkeley Packet Filter (BPF)
https://www.kernel.org/doc/Documentation/networking/filter.txt
tcpdump cheat-sheets
http://packetlife.net/media/library/12/tcpdump.pdf
how to defend DNS authoritative server against DNS WaterTorture
http://www.slideshare.net/twovs/how-to-defend-dns-authoritative-server-against-dns-watertorture
iptables BPF module 効果測定 DROP! the ${RANDOM} queries
http://www.slideshare.net/twovs/iptables-bpf-module