github.com/gopacket/gopacket@v1.1.0/examples/pcaplay/main.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  // The pcaplay binary load an offline capture (pcap file) and replay
     8  // it on the select interface, with an emphasis on packet timing
     9  package main
    10  
    11  import (
    12  	"flag"
    13  	"fmt"
    14  	"io"
    15  	"log"
    16  	"os"
    17  	"strings"
    18  	"time"
    19  
    20  	"github.com/gopacket/gopacket"
    21  	"github.com/gopacket/gopacket/examples/util"
    22  	"github.com/gopacket/gopacket/pcap"
    23  )
    24  
    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")
    28  
    29  var lastTS time.Time
    30  var lastSend time.Time
    31  
    32  var start time.Time
    33  var bytesSent int
    34  
    35  func writePacketDelayed(handle *pcap.Handle, buf []byte, ci gopacket.CaptureInfo) {
    36  	if ci.CaptureLength != ci.Length {
    37  		// do not write truncated packets
    38  		return
    39  	}
    40  
    41  	intervalInCapture := ci.Timestamp.Sub(lastTS)
    42  	elapsedTime := time.Since(lastSend)
    43  
    44  	if (intervalInCapture > elapsedTime) && !lastSend.IsZero() {
    45  		time.Sleep(intervalInCapture - elapsedTime)
    46  	}
    47  
    48  	lastSend = time.Now()
    49  	writePacket(handle, buf)
    50  	lastTS = ci.Timestamp
    51  }
    52  
    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)
    56  		return err
    57  	}
    58  	return nil
    59  }
    60  
    61  func pcapInfo(filename string) (start time.Time, end time.Time, packets int, size int) {
    62  	handleRead, err := pcap.OpenOffline(*fname)
    63  	if err != nil {
    64  		log.Fatal("PCAP OpenOffline error (handle to read packet):", err)
    65  	}
    66  
    67  	var previousTs time.Time
    68  	var deltaTotal time.Duration
    69  
    70  	for {
    71  		data, ci, err := handleRead.ReadPacketData()
    72  		if err != nil && err != io.EOF {
    73  			log.Fatal(err)
    74  		} else if err == io.EOF {
    75  			break
    76  		} else {
    77  
    78  			if start.IsZero() {
    79  				start = ci.Timestamp
    80  			}
    81  			end = ci.Timestamp
    82  			packets++
    83  			size += len(data)
    84  
    85  			if previousTs.IsZero() {
    86  				previousTs = ci.Timestamp
    87  			} else {
    88  				deltaTotal += ci.Timestamp.Sub(previousTs)
    89  				previousTs = ci.Timestamp
    90  			}
    91  		}
    92  	}
    93  	sec := int(deltaTotal.Seconds())
    94  	if sec == 0 {
    95  		sec = 1
    96  	}
    97  	fmt.Printf("Avg packet rate %d/s\n", packets/sec)
    98  	return start, end, packets, size
    99  }
   100  
   101  func main() {
   102  	defer util.Run()()
   103  
   104  	// Sanity checks
   105  	if *fname == "" {
   106  		log.Fatal("Need a input file")
   107  	}
   108  
   109  	// Open PCAP file + handle potential BPF Filter
   110  	handleRead, err := pcap.OpenOffline(*fname)
   111  	if err != nil {
   112  		log.Fatal("PCAP OpenOffline error (handle to read packet):", err)
   113  	}
   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)
   120  		}
   121  	}
   122  	// Open up a second pcap handle for packet writes.
   123  	handleWrite, err := pcap.OpenLive(*iface, 65536, true, pcap.BlockForever)
   124  	if err != nil {
   125  		log.Fatal("PCAP OpenLive error (handle to write packet):", err)
   126  	}
   127  	defer handleWrite.Close()
   128  
   129  	start = time.Now()
   130  	pkt := 0
   131  	tsStart, tsEnd, packets, size := pcapInfo(*fname)
   132  
   133  	// Loop over packets and write them
   134  	for {
   135  		data, ci, err := handleRead.ReadPacketData()
   136  		switch {
   137  		case err == io.EOF:
   138  			fmt.Printf("\nFinished in %s", time.Since(start))
   139  			return
   140  		case err != nil:
   141  			log.Printf("Failed to read packet %d: %s\n", pkt, err)
   142  		default:
   143  			if *fast {
   144  				writePacket(handleWrite, data)
   145  			} else {
   146  				writePacketDelayed(handleWrite, data, ci)
   147  			}
   148  
   149  			bytesSent += len(data)
   150  			duration := time.Since(start)
   151  			pkt++
   152  
   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)
   159  			}
   160  		}
   161  	}
   162  
   163  }