diff options
Diffstat (limited to 'src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/google/gopacket/examples/reassemblydump/main.go')
-rw-r--r-- | src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/google/gopacket/examples/reassemblydump/main.go | 661 |
1 files changed, 0 insertions, 661 deletions
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/google/gopacket/examples/reassemblydump/main.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/google/gopacket/examples/reassemblydump/main.go deleted file mode 100644 index 827901185a9..00000000000 --- a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/vendor/github.com/google/gopacket/examples/reassemblydump/main.go +++ /dev/null @@ -1,661 +0,0 @@ -// Copyright 2012 Google, Inc. All rights reserved. -// -// Use of this source code is governed by a BSD-style license -// that can be found in the LICENSE file in the root of the source -// tree. - -// The pcapdump binary implements a tcpdump-like command line tool with gopacket -// using pcap as a backend data collection mechanism. -package main - -import ( - "bufio" - "bytes" - "compress/gzip" - "encoding/binary" - "encoding/hex" - "flag" - "fmt" - "io" - "io/ioutil" - "log" - "net/http" - "net/url" - "os" - "os/signal" - "path" - "runtime/pprof" - "strings" - "sync" - "time" - - "github.com/google/gopacket" - "github.com/google/gopacket/examples/util" - "github.com/google/gopacket/ip4defrag" - "github.com/google/gopacket/layers" // pulls in all layers decoders - "github.com/google/gopacket/pcap" - "github.com/google/gopacket/reassembly" -) - -var maxcount = flag.Int("c", -1, "Only grab this many packets, then exit") -var decoder = flag.String("decoder", "", "Name of the decoder to use (default: guess from capture)") -var statsevery = flag.Int("stats", 1000, "Output statistics every N packets") -var lazy = flag.Bool("lazy", false, "If true, do lazy decoding") -var nodefrag = flag.Bool("nodefrag", false, "If true, do not do IPv4 defrag") -var checksum = flag.Bool("checksum", false, "Check TCP checksum") -var nooptcheck = flag.Bool("nooptcheck", false, "Do not check TCP options (useful to ignore MSS on captures with TSO)") -var ignorefsmerr = flag.Bool("ignorefsmerr", false, "Ignore TCP FSM errors") -var allowmissinginit = flag.Bool("allowmissinginit", false, "Support streams without SYN/SYN+ACK/ACK sequence") -var verbose = flag.Bool("verbose", false, "Be verbose") -var debug = flag.Bool("debug", false, "Display debug information") -var quiet = flag.Bool("quiet", false, "Be quiet regarding errors") - -// http -var nohttp = flag.Bool("nohttp", false, "Disable HTTP parsing") -var output = flag.String("output", "", "Path to create file for HTTP 200 OK responses") -var writeincomplete = flag.Bool("writeincomplete", false, "Write incomplete response") - -var hexdump = flag.Bool("dump", false, "Dump HTTP request/response as hex") -var hexdumppkt = flag.Bool("dumppkt", false, "Dump packet as hex") - -// capture -var iface = flag.String("i", "eth0", "Interface to read packets from") -var fname = flag.String("r", "", "Filename to read from, overrides -i") -var snaplen = flag.Int("s", 65536, "Snap length (number of bytes max to read per packet") -var tstype = flag.String("timestamp_type", "", "Type of timestamps to use") -var promisc = flag.Bool("promisc", true, "Set promiscuous mode") - -var memprofile = flag.String("memprofile", "", "Write memory profile") - -var stats struct { - ipdefrag int - missedBytes int - pkt int - sz int - totalsz int - rejectFsm int - rejectOpt int - rejectConnFsm int - reassembled int - outOfOrderBytes int - outOfOrderPackets int - biggestChunkBytes int - biggestChunkPackets int - overlapBytes int - overlapPackets int -} - -const closeTimeout time.Duration = time.Hour * 24 // Closing inactive: TODO: from CLI -const timeout time.Duration = time.Minute * 5 // Pending bytes: TODO: from CLI - -/* - * HTTP part - */ - -type httpReader struct { - ident string - isClient bool - bytes chan []byte - data []byte - hexdump bool - parent *tcpStream -} - -func (h *httpReader) Read(p []byte) (int, error) { - ok := true - for ok && len(h.data) == 0 { - h.data, ok = <-h.bytes - } - if !ok || len(h.data) == 0 { - return 0, io.EOF - } - - l := copy(p, h.data) - h.data = h.data[l:] - return l, nil -} - -var outputLevel int -var errorsMap map[string]uint -var errorsMapMutex sync.Mutex -var errors uint - -// Too bad for perf that a... is evaluated -func Error(t string, s string, a ...interface{}) { - errorsMapMutex.Lock() - errors++ - nb, _ := errorsMap[t] - errorsMap[t] = nb + 1 - errorsMapMutex.Unlock() - if outputLevel >= 0 { - fmt.Printf(s, a...) - } -} -func Info(s string, a ...interface{}) { - if outputLevel >= 1 { - fmt.Printf(s, a...) - } -} -func Debug(s string, a ...interface{}) { - if outputLevel >= 2 { - fmt.Printf(s, a...) - } -} - -func (h *httpReader) run(wg *sync.WaitGroup) { - defer wg.Done() - b := bufio.NewReader(h) - for true { - if h.isClient { - req, err := http.ReadRequest(b) - if err == io.EOF || err == io.ErrUnexpectedEOF { - break - } else if err != nil { - Error("HTTP-request", "HTTP/%s Request error: %s (%v,%+v)\n", h.ident, err, err, err) - continue - } - body, err := ioutil.ReadAll(req.Body) - s := len(body) - if err != nil { - Error("HTTP-request-body", "Got body err: %s\n", err) - } else if h.hexdump { - Info("Body(%d/0x%x)\n%s\n", len(body), len(body), hex.Dump(body)) - } - req.Body.Close() - Info("HTTP/%s Request: %s %s (body:%d)\n", h.ident, req.Method, req.URL, s) - h.parent.Lock() - h.parent.urls = append(h.parent.urls, req.URL.String()) - h.parent.Unlock() - } else { - res, err := http.ReadResponse(b, nil) - var req string - h.parent.Lock() - if len(h.parent.urls) == 0 { - req = fmt.Sprintf("<no-request-seen>") - } else { - req, h.parent.urls = h.parent.urls[0], h.parent.urls[1:] - } - h.parent.Unlock() - if err == io.EOF || err == io.ErrUnexpectedEOF { - break - } else if err != nil { - Error("HTTP-response", "HTTP/%s Response error: %s (%v,%+v)\n", h.ident, err, err, err) - continue - } - body, err := ioutil.ReadAll(res.Body) - s := len(body) - if err != nil { - Error("HTTP-response-body", "HTTP/%s: failed to get body(parsed len:%d): %s\n", h.ident, s, err) - } - if h.hexdump { - Info("Body(%d/0x%x)\n%s\n", len(body), len(body), hex.Dump(body)) - } - res.Body.Close() - sym := "," - if res.ContentLength > 0 && res.ContentLength != int64(s) { - sym = "!=" - } - contentType, ok := res.Header["Content-Type"] - if !ok { - contentType = []string{http.DetectContentType(body)} - } - encoding := res.Header["Content-Encoding"] - Info("HTTP/%s Response: %s URL:%s (%d%s%d%s) -> %s\n", h.ident, res.Status, req, res.ContentLength, sym, s, contentType, encoding) - if (err == nil || *writeincomplete) && *output != "" { - base := url.QueryEscape(path.Base(req)) - if err != nil { - base = "incomplete-" + base - } - base = path.Join(*output, base) - if len(base) > 250 { - base = base[:250] + "..." - } - if base == *output { - base = path.Join(*output, "noname") - } - target := base - n := 0 - for true { - _, err := os.Stat(target) - //if os.IsNotExist(err) != nil { - if err != nil { - break - } - target = fmt.Sprintf("%s-%d", base, n) - n++ - } - f, err := os.Create(target) - if err != nil { - Error("HTTP-create", "Cannot create %s: %s\n", target, err) - continue - } - var r io.Reader - r = bytes.NewBuffer(body) - if len(encoding) > 0 && (encoding[0] == "gzip" || encoding[0] == "deflate") { - r, err = gzip.NewReader(r) - if err != nil { - Error("HTTP-gunzip", "Failed to gzip decode: %s", err) - } - } - if err == nil { - w, err := io.Copy(f, r) - if _, ok := r.(*gzip.Reader); ok { - r.(*gzip.Reader).Close() - } - f.Close() - if err != nil { - Error("HTTP-save", "%s: failed to save %s (l:%d): %s\n", h.ident, target, w, err) - } else { - Info("%s: Saved %s (l:%d)\n", h.ident, target, w) - } - } - } - } - } -} - -/* - * The TCP factory: returns a new Stream - */ -type tcpStreamFactory struct { - wg sync.WaitGroup - doHTTP bool -} - -func (factory *tcpStreamFactory) New(net, transport gopacket.Flow, tcp *layers.TCP, ac reassembly.AssemblerContext) reassembly.Stream { - Debug("* NEW: %s %s\n", net, transport) - fsmOptions := reassembly.TCPSimpleFSMOptions{ - SupportMissingEstablishment: *allowmissinginit, - } - stream := &tcpStream{ - net: net, - transport: transport, - isDNS: tcp.SrcPort == 53 || tcp.DstPort == 53, - isHTTP: (tcp.SrcPort == 80 || tcp.DstPort == 80) && factory.doHTTP, - reversed: tcp.SrcPort == 80, - tcpstate: reassembly.NewTCPSimpleFSM(fsmOptions), - ident: fmt.Sprintf("%s:%s", net, transport), - optchecker: reassembly.NewTCPOptionCheck(), - } - if stream.isHTTP { - stream.client = httpReader{ - bytes: make(chan []byte), - ident: fmt.Sprintf("%s %s", net, transport), - hexdump: *hexdump, - parent: stream, - isClient: true, - } - stream.server = httpReader{ - bytes: make(chan []byte), - ident: fmt.Sprintf("%s %s", net.Reverse(), transport.Reverse()), - hexdump: *hexdump, - parent: stream, - } - factory.wg.Add(2) - go stream.client.run(&factory.wg) - go stream.server.run(&factory.wg) - } - return stream -} - -func (factory *tcpStreamFactory) WaitGoRoutines() { - factory.wg.Wait() -} - -/* - * The assembler context - */ -type Context struct { - CaptureInfo gopacket.CaptureInfo -} - -func (c *Context) GetCaptureInfo() gopacket.CaptureInfo { - return c.CaptureInfo -} - -/* - * TCP stream - */ - -/* It's a connection (bidirectional) */ -type tcpStream struct { - tcpstate *reassembly.TCPSimpleFSM - fsmerr bool - optchecker reassembly.TCPOptionCheck - net, transport gopacket.Flow - isDNS bool - isHTTP bool - reversed bool - client httpReader - server httpReader - urls []string - ident string - sync.Mutex -} - -func (t *tcpStream) Accept(tcp *layers.TCP, ci gopacket.CaptureInfo, dir reassembly.TCPFlowDirection, nextSeq reassembly.Sequence, start *bool, ac reassembly.AssemblerContext) bool { - // FSM - if !t.tcpstate.CheckState(tcp, dir) { - Error("FSM", "%s: Packet rejected by FSM (state:%s)\n", t.ident, t.tcpstate.String()) - stats.rejectFsm++ - if !t.fsmerr { - t.fsmerr = true - stats.rejectConnFsm++ - } - if !*ignorefsmerr { - return false - } - } - // Options - err := t.optchecker.Accept(tcp, ci, dir, nextSeq, start) - if err != nil { - Error("OptionChecker", "%s: Packet rejected by OptionChecker: %s\n", t.ident, err) - stats.rejectOpt++ - if !*nooptcheck { - return false - } - } - // Checksum - accept := true - if *checksum { - c, err := tcp.ComputeChecksum() - if err != nil { - Error("ChecksumCompute", "%s: Got error computing checksum: %s\n", t.ident, err) - accept = false - } else if c != 0x0 { - Error("Checksum", "%s: Invalid checksum: 0x%x\n", t.ident, c) - accept = false - } - } - if !accept { - stats.rejectOpt++ - } - return accept -} - -func (t *tcpStream) ReassembledSG(sg reassembly.ScatterGather, ac reassembly.AssemblerContext) { - dir, start, end, skip := sg.Info() - length, saved := sg.Lengths() - // update stats - sgStats := sg.Stats() - if skip > 0 { - stats.missedBytes += skip - } - stats.sz += length - saved - stats.pkt += sgStats.Packets - if sgStats.Chunks > 1 { - stats.reassembled++ - } - stats.outOfOrderPackets += sgStats.QueuedPackets - stats.outOfOrderBytes += sgStats.QueuedBytes - if length > stats.biggestChunkBytes { - stats.biggestChunkBytes = length - } - if sgStats.Packets > stats.biggestChunkPackets { - stats.biggestChunkPackets = sgStats.Packets - } - if sgStats.OverlapBytes != 0 && sgStats.OverlapPackets == 0 { - fmt.Printf("bytes:%d, pkts:%d\n", sgStats.OverlapBytes, sgStats.OverlapPackets) - panic("Invalid overlap") - } - stats.overlapBytes += sgStats.OverlapBytes - stats.overlapPackets += sgStats.OverlapPackets - - var ident string - if dir == reassembly.TCPDirClientToServer { - ident = fmt.Sprintf("%v %v(%s): ", t.net, t.transport, dir) - } else { - ident = fmt.Sprintf("%v %v(%s): ", t.net.Reverse(), t.transport.Reverse(), dir) - } - Debug("%s: SG reassembled packet with %d bytes (start:%v,end:%v,skip:%d,saved:%d,nb:%d,%d,overlap:%d,%d)\n", ident, length, start, end, skip, saved, sgStats.Packets, sgStats.Chunks, sgStats.OverlapBytes, sgStats.OverlapPackets) - if skip == -1 && *allowmissinginit { - // this is allowed - } else if skip != 0 { - // Missing bytes in stream: do not even try to parse it - return - } - data := sg.Fetch(length) - if t.isDNS { - dns := &layers.DNS{} - var decoded []gopacket.LayerType - if len(data) < 2 { - if len(data) > 0 { - sg.KeepFrom(0) - } - return - } - dnsSize := binary.BigEndian.Uint16(data[:2]) - missing := int(dnsSize) - len(data[2:]) - Debug("dnsSize: %d, missing: %d\n", dnsSize, missing) - if missing > 0 { - Info("Missing some bytes: %d\n", missing) - sg.KeepFrom(0) - return - } - p := gopacket.NewDecodingLayerParser(layers.LayerTypeDNS, dns) - err := p.DecodeLayers(data[2:], &decoded) - if err != nil { - Error("DNS-parser", "Failed to decode DNS: %v\n", err) - } else { - Debug("DNS: %s\n", gopacket.LayerDump(dns)) - } - if len(data) > 2+int(dnsSize) { - sg.KeepFrom(2 + int(dnsSize)) - } - } else if t.isHTTP { - if length > 0 { - if *hexdump { - Debug("Feeding http with:\n%s", hex.Dump(data)) - } - if dir == reassembly.TCPDirClientToServer && !t.reversed { - t.client.bytes <- data - } else { - t.server.bytes <- data - } - } - } -} - -func (t *tcpStream) ReassemblyComplete(ac reassembly.AssemblerContext) bool { - Debug("%s: Connection closed\n", t.ident) - if t.isHTTP { - close(t.client.bytes) - close(t.server.bytes) - } - // do not remove the connection to allow last ACK - return false -} - -func main() { - defer util.Run()() - var handle *pcap.Handle - var err error - if *debug { - outputLevel = 2 - } else if *verbose { - outputLevel = 1 - } else if *quiet { - outputLevel = -1 - } - errorsMap = make(map[string]uint) - if *fname != "" { - if handle, err = pcap.OpenOffline(*fname); err != nil { - log.Fatal("PCAP OpenOffline error:", err) - } - } else { - // This is a little complicated because we want to allow all possible options - // for creating the packet capture handle... instead of all this you can - // just call pcap.OpenLive if you want a simple handle. - inactive, err := pcap.NewInactiveHandle(*iface) - if err != nil { - log.Fatal("could not create: %v", err) - } - defer inactive.CleanUp() - if err = inactive.SetSnapLen(*snaplen); err != nil { - log.Fatal("could not set snap length: %v", err) - } else if err = inactive.SetPromisc(*promisc); err != nil { - log.Fatal("could not set promisc mode: %v", err) - } else if err = inactive.SetTimeout(time.Second); err != nil { - log.Fatal("could not set timeout: %v", err) - } - if *tstype != "" { - if t, err := pcap.TimestampSourceFromString(*tstype); err != nil { - log.Fatalf("Supported timestamp types: %v", inactive.SupportedTimestamps()) - } else if err := inactive.SetTimestampSource(t); err != nil { - log.Fatalf("Supported timestamp types: %v", inactive.SupportedTimestamps()) - } - } - if handle, err = inactive.Activate(); err != nil { - log.Fatal("PCAP Activate error:", err) - } - defer handle.Close() - } - if len(flag.Args()) > 0 { - bpffilter := strings.Join(flag.Args(), " ") - Info("Using BPF filter %q\n", bpffilter) - if err = handle.SetBPFFilter(bpffilter); err != nil { - log.Fatal("BPF filter error:", err) - } - } - - var dec gopacket.Decoder - var ok bool - decoder_name := *decoder - if decoder_name == "" { - decoder_name = fmt.Sprintf("%s", handle.LinkType()) - } - if dec, ok = gopacket.DecodersByLayerName[decoder_name]; !ok { - log.Fatalln("No decoder named", decoder_name) - } - source := gopacket.NewPacketSource(handle, dec) - source.Lazy = *lazy - source.NoCopy = true - Info("Starting to read packets\n") - count := 0 - bytes := int64(0) - start := time.Now() - defragger := ip4defrag.NewIPv4Defragmenter() - - streamFactory := &tcpStreamFactory{doHTTP: !*nohttp} - streamPool := reassembly.NewStreamPool(streamFactory) - assembler := reassembly.NewAssembler(streamPool) - - signalChan := make(chan os.Signal, 1) - signal.Notify(signalChan, os.Interrupt) - - for packet := range source.Packets() { - count++ - Debug("PACKET #%d\n", count) - data := packet.Data() - bytes += int64(len(data)) - if *hexdumppkt { - Debug("Packet content (%d/0x%x)\n%s\n", len(data), len(data), hex.Dump(data)) - } - - // defrag the IPv4 packet if required - if !*nodefrag { - ip4Layer := packet.Layer(layers.LayerTypeIPv4) - if ip4Layer == nil { - continue - } - ip4 := ip4Layer.(*layers.IPv4) - l := ip4.Length - newip4, err := defragger.DefragIPv4(ip4) - if err != nil { - log.Fatalln("Error while de-fragmenting", err) - } else if newip4 == nil { - Debug("Fragment...\n") - continue // packet fragment, we don't have whole packet yet. - } - if newip4.Length != l { - stats.ipdefrag++ - Debug("Decoding re-assembled packet: %s\n", newip4.NextLayerType()) - pb, ok := packet.(gopacket.PacketBuilder) - if !ok { - panic("Not a PacketBuilder") - } - nextDecoder := newip4.NextLayerType() - nextDecoder.Decode(newip4.Payload, pb) - } - } - - tcp := packet.Layer(layers.LayerTypeTCP) - if tcp != nil { - tcp := tcp.(*layers.TCP) - if *checksum { - err := tcp.SetNetworkLayerForChecksum(packet.NetworkLayer()) - if err != nil { - log.Fatalf("Failed to set network layer for checksum: %s\n", err) - } - } - c := Context{ - CaptureInfo: packet.Metadata().CaptureInfo, - } - stats.totalsz += len(tcp.Payload) - assembler.AssembleWithContext(packet.NetworkLayer().NetworkFlow(), tcp, &c) - } - if count%*statsevery == 0 { - ref := packet.Metadata().CaptureInfo.Timestamp - flushed, closed := assembler.FlushWithOptions(reassembly.FlushOptions{T: ref.Add(-timeout), TC: ref.Add(-closeTimeout)}) - Debug("Forced flush: %d flushed, %d closed (%s)", flushed, closed, ref) - } - - done := *maxcount > 0 && count >= *maxcount - if count%*statsevery == 0 || done { - errorsMapMutex.Lock() - errorMapLen := len(errorsMap) - errorsMapMutex.Unlock() - fmt.Fprintf(os.Stderr, "Processed %v packets (%v bytes) in %v (errors: %v, errTypes:%v)\n", count, bytes, time.Since(start), errors, errorMapLen) - } - select { - case <-signalChan: - fmt.Fprintf(os.Stderr, "\nCaught SIGINT: aborting\n") - done = true - default: - // NOP: continue - } - if done { - break - } - } - - closed := assembler.FlushAll() - Debug("Final flush: %d closed", closed) - if outputLevel >= 2 { - streamPool.Dump() - } - - if *memprofile != "" { - f, err := os.Create(*memprofile) - if err != nil { - log.Fatal(err) - } - pprof.WriteHeapProfile(f) - f.Close() - } - - streamFactory.WaitGoRoutines() - Debug("%s\n", assembler.Dump()) - if !*nodefrag { - fmt.Printf("IPdefrag:\t\t%d\n", stats.ipdefrag) - } - fmt.Printf("TCP stats:\n") - fmt.Printf(" missed bytes:\t\t%d\n", stats.missedBytes) - fmt.Printf(" total packets:\t\t%d\n", stats.pkt) - fmt.Printf(" rejected FSM:\t\t%d\n", stats.rejectFsm) - fmt.Printf(" rejected Options:\t%d\n", stats.rejectOpt) - fmt.Printf(" reassembled bytes:\t%d\n", stats.sz) - fmt.Printf(" total TCP bytes:\t%d\n", stats.totalsz) - fmt.Printf(" conn rejected FSM:\t%d\n", stats.rejectConnFsm) - fmt.Printf(" reassembled chunks:\t%d\n", stats.reassembled) - fmt.Printf(" out-of-order packets:\t%d\n", stats.outOfOrderPackets) - fmt.Printf(" out-of-order bytes:\t%d\n", stats.outOfOrderBytes) - fmt.Printf(" biggest-chunk packets:\t%d\n", stats.biggestChunkPackets) - fmt.Printf(" biggest-chunk bytes:\t%d\n", stats.biggestChunkBytes) - fmt.Printf(" overlap packets:\t%d\n", stats.overlapPackets) - fmt.Printf(" overlap bytes:\t\t%d\n", stats.overlapBytes) - fmt.Printf("Errors: %d\n", errors) - for e, _ := range errorsMap { - fmt.Printf(" %s:\t\t%d\n", e, errorsMap[e]) - } -} |