github.com/gopacket/gopacket@v1.1.0/pcapgo/capture_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 //go:build linux 7 8 package pcapgo_test 9 10 import ( 11 "bytes" 12 "context" 13 "fmt" 14 "log" 15 "os" 16 "sync/atomic" 17 "testing" 18 "time" 19 20 "github.com/vishvananda/netlink" 21 22 "github.com/gopacket/gopacket" 23 "github.com/gopacket/gopacket/layers" 24 "github.com/gopacket/gopacket/pcapgo" 25 ) 26 27 const ( 28 timeout = 100 * time.Millisecond 29 ) 30 31 func Example_captureEthernet() { 32 f, err := os.Create("/tmp/lo.pcap") 33 if err != nil { 34 log.Fatal(err) 35 } 36 defer f.Close() 37 pcapw := pcapgo.NewWriter(f) 38 if err := pcapw.WriteFileHeader(1600, layers.LinkTypeEthernet); err != nil { 39 log.Fatalf("WriteFileHeader: %v", err) 40 } 41 42 handle, err := pcapgo.NewEthernetHandle("lo") 43 if err != nil { 44 log.Fatalf("OpenEthernet: %v", err) 45 } 46 47 pkgsrc := gopacket.NewPacketSource(handle, layers.LayerTypeEthernet) 48 ctx, cancel := context.WithCancel(context.Background()) 49 defer cancel() 50 for packet := range pkgsrc.PacketsCtx(ctx) { 51 if err := pcapw.WritePacket(packet.Metadata().CaptureInfo, packet.Data()); err != nil { 52 log.Fatalf("pcap.WritePacket(): %v", err) 53 } 54 } 55 } 56 57 func TestEthernetHandle_Close_WithTimeout(t *testing.T) { 58 var ( 59 handle *pcapgo.EthernetHandle 60 err error 61 done = make(chan struct{}) 62 ) 63 64 handle, err = pcapgo.NewEthernetHandle(setupDummyInterface(t)) 65 if err != nil { 66 t.Fatalf("OpenEthernet: %v", err) 67 } 68 69 ctx, cancel := context.WithTimeout(context.Background(), timeout) 70 defer cancel() 71 72 pkgsrc := gopacket.NewPacketSource(handle, layers.LayerTypeEthernet) 73 74 go consumePacketSource(ctx, t, pkgsrc, done) 75 76 select { 77 case _, more := <-done: 78 if more { 79 t.Fatalf("done channel is polluted?!") 80 } else { 81 t.Log("PacketSource got closed") 82 } 83 case <-time.After(2 * timeout): 84 } 85 } 86 87 func TestEthernetHandle_Close_WithCancel(t *testing.T) { 88 var ( 89 handle *pcapgo.EthernetHandle 90 err error 91 done = make(chan struct{}) 92 ) 93 94 handle, err = pcapgo.NewEthernetHandle(setupDummyInterface(t)) 95 if err != nil { 96 t.Fatalf("OpenEthernet: %v", err) 97 } 98 99 ctx, cancel := context.WithCancel(context.Background()) 100 101 pkgsrc := gopacket.NewPacketSource(handle, layers.LayerTypeEthernet) 102 go consumePacketSource(ctx, t, pkgsrc, done) 103 104 go func() { 105 <-time.After(timeout) 106 cancel() 107 }() 108 109 select { 110 case _, more := <-done: 111 if more { 112 t.Fatalf("done channel is polluted?!") 113 } else { 114 t.Log("PacketSource got closed") 115 } 116 case <-time.After(2 * timeout): 117 } 118 } 119 120 func consumePacketSource(ctx context.Context, tb testing.TB, pkgsrc *gopacket.PacketSource, done chan<- struct{}) { 121 tb.Helper() 122 var writer = pcapgo.NewWriter(new(bytes.Buffer)) 123 defer close(done) 124 for packet := range pkgsrc.PacketsCtx(ctx) { 125 if err := writer.WritePacket(packet.Metadata().CaptureInfo, packet.Data()); err != nil { 126 tb.Errorf("pcap.WritePacket(): %v", err) 127 } 128 } 129 } 130 131 var ( 132 dummyInterfaceIdx int32 = -1 133 ) 134 135 // setupDummyInterface configures a dummy interface and returns the generated interface name. 136 // It assigns an address from the 127.10.0.0/24 network. 137 // It does not check if there are already more than 254 interfaces. 138 // If there are the call to netlink.ParseAddr will fail because 127.10.0.256/24 isn't a valid IP address, 139 // but it should be fine for testing purposes. 140 func setupDummyInterface(tb testing.TB) (ifName string) { 141 tb.Helper() 142 la := netlink.NewLinkAttrs() 143 idx := atomic.AddInt32(&dummyInterfaceIdx, 1) 144 la.Name = fmt.Sprintf("dummy%02d", idx) 145 dummyInterface := &netlink.Dummy{LinkAttrs: la} 146 if err := netlink.LinkAdd(dummyInterface); err != nil { 147 tb.Fatalf("netlink.LinkAdd() error = %v", err) 148 } 149 150 var ( 151 link netlink.Link 152 addr *netlink.Addr 153 err error 154 ) 155 156 link, err = netlink.LinkByName(la.Name) 157 if err != nil { 158 tb.Fatalf("netlink.LinkByName() error = %v", err) 159 } 160 161 tb.Cleanup(func() { 162 if err := netlink.LinkDel(link); err != nil { 163 tb.Fatalf("netlink.LinkDel() error = %v", err) 164 } 165 }) 166 167 addr, err = netlink.ParseAddr(fmt.Sprintf("127.10.0.%d/24", idx+1)) 168 if err != nil { 169 tb.Fatalf("netlink.ParseAddr() = %v", err) 170 } 171 172 if err := netlink.AddrAdd(link, addr); err != nil { 173 tb.Fatalf("netlink.AddrAdd() error = %v", err) 174 } 175 176 if err := netlink.LinkSetUp(link); err != nil { 177 tb.Fatalf("netlink.LinkSetUp() error = %v", err) 178 } 179 180 return la.Name 181 }