github.com/gopacket/gopacket@v1.1.0/dumpcommand/tcpdump.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 dumpcommand implements a run function for pfdump and pcapdump
     8  // with many similar flags/features to tcpdump.  This code is split out seperate
     9  // from data sources (pcap/pfring) so it can be used by both.
    10  package dumpcommand
    11  
    12  import (
    13  	"flag"
    14  	"fmt"
    15  	"log"
    16  	"os"
    17  	"time"
    18  
    19  	"github.com/gopacket/gopacket"
    20  	"github.com/gopacket/gopacket/ip4defrag"
    21  	"github.com/gopacket/gopacket/layers" // pulls in all layers decoders
    22  )
    23  
    24  var (
    25  	print       = flag.Bool("print", true, "Print out packets, if false only prints out statistics")
    26  	maxcount    = flag.Int("c", -1, "Only grab this many packets, then exit")
    27  	decoder     = flag.String("decoder", "Ethernet", "Name of the decoder to use")
    28  	dump        = flag.Bool("X", false, "If true, dump very verbose info on each packet")
    29  	statsevery  = flag.Int("stats", 1000, "Output statistics every N packets")
    30  	printErrors = flag.Bool("errors", false, "Print out packet dumps of decode errors, useful for checking decoders against live traffic")
    31  	lazy        = flag.Bool("lazy", false, "If true, do lazy decoding")
    32  	defrag      = flag.Bool("defrag", false, "If true, do IPv4 defrag")
    33  )
    34  
    35  func Run(src gopacket.PacketDataSource) {
    36  	if !flag.Parsed() {
    37  		log.Fatalln("Run called without flags.Parse() being called")
    38  	}
    39  	var dec gopacket.Decoder
    40  	var ok bool
    41  	if dec, ok = gopacket.DecodersByLayerName[*decoder]; !ok {
    42  		log.Fatalln("No decoder named", *decoder)
    43  	}
    44  	source := gopacket.NewPacketSource(src, dec)
    45  	source.Lazy = *lazy
    46  	source.NoCopy = true
    47  	source.DecodeStreamsAsDatagrams = true
    48  	fmt.Fprintln(os.Stderr, "Starting to read packets")
    49  	count := 0
    50  	bytes := int64(0)
    51  	start := time.Now()
    52  	errors := 0
    53  	truncated := 0
    54  	layertypes := map[gopacket.LayerType]int{}
    55  	defragger := ip4defrag.NewIPv4Defragmenter()
    56  
    57  	for packet := range source.Packets() {
    58  		count++
    59  		bytes += int64(len(packet.Data()))
    60  
    61  		// defrag the IPv4 packet if required
    62  		if *defrag {
    63  			ip4Layer := packet.Layer(layers.LayerTypeIPv4)
    64  			if ip4Layer == nil {
    65  				continue
    66  			}
    67  			ip4 := ip4Layer.(*layers.IPv4)
    68  			l := ip4.Length
    69  
    70  			newip4, err := defragger.DefragIPv4(ip4)
    71  			if err != nil {
    72  				log.Fatalln("Error while de-fragmenting", err)
    73  			} else if newip4 == nil {
    74  				continue // packet fragment, we don't have whole packet yet.
    75  			}
    76  			if newip4.Length != l {
    77  				fmt.Printf("Decoding re-assembled packet: %s\n", newip4.NextLayerType())
    78  				pb, ok := packet.(gopacket.PacketBuilder)
    79  				if !ok {
    80  					panic("Not a PacketBuilder")
    81  				}
    82  				nextDecoder := newip4.NextLayerType()
    83  				nextDecoder.Decode(newip4.Payload, pb)
    84  			}
    85  		}
    86  
    87  		if *dump {
    88  			fmt.Println(packet.Dump())
    89  		} else if *print {
    90  			fmt.Println(packet)
    91  		}
    92  		if !*lazy || *print || *dump { // if we've already decoded all layers...
    93  			for _, layer := range packet.Layers() {
    94  				layertypes[layer.LayerType()]++
    95  			}
    96  			if packet.Metadata().Truncated {
    97  				truncated++
    98  			}
    99  			if errLayer := packet.ErrorLayer(); errLayer != nil {
   100  				errors++
   101  				if *printErrors {
   102  					fmt.Println("Error:", errLayer.Error())
   103  					fmt.Println("--- Packet ---")
   104  					fmt.Println(packet.Dump())
   105  				}
   106  			}
   107  		}
   108  		done := *maxcount > 0 && count >= *maxcount
   109  		if count%*statsevery == 0 || done {
   110  			fmt.Fprintf(os.Stderr, "Processed %v packets (%v bytes) in %v, %v errors and %v truncated packets\n", count, bytes, time.Since(start), errors, truncated)
   111  			if len(layertypes) > 0 {
   112  				fmt.Fprintf(os.Stderr, "Layer types seen: %+v\n", layertypes)
   113  			}
   114  		}
   115  		if done {
   116  			break
   117  		}
   118  	}
   119  }