// 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, ð, &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) }
func (h *dnsStream) creatPacket(msg_buf []byte, nomalPack chan gopacket.Packet) { var sourcePort, DesPort int16 //read the port from tranport flow b_buf := bytes.NewBuffer(h.transport.Src().Raw()) binary.Read(b_buf, binary.BigEndian, &sourcePort) b_buf = bytes.NewBuffer(h.transport.Dst().Raw()) binary.Read(b_buf, binary.BigEndian, &DesPort) //new a UDP layer udpLayer := layers.UDP{ BaseLayer: layers.BaseLayer{ Contents: []byte{}, Payload: msg_buf, }, SrcPort: layers.UDPPort(sourcePort), DstPort: layers.UDPPort(DesPort), Length: 1024, Checksum: 30026, } UDPNewSerializBuffer := gopacket.NewSerializeBuffer() // this buffer could be used as a payload of IP layer udpBuffer, _ := UDPNewSerializBuffer.PrependBytes(len(msg_buf)) copy(udpBuffer, msg_buf) ops := gopacket.SerializeOptions{ FixLengths: true, ComputeChecksums: true, } if h.net.EndpointType() == layers.EndpointIPv4 { ip_checksum := layers.IPv4{} ip_checksum.Version = 4 ip_checksum.TTL = 0 ip_checksum.SrcIP = h.net.Src().Raw() ip_checksum.DstIP = h.net.Dst().Raw() udpLayer.SetNetworkLayerForChecksum(&ip_checksum) } else { ip6_checksum := layers.IPv6{} ip6_checksum.Version = 6 ip6_checksum.NextHeader = layers.IPProtocolNoNextHeader ip6_checksum.HopLimit = 0 ip6_checksum.SrcIP = h.net.Src().Raw() ip6_checksum.DstIP = h.net.Dst().Raw() udpLayer.SetNetworkLayerForChecksum(&ip6_checksum) } err := udpLayer.SerializeTo(UDPNewSerializBuffer, ops) if err != nil { fmt.Print("error in create udp Layer") return //err = nil // need err handle there } fmt.Println("finished creat udplayer, the length is ", udpLayer.Length) if h.net.EndpointType() == layers.EndpointIPv4 { // if it is from ipv4, construct a ipv4 layer ip := layers.IPv4{ BaseLayer: layers.BaseLayer{ Contents: []byte{}, Payload: UDPNewSerializBuffer.Bytes(), }, Version: 4, IHL: 0, TOS: 0, Length: 0, Id: 0, Flags: 0, FragOffset: 0, TTL: 0, Protocol: layers.IPProtocolUDP, Checksum: 0, SrcIP: h.net.Src().Raw(), DstIP: h.net.Dst().Raw(), Options: []layers.IPv4Option{}, Padding: []byte{}, } //serialize it and use the serilize buffer to new packet IPserializeBuffer := gopacket.NewSerializeBuffer() ipBuffer, _ := IPserializeBuffer.PrependBytes(len(UDPNewSerializBuffer.Bytes())) copy(ipBuffer, UDPNewSerializBuffer.Bytes()) err = ip.SerializeTo(IPserializeBuffer, ops) if err != nil { fmt.Print("error in create ipv4 Layer") return //err = nil // need err handle there } fmt.Println("finished creat ip, the length is ", ip.Length) resultPack := gopacket.NewPacket(IPserializeBuffer.Bytes(), layers.LayerTypeIPv4, gopacket.Default) resultPack.Metadata().CaptureLength = len(resultPack.Data()) resultPack.Metadata().Length = len(resultPack.Data()) //seems the capture length is 0 so the pcapwrite cannot write it, try to give them a write value nomalPack <- resultPack return } else if h.net.EndpointType() == layers.EndpointIPv6 { // if it is in IPV6 contruct ipv6 packet ip := layers.IPv6{ BaseLayer: layers.BaseLayer{ Contents: []byte{}, Payload: UDPNewSerializBuffer.Bytes(), }, Version: 6, TrafficClass: 0, FlowLabel: 0, Length: 0, NextHeader: layers.IPProtocolNoNextHeader, //no sure what next header should be used there HopLimit: 0, SrcIP: h.net.Src().Raw(), DstIP: h.net.Dst().Raw(), HopByHop: nil, // hbh will be pointed to by HopByHop if that layer exists. } IPserializeBuffer := gopacket.NewSerializeBuffer() err := ip.SerializeTo(IPserializeBuffer, ops) if err != nil { fmt.Printf("error in creat IPV6 Layer") return } fmt.Println("finished creat ip, the length is ", ip.Length) resultPack := gopacket.NewPacket(IPserializeBuffer.Bytes(), layers.LayerTypeIPv6, gopacket.Default) resultPack.Metadata().CaptureLength = len(resultPack.Data()) resultPack.Metadata().Length = len(resultPack.Data()) //seems the capture length is 0 so the pcapwrite cannot write it, try to give them a write value nomalPack <- resultPack return } else { return //unknown network just return? } }
// Given an EvePacket, convert the payload to a PCAP faking out the // headers as best we can. // // A buffer containing the 1 packet pcap file will be returned. func EvePayloadToPcap(event *EveEvent) ([]byte, error) { buffer := gopacket.NewSerializeBuffer() options := gopacket.SerializeOptions{ FixLengths: true, ComputeChecksums: true, } payloadLayer := gopacket.Payload(event.Payload.Bytes()) payloadLayer.SerializeTo(buffer, options) srcIp := net.ParseIP(event.SrcIP) if srcIp == nil { return nil, fmt.Errorf("Failed to parse IP address %s.", event.SrcIP) } dstIp := net.ParseIP(event.DstIP) if dstIp == nil { return nil, fmt.Errorf("Failed to parse IP address %s.", event.DstIP) } proto, err := ProtoNumber(event.Proto) if err != nil { return nil, err } switch proto { case layers.IPProtocolTCP: // Could probably fake up a better TCP layer here. tcpLayer := layers.TCP{ SrcPort: layers.TCPPort(event.SrcPort), DstPort: layers.TCPPort(event.DstPort), } tcpLayer.SerializeTo(buffer, options) break case layers.IPProtocolUDP: udpLayer := layers.UDP{ SrcPort: layers.UDPPort(event.SrcPort), DstPort: layers.UDPPort(event.DstPort), } udpLayer.SerializeTo(buffer, options) break case layers.IPProtocolICMPv4: icmpLayer := layers.ICMPv4{ TypeCode: layers.CreateICMPv4TypeCode( event.IcmpType, event.IcmpCode), Id: 0, Seq: 0, } icmpLayer.SerializeTo(buffer, options) break case layers.IPProtocolICMPv6: icmp6Layer := layers.ICMPv6{ TypeCode: layers.CreateICMPv6TypeCode( event.IcmpType, event.IcmpCode), } icmp6Layer.SerializeTo(buffer, options) break default: return nil, fmt.Errorf("Unsupported protocol %d.", proto) } isIp6 := dstIp.To4() == nil if !isIp6 { ipLayer := layers.IPv4{ SrcIP: srcIp, DstIP: dstIp, Version: 4, Protocol: proto, TTL: 64, } ipLayer.SerializeTo(buffer, options) } else { ip6Layer := layers.IPv6{ Version: 6, SrcIP: srcIp, DstIP: dstIp, } ip6Layer.SerializeTo(buffer, options) } return pcap.CreatePcap(event.Timestamp.Time, buffer.Bytes(), layers.LinkTypeRaw) }
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, ð, &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)) }