1 // Copyright 2012 Google, Inc. All rights reserved.
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
7 // The pcaplay binary load an offline capture (pcap file) and replay
8 // it on the select interface, with an emphasis on packet timing
20 "github.com/google/gopacket"
21 "github.com/google/gopacket/examples/util"
22 "github.com/google/gopacket/pcap"
25 var iface = flag.String("i", "eth0", "Interface to write packets to")
26 var fname = flag.String("r", "", "Filename to read from")
27 var fast = flag.Bool("f", false, "Send each packets as fast as possible")
30 var lastSend time.Time
35 func writePacketDelayed(handle *pcap.Handle, buf []byte, ci gopacket.CaptureInfo) {
36 if ci.CaptureLength != ci.Length {
37 // do not write truncated packets
41 intervalInCapture := ci.Timestamp.Sub(lastTS)
42 elapsedTime := time.Since(lastSend)
44 if (intervalInCapture > elapsedTime) && !lastSend.IsZero() {
45 time.Sleep(intervalInCapture - elapsedTime)
49 writePacket(handle, buf)
53 func writePacket(handle *pcap.Handle, buf []byte) error {
54 if err := handle.WritePacketData(buf); err != nil {
55 log.Printf("Failed to send packet: %s\n", err)
61 func pcapInfo(filename string) (start time.Time, end time.Time, packets int, size int) {
62 handleRead, err := pcap.OpenOffline(*fname)
64 log.Fatal("PCAP OpenOffline error (handle to read packet):", err)
67 var previousTs time.Time
68 var deltaTotal time.Duration
71 data, ci, err := handleRead.ReadPacketData()
72 if err != nil && err != io.EOF {
74 } else if err == io.EOF {
85 if previousTs.IsZero() {
86 previousTs = ci.Timestamp
88 deltaTotal += ci.Timestamp.Sub(previousTs)
89 previousTs = ci.Timestamp
93 sec := int(deltaTotal.Seconds())
97 fmt.Printf("Avg packet rate %d/s\n", packets/sec)
98 return start, end, packets, size
106 log.Fatal("Need a input file")
109 // Open PCAP file + handle potential BPF Filter
110 handleRead, err := pcap.OpenOffline(*fname)
112 log.Fatal("PCAP OpenOffline error (handle to read packet):", err)
114 defer handleRead.Close()
115 if len(flag.Args()) > 0 {
116 bpffilter := strings.Join(flag.Args(), " ")
117 fmt.Fprintf(os.Stderr, "Using BPF filter %q\n", bpffilter)
118 if err = handleRead.SetBPFFilter(bpffilter); err != nil {
119 log.Fatal("BPF filter error:", err)
122 // Open up a second pcap handle for packet writes.
123 handleWrite, err := pcap.OpenLive(*iface, 65536, true, pcap.BlockForever)
125 log.Fatal("PCAP OpenLive error (handle to write packet):", err)
127 defer handleWrite.Close()
131 tsStart, tsEnd, packets, size := pcapInfo(*fname)
133 // Loop over packets and write them
135 data, ci, err := handleRead.ReadPacketData()
138 fmt.Printf("\nFinished in %s", time.Since(start))
141 log.Printf("Failed to read packet %d: %s\n", pkt, err)
144 writePacket(handleWrite, data)
146 writePacketDelayed(handleWrite, data, ci)
149 bytesSent += len(data)
150 duration := time.Since(start)
153 if duration > time.Second {
154 rate := bytesSent / int(duration.Seconds())
155 remainingTime := tsEnd.Sub(tsStart) - duration
156 fmt.Printf("\rrate %d kB/sec - sent %d/%d kB - %d/%d packets - remaining time %s",
157 rate/1000, bytesSent/1000, size/1000,
158 pkt, packets, remainingTime)