04f18124000302e1086ba3b158f6c1aad593c0b9
[govpp.git] / vendor / github.com / google / gopacket / pcap / pcap_test.go
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/google/gopacket"
18         "github.com/google/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         defer os.Remove(invalidPcap.Name())
43
44         err = ioutil.WriteFile(invalidPcap.Name(), invalidData, 0644)
45         if err != nil {
46                 t.Fatal(err)
47         }
48         defer invalidPcap.Close()
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: 16,
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         } {
136                 data, ci, err := handle.ReadPacketData()
137                 if err != nil {
138                         t.Fatal(err)
139                 }
140                 t.Log("Testing filter", expected.expr)
141                 if bpf, err := handle.NewBPF(expected.expr); err != nil {
142                         if !expected.Error {
143                                 t.Error(err, "while compiling filter was unexpected")
144                         }
145                 } else if expected.Error {
146                         t.Error("expected error but didn't see one")
147                 } else if matches := bpf.Matches(ci, data); matches != expected.Result {
148                         t.Error("Filter result was", matches, "but should be", expected.Result)
149                 }
150         }
151 }
152
153 func TestBPFInstruction(t *testing.T) {
154         handle, err := OpenOffline("test_ethernet.pcap")
155         if err != nil {
156                 t.Fatal(err)
157         }
158
159         cntr := 0
160         oversizedBpfInstructionBuffer := [MaxBpfInstructions + 1]BPFInstruction{}
161
162         for _, expected := range []struct {
163                 Filter         string
164                 BpfInstruction []BPFInstruction
165                 Error          bool
166                 Result         bool
167         }{
168                 // {"foobar", true, false},
169                 {"foobar", []BPFInstruction{}, true, false},
170
171                 // tcpdump -dd 'tcp[tcpflags] & (tcp-syn|tcp-ack) == (tcp-syn|tcp-ack)'
172                 {"tcp[tcpflags] & (tcp-syn|tcp-ack) == (tcp-syn|tcp-ack)",
173                         []BPFInstruction{
174                                 {0x28, 0, 0, 0x0000000c},
175                                 {0x15, 0, 9, 0x00000800},
176                                 {0x30, 0, 0, 0x00000017},
177                                 {0x15, 0, 7, 0x00000006},
178                                 {0x28, 0, 0, 0x00000014},
179                                 {0x45, 5, 0, 0x00001fff},
180                                 {0xb1, 0, 0, 0x0000000e},
181                                 {0x50, 0, 0, 0x0000001b},
182                                 {0x54, 0, 0, 0x00000012},
183                                 {0x15, 0, 1, 0x00000012},
184                                 {0x6, 0, 0, 0x0000ffff},
185                                 {0x6, 0, 0, 0x00000000},
186                         }, false, true},
187
188                 // tcpdump -dd 'tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-ack'
189                 {"tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-ack",
190                         []BPFInstruction{
191                                 {0x28, 0, 0, 0x0000000c},
192                                 {0x15, 0, 9, 0x00000800},
193                                 {0x30, 0, 0, 0x00000017},
194                                 {0x15, 0, 7, 0x00000006},
195                                 {0x28, 0, 0, 0x00000014},
196                                 {0x45, 5, 0, 0x00001fff},
197                                 {0xb1, 0, 0, 0x0000000e},
198                                 {0x50, 0, 0, 0x0000001b},
199                                 {0x54, 0, 0, 0x00000012},
200                                 {0x15, 0, 1, 0x00000010},
201                                 {0x6, 0, 0, 0x0000ffff},
202                                 {0x6, 0, 0, 0x00000000},
203                         }, false, true},
204
205                 // tcpdump -dd 'udp'
206                 {"udp",
207                         []BPFInstruction{
208                                 {0x28, 0, 0, 0x0000000c},
209                                 {0x15, 0, 5, 0x000086dd},
210                                 {0x30, 0, 0, 0x00000014},
211                                 {0x15, 6, 0, 0x00000011},
212                                 {0x15, 0, 6, 0x0000002c},
213                                 {0x30, 0, 0, 0x00000036},
214                                 {0x15, 3, 4, 0x00000011},
215                                 {0x15, 0, 3, 0x00000800},
216                                 {0x30, 0, 0, 0x00000017},
217                                 {0x15, 0, 1, 0x00000011},
218                                 {0x6, 0, 0, 0x0000ffff},
219                                 {0x6, 0, 0, 0x00000000},
220                         }, false, false},
221
222                 {"", oversizedBpfInstructionBuffer[:], true, false},
223         } {
224                 cntr++
225                 data, ci, err := handle.ReadPacketData()
226                 if err != nil {
227                         t.Fatal(err)
228                 }
229
230                 t.Log("Testing BpfInstruction filter", cntr)
231                 if bpf, err := handle.NewBPFInstructionFilter(expected.BpfInstruction); err != nil {
232                         if !expected.Error {
233                                 t.Error(err, "while compiling filter was unexpected")
234                         }
235                 } else if expected.Error {
236                         t.Error("expected error but didn't see one")
237                 } else if matches := bpf.Matches(ci, data); matches != expected.Result {
238                         t.Error("Filter result was", matches, "but should be", expected.Result)
239                 }
240
241                 if expected.Filter != "" {
242                         t.Log("Testing dead bpf filter", cntr)
243                         if bpf, err := CompileBPFFilter(layers.LinkTypeEthernet, 65535, expected.Filter); err != nil {
244                                 if !expected.Error {
245                                         t.Error(err, "while compiling filter was unexpected")
246                                 }
247                         } else if expected.Error {
248                                 t.Error("expected error but didn't see one")
249                         } else {
250                                 if len(bpf) != len(expected.BpfInstruction) {
251                                         t.Errorf("expected %d instructions, got %d", len(expected.BpfInstruction), len(bpf))
252                                 }
253                                 for i := 0; i < len(bpf); i++ {
254                                         if bpf[i] != expected.BpfInstruction[i] {
255                                                 t.Errorf("expected instruction %d = %d, got %d", i, expected.BpfInstruction[i], bpf[i])
256                                         }
257                                 }
258                         }
259                 }
260         }
261 }
262
263 func ExampleBPF() {
264         handle, err := OpenOffline("test_ethernet.pcap")
265         if err != nil {
266                 log.Fatal(err)
267         }
268         synack, err := handle.NewBPF("tcp[tcpflags] & (tcp-syn|tcp-ack) == (tcp-syn|tcp-ack)")
269         if err != nil {
270                 log.Fatal(err)
271         }
272         syn, err := handle.NewBPF("tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn")
273         if err != nil {
274                 log.Fatal(err)
275         }
276         for {
277                 data, ci, err := handle.ReadPacketData()
278                 switch {
279                 case err == io.EOF:
280                         return
281                 case err != nil:
282                         log.Fatal(err)
283                 case synack.Matches(ci, data):
284                         fmt.Println("SYN/ACK packet")
285                 case syn.Matches(ci, data):
286                         fmt.Println("SYN packet")
287                 default:
288                         fmt.Println("SYN flag not set")
289                 }
290         }
291         // Output:
292         // SYN packet
293         // SYN/ACK packet
294         // SYN flag not set
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         // SYN flag not set
304         // SYN flag not set
305         // SYN flag not set
306         // SYN flag not set
307         // SYN flag not set
308 }