commit
5cb3c6d651
@ -0,0 +1 @@
|
||||
.idea
|
@ -0,0 +1,280 @@
|
||||
package bcap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
"net"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Packets struct {
|
||||
sync.RWMutex
|
||||
cu map[string]PacketInfo
|
||||
}
|
||||
|
||||
type PacketInfo struct {
|
||||
Key string
|
||||
ReverseKey string
|
||||
Type string
|
||||
SrcMac net.HardwareAddr
|
||||
DstMac net.HardwareAddr
|
||||
SrcIP string
|
||||
SrcPort string
|
||||
DstIP string
|
||||
DstPort string
|
||||
comment string
|
||||
packet gopacket.Packet
|
||||
tcpSeq uint32
|
||||
tcpAck uint32
|
||||
tcpWindow uint16
|
||||
tcpPayloads int
|
||||
finState bool
|
||||
synState bool
|
||||
isFirst bool
|
||||
//stateDescript 0=unknown 1=tcp_connect_1 2=tcp_connect_2 3=tcp_connect_3
|
||||
// 4=tcp_disconnect_1 5=tcp_disconnect_2 6=tcp_disconnect_2+3 7=tcp_disconnect_3
|
||||
// 8=tcp_disconnect_4 9=tcp_ack_ok 10=tcp_retransmit 11=tcp_ece 12=tcp_cwr 13=tcp_rst
|
||||
// 14=tcp_keepalived 20=udp
|
||||
stateDescript uint8
|
||||
}
|
||||
|
||||
func (p *Packets) Key(key string) PacketInfo {
|
||||
return p.cu[key]
|
||||
}
|
||||
|
||||
func (p *Packets) SetComment(key, comment string) {
|
||||
p.Lock()
|
||||
c := p.cu[key]
|
||||
c.comment = comment
|
||||
p.cu[key] = c
|
||||
p.Unlock()
|
||||
}
|
||||
|
||||
func (p *PacketInfo) SetComment(comment string) {
|
||||
p.comment = comment
|
||||
}
|
||||
|
||||
func (p PacketInfo) StateDescript() uint8 {
|
||||
return p.stateDescript
|
||||
}
|
||||
|
||||
func (p PacketInfo) TcpPayloads() int {
|
||||
return p.tcpPayloads
|
||||
}
|
||||
|
||||
func (p PacketInfo) FinState() bool {
|
||||
return p.finState
|
||||
}
|
||||
|
||||
func (p PacketInfo) SynState() bool {
|
||||
return p.synState
|
||||
}
|
||||
|
||||
func (p PacketInfo) TcpWindow() uint16 {
|
||||
return p.tcpWindow
|
||||
}
|
||||
|
||||
func (p PacketInfo) TcpAck() uint32 {
|
||||
return p.tcpAck
|
||||
}
|
||||
|
||||
func (p PacketInfo) TcpSeq() uint32 {
|
||||
return p.tcpSeq
|
||||
}
|
||||
|
||||
func (p PacketInfo) Packet() gopacket.Packet {
|
||||
return p.packet
|
||||
}
|
||||
|
||||
func (p PacketInfo) Comment() string {
|
||||
return p.comment
|
||||
}
|
||||
|
||||
func NewPackets() *Packets {
|
||||
return &Packets{
|
||||
cu: make(map[string]PacketInfo),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Packets) ParsePacket(packet gopacket.Packet, opts ...interface{}) (PacketInfo, error) {
|
||||
var info PacketInfo
|
||||
//firstOpts is macaddr(nfqueue)
|
||||
if ew := packet.Layer(layers.LayerTypeEthernet); ew != nil {
|
||||
eth := ew.(*layers.Ethernet)
|
||||
info.SrcMac = eth.SrcMAC
|
||||
info.DstMac = eth.DstMAC
|
||||
}
|
||||
for k, v := range opts {
|
||||
switch tp := v.(type) {
|
||||
case *[]byte:
|
||||
if tp != nil && k == 0 {
|
||||
//nfqueue src mac addr
|
||||
info.SrcMac = net.HardwareAddr(*tp)
|
||||
}
|
||||
}
|
||||
}
|
||||
if nw := packet.NetworkLayer(); nw != nil {
|
||||
srcp, dstp := nw.NetworkFlow().Endpoints()
|
||||
info.SrcIP = srcp.String()
|
||||
info.DstIP = dstp.String()
|
||||
} else {
|
||||
return info, fmt.Errorf("Failed to parse packet,not a valid network info")
|
||||
}
|
||||
{
|
||||
//tcp valid
|
||||
layer := packet.Layer(layers.LayerTypeTCP)
|
||||
if layer != nil {
|
||||
if tcp, ok := layer.(*layers.TCP); ok {
|
||||
return p.parseTcp(info, packet, layer, tcp)
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
layer := packet.Layer(layers.LayerTypeUDP)
|
||||
if layer != nil {
|
||||
if udp, ok := layer.(*layers.UDP); ok {
|
||||
return p.parseUdp(info, packet, layer, udp)
|
||||
}
|
||||
}
|
||||
}
|
||||
//icmp
|
||||
return info, fmt.Errorf("not support packet")
|
||||
}
|
||||
|
||||
func (p *Packets) parseTcp(info PacketInfo, packet gopacket.Packet, layer gopacket.Layer, tcp *layers.TCP) (PacketInfo, error) {
|
||||
info.Key = fmt.Sprintf("tcp://%s:%d=%s:%d", info.SrcIP, tcp.SrcPort, info.DstIP, tcp.DstPort)
|
||||
info.ReverseKey = fmt.Sprintf("tcp://%s:%d=%s:%d", info.DstIP, tcp.DstPort, info.SrcIP, tcp.SrcPort)
|
||||
info.Type = "tcp"
|
||||
info.SrcPort = fmt.Sprintf("%d", tcp.SrcPort)
|
||||
info.DstPort = fmt.Sprintf("%d", tcp.DstPort)
|
||||
info.packet = packet
|
||||
info.tcpSeq = tcp.Seq
|
||||
info.tcpAck = tcp.Ack
|
||||
info.tcpPayloads = len(layer.LayerPayload())
|
||||
info.finState = tcp.FIN
|
||||
info.synState = tcp.SYN
|
||||
info.tcpWindow = tcp.Window
|
||||
lastPacket := p.cu[info.Key]
|
||||
if lastPacket.Key != info.Key {
|
||||
lastPacket = PacketInfo{
|
||||
Key: info.Key,
|
||||
ReverseKey: info.ReverseKey,
|
||||
Type: "tcp",
|
||||
SrcIP: info.SrcIP,
|
||||
SrcPort: info.SrcPort,
|
||||
DstIP: info.DstIP,
|
||||
DstPort: info.DstPort,
|
||||
comment: "",
|
||||
packet: packet,
|
||||
tcpSeq: tcp.Seq,
|
||||
tcpAck: tcp.Ack,
|
||||
tcpWindow: tcp.Window,
|
||||
tcpPayloads: len(layer.LayerPayload()),
|
||||
finState: tcp.FIN,
|
||||
synState: tcp.SYN,
|
||||
isFirst: true,
|
||||
stateDescript: 0,
|
||||
}
|
||||
p.Lock()
|
||||
p.cu[info.Key] = lastPacket
|
||||
p.Unlock()
|
||||
}
|
||||
lastReverse := p.cu[info.ReverseKey]
|
||||
if !lastPacket.isFirst {
|
||||
info.comment = lastPacket.comment
|
||||
if lastPacket.SrcMac != nil && len(info.SrcMac) == 0 {
|
||||
info.SrcMac = lastPacket.SrcMac
|
||||
}
|
||||
if lastPacket.SrcMac != nil && len(info.SrcMac) == 0 {
|
||||
info.SrcMac = lastPacket.SrcMac
|
||||
}
|
||||
}
|
||||
if lastReverse.SrcMac != nil && len(info.DstMac) == 0 {
|
||||
info.DstMac = lastReverse.SrcMac
|
||||
}
|
||||
{
|
||||
//state judge
|
||||
if tcp.RST {
|
||||
info.stateDescript = 13
|
||||
p.Lock()
|
||||
delete(p.cu, info.Key)
|
||||
delete(p.cu, info.ReverseKey)
|
||||
p.Unlock()
|
||||
return info, nil
|
||||
}
|
||||
if tcp.SYN && !tcp.ACK {
|
||||
info.stateDescript = 1
|
||||
} else if tcp.SYN && tcp.ACK {
|
||||
info.stateDescript = 2
|
||||
} else if tcp.ACK {
|
||||
|
||||
if !tcp.FIN {
|
||||
if lastReverse.tcpSeq+1 == tcp.Ack && lastReverse.stateDescript == 2 {
|
||||
info.stateDescript = 3
|
||||
} else if tcp.CWR {
|
||||
info.stateDescript = 12
|
||||
} else if tcp.ECE {
|
||||
info.stateDescript = 11
|
||||
}
|
||||
if info.stateDescript != 0 {
|
||||
goto savereturn
|
||||
}
|
||||
if info.tcpSeq == lastReverse.tcpAck-1 && info.tcpSeq == lastPacket.tcpSeq+uint32(lastPacket.tcpPayloads)-1 {
|
||||
//keepalive
|
||||
info.stateDescript = 14
|
||||
goto savereturn
|
||||
}
|
||||
if !lastPacket.isFirst {
|
||||
if info.tcpSeq < lastPacket.tcpSeq+uint32(lastPacket.tcpPayloads) {
|
||||
//retransmit
|
||||
info.stateDescript = 10
|
||||
goto savereturn
|
||||
}
|
||||
}
|
||||
if lastReverse.finState && lastPacket.finState {
|
||||
info.stateDescript = 8
|
||||
p.Lock()
|
||||
delete(p.cu, info.Key)
|
||||
delete(p.cu, info.ReverseKey)
|
||||
p.Unlock()
|
||||
return info, nil
|
||||
}
|
||||
if lastReverse.finState && lastReverse.tcpSeq+1 == info.tcpAck {
|
||||
info.stateDescript = 5
|
||||
goto savereturn
|
||||
}
|
||||
info.stateDescript = 9
|
||||
} else {
|
||||
if !lastReverse.finState {
|
||||
info.stateDescript = 4
|
||||
} else {
|
||||
if lastReverse.finState && lastReverse.tcpSeq+1 == info.tcpAck && lastPacket.tcpAck == info.tcpAck && lastPacket.tcpSeq == info.tcpSeq {
|
||||
info.stateDescript = 7
|
||||
} else {
|
||||
info.stateDescript = 6
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
savereturn:
|
||||
p.Lock()
|
||||
p.cu[info.Key] = info
|
||||
p.Unlock()
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func (p *Packets) parseUdp(info PacketInfo, packet gopacket.Packet, layer gopacket.Layer, udp *layers.UDP) (PacketInfo, error) {
|
||||
info.Key = fmt.Sprintf("udp://%s:%d=%s:%d", info.SrcIP, udp.SrcPort, info.DstIP, udp.DstPort)
|
||||
info.ReverseKey = fmt.Sprintf("udp://%s:%d=%s:%d", info.DstIP, udp.DstPort, info.SrcIP, udp.SrcPort)
|
||||
info.Type = "udp"
|
||||
info.SrcPort = fmt.Sprintf("%d", udp.SrcPort)
|
||||
info.DstPort = fmt.Sprintf("%d", udp.DstPort)
|
||||
info.packet = packet
|
||||
info.tcpPayloads = len(layer.LayerPayload())
|
||||
p.Lock()
|
||||
p.cu[info.Key] = info
|
||||
p.Unlock()
|
||||
return info, nil
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
module b612.me/bcap
|
||||
|
||||
go 1.22.4
|
||||
|
||||
require (
|
||||
github.com/florianl/go-nfqueue/v2 v2.0.0
|
||||
github.com/google/gopacket v1.1.19
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/josharian/native v1.1.0 // indirect
|
||||
github.com/mdlayher/netlink v1.7.2 // indirect
|
||||
github.com/mdlayher/socket v0.4.1 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
)
|
@ -0,0 +1,30 @@
|
||||
github.com/florianl/go-nfqueue/v2 v2.0.0 h1:NTCxS9b0GSbHkWv1a7oOvZn679fsyDkaSkRvOYpQ9Oo=
|
||||
github.com/florianl/go-nfqueue/v2 v2.0.0/go.mod h1:M2tBLIj62QpwqjwV0qfcjqGOqP3qiTuXr2uSRBXH9Qk=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
||||
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
|
||||
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
|
||||
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
|
||||
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
@ -0,0 +1,77 @@
|
||||
package libpcap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/pcap"
|
||||
)
|
||||
|
||||
type NetCatch struct {
|
||||
eth string
|
||||
host string
|
||||
sentence string
|
||||
fn func(gopacket.Packet)
|
||||
*pcap.Handle
|
||||
}
|
||||
|
||||
func (n *NetCatch) SetRecall(fn func(p gopacket.Packet)) {
|
||||
n.fn = fn
|
||||
}
|
||||
|
||||
func FindAllDevs() ([]pcap.Interface, error) {
|
||||
return pcap.FindAllDevs()
|
||||
}
|
||||
|
||||
func NewCatch(host string, sentence string) (*NetCatch, error) {
|
||||
ifs, err := pcap.FindAllDevs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
eth := ""
|
||||
for _, v := range ifs {
|
||||
if host == "127.0.0.1" && v.Name == "\\Device\\NPF_Loopback" {
|
||||
eth = v.Name
|
||||
}
|
||||
for _, addr := range v.Addresses {
|
||||
if addr.IP.String() == host {
|
||||
eth = v.Name
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(eth) == 0 {
|
||||
return nil, fmt.Errorf("cannot found eth")
|
||||
}
|
||||
nc := new(NetCatch)
|
||||
nc.host = host
|
||||
nc.eth = eth
|
||||
nc.sentence = sentence
|
||||
return nc, nil
|
||||
}
|
||||
|
||||
func NewCatchEth(eth string, sentence string) (*NetCatch, error) {
|
||||
nc := new(NetCatch)
|
||||
nc.eth = eth
|
||||
nc.sentence = sentence
|
||||
return nc, nil
|
||||
}
|
||||
|
||||
func (n *NetCatch) Run() error {
|
||||
if n.eth == "" {
|
||||
return fmt.Errorf("no pcap device")
|
||||
}
|
||||
handle, err := pcap.OpenLive(n.eth, 65535, true, pcap.BlockForever)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n.Handle = handle
|
||||
if err = handle.SetBPFFilter(n.sentence); err != nil {
|
||||
return err
|
||||
}
|
||||
pks := gopacket.NewPacketSource(handle, handle.LinkType())
|
||||
for packet := range pks.Packets() {
|
||||
if n.fn != nil {
|
||||
n.fn(packet)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
package nfq
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/florianl/go-nfqueue/v2"
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
"time"
|
||||
)
|
||||
|
||||
type NfQueue struct {
|
||||
queid uint16
|
||||
maxqueue uint32
|
||||
ctx context.Context
|
||||
stopFn context.CancelFunc
|
||||
recallFn func(id uint32, q *nfqueue.Nfqueue, p Packet)
|
||||
}
|
||||
|
||||
type Packet struct {
|
||||
Packet gopacket.Packet
|
||||
Attr nfqueue.Attribute
|
||||
}
|
||||
|
||||
func NewNfQueue(ctx context.Context, queid uint16, maxqueue uint32) *NfQueue {
|
||||
var q = new(NfQueue)
|
||||
if ctx == nil {
|
||||
q.ctx, q.stopFn = context.WithCancel(context.Background())
|
||||
} else {
|
||||
q.ctx, q.stopFn = context.WithCancel(ctx)
|
||||
}
|
||||
q.queid = queid
|
||||
q.maxqueue = maxqueue
|
||||
return q
|
||||
}
|
||||
|
||||
func (n *NfQueue) SetRecall(fn func(id uint32, q *nfqueue.Nfqueue, p Packet)) {
|
||||
n.recallFn = fn
|
||||
}
|
||||
|
||||
func (n *NfQueue) Run() error {
|
||||
cfg := nfqueue.Config{
|
||||
NfQueue: n.queid,
|
||||
MaxQueueLen: n.maxqueue,
|
||||
Copymode: nfqueue.NfQnlCopyPacket,
|
||||
WriteTimeout: time.Second * 10,
|
||||
}
|
||||
nfq, err := nfqueue.Open(&cfg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open nfqueue, err:", err)
|
||||
}
|
||||
|
||||
if err := nfq.RegisterWithErrorFunc(n.ctx, func(a nfqueue.Attribute) int {
|
||||
return n.handlePacket(nfq, a)
|
||||
}, func(e error) int {
|
||||
return 0
|
||||
}); err != nil {
|
||||
return fmt.Errorf("failed to register handlers, err:", err)
|
||||
}
|
||||
<-n.ctx.Done()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *NfQueue) handlePacket(q *nfqueue.Nfqueue, a nfqueue.Attribute) int {
|
||||
if a.Payload != nil && len(*a.Payload) != 0 {
|
||||
var packet gopacket.Packet
|
||||
data := *a.Payload
|
||||
if data[0]&0xf0 == 0x40 {
|
||||
packet = gopacket.NewPacket(data, layers.LayerTypeIPv4, gopacket.DecodeOptions{Lazy: true, NoCopy: true})
|
||||
} else {
|
||||
packet = gopacket.NewPacket(data, layers.LayerTypeIPv6, gopacket.DecodeOptions{Lazy: true, NoCopy: true})
|
||||
}
|
||||
if n.recallFn != nil {
|
||||
n.recallFn(*a.PacketID, q, Packet{
|
||||
Packet: packet,
|
||||
Attr: a,
|
||||
})
|
||||
} else {
|
||||
q.SetVerdict(*a.PacketID, nfqueue.NfAccept)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
q.SetVerdict(*a.PacketID, nfqueue.NfAccept)
|
||||
return 0
|
||||
}
|
Loading…
Reference in New Issue