packetcap / go-pcap

Packet capture library and tools in native go
Apache License 2.0
14 stars 4 forks source link

Using BPF filter with not keyword or net mask #48

Closed Snshadow closed 1 month ago

Snshadow commented 2 months ago

Looks like setting BPF filter using "not" keyword and net mask does not work correctly. In tcpdump these BPF filters works correctly.

test@test:~/GitProject/go-pcap$ sudo tcpdump -i any "not net 127.0.0.0/8"
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
10:36:46.164536 ens32 Out IP test.ssh > _gateway.54080: Flags [P.], seq 1977339556:1977339640, ack 1936456696, win 65535, length 84
10:36:46.164831 ens32 In  IP _gateway.54080 > test.ssh: Flags [.], ack 84, win 64240, length 0
10:36:46.232912 ens32 Out IP test.38631 > _gateway.domain: 12017+ [1au] PTR? 2.46.168.192.in-addr.arpa. (54)
10:36:46.234333 ens32 In  IP _gateway.domain > test.38631: 12017 NXDomain 0/0/1 (54)
10:36:46.234467 ens32 Out IP test.38631 > _gateway.domain: 12017+ PTR? 2.46.168.192.in-addr.arpa. (43)
10:36:46.235756 ens32 In  IP _gateway.domain > test.38631: 12017 NXDomain 0/0/0 (43)
10:36:46.236849 ens32 Out IP test.55121 > _gateway.domain: 7120+ [1au] PTR? 130.46.168.192.in-addr.arpa. (56)
10:36:46.238146 ens32 In  IP _gateway.domain > test.55121: 7120 NXDomain 0/0/1 (56)
10:36:46.238274 ens32 Out IP test.55121 > _gateway.domain: 7120+ PTR? 130.46.168.192.in-addr.arpa. (45)
10:36:46.239678 ens32 In  IP _gateway.domain > test.55121: 7120 NXDomain 0/0/0 (45)
^C
10 packets captured
10 packets received by filter
0 packets dropped by kernel
test@test:~/GitProject/go-pcap$ sudo tcpdump -i any "net 127.0.0.0/8"
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
10:43:01.006039 lo    In  IP localhost.54190 > localhost.43791: Flags [P.], seq 3506288800:3506288844, ack 401878399, win 14838, options [nop,nop,TS val 3060264020 ecr 3060262360], length 44
10:43:01.006079 lo    In  IP localhost.43791 > localhost.54190: Flags [.], ack 44, win 11256, options [nop,nop,TS val 3060264020 ecr 3060264020], length 0
10:43:01.020768 lo    In  IP localhost.54190 > localhost.43791: Flags [P.], seq 44:89, ack 1, win 14838, options [nop,nop,TS val 3060264035 ecr 3060264020], length 45
10:43:01.020807 lo    In  IP localhost.43791 > localhost.54190: Flags [.], ack 89, win 11256, options [nop,nop,TS val 3060264035 ecr 3060264035], length 0
10:43:01.311493 lo    In  IP localhost.40273 > localhost.40802: Flags [P.], seq 631682537:631682585, ack 3573312487, win 24572, options [nop,nop,TS val 3060264326 ecr 3060262589], length 48
10:43:01.311525 lo    In  IP localhost.40802 > localhost.40273: Flags [.], ack 48, win 22004, options [nop,nop,TS val 3060264326 ecr 3060264326], length 0
^C
6 packets captured
12 packets received by filter
0 packets dropped by kernel

Expected Behavior

Actual Behavior

Steps to Reproduce the Problem

  1. Run sample binary pcap with "not net 127.0.0.1" as parameter and it captures all packets from/to 127.0.0.1.
  2. Run sample binary pcap with "net 127.0.0.0/8" as parameter and it captures nothing.

Specifications

deitch commented 1 month ago

It should work, as the correct token is supported, see here and here. Obviously something is mishandled about the negator.

If you can figure something out and get a PR in, that would be great. I will try to look as well, when I have time.

deitch commented 1 month ago

The problem appears to be here in primitive.Compile(). It switches on the p.kind, but never checks p.negator. The creation of the primitive sets it up correctly, but it never actually checks it when building the bpf instructions.

For example, here is the compiled bpf structure for the not net 127.0.0.1 that you used:

        ~r0: []golang.org/x/net/bpf.Instruction len: 14, cap: 24, [
                golang.org/x/net/bpf.LoadAbsolute {Off: 12, Size: 2},
                golang.org/x/net/bpf.JumpIf {Cond: JumpEqual (0), Val: 2048, SkipTrue: 0, SkipFalse: 4},
                golang.org/x/net/bpf.LoadAbsolute {Off: 26, Size: 4},
                golang.org/x/net/bpf.JumpIf {Cond: JumpEqual (0), Val: 2130706433, SkipTrue: 8, SkipFalse: 0},
                golang.org/x/net/bpf.LoadAbsolute {Off: 30, Size: 4},
                golang.org/x/net/bpf.JumpIf {Cond: JumpEqual (0), Val: 2130706433, SkipTrue: 6, SkipFalse: 7},
                golang.org/x/net/bpf.JumpIf {Cond: JumpEqual (0), Val: 2054, SkipTrue: 1, SkipFalse: 0},
                golang.org/x/net/bpf.JumpIf {Cond: JumpEqual (0), Val: 32821, SkipTrue: 0, SkipFalse: 5},
                golang.org/x/net/bpf.LoadAbsolute {Off: 28, Size: 4},
                golang.org/x/net/bpf.JumpIf {Cond: JumpEqual (0), Val: 2130706433, SkipTrue: 2, SkipFalse: 0},
                golang.org/x/net/bpf.LoadAbsolute {Off: 38, Size: 4},
                golang.org/x/net/bpf.JumpIf {Cond: JumpEqual (0), Val: 2130706433, SkipTrue: 0, SkipFalse: 1},
                golang.org/x/net/bpf.RetConstant {Val: 262144},
                golang.org/x/net/bpf.RetConstant {Val: 0},
        ]

We would need to check how you use a negator in ebpf. If you have any experience in that space, it has been a long time since I delved into this.

deitch commented 1 month ago

@Snshadow can you try the branch provided in #49 ?

Snshadow commented 1 month ago

The "not" keyword works in the branch from https://github.com/packetcap/go-pcap/pull/49. Thank you for checking. running output

test@test:~/GitProject/go-pcap$ sudo ./dist/pcap-linux-amd64 "not net 127.0.0.1"
capturing from interface 
INFO[0000] mmap buffer created at 0x73818bea8000 with size 131072  iface= promiscuous=false snaplen=1600 syscalls=false timeout=0s
0: IP packet From src [192 168 46 2] to dst [192 168 46 130]
0: TCP packet From src port 62491 to dst port 22
0: PACKET LAYER 0: Ethernet
0: PACKET LAYER 1: IPv4
0: PACKET LAYER 2: TCP
0: PACKET LAYER 3: Payload
0: packet size 0, first bytes [0 12 41 168 86 216 0 80 86 232 71 85 8 0 69 0 0 164 229 174 0 0 128 6 118 208 192 168 46 2 192 168 46 130 244 27 0 22 60 253 101 44 74 228 2 230 80 24 250 240]
1: IP packet From src [192 168 46 130] to dst [192 168 46 2]
1: TCP packet From src port 22 to dst port 62491
1: PACKET LAYER 0: Ethernet
1: PACKET LAYER 1: IPv4
1: PACKET LAYER 2: TCP
1: packet size 0, first bytes [0 80 86 232 71 85 0 12 41 168 86 216 8 0 69 8 0 40 115 232 64 0 64 6 233 10 192 168 46 130 192 168 46 2 0 22 244 27 74 228 2 230 60 253 101 168 80 16 255 255]
2: IP packet From src [192 168 46 130] to dst [192 168 46 2]
2: TCP packet From src port 22 to dst port 62491
2: PACKET LAYER 0: Ethernet
2: PACKET LAYER 1: IPv4
2: PACKET LAYER 2: TCP
2: PACKET LAYER 3: Payload
2: packet size 0, first bytes [0 80 86 232 71 85 0 12 41 168 86 216 8 0 69 8 0 124 115 233 64 0 64 6 232 181 192 168 46 130 192 168 46 2 0 22 244 27 74 228 2 230 60 253 101 168 80 24 255 255]
3: IP packet From src [192 168 46 2] to dst [192 168 46 130]
3: TCP packet From src port 62491 to dst port 22
3: PACKET LAYER 0: Ethernet
3: PACKET LAYER 1: IPv4
3: PACKET LAYER 2: TCP
3: packet size 0, first bytes [0 12 41 168 86 216 0 80 86 232 71 85 8 0 69 0 0 40 229 175 0 0 128 6 119 75 192 168 46 2 192 168 46 130 244 27 0 22 60 253 101 168 74 228 3 58 80 16 250 240]
4: IP packet From src [192 168 46 130] to dst [192 168 46 2]
4: TCP packet From src port 22 to dst port 62491
4: PACKET LAYER 0: Ethernet
4: PACKET LAYER 1: IPv4
4: PACKET LAYER 2: TCP
4: PACKET LAYER 3: Payload
4: packet size 0, first bytes [0 80 86 232 71 85 0 12 41 168 86 216 8 0 69 8 0 124 115 234 64 0 64 6 232 180 192 168 46 130 192 168 46 2 0 22 244 27 74 228 3 58 60 253 101 168 80 24 255 255]
5: IP packet From src [192 168 46 2] to dst [192 168 46 130]
5: TCP packet From src port 62491 to dst port 22
5: PACKET LAYER 0: Ethernet
5: PACKET LAYER 1: IPv4
5: PACKET LAYER 2: TCP
5: packet size 0, first bytes [0 12 41 168 86 216 0 80 86 232 71 85 8 0 69 0 0 40 229 190 0 0 128 6 119 60 192 168 46 2 192 168 46 130 244 27 0 22 60 253 101 168 74 228 3 142 80 16 250 240]

However, in the case of using netmask in bpf filter, no packet is captured at all as mentioned above. Looking into the test cases in https://github.com/packetcap/go-pcap/blob/master/filter/compile_cases_test.go#L1125, the test from https://github.com/packetcap/go-pcap/blob/master/filter/compile_test.go#L166-L178 passes with "net 192.168.0.0/24" without any issue, making it look like it should work. As I'm new to bpf filter, I would have to look how netmask works in bpf structure.

deitch commented 1 month ago

However, in the case of using netmask in bpf filter, no packet is captured at all as mentioned above. Looking into the test cases in https://github.com/packetcap/go-pcap/blob/master/filter/compile_cases_test.go#L1125, the test from https://github.com/packetcap/go-pcap/blob/master/filter/compile_test.go#L166-L178 passes with "net 192.168.0.0/24" without any issue, making it look like it should work. As I'm new to bpf filter, I would have to look how netmask works in bpf structure

Open a new issue on this.