ndpi+nfq

注意点,对于nfq来的流量,  gopacket.NewDecodingLayerParser(layers.LayerTypeIPv4, eth, ip4, tcp, udp, payload)中的layers.LayerTypeIPv4要标记为IPV4,因为流量是来自于nfq,而不是直接的网卡,网卡是以太网帧,这里是从网卡抓和从nfq抓的区别

/*
Example of simple uage:
- Packet Capture by libpcap
- Packet L2 - L4 inspection by gopacket
- Packet L7 inspection by nDPI
- Golang map for flow recording
*/

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"os"
	"sync"

	"go-ndpi/gondpi"

	"github.com/fs714/go-ndpi/gondpi/types"
	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	nfqueue "github.com/subgraph/go-nfnetlink/nfqueue"
)

const (
	MaxPacketsUdpDissection = 24
	MaxPacketsTcpDissection = 80
)

type FlowFingerprint struct {
	SrcAddr  uint32
	DstAddr  uint32
	SrcPort  uint16
	DstPort  uint16
	Protocol uint8
}

func (f *FlowFingerprint) ToString() string {
	ff := struct {
		SrcAddr  string
		DstAddr  string
		SrcPort  uint16
		DstPort  uint16
		Protocol string
	}{
		SrcAddr:  types.IntToIPv4(f.SrcAddr).String(),
		DstAddr:  types.IntToIPv4(f.DstAddr).String(),
		SrcPort:  f.SrcPort,
		DstPort:  f.DstPort,
		Protocol: (*types.IPProto)(&f.Protocol).ToName(),
	}

	ffJson, _ := json.MarshalIndent(ff, "", "  ")

	return string(ffJson)
}

type FlowInfo struct {
	TotalL2Packets         int64
	TotalL3PayloadBytes    int64
	StartTsMilli           int64
	EndTsMilli             int64
	NdpiProcessedPackets   int64
	NdpiProcessedBytes     int64
	NdpiDetectionCompleted bool
	NdpiIsGuessed          bool
	NdpiFlow               *gondpi.NdpiFlow
	Mu                     sync.Mutex
}

func NewFlowInfo() (*FlowInfo, error) {
	flowInfo := FlowInfo{}

	ndpiFlow, err := gondpi.NewNdpiFlow()
	if err != nil {
		return nil, err
	}

	flowInfo.NdpiFlow = ndpiFlow

	return &flowInfo, nil
}

type IfaceStats struct {
	FlowMap map[FlowFingerprint]*FlowInfo
	Mu      sync.Mutex
}

func (s *IfaceStats) AddFlow(fp FlowFingerprint, flowInfo *FlowInfo) {
	s.Mu.Lock()
	defer s.Mu.Unlock()

	s.FlowMap[fp] = flowInfo
}

func (s *IfaceStats) DeleteFlow(fp FlowFingerprint) {
	s.Mu.Lock()
	defer s.Mu.Unlock()

	_, ok := s.FlowMap[fp]
	if !ok {
		return
	}

	delete(s.FlowMap, fp)
}

func (s *IfaceStats) GetFlow(fp FlowFingerprint) *FlowInfo {
	s.Mu.Lock()
	defer s.Mu.Unlock()

	flowInfo, ok := s.FlowMap[fp]
	if ok {
		return flowInfo
	}

	fpr := FlowFingerprint{
		SrcAddr:  fp.DstAddr,
		DstAddr:  fp.SrcAddr,
		SrcPort:  fp.DstPort,
		DstPort:  fp.SrcPort,
		Protocol: fp.Protocol,
	}

	flowInfo, ok = s.FlowMap[fpr]
	if ok {
		return flowInfo
	}

	return nil
}

func main() {

	q := nfqueue.NewNFQueue(1)

	ps, err := q.Open()
	if err != nil {
		fmt.Printf("Error opening NFQueue: %v\n", err)
		os.Exit(1)
	}
	defer q.Close()

	//-------------------------------------------------------------------------

	var ifaceName string
	var enableGuess bool
	flag.StringVar(&ifaceName, "i", "", "interface name")
	flag.BoolVar(&enableGuess, "g", true, "enable protocol guess or not")
	flag.Parse()

	Stats := IfaceStats{
		FlowMap: map[FlowFingerprint]*FlowInfo{},
	}

	detectionBitmask := gondpi.NewNdpiProtocolBitmask()
	detectionBitmask = gondpi.NdpiProtocolBitmaskSetAll(detectionBitmask)
	ndpiDM, err := gondpi.NdpiDetectionModuleInitialize(types.NDPI_NO_PREFS, detectionBitmask)
	if err != nil {
		fmt.Printf("failed to initialize ndpi detection module with err: %s\n", err.Error())
		return
	}

	defer ndpiDM.Close()

	for p := range ps {

		eth := &layers.Ethernet{}
		ip4 := &layers.IPv4{}
		tcp := &layers.TCP{}
		udp := &layers.UDP{}
		payload := &gopacket.Payload{}
		parser := gopacket.NewDecodingLayerParser(layers.LayerTypeIPv4, eth, ip4, tcp, udp, payload)
		decoded := make([]gopacket.LayerType, 0, 4)

		//var data []byte
		var ci gopacket.CaptureInfo
		var fp FlowFingerprint
		var flowInfo *FlowInfo
		var ndpiProto gondpi.NdpiProto
		var ts int64
		var ipData []byte
		var ipLength uint16
		var isGuessed bool

		//id := *a.PacketID
		// Just print out the id and payload of the nfqueue packet
		networkLayer := p.Packet.NetworkLayer()
		ipsrc, ipdst := networkLayer.NetworkFlow().Endpoints()

		transportLayer := p.Packet.TransportLayer()
		tcpsrc, tcpdst := transportLayer.TransportFlow().Endpoints()

		fmt.Printf("A new tcp connection will be established: %s:%s -> %s:%s\n",
			ipsrc, tcpsrc, ipdst, tcpdst)

		//data, ci, err = handle.ZeroCopyReadPacketData()
		if err != nil {
			fmt.Printf("error getting packet: %s\n", err.Error())

		}

		err = parser.DecodeLayers(p.Packet.Data(), &decoded)
		// if p.Packet.ApplicationLayer() != nil {
		// 	err = parser.DecodeLayers(p.Packet.ApplicationLayer().LayerPayload(), &decoded)
		// }

		if err != nil {
			fmt.Printf("error decoding packet: %s\n", err.Error())
		}

		for _, typ := range decoded {
			fmt.Printf("type is %d \n", typ)
			switch typ {
			case layers.LayerTypeTCP:
				ipLength = ip4.Length
				fp = FlowFingerprint{
					SrcAddr:  types.IPv4ToInt(ip4.SrcIP),
					DstAddr:  types.IPv4ToInt(ip4.DstIP),
					SrcPort:  uint16(tcp.SrcPort),
					DstPort:  uint16(tcp.DstPort),
					Protocol: uint8(types.IPProtocolTCP),
				}

				flowInfo = Stats.GetFlow(fp)
				if flowInfo == nil {
					fmt.Printf("flowInfo is null\n")
					flowInfo, err = NewFlowInfo()
					if err != nil {
						fmt.Printf("failed to new FlowInfo with err: %s\n", err.Error())
						continue
					}

					flowInfo.Mu.Lock()
					flowInfo.StartTsMilli = ci.Timestamp.UnixMilli()
					flowInfo.Mu.Unlock()

					Stats.AddFlow(fp, flowInfo)
				}

				flowInfo.Mu.Lock()
				flowInfo.TotalL2Packets++
				flowInfo.TotalL3PayloadBytes += int64(ipLength)
				flowInfo.EndTsMilli = ci.Timestamp.UnixMilli()

				//fmt.Printf("NdpiDetectionCompleted %d: \n", !flowInfo.NdpiDetectionCompleted)
				if !flowInfo.NdpiDetectionCompleted {
					flowInfo.NdpiProcessedPackets++
					flowInfo.NdpiProcessedBytes += int64(ipLength)

					// ipData := make([]byte, len(eth.Payload))
					// copy(ipData, eth.Payload)
					ipData = p.Packet.Data()
					ndpiProto = ndpiDM.PacketProcessing(flowInfo.NdpiFlow, ipData, ipLength, ts)

					enoughPackets := false
					if flowInfo.NdpiProcessedPackets > MaxPacketsTcpDissection {
						enoughPackets = true
					}

					extraDissectionPossible := ndpiDM.IsExtraDissectionPossible(flowInfo.NdpiFlow)

					if enoughPackets || ndpiProto.AppProtocolId != types.NDPI_PROTOCOL_UNKNOWN {
						if !enoughPackets && extraDissectionPossible {

						} else {
							if enableGuess && ndpiProto.AppProtocolId == types.NDPI_PROTOCOL_UNKNOWN {
								ndpiProto, isGuessed = ndpiDM.DetectionGiveup(flowInfo.NdpiFlow, enableGuess)
								flowInfo.NdpiIsGuessed = isGuessed
							}

							flowInfo.NdpiDetectionCompleted = true

							fmt.Println("------")
							masterProto := ndpiProto.MasterProtocolId.ToName()
							appProto := ndpiProto.AppProtocolId.ToName()
							category := ndpiProto.CategoryId.ToName()

							fmt.Printf("Master Protocol: %s, App Protocol: %s, Category: %s\n", masterProto, appProto, category)

							fpString := fp.ToString()
							flowInfoJson, _ := json.MarshalIndent(flowInfo, "", "  ")
							fmt.Println(string(fpString))
							fmt.Println(string(flowInfoJson))

							fmt.Printf("hostname: %s\n", flowInfo.NdpiFlow.GetHostServerName())

							httpJson, _ := json.MarshalIndent(flowInfo.NdpiFlow.GetHttp(), "", "  ")
							fmt.Println(string(httpJson))

							flowInfo.NdpiFlow.Close()
						}
					}
				}

				flowInfo.Mu.Unlock()
			}
		}

		//nf.SetVerdict(id, nfqueue.NfAccept)
		//return 0
		p.Accept()
	}

	// Register your function to listen on nflqueue queue 100
	// err = nf.Register(ctx, fn)
	// if err != nil {
	// 	fmt.Println(err)
	// 	return
	// }

	// for {
	// 	data, ci, err = handle.ZeroCopyReadPacketData()
	// 	fmt.Printf("payload is %v\n", data)
	// 	if err != nil {
	// 		fmt.Printf("error getting packet: %s\n", err.Error())
	// 		continue
	// 	}

	// 	err = parser.DecodeLayers(data, &decoded)
	// 	if err != nil {
	// 		fmt.Printf("error decoding packet: %s\n", err.Error())
	// 		continue
	// 	}

	// 	for _, typ := range decoded {
	// 		switch typ {
	// 		case layers.LayerTypeTCP:
	// 			ipLength = ip4.Length
	// 			fp = FlowFingerprint{
	// 				SrcAddr:  types.IPv4ToInt(ip4.SrcIP),
	// 				DstAddr:  types.IPv4ToInt(ip4.DstIP),
	// 				SrcPort:  uint16(tcp.SrcPort),
	// 				DstPort:  uint16(tcp.DstPort),
	// 				Protocol: uint8(types.IPProtocolTCP),
	// 			}

	// 			flowInfo = Stats.GetFlow(fp)
	// 			if flowInfo == nil {
	// 				flowInfo, err = NewFlowInfo()
	// 				if err != nil {
	// 					fmt.Printf("failed to new FlowInfo with err: %s\n", err.Error())
	// 					continue
	// 				}

	// 				flowInfo.Mu.Lock()
	// 				flowInfo.StartTsMilli = ci.Timestamp.UnixMilli()
	// 				flowInfo.Mu.Unlock()

	// 				Stats.AddFlow(fp, flowInfo)
	// 			}

	// 			flowInfo.Mu.Lock()
	// 			flowInfo.TotalL2Packets++
	// 			flowInfo.TotalL3PayloadBytes += int64(ipLength)
	// 			flowInfo.EndTsMilli = ci.Timestamp.UnixMilli()

	// 			if !flowInfo.NdpiDetectionCompleted {
	// 				flowInfo.NdpiProcessedPackets++
	// 				flowInfo.NdpiProcessedBytes += int64(ipLength)

	// 				// ipData := make([]byte, len(eth.Payload))
	// 				// copy(ipData, eth.Payload)
	// 				ipData = eth.Payload
	// 				ts = ci.Timestamp.UnixMilli()
	// 				ndpiProto = ndpiDM.PacketProcessing(flowInfo.NdpiFlow, ipData, ipLength, ts)

	// 				enoughPackets := false
	// 				if flowInfo.NdpiProcessedPackets > MaxPacketsTcpDissection {
	// 					enoughPackets = true
	// 				}

	// 				extraDissectionPossible := ndpiDM.IsExtraDissectionPossible(flowInfo.NdpiFlow)

	// 				if enoughPackets || ndpiProto.AppProtocolId != types.NDPI_PROTOCOL_UNKNOWN {
	// 					if !enoughPackets && extraDissectionPossible {

	// 					} else {
	// 						if enableGuess && ndpiProto.AppProtocolId == types.NDPI_PROTOCOL_UNKNOWN {
	// 							ndpiProto, isGuessed = ndpiDM.DetectionGiveup(flowInfo.NdpiFlow, enableGuess)
	// 							flowInfo.NdpiIsGuessed = isGuessed
	// 						}

	// 						flowInfo.NdpiDetectionCompleted = true

	// 						fmt.Println("------")
	// 						masterProto := ndpiProto.MasterProtocolId.ToName()
	// 						appProto := ndpiProto.AppProtocolId.ToName()
	// 						category := ndpiProto.CategoryId.ToName()

	// 						fmt.Printf("Master Protocol: %s, App Protocol: %s, Category: %s\n", masterProto, appProto, category)

	// 						fpString := fp.ToString()
	// 						flowInfoJson, _ := json.MarshalIndent(flowInfo, "", "  ")
	// 						ndpiFlowInfoString := flowInfo.NdpiFlow.ToNdpiFlowInfo().ToString()
	// 						fmt.Println(fpString)
	// 						fmt.Println(string(flowInfoJson))
	// 						fmt.Println(ndpiFlowInfoString)

	// 						flowInfo.NdpiFlow.Close()
	// 					}
	// 				}
	// 			}

	// 			flowInfo.Mu.Unlock()
	// 		}
	// 	}
	// }

	//<-ctx.Done()
}

iptables -t mangle -I INPUT  -j NFQUEUE -s 192.168.132.10 --queue-num 1
iptables -t mangle -I INPUT  -j NFQUEUE -d 192.168.132.10 --queue-num 1
iptables -t mangle -I FORWARD  -j NFQUEUE -d 192.168.132.10 --queue-num 1
iptables -t mangle -I POSTROUTING  -j NFQUEUE -d 192.168.132.10 --queue-num 1
iptables -t mangle -I OUTPUT  -j NFQUEUE -d 192.168.132.10 --queue-num 1

上述的

//if !enoughPackets && extraDissectionPossible {
                        //} else {

会导致只处理响应包,要处理请求包,要去掉上面的代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

信安成长日记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值