注意点,对于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 {
会导致只处理响应包,要处理请求包,要去掉上面的代码