github.com/gopacket/gopacket@v1.1.0/pcap/pcap_test.go (about) 1 // Copyright 2012 Google, Inc. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style license 4 // that can be found in the LICENSE file in the root of the source 5 // tree. 6 7 package pcap 8 9 import ( 10 "fmt" 11 "io" 12 "io/ioutil" 13 "log" 14 "os" 15 "testing" 16 17 "github.com/gopacket/gopacket" 18 "github.com/gopacket/gopacket/layers" 19 ) 20 21 func TestPcapNonexistentFile(t *testing.T) { 22 handle, err := OpenOffline("/path/to/nonexistent/file") 23 if err == nil { 24 t.Error("No error returned for nonexistent file open") 25 } else { 26 t.Logf("Error returned for nonexistent file: %v", err) 27 } 28 if handle != nil { 29 t.Error("Non-nil handle returned for nonexistent file open") 30 } 31 } 32 33 func TestPcapFileRead(t *testing.T) { 34 invalidData := []byte{ 35 0xAB, 0xAD, 0x1D, 0xEA, 36 } 37 38 invalidPcap, err := ioutil.TempFile("", "invalid.pcap") 39 if err != nil { 40 t.Fatal(err) 41 } 42 invalidPcap.Close() // if the file is still open later, the invalid test fails with permission denied on windows 43 defer os.Remove(invalidPcap.Name()) 44 45 err = ioutil.WriteFile(invalidPcap.Name(), invalidData, 0644) 46 if err != nil { 47 t.Fatal(err) 48 } 49 50 for _, file := range []struct { 51 filename string 52 num int 53 expectedLayers []gopacket.LayerType 54 err string 55 }{ 56 {filename: "test_loopback.pcap", 57 num: 24, 58 expectedLayers: []gopacket.LayerType{ 59 layers.LayerTypeLoopback, 60 layers.LayerTypeIPv6, 61 layers.LayerTypeTCP, 62 }, 63 }, 64 {filename: "test_ethernet.pcap", 65 num: 10, 66 expectedLayers: []gopacket.LayerType{ 67 layers.LayerTypeEthernet, 68 layers.LayerTypeIPv4, 69 layers.LayerTypeTCP, 70 }, 71 }, 72 {filename: "test_dns.pcap", 73 num: 10, 74 expectedLayers: []gopacket.LayerType{ 75 layers.LayerTypeEthernet, 76 layers.LayerTypeIPv4, 77 layers.LayerTypeUDP, 78 layers.LayerTypeDNS, 79 }, 80 }, 81 {filename: invalidPcap.Name(), 82 num: 0, 83 err: "unknown file format", 84 }, 85 } { 86 t.Logf("\n\n\n\nProcessing file %s\n\n\n\n", file.filename) 87 88 packets := []gopacket.Packet{} 89 if handle, err := OpenOffline(file.filename); err != nil { 90 if file.err != "" { 91 if err.Error() != file.err { 92 t.Errorf("expected message %q; got %q", file.err, err.Error()) 93 } 94 } else { 95 t.Fatal(err) 96 } 97 } else { 98 if file.err != "" { 99 t.Fatalf("Expected error, got none") 100 } 101 packetSource := gopacket.NewPacketSource(handle, handle.LinkType()) 102 for packet := range packetSource.Packets() { 103 packets = append(packets, packet) 104 } 105 } 106 if len(packets) != file.num { 107 t.Fatal("Incorrect number of packets, want", file.num, "got", len(packets)) 108 } 109 for i, p := range packets { 110 t.Log(p.Dump()) 111 for _, layertype := range file.expectedLayers { 112 if p.Layer(layertype) == nil { 113 t.Fatal("Packet", i, "has no layer type\n%s", layertype, p.Dump()) 114 } 115 } 116 } 117 } 118 } 119 120 func TestBPF(t *testing.T) { 121 handle, err := OpenOffline("test_ethernet.pcap") 122 if err != nil { 123 t.Fatal(err) 124 } 125 126 for _, expected := range []struct { 127 expr string 128 Error bool 129 Result bool 130 }{ 131 {"foobar", true, false}, 132 {"tcp[tcpflags] & (tcp-syn|tcp-ack) == (tcp-syn|tcp-ack)", false, true}, 133 {"tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-ack", false, true}, 134 {"udp", false, false}, 135 {string([]byte("udp")), false, false}, // test for #664 136 } { 137 data, ci, err := handle.ReadPacketData() 138 if err != nil { 139 t.Fatal(err) 140 } 141 t.Log("Testing filter", expected.expr) 142 if bpf, err := handle.NewBPF(expected.expr); err != nil { 143 if !expected.Error { 144 t.Error(err, "while compiling filter was unexpected") 145 } 146 } else if expected.Error { 147 t.Error("expected error but didn't see one") 148 } else if matches := bpf.Matches(ci, data); matches != expected.Result { 149 t.Error("Filter result was", matches, "but should be", expected.Result) 150 } 151 } 152 } 153 154 func TestBPFInstruction(t *testing.T) { 155 handle, err := OpenOffline("test_ethernet.pcap") 156 if err != nil { 157 t.Fatal(err) 158 } 159 160 cntr := 0 161 oversizedBpfInstructionBuffer := [MaxBpfInstructions + 1]BPFInstruction{} 162 163 for _, expected := range []struct { 164 Filter string 165 BpfInstruction []BPFInstruction 166 Error bool 167 Result bool 168 }{ 169 // {"foobar", true, false}, 170 {"foobar", []BPFInstruction{}, true, false}, 171 172 // tcpdump -dd 'tcp[tcpflags] & (tcp-syn|tcp-ack) == (tcp-syn|tcp-ack)' 173 {"tcp[tcpflags] & (tcp-syn|tcp-ack) == (tcp-syn|tcp-ack)", 174 []BPFInstruction{ 175 {0x28, 0, 0, 0x0000000c}, 176 {0x15, 0, 9, 0x00000800}, 177 {0x30, 0, 0, 0x00000017}, 178 {0x15, 0, 7, 0x00000006}, 179 {0x28, 0, 0, 0x00000014}, 180 {0x45, 5, 0, 0x00001fff}, 181 {0xb1, 0, 0, 0x0000000e}, 182 {0x50, 0, 0, 0x0000001b}, 183 {0x54, 0, 0, 0x00000012}, 184 {0x15, 0, 1, 0x00000012}, 185 {0x6, 0, 0, 0x0000ffff}, 186 {0x6, 0, 0, 0x00000000}, 187 }, false, true}, 188 189 // tcpdump -dd 'tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-ack' 190 {"tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-ack", 191 []BPFInstruction{ 192 {0x28, 0, 0, 0x0000000c}, 193 {0x15, 0, 9, 0x00000800}, 194 {0x30, 0, 0, 0x00000017}, 195 {0x15, 0, 7, 0x00000006}, 196 {0x28, 0, 0, 0x00000014}, 197 {0x45, 5, 0, 0x00001fff}, 198 {0xb1, 0, 0, 0x0000000e}, 199 {0x50, 0, 0, 0x0000001b}, 200 {0x54, 0, 0, 0x00000012}, 201 {0x15, 0, 1, 0x00000010}, 202 {0x6, 0, 0, 0x0000ffff}, 203 {0x6, 0, 0, 0x00000000}, 204 }, false, true}, 205 206 // tcpdump -dd 'udp' 207 {"udp", 208 []BPFInstruction{ 209 {0x28, 0, 0, 0x0000000c}, 210 {0x15, 0, 5, 0x000086dd}, 211 {0x30, 0, 0, 0x00000014}, 212 {0x15, 6, 0, 0x00000011}, 213 {0x15, 0, 6, 0x0000002c}, 214 {0x30, 0, 0, 0x00000036}, 215 {0x15, 3, 4, 0x00000011}, 216 {0x15, 0, 3, 0x00000800}, 217 {0x30, 0, 0, 0x00000017}, 218 {0x15, 0, 1, 0x00000011}, 219 {0x6, 0, 0, 0x0000ffff}, 220 {0x6, 0, 0, 0x00000000}, 221 }, false, false}, 222 223 {"", oversizedBpfInstructionBuffer[:], true, false}, 224 } { 225 cntr++ 226 data, ci, err := handle.ReadPacketData() 227 if err != nil { 228 t.Fatal(err) 229 } 230 231 t.Log("Testing BpfInstruction filter", cntr) 232 if bpf, err := handle.NewBPFInstructionFilter(expected.BpfInstruction); err != nil { 233 if !expected.Error { 234 t.Error(err, "while compiling filter was unexpected") 235 } 236 } else if expected.Error { 237 t.Error("expected error but didn't see one") 238 } else if matches := bpf.Matches(ci, data); matches != expected.Result { 239 t.Error("Filter result was", matches, "but should be", expected.Result) 240 } 241 242 if expected.Filter != "" { 243 t.Log("Testing dead bpf filter", cntr) 244 if bpf, err := CompileBPFFilter(layers.LinkTypeEthernet, 65535, expected.Filter); err != nil { 245 if !expected.Error { 246 t.Error(err, "while compiling filter was unexpected") 247 } 248 } else if expected.Error { 249 t.Error("expected error but didn't see one") 250 } else { 251 if len(bpf) != len(expected.BpfInstruction) { 252 t.Errorf("expected %d instructions, got %d", len(expected.BpfInstruction), len(bpf)) 253 } 254 for i := 0; i < len(bpf); i++ { 255 if bpf[i] != expected.BpfInstruction[i] { 256 t.Errorf("expected instruction %d = %d, got %d", i, expected.BpfInstruction[i], bpf[i]) 257 } 258 } 259 } 260 } 261 } 262 } 263 264 func ExampleBPF() { 265 handle, err := OpenOffline("test_ethernet.pcap") 266 if err != nil { 267 log.Fatal(err) 268 } 269 synack, err := handle.NewBPF("tcp[tcpflags] & (tcp-syn|tcp-ack) == (tcp-syn|tcp-ack)") 270 if err != nil { 271 log.Fatal(err) 272 } 273 syn, err := handle.NewBPF("tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn") 274 if err != nil { 275 log.Fatal(err) 276 } 277 for { 278 data, ci, err := handle.ReadPacketData() 279 switch { 280 case err == io.EOF: 281 return 282 case err != nil: 283 log.Fatal(err) 284 case synack.Matches(ci, data): 285 fmt.Println("SYN/ACK packet") 286 case syn.Matches(ci, data): 287 fmt.Println("SYN packet") 288 default: 289 fmt.Println("SYN flag not set") 290 } 291 } 292 // Output: 293 // SYN packet 294 // SYN/ACK packet 295 // SYN flag not set 296 // SYN flag not set 297 // SYN flag not set 298 // SYN flag not set 299 // SYN flag not set 300 // SYN flag not set 301 // SYN flag not set 302 // SYN flag not set 303 }