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, ð, &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) } } }
// 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 }
// AssembleWithTimestamp reassembles the given TCP packet into its appropriate // stream. // // The timestamp passed in must be the timestamp the packet was seen. // For packets read off the wire, time.Now() should be fine. For packets read // from PCAP files, CaptureInfo.Timestamp should be passed in. This timestamp // will affect which streams are flushed by a call to FlushOlderThan. // // Each Assemble call results in, in order: // // zero or one calls to StreamFactory.New, creating a stream // zero or one calls to Reassembled on a single stream // zero or one calls to ReassemblyComplete on the same stream func (a *Assembler) AssembleWithTimestamp(netFlow gopacket.Flow, t *layers.TCP, timestamp time.Time) { // Ignore empty TCP packets if !t.SYN && !t.FIN && !t.RST && len(t.LayerPayload()) == 0 { if *debugLog { log.Println("ignoring useless packet") } return } a.ret = a.ret[:0] key := key{netFlow, t.TransportFlow()} var conn *connection // This for loop handles a race condition where a connection will close, lock // the connection pool, and remove itself, but before it locked the connection // pool it's returned to another Assemble statement. This should loop 0-1 // times for the VAST majority of cases. for { conn = a.connPool.getConnection( key, !t.SYN && len(t.LayerPayload()) == 0, timestamp) if conn == nil { if *debugLog { log.Printf("%v got empty packet on otherwise empty connection", key) } return } conn.mu.Lock() if !conn.closed { break } conn.mu.Unlock() } if conn.lastSeen.Before(timestamp) { conn.lastSeen = timestamp } seq, bytes := Sequence(t.Seq), t.Payload if conn.nextSeq == invalidSequence { if t.SYN { if *debugLog { log.Printf("%v saw first SYN packet, returning immediately, seq=%v", key, seq) } a.ret = append(a.ret, Reassembly{ Bytes: bytes, Skip: 0, Start: true, Seen: timestamp, }) conn.nextSeq = seq.Add(len(bytes) + 1) } else { if *debugLog { log.Printf("%v waiting for start, storing into connection", key) } a.insertIntoConn(t, conn, timestamp) } } else if diff := conn.nextSeq.Difference(seq); diff > 0 { if *debugLog { log.Printf("%v gap in sequence numbers (%v, %v) diff %v, storing into connection", key, conn.nextSeq, seq, diff) } a.insertIntoConn(t, conn, timestamp) } else { bytes, conn.nextSeq = byteSpan(conn.nextSeq, seq, bytes) if *debugLog { log.Printf("%v found contiguous data (%v, %v), returning immediately", key, seq, conn.nextSeq) } a.ret = append(a.ret, Reassembly{ Bytes: bytes, Skip: 0, End: t.RST || t.FIN, Seen: timestamp, }) } if len(a.ret) > 0 { a.sendToConnection(conn) } conn.mu.Unlock() }
// 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(), } }
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, ð, &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) } } }
// AssembleWithTimestamp reassembles the given TCP packet into its appropriate // stream. // // The timestamp passed in must be the timestamp the packet was seen. For // packets read off the wire, time.Now() should be fine. For packets read from // PCAP files, CaptureInfo.Timestamp should be passed in. This timestamp will // affect which streams are flushed by a call to FlushOlderThan. // // Each Assemble call results in, in order: // // zero or one calls to StreamFactory.New, creating a stream // zero or one calls to Reassembled on a single stream // zero or one calls to ReassemblyComplete on the same stream func (a *Assembler) AssembleWithTimestamp(netFlow gopacket.Flow, t *layers.TCP, timestamp time.Time) { // Ignore empty TCP packets if !t.SYN && !t.FIN && !t.RST && len(t.LayerPayload()) == 0 { return } a.ret = a.ret[:0] key := key{netFlow, t.TransportFlow()} var conn *connection // This for loop handles a race condition where a connection will close, // lock the connection pool, and remove itself, but before it locked the // connection pool it's returned to another Assemble statement. This should // loop 0-1 times for the VAST majority of cases. for { conn = a.connPool.getConnection( key, !t.SYN && len(t.LayerPayload()) == 0, timestamp) if conn == nil { if *debugLog { log.Printf("%v got empty packet on otherwise empty connection", key) } return } conn.mu.Lock() if !conn.closed { break } conn.mu.Unlock() } if conn.lastSeen.Before(timestamp) { conn.lastSeen = timestamp } seq, bytes := Sequence(t.Seq), t.Payload if conn.nextSeq == invalidSequence { // Handling the first packet we've seen on the stream. skip := 0 if !t.SYN { // don't add 1 since we're just going to assume the sequence number // without the SYN packet. // stream was picked up somewhere in the middle, so indicate that we // don't know how many packets came before it. conn.nextSeq = seq.Add(len(bytes)) skip = -1 } else { // for SYN packets, also increment the sequence number by 1 conn.nextSeq = seq.Add(len(bytes) + 1) } a.ret = append(a.ret, tcpassembly.Reassembly{ Bytes: bytes, Skip: skip, Start: t.SYN, Seen: timestamp, }) a.insertIntoConn(t, conn, timestamp) } else if diff := conn.nextSeq.Difference(seq); diff > 0 { a.insertIntoConn(t, conn, timestamp) } else { bytes, conn.nextSeq = byteSpan(conn.nextSeq, seq, bytes) a.ret = append(a.ret, tcpassembly.Reassembly{ Bytes: bytes, Skip: 0, End: t.RST || t.FIN, Seen: timestamp, }) } if len(a.ret) > 0 { a.sendToConnection(conn) } conn.mu.Unlock() }