Example #1
0
func (i *Sniffer) decodePackets() {
	var eth layers.Ethernet
	var ip layers.IPv4
	var tcp layers.TCP
	var payload gopacket.Payload

	parser := gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, &eth, &ip, &tcp, &payload)
	decoded := make([]gopacket.LayerType, 0, 4)

	for {
		select {
		case <-i.stopDecodeChan:
			return
		case timedRawPacket := <-i.decodePacketChan:
			newPayload := new(gopacket.Payload)
			payload = *newPayload
			err := parser.DecodeLayers(timedRawPacket.RawPacket, &decoded)
			if err != nil {
				continue
			}
			flow := types.NewTcpIpFlowFromFlows(ip.NetworkFlow(), tcp.TransportFlow())
			packetManifest := types.PacketManifest{
				Timestamp: timedRawPacket.Timestamp,
				Flow:      flow,
				RawPacket: timedRawPacket.RawPacket,
				IP:        ip,
				TCP:       tcp,
				Payload:   payload,
			}
			i.dispatcher.ReceivePacket(&packetManifest)
		}
	}
}
Example #2
0
// getPacketFlow returns a TcpIpFlow struct given a byte array packet
func NewTcpIpFlowFromPacket(packet []byte) (*TcpIpFlow, error) {
	var ip layers.IPv4
	var tcp layers.TCP
	decoded := []gopacket.LayerType{}
	parser := gopacket.NewDecodingLayerParser(layers.LayerTypeIPv4, &ip, &tcp)
	err := parser.DecodeLayers(packet, &decoded)
	if err != nil {
		return &TcpIpFlow{}, err
	}
	return &TcpIpFlow{
		ipFlow:  ip.NetworkFlow(),
		tcpFlow: tcp.TransportFlow(),
	}, nil
}
Example #3
0
func benchmarkLayerDecode(source *BufferPacketSource, assemble bool) {
	var tcp layers.TCP
	var ip layers.IPv4
	var eth layers.Ethernet
	var udp layers.UDP
	var icmp layers.ICMPv4
	var payload gopacket.Payload
	parser := gopacket.NewDecodingLayerParser(
		layers.LayerTypeEthernet,
		&eth, &ip, &icmp, &tcp, &udp, &payload)
	pool := tcpassembly.NewStreamPool(&streamFactory{})
	assembler := tcpassembly.NewAssembler(pool)
	var decoded []gopacket.LayerType
	start := time.Now()
	packets, decodedlayers, assembled := 0, 0, 0
	for {
		packets++
		data, ci, err := source.ReadPacketData()
		if err == io.EOF {
			break
		} else if err != nil {
			fmt.Println("Error reading packet: ", err)
			continue
		}
		err = parser.DecodeLayers(data, &decoded)
		for _, typ := range decoded {
			decodedlayers++
			if typ == layers.LayerTypeTCP && assemble {
				assembled++
				assembler.AssembleWithTimestamp(ip.NetworkFlow(), &tcp, ci.Timestamp)
			}
		}
	}
	if assemble {
		assembler.FlushAll()
	}
	duration := time.Since(start)
	fmt.Printf("\tRead in %d packets in %v, decoded %v layers, assembled %v packets: %v per packet\n", packets, duration, decodedlayers, assembled, duration/time.Duration(packets))
}
Example #4
0
//kick off packet procesing threads and start the packet capture loop
func doCapture(handle *pcap.Handle, logChan chan dnsLogEntry,
	config *pdnsConfig, reChan chan tcpDataStruct,
	stats *statsd.StatsdBuffer) {

	gcAgeDur, err := time.ParseDuration(config.gcAge)

	if err != nil {
		log.Fatal("Your gc_age parameter was not parseable.  Use a string like '-1m'")
	}

	gcIntervalDur, err := time.ParseDuration(config.gcInterval)

	if err != nil {
		log.Fatal("Your gc_age parameter was not parseable.  Use a string like '3m'")
	}

	//setup the global channel for reassembled TCP streams
	reassembleChan = reChan

	/* init channels for the packet handlers and kick off handler threads */
	var channels []chan *packetData
	for i := 0; i < config.numprocs; i++ {
		channels = append(channels, make(chan *packetData, 100))
	}

	for i := 0; i < config.numprocs; i++ {
		go handlePacket(channels[i], logChan, gcIntervalDur, gcAgeDur, i, stats)
	}

	// Use the handle as a packet source to process all packets
	packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
	//only decode packet in response to function calls, this moves the
	//packet processing to the processing threads
	packetSource.DecodeOptions.Lazy = true
	//We don't mutate bytes of the packets, so no need to make a copy
	//this does mean we need to pass the packet via the channel, not a pointer to the packet
	//as the underlying buffer will get re-allocated
	packetSource.DecodeOptions.NoCopy = true

	/*
		parse up to the IP layer so we can consistently balance the packets across our
		processing threads

		TODO: in the future maybe pass this on the channel to so we don't reparse
				but the profiling I've done doesn't point to this as a problem
	*/

	var ethLayer layers.Ethernet
	var ipLayer layers.IPv4

	parser := gopacket.NewDecodingLayerParser(
		layers.LayerTypeEthernet,
		&ethLayer,
		&ipLayer,
	)

	foundLayerTypes := []gopacket.LayerType{}

CAPTURE:
	for {
		select {
		case reassembledTcp := <-reChan:
			pd := NewTcpData(reassembledTcp)
			channels[int(reassembledTcp.IpLayer.FastHash())&(config.numprocs-1)] <- pd
			if stats != nil {
				stats.Incr("reassembed_tcp", 1)
			}
		case packet := <-packetSource.Packets():
			if packet != nil {
				parser.DecodeLayers(packet.Data(), &foundLayerTypes)
				if foundLayerType(layers.LayerTypeIPv4, foundLayerTypes) {
					pd := NewPacketData(packet)
					channels[int(ipLayer.NetworkFlow().FastHash())&(config.numprocs-1)] <- pd
					if stats != nil {
						stats.Incr("packets", 1)
					}
				}
			} else {
				//if we get here, we're likely reading a pcap and we've finished
				//or, potentially, the physical device we've been reading from has been
				//downed.  Or something else crazy has gone wrong...so we break
				//out of the capture loop entirely.

				log.Debug("packetSource returned nil.")
				break CAPTURE
			}
		}
	}

	gracefulShutdown(channels, reChan, logChan)

}
Example #5
0
// newIPv4 returns a new initialized IPv4 Flow
func newIPv4(ip *layers.IPv4) ipv4 {
	return ipv4{
		ip4: ip.NetworkFlow(),
		id:  ip.Id,
	}
}
Example #6
0
// processor is a worker that decodes packets and passes on to Account and Log.
func (c *Capture) processor(num int, packetsCh <-chan gopacket.Packet) {
	log.Printf("processor %d: starting", num)

	buffer := c.nextBuffer()
	defer func() {
		// TODO: Save a checkpoint.
		if c.Log != nil {
			c.Log(buffer)
		}
	}()

	var (
		eth     layers.Ethernet
		ip4     layers.IPv4
		ip6     layers.IPv6
		tcp     layers.TCP
		udp     layers.UDP
		dns     layers.DNS
		payload gopacket.Payload
	)
	parser := gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, &eth, &ip4, &ip6, &tcp, &udp, &dns, &payload)
	for packet := range packetsCh {
		var decoded []gopacket.LayerType
		if err := parser.DecodeLayers(packet.Data(), &decoded); err != nil {
			log.Printf("processor %d: %v", num, err)
		}
		m := packet.Metadata()
		b := Metadata{
			Timestamp: m.Timestamp,
			Size:      uint64(m.Length),
		}
		for _, layerType := range decoded {
			switch layerType {
			case layers.LayerTypeIPv6:
				b.SrcIP, b.DstIP = ip6.SrcIP, ip6.DstIP
				b.SrcName, b.DstName = c.revDNS.names(local(b.SrcIP, b.DstIP), ip6.NetworkFlow())
				b.V6 = true
			case layers.LayerTypeIPv4:
				b.SrcIP, b.DstIP = ip4.SrcIP, ip4.DstIP
				b.SrcName, b.DstName = c.revDNS.names(local(b.SrcIP, b.DstIP), ip4.NetworkFlow())
			case layers.LayerTypeTCP:
				b.SrcPort, b.DstPort = uint16(tcp.SrcPort), uint16(tcp.DstPort)
			case layers.LayerTypeUDP:
				b.SrcPort, b.DstPort = uint16(udp.SrcPort), uint16(udp.DstPort)
			case layers.LayerTypeDNS:
				// Add DNS answers to reverse DNS map.
				// The "src" is the host who did the query, but answers are replies, so "src" = dst.
				// Should be here only after b.DstIP is set.
				c.revDNS.add(b.DstIP, &dns)
			}
		}

		c.Account(&b)

		if c.Log != nil {
			buffer = append(buffer, b)
			if len(buffer) >= c.BufferSize {
				go c.logBuffer(buffer)
				buffer = c.nextBuffer()
			}
		}
	}
	log.Printf("processor %d: stopping", num)
}
Example #7
0
// NewTcpIpFlowFromLayers given IPv4 and TCP layers it returns a TcpIpFlow
func NewTcpIpFlowFromLayers(ipLayer layers.IPv4, tcpLayer layers.TCP) *TcpIpFlow {
	return &TcpIpFlow{
		ipFlow:  ipLayer.NetworkFlow(),
		tcpFlow: tcpLayer.TransportFlow(),
	}
}
Example #8
0
func (i *Filter) decodePackets() {
	var eth layers.Ethernet
	var ip layers.IPv4
	var ipv6 layers.IPv6
	var tcp layers.TCP
	var udp layers.UDP
	var payload gopacket.Payload
	anomalyTest := make(chan *Pan)
	alertChan := make(chan *AlertMessage)
	panClose := make(chan *PanCtl)

	//_, IPNet, err := net.ParseCIDR("10.240.0.0/16")
	_, IPNet, err := net.ParseCIDR(i.options.FilterIpCIDR)
	if err != nil {
		log.Errorf("Error parsing CIDR: %#v", err)
		i.Stop()
	}

	decodedLen := 6
	parser := gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet, &eth, &ip, &ipv6, &tcp, &udp, &payload)
	decoded := make([]gopacket.LayerType, 0, decodedLen)

	// Initialize wherefore goroutines
	piChan := PanopticonInfo()
	/*
		for at := 0; at < 10; at++ {
		}
	*/
	go i.AnomalyTester(anomalyTest, piChan, alertChan)
	go i.AlertSlack(alertChan)
	go i.PanRemover(panClose)

	for {
		select {
		case <-i.stopDecodeChan:
			return
		case timedRawPacket := <-i.decodePacketChan:
			newPayload := new(gopacket.Payload)
			payload = *newPayload
			err := parser.DecodeLayers(timedRawPacket.RawPacket, &decoded)
			if err != nil {
				continue
			}

			flow := types.NewTcpIpFlowFromFlows(ip.NetworkFlow(), tcp.TransportFlow())
			dcopy := make([]gopacket.LayerType, decodedLen, decodedLen)
			if dc := copy(dcopy, decoded); dc <= 0 {
				log.Errorf("Copy of decoded layers failed: %d", dc)
				continue
			}
			packetManifest := types.PacketManifest{
				Timestamp:     timedRawPacket.Timestamp,
				Flow:          flow,
				RawPacket:     timedRawPacket.RawPacket,
				DecodedLayers: dcopy,
				Eth:           eth,
				IP:            ip,
				IPv4:          ip,
				IPv6:          ipv6,
				TCP:           tcp,
				UDP:           udp,
				Payload:       payload,
			}

			//Short circut to only watch traffic heading in one direction
			//if FilterExternal(&packetManifest) == nil {
			if i.options.FilterSrc {
				if i.options.FilterBool && IPNet.Contains(packetManifest.IP.SrcIP) {
					continue
				}
			}

			if i.options.FilterDst {
				if i.options.FilterBool && IPNet.Contains(packetManifest.IP.DstIP) {
					continue
				}
			}

			//Pass packet manifest to the PM-Monitor function
			//TODO: Improve the flow around packet processing from the sniffer/splitter
			i.PMMonitor(&packetManifest, anomalyTest, panClose)

		}
	}
}
func main() {
	defer util.Run()()
	var handle *pcap.Handle
	var err error

	flushDuration, err := time.ParseDuration(*flushAfter)
	if err != nil {
		log.Fatal("invalid flush duration: ", *flushAfter)
	}

	// log.Printf("starting capture on interface %q", *iface)
	// // Set up pcap packet capture
	// handle, err := pcap.OpenLive(*iface, int32(*snaplen), true, flushDuration/2)
	// if err != nil {
	// 	log.Fatal("error opening pcap handle: ", err)
	// }
	// Set up pcap packet capture
	if *fname != "" {
		log.Printf("Reading from pcap dump %q", *fname)
		handle, err = pcap.OpenOffline(*fname)
	} else {
		log.Fatalln("Error: pcap file name is required!")
		// log.Printf("Starting capture on interface %q", *iface)
		// handle, err = pcap.OpenLive(*iface, int32(*snaplen), true, pcap.BlockForever)
	}
	if err != nil {
		log.Fatal(err)
	}

	if err := handle.SetBPFFilter(*filter); err != nil {
		log.Fatal("error setting BPF filter: ", err)
	}

	// Set up assembly
	streamFactory := &statsStreamFactory{}
	streamPool := tcpassembly.NewStreamPool(streamFactory)
	assembler := tcpassembly.NewAssembler(streamPool)
	assembler.MaxBufferedPagesPerConnection = *bufferedPerConnection
	assembler.MaxBufferedPagesTotal = *bufferedTotal

	log.Println("reading in packets")

	// We use a DecodingLayerParser here instead of a simpler PacketSource.
	// This approach should be measurably faster, but is also more rigid.
	// PacketSource will handle any known type of packet safely and easily,
	// but DecodingLayerParser will only handle those packet types we
	// specifically pass in.  This trade-off can be quite useful, though, in
	// high-throughput situations.
	var eth layers.Ethernet
	var dot1q layers.Dot1Q
	var ip4 layers.IPv4
	var ip6 layers.IPv6
	var ip6extensions layers.IPv6ExtensionSkipper
	var tcp layers.TCP
	var payload gopacket.Payload
	parser := gopacket.NewDecodingLayerParser(layers.LayerTypeEthernet,
		&eth, &dot1q, &ip4, &ip6, &ip6extensions, &tcp, &payload)
	decoded := make([]gopacket.LayerType, 0, 4)

	nextFlush := time.Now().Add(flushDuration / 2)

	var byteCount int64
	start := time.Now()

loop:
	for ; *packetCount != 0; *packetCount-- {
		// Check to see if we should flush the streams we have
		// that haven't seen any new data in a while.  Note we set a
		// timeout on our PCAP handle, so this should happen even if we
		// never see packet data.
		if time.Now().After(nextFlush) {
			stats, _ := handle.Stats()
			log.Printf("flushing all streams that haven't seen packets in the last 2 minutes, pcap stats: %+v", stats)
			assembler.FlushOlderThan(time.Now().Add(flushDuration))
			nextFlush = time.Now().Add(flushDuration / 2)
		}

		// To speed things up, we're also using the ZeroCopy method for
		// reading packet data.  This method is faster than the normal
		// ReadPacketData, but the returned bytes in 'data' are
		// invalidated by any subsequent ZeroCopyReadPacketData call.
		// Note that tcpassembly is entirely compatible with this packet
		// reading method.  This is another trade-off which might be
		// appropriate for high-throughput sniffing:  it avoids a packet
		// copy, but its cost is much more careful handling of the
		// resulting byte slice.
		data, ci, err := handle.ZeroCopyReadPacketData()

		if err != nil {
			log.Printf("error getting packet: %v", err)
			break loop // continue
		}
		err = parser.DecodeLayers(data, &decoded)
		if err != nil {
			log.Printf("error decoding packet: %v", err)
			continue
		}
		if *logAllPackets {
			log.Printf("decoded the following layers: %v", decoded)
		}
		byteCount += int64(len(data))
		// Find either the IPv4 or IPv6 address to use as our network
		// layer.
		foundNetLayer := false
		var netFlow gopacket.Flow
		for _, typ := range decoded {
			switch typ {
			case layers.LayerTypeIPv4:
				netFlow = ip4.NetworkFlow()
				foundNetLayer = true
			case layers.LayerTypeIPv6:
				netFlow = ip6.NetworkFlow()
				foundNetLayer = true
			case layers.LayerTypeTCP:
				if foundNetLayer {
					assembler.AssembleWithTimestamp(netFlow, &tcp, ci.Timestamp)
				} else {
					log.Println("could not find IPv4 or IPv6 layer, inoring")
				}
				continue loop
			}
		}
		log.Println("could not find TCP layer")
	}
	assembler.FlushAll()
	log.Printf("processed %d bytes in %v", byteCount, time.Since(start))
}