add windows support

This commit is contained in:
xiaobiao
2022-04-18 22:28:49 +08:00
parent 87a877750f
commit 43c68ecf2f
33 changed files with 2697 additions and 346 deletions

View File

@@ -1,10 +1,11 @@
package capture
import (
log "github.com/sirupsen/logrus"
sd "github.com/zr-hebo/sniffer-agent/session-dealer"
"math/rand"
"time"
log "github.com/golang/glog"
sd "github.com/zr-hebo/sniffer-agent/session-dealer"
)
var (
@@ -21,7 +22,10 @@ func init() {
}
localIPAddr = &ipAddr
log.Infof("parsed local ip address:%s", *localIPAddr)
rand.Seed(time.Now().UnixNano())
}
func ShowLocalIP() {
log.Infof("parsed local ip address:%s", *localIPAddr)
}

11
capture/model.go Normal file
View File

@@ -0,0 +1,11 @@
package capture
import (
"github.com/google/gopacket/layers"
)
type TCPIPPair struct {
srcIP string
dstIP string
tcpPkt *layers.TCP
}

View File

@@ -4,14 +4,13 @@ import (
"bufio"
"bytes"
"flag"
"fmt"
"math/rand"
"time"
log "github.com/golang/glog"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
pp "github.com/pires/go-proxyproto"
log "github.com/sirupsen/logrus"
"github.com/zr-hebo/sniffer-agent/communicator"
"github.com/zr-hebo/sniffer-agent/model"
sd "github.com/zr-hebo/sniffer-agent/session-dealer"
@@ -57,14 +56,34 @@ func (nc *networkCard) Listen() (receiver chan model.QueryPiece) {
// Listen get a connection.
func (nc *networkCard) listenNormal() {
go func() {
dealTCPPacket := func(srcIP, dstIP string, tcpPkt *layers.TCP, capturePacketRate float64) {
// send FIN tcp packet to avoid not complete session cannot be released
// deal FIN packet
if tcpPkt.FIN {
nc.parseTCPPackage(srcIP, dstIP, tcpPkt, nil)
return
}
// deal auth packet
if sd.IsAuthPacket(tcpPkt.Payload) {
authHeader, _ := pp.Read(bufio.NewReader(bytes.NewReader(tcpPkt.Payload)))
nc.parseTCPPackage(srcIP, dstIP, tcpPkt, authHeader)
return
}
if 0 < capturePacketRate && capturePacketRate < 1.0 {
// fall into throw range
rn := rand.Float64()
if rn > capturePacketRate {
return
}
}
nc.parseTCPPackage(srcIP, dstIP, tcpPkt, nil)
}
aliveCounter := 0
handler := initEthernetHandlerFromPacp()
for {
var data []byte
var ci gopacket.CaptureInfo
var err error
dealTCPIPPacket := func(tcpIPPkt *TCPIPPair) {
// capture packets according to a certain probability
capturePacketRate := communicator.GetTCPCapturePacketRate()
if capturePacketRate <= 0 {
@@ -74,53 +93,19 @@ func (nc *networkCard) listenNormal() {
aliveCounter = 0
nc.receiver <- model.NewBaseQueryPiece(localIPAddr, nc.listenPort, capturePacketRate)
}
continue
} else {
dealTCPPacket(tcpIPPkt.srcIP, tcpIPPkt.dstIP, tcpIPPkt.tcpPkt, capturePacketRate)
}
data, ci, err = handler.ZeroCopyReadPacketData()
if err != nil {
log.Error(err.Error())
time.Sleep(time.Second * 3)
continue
}
packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy)
// packet := gopacket.NewPacket(data, handler.LinkType(), gopacket.NoCopy)
m := packet.Metadata()
m.CaptureInfo = ci
tcpPkt := packet.TransportLayer().(*layers.TCP)
// send FIN tcp packet to avoid not complete session cannot be released
// deal FIN packet
if tcpPkt.FIN {
nc.parseTCPPackage(packet, nil)
continue
}
// deal auth packet
if sd.IsAuthPacket(tcpPkt.Payload) {
authHeader, _ := pp.Read(bufio.NewReader(bytes.NewReader(tcpPkt.Payload)))
nc.parseTCPPackage(packet, authHeader)
continue
}
if 0 < capturePacketRate && capturePacketRate < 1.0 {
// fall into throw range
rn := rand.Float64()
if rn > capturePacketRate {
continue
}
}
aliveCounter = 0
nc.parseTCPPackage(packet, nil)
}
dealEachTCPIPPacket(dealTCPIPPacket)
}()
return
}
func (nc *networkCard) parseTCPPackage(packet gopacket.Packet, authHeader *pp.Header) {
func (nc *networkCard) parseTCPPackage(srcIP, dstIP string, tcpPkt *layers.TCP, authHeader *pp.Header) {
var err error
defer func() {
if err != nil {
@@ -128,25 +113,10 @@ func (nc *networkCard) parseTCPPackage(packet gopacket.Packet, authHeader *pp.He
}
}()
tcpPkt := packet.TransportLayer().(*layers.TCP)
if tcpPkt.SYN || tcpPkt.RST {
return
}
ipLayer := packet.Layer(layers.LayerTypeIPv4)
if ipLayer == nil {
err = fmt.Errorf("no ip layer found in package")
return
}
ipInfo, ok := ipLayer.(*layers.IPv4)
if !ok {
err = fmt.Errorf("parsed no ip address")
return
}
srcIP := ipInfo.SrcIP.String()
dstIP := ipInfo.DstIP.String()
srcPort := int(tcpPkt.SrcPort)
dstPort := int(tcpPkt.DstPort)
@@ -231,7 +201,7 @@ func readToServerPackage(
session.Close()
delete(sessionPool, *sessionKey)
}
log.Debugf("close connection from %s", *sessionKey)
log.Infof("close connection from %s", *sessionKey)
return
}

View File

@@ -1,17 +1,21 @@
//go:build linux
// +build linux
package capture
import (
"fmt"
"time"
log "github.com/golang/glog"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
"github.com/google/gopacket/pcapgo"
"golang.org/x/net/bpf"
)
func initEthernetHandlerFromPacp() (handler PcapHandler) {
func initEthernetHandlerFromPacp() (pcapgoHandler *pcapgo.EthernetHandle) {
pcapgoHandler, err := pcapgo.NewEthernetHandle(DeviceName)
if err != nil {
panic(fmt.Sprintf("cannot open network interface %s <-- %s", DeviceName, err.Error()))
@@ -40,6 +44,58 @@ func initEthernetHandlerFromPacp() (handler PcapHandler) {
}
_ = pcapgoHandler.SetCaptureLength(65536)
handler = pcapgoHandler
return
}
func dealEachTCPIPPacket(dealTCPIPPacket func(tcpIPPkt *TCPIPPair)) {
handler := initEthernetHandlerFromPacp()
defer func() {
handler.Close()
}()
for {
var ci gopacket.CaptureInfo
data, ci, err := handler.ZeroCopyReadPacketData()
if err != nil {
log.Error(err.Error())
time.Sleep(time.Second * 3)
continue
}
packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy)
m := packet.Metadata()
m.CaptureInfo = ci
tcpPkt, ok := packet.TransportLayer().(*layers.TCP)
if !ok {
continue
}
ipLayer := packet.NetworkLayer()
if ipLayer == nil {
log.Error("no ip layer found in package")
continue
}
var srcIP, dstIP string
switch realIPLayer := ipLayer.(type) {
case *layers.IPv6:
{
srcIP = realIPLayer.SrcIP.String()
dstIP = realIPLayer.DstIP.String()
}
case *layers.IPv4:
{
srcIP = realIPLayer.SrcIP.String()
dstIP = realIPLayer.DstIP.String()
}
}
tcpipPair := &TCPIPPair{
srcIP: srcIP,
dstIP: dstIP,
tcpPkt: tcpPkt,
}
dealTCPIPPacket(tcpipPair)
}
}

View File

@@ -1,15 +1,20 @@
//go:build darwin
// +build darwin
package capture
import (
"fmt"
"time"
log "github.com/golang/glog"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
)
// in online use, we found a strange bug: pcap cost 100% core CPU and memory increase along
func initEthernetHandlerFromPacp() (handler PcapHandler) {
func initEthernetHandlerFromPacp() (pcapHandler *pcap.Handle) {
pcapHandler, err := pcap.OpenLive(DeviceName, 65536, false, pcap.BlockForever)
if err != nil {
panic(fmt.Sprintf("cannot open network interface %s <-- %s", DeviceName, err.Error()))
@@ -20,6 +25,58 @@ func initEthernetHandlerFromPacp() (handler PcapHandler) {
panic(err.Error())
}
handler = pcapHandler
return
}
func dealEachTCPIPPacket(dealTCPIPPacket func(tcpIPPkt *TCPIPPair)) {
handler := initEthernetHandlerFromPacp()
defer func() {
handler.Close()
}()
for {
var ci gopacket.CaptureInfo
data, ci, err := handler.ZeroCopyReadPacketData()
if err != nil {
log.Error(err.Error())
time.Sleep(time.Second * 3)
continue
}
packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.NoCopy)
m := packet.Metadata()
m.CaptureInfo = ci
tcpPkt, ok := packet.TransportLayer().(*layers.TCP)
if !ok {
continue
}
ipLayer := packet.NetworkLayer()
if ipLayer == nil {
log.Error("no ip layer found in package")
continue
}
var srcIP, dstIP string
switch realIPLayer := ipLayer.(type) {
case *layers.IPv6:
{
srcIP = realIPLayer.SrcIP.String()
dstIP = realIPLayer.DstIP.String()
}
case *layers.IPv4:
{
srcIP = realIPLayer.SrcIP.String()
dstIP = realIPLayer.DstIP.String()
}
}
tcpipPair := &TCPIPPair{
srcIP: srcIP,
dstIP: dstIP,
tcpPkt: tcpPkt,
}
dealTCPIPPacket(tcpipPair)
}
}

81
capture/pacp_windows.go Normal file
View File

@@ -0,0 +1,81 @@
//go:build windows
// +build windows
package capture
import (
"fmt"
"time"
log "github.com/golang/glog"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
)
var (
handler *pcap.Handle
)
func initEthernetHandlerFromPacp() (pcapHandler *pcap.Handle) {
devices, err := pcap.FindAllDevs()
if err != nil {
log.Fatal(err)
}
for _, device := range devices {
log.Infof("found Windows device:'%s', device info:%s", device.Name, device.Description)
}
pcapHandler, err = pcap.OpenLive(DeviceName, 1024, false, time.Hour*24)
if err != nil {
panic(fmt.Sprintf("cannot open network interface %s <-- %s", DeviceName, err.Error()))
}
return
}
func dealEachTCPIPPacket(dealTCPIPPacket func(tcpIPPkt *TCPIPPair)) {
handler = initEthernetHandlerFromPacp()
defer handler.Close()
packetSource := gopacket.NewPacketSource(handler, handler.LinkType())
for packet := range packetSource.Packets() {
if err := packet.ErrorLayer(); err != nil {
log.Error(err.Error())
continue
}
// Process packet here
tcpLayer := packet.Layer(layers.LayerTypeTCP)
if tcpLayer == nil {
continue
}
tcpPkt := tcpLayer.(*layers.TCP)
if (int(tcpPkt.SrcPort) != snifferPort && int(tcpPkt.DstPort) != snifferPort) {
continue
}
var srcIP, dstIP string
ipLayer := packet.NetworkLayer()
switch realIPLayer := ipLayer.(type) {
case *layers.IPv6:
{
srcIP = realIPLayer.SrcIP.String()
dstIP = realIPLayer.DstIP.String()
}
case *layers.IPv4:
{
srcIP = realIPLayer.SrcIP.String()
dstIP = realIPLayer.DstIP.String()
}
}
tcpipPair := &TCPIPPair{
srcIP: srcIP,
dstIP: dstIP,
tcpPkt: tcpPkt,
}
dealTCPIPPacket(tcpipPair)
}
return
}