mac resolution
This commit is contained in:
@@ -2,6 +2,7 @@ package engine
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/binary"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"git.difuse.io/Difuse/Mellaris/io"
|
"git.difuse.io/Difuse/Mellaris/io"
|
||||||
@@ -24,6 +25,7 @@ func NewEngine(config Config) (Engine, error) {
|
|||||||
if workerCount <= 0 {
|
if workerCount <= 0 {
|
||||||
workerCount = runtime.NumCPU()
|
workerCount = runtime.NumCPU()
|
||||||
}
|
}
|
||||||
|
macResolver := newSourceMACResolver()
|
||||||
var err error
|
var err error
|
||||||
workers := make([]*worker, workerCount)
|
workers := make([]*worker, workerCount)
|
||||||
for i := range workers {
|
for i := range workers {
|
||||||
@@ -32,6 +34,7 @@ func NewEngine(config Config) (Engine, error) {
|
|||||||
ChanSize: config.WorkerQueueSize,
|
ChanSize: config.WorkerQueueSize,
|
||||||
Logger: config.Logger,
|
Logger: config.Logger,
|
||||||
Ruleset: config.Ruleset,
|
Ruleset: config.Ruleset,
|
||||||
|
MACResolver: macResolver,
|
||||||
TCPMaxBufferedPagesTotal: config.WorkerTCPMaxBufferedPagesTotal,
|
TCPMaxBufferedPagesTotal: config.WorkerTCPMaxBufferedPagesTotal,
|
||||||
TCPMaxBufferedPagesPerConn: config.WorkerTCPMaxBufferedPagesPerConn,
|
TCPMaxBufferedPagesPerConn: config.WorkerTCPMaxBufferedPagesPerConn,
|
||||||
UDPMaxStreams: config.WorkerUDPMaxStreams,
|
UDPMaxStreams: config.WorkerUDPMaxStreams,
|
||||||
@@ -90,13 +93,8 @@ func (e *engine) Run(ctx context.Context) error {
|
|||||||
// dispatch dispatches a packet to a worker.
|
// dispatch dispatches a packet to a worker.
|
||||||
func (e *engine) dispatch(p io.Packet) bool {
|
func (e *engine) dispatch(p io.Packet) bool {
|
||||||
data := p.Data()
|
data := p.Data()
|
||||||
ipVersion := data[0] >> 4
|
layerType, srcMAC, dstMAC, ok := classifyPacket(data)
|
||||||
var layerType gopacket.LayerType
|
if !ok {
|
||||||
if ipVersion == 4 {
|
|
||||||
layerType = layers.LayerTypeIPv4
|
|
||||||
} else if ipVersion == 6 {
|
|
||||||
layerType = layers.LayerTypeIPv6
|
|
||||||
} else {
|
|
||||||
// Unsupported network layer
|
// Unsupported network layer
|
||||||
_ = e.io.SetVerdict(p, io.VerdictAcceptStream, nil)
|
_ = e.io.SetVerdict(p, io.VerdictAcceptStream, nil)
|
||||||
return true
|
return true
|
||||||
@@ -107,9 +105,41 @@ func (e *engine) dispatch(p io.Packet) bool {
|
|||||||
e.workers[index].Feed(&workerPacket{
|
e.workers[index].Feed(&workerPacket{
|
||||||
StreamID: p.StreamID(),
|
StreamID: p.StreamID(),
|
||||||
Packet: packet,
|
Packet: packet,
|
||||||
|
SrcMAC: srcMAC,
|
||||||
|
DstMAC: dstMAC,
|
||||||
SetVerdict: func(v io.Verdict, b []byte) error {
|
SetVerdict: func(v io.Verdict, b []byte) error {
|
||||||
return e.io.SetVerdict(p, v, b)
|
return e.io.SetVerdict(p, v, b)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// classifyPacket detects packet framing and returns a gopacket decode layer
|
||||||
|
// plus best-effort source/destination MAC addresses when available.
|
||||||
|
func classifyPacket(data []byte) (gopacket.LayerType, []byte, []byte, bool) {
|
||||||
|
if len(data) == 0 {
|
||||||
|
return 0, nil, nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fast path for IP packets (NFQUEUE payloads are typically IP-only).
|
||||||
|
ipVersion := data[0] >> 4
|
||||||
|
if ipVersion == 4 {
|
||||||
|
return layers.LayerTypeIPv4, nil, nil, true
|
||||||
|
}
|
||||||
|
if ipVersion == 6 {
|
||||||
|
return layers.LayerTypeIPv6, nil, nil, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ethernet frame path (for custom PacketIO implementations).
|
||||||
|
if len(data) >= 14 {
|
||||||
|
etherType := binary.BigEndian.Uint16(data[12:14])
|
||||||
|
if etherType == uint16(layers.EthernetTypeIPv4) || etherType == uint16(layers.EthernetTypeIPv6) {
|
||||||
|
return layers.LayerTypeEthernet,
|
||||||
|
append([]byte(nil), data[6:12]...),
|
||||||
|
append([]byte(nil), data[:6]...),
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, nil, nil, false
|
||||||
|
}
|
||||||
|
|||||||
145
engine/mac_resolver.go
Normal file
145
engine/mac_resolver.go
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
package engine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ifaceCacheTTL = 30 * time.Second
|
||||||
|
arpCacheTTL = 10 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
|
type sourceMACResolver struct {
|
||||||
|
mu sync.RWMutex
|
||||||
|
|
||||||
|
lastIfaceRefresh time.Time
|
||||||
|
ifaceByIP map[string]net.HardwareAddr
|
||||||
|
|
||||||
|
lastARPRefresh time.Time
|
||||||
|
arpByIP map[string]net.HardwareAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSourceMACResolver() *sourceMACResolver {
|
||||||
|
return &sourceMACResolver{
|
||||||
|
ifaceByIP: make(map[string]net.HardwareAddr),
|
||||||
|
arpByIP: make(map[string]net.HardwareAddr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *sourceMACResolver) Resolve(ip net.IP) net.HardwareAddr {
|
||||||
|
if ip == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ipKey := ip.String()
|
||||||
|
if ipKey == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
r.mu.RLock()
|
||||||
|
ifaceRefreshDue := now.Sub(r.lastIfaceRefresh) > ifaceCacheTTL
|
||||||
|
arpRefreshDue := now.Sub(r.lastARPRefresh) > arpCacheTTL
|
||||||
|
if mac := r.ifaceByIP[ipKey]; len(mac) != 0 {
|
||||||
|
out := append(net.HardwareAddr(nil), mac...)
|
||||||
|
r.mu.RUnlock()
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
if mac := r.arpByIP[ipKey]; len(mac) != 0 && !arpRefreshDue {
|
||||||
|
out := append(net.HardwareAddr(nil), mac...)
|
||||||
|
r.mu.RUnlock()
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
r.mu.RUnlock()
|
||||||
|
|
||||||
|
if ifaceRefreshDue {
|
||||||
|
r.refreshIfaceCache(now)
|
||||||
|
}
|
||||||
|
if arpRefreshDue {
|
||||||
|
r.refreshARPCache(now)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.mu.RLock()
|
||||||
|
defer r.mu.RUnlock()
|
||||||
|
if mac := r.ifaceByIP[ipKey]; len(mac) != 0 {
|
||||||
|
return append(net.HardwareAddr(nil), mac...)
|
||||||
|
}
|
||||||
|
if mac := r.arpByIP[ipKey]; len(mac) != 0 {
|
||||||
|
return append(net.HardwareAddr(nil), mac...)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *sourceMACResolver) refreshIfaceCache(now time.Time) {
|
||||||
|
interfaces, err := net.Interfaces()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m := make(map[string]net.HardwareAddr)
|
||||||
|
for _, iface := range interfaces {
|
||||||
|
if len(iface.HardwareAddr) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addrs, err := iface.Addrs()
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, addr := range addrs {
|
||||||
|
ipNet, ok := addr.(*net.IPNet)
|
||||||
|
if !ok || ipNet.IP == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
m[ipNet.IP.String()] = append(net.HardwareAddr(nil), iface.HardwareAddr...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r.mu.Lock()
|
||||||
|
r.ifaceByIP = m
|
||||||
|
r.lastIfaceRefresh = now
|
||||||
|
r.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *sourceMACResolver) refreshARPCache(now time.Time) {
|
||||||
|
f, err := os.Open("/proc/net/arp")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
m := make(map[string]net.HardwareAddr)
|
||||||
|
scanner := bufio.NewScanner(f)
|
||||||
|
lineNo := 0
|
||||||
|
for scanner.Scan() {
|
||||||
|
lineNo++
|
||||||
|
if lineNo == 1 {
|
||||||
|
continue // header
|
||||||
|
}
|
||||||
|
fields := strings.Fields(scanner.Text())
|
||||||
|
if len(fields) < 4 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ipStr := fields[0]
|
||||||
|
hwAddr := fields[3]
|
||||||
|
if hwAddr == "00:00:00:00:00:00" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
mac, err := net.ParseMAC(hwAddr)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
m[ipStr] = append(net.HardwareAddr(nil), mac...)
|
||||||
|
}
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.mu.Lock()
|
||||||
|
r.arpByIP = m
|
||||||
|
r.lastARPRefresh = now
|
||||||
|
r.mu.Unlock()
|
||||||
|
}
|
||||||
@@ -28,6 +28,7 @@ const (
|
|||||||
type tcpContext struct {
|
type tcpContext struct {
|
||||||
*gopacket.PacketMetadata
|
*gopacket.PacketMetadata
|
||||||
Verdict tcpVerdict
|
Verdict tcpVerdict
|
||||||
|
SrcMAC, DstMAC net.HardwareAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *tcpContext) GetCaptureInfo() gopacket.CaptureInfo {
|
func (ctx *tcpContext) GetCaptureInfo() gopacket.CaptureInfo {
|
||||||
@@ -46,9 +47,12 @@ type tcpStreamFactory struct {
|
|||||||
func (f *tcpStreamFactory) New(ipFlow, tcpFlow gopacket.Flow, tcp *layers.TCP, ac reassembly.AssemblerContext) reassembly.Stream {
|
func (f *tcpStreamFactory) New(ipFlow, tcpFlow gopacket.Flow, tcp *layers.TCP, ac reassembly.AssemblerContext) reassembly.Stream {
|
||||||
id := f.Node.Generate()
|
id := f.Node.Generate()
|
||||||
ipSrc, ipDst := net.IP(ipFlow.Src().Raw()), net.IP(ipFlow.Dst().Raw())
|
ipSrc, ipDst := net.IP(ipFlow.Src().Raw()), net.IP(ipFlow.Dst().Raw())
|
||||||
|
ctx := ac.(*tcpContext)
|
||||||
info := ruleset.StreamInfo{
|
info := ruleset.StreamInfo{
|
||||||
ID: id.Int64(),
|
ID: id.Int64(),
|
||||||
Protocol: ruleset.ProtocolTCP,
|
Protocol: ruleset.ProtocolTCP,
|
||||||
|
SrcMAC: append(net.HardwareAddr(nil), ctx.SrcMAC...),
|
||||||
|
DstMAC: append(net.HardwareAddr(nil), ctx.DstMAC...),
|
||||||
SrcIP: ipSrc,
|
SrcIP: ipSrc,
|
||||||
DstIP: ipDst,
|
DstIP: ipDst,
|
||||||
SrcPort: uint16(tcp.SrcPort),
|
SrcPort: uint16(tcp.SrcPort),
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ var errInvalidModifier = errors.New("invalid modifier")
|
|||||||
type udpContext struct {
|
type udpContext struct {
|
||||||
Verdict udpVerdict
|
Verdict udpVerdict
|
||||||
Packet []byte
|
Packet []byte
|
||||||
|
SrcMAC, DstMAC net.HardwareAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
type udpStreamFactory struct {
|
type udpStreamFactory struct {
|
||||||
@@ -50,6 +51,8 @@ func (f *udpStreamFactory) New(ipFlow, udpFlow gopacket.Flow, udp *layers.UDP, u
|
|||||||
info := ruleset.StreamInfo{
|
info := ruleset.StreamInfo{
|
||||||
ID: id.Int64(),
|
ID: id.Int64(),
|
||||||
Protocol: ruleset.ProtocolUDP,
|
Protocol: ruleset.ProtocolUDP,
|
||||||
|
SrcMAC: append(net.HardwareAddr(nil), uc.SrcMAC...),
|
||||||
|
DstMAC: append(net.HardwareAddr(nil), uc.DstMAC...),
|
||||||
SrcIP: ipSrc,
|
SrcIP: ipSrc,
|
||||||
DstIP: ipDst,
|
DstIP: ipDst,
|
||||||
SrcPort: uint16(udp.SrcPort),
|
SrcPort: uint16(udp.SrcPort),
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package engine
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"net"
|
||||||
|
|
||||||
"git.difuse.io/Difuse/Mellaris/io"
|
"git.difuse.io/Difuse/Mellaris/io"
|
||||||
"git.difuse.io/Difuse/Mellaris/ruleset"
|
"git.difuse.io/Difuse/Mellaris/ruleset"
|
||||||
@@ -22,6 +23,8 @@ const (
|
|||||||
type workerPacket struct {
|
type workerPacket struct {
|
||||||
StreamID uint32
|
StreamID uint32
|
||||||
Packet gopacket.Packet
|
Packet gopacket.Packet
|
||||||
|
SrcMAC net.HardwareAddr
|
||||||
|
DstMAC net.HardwareAddr
|
||||||
SetVerdict func(io.Verdict, []byte) error
|
SetVerdict func(io.Verdict, []byte) error
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,6 +32,7 @@ type worker struct {
|
|||||||
id int
|
id int
|
||||||
packetChan chan *workerPacket
|
packetChan chan *workerPacket
|
||||||
logger Logger
|
logger Logger
|
||||||
|
macResolver *sourceMACResolver
|
||||||
|
|
||||||
tcpStreamFactory *tcpStreamFactory
|
tcpStreamFactory *tcpStreamFactory
|
||||||
tcpStreamPool *reassembly.StreamPool
|
tcpStreamPool *reassembly.StreamPool
|
||||||
@@ -45,6 +49,7 @@ type workerConfig struct {
|
|||||||
ChanSize int
|
ChanSize int
|
||||||
Logger Logger
|
Logger Logger
|
||||||
Ruleset ruleset.Ruleset
|
Ruleset ruleset.Ruleset
|
||||||
|
MACResolver *sourceMACResolver
|
||||||
TCPMaxBufferedPagesTotal int
|
TCPMaxBufferedPagesTotal int
|
||||||
TCPMaxBufferedPagesPerConn int
|
TCPMaxBufferedPagesPerConn int
|
||||||
UDPMaxStreams int
|
UDPMaxStreams int
|
||||||
@@ -95,6 +100,7 @@ func newWorker(config workerConfig) (*worker, error) {
|
|||||||
id: config.ID,
|
id: config.ID,
|
||||||
packetChan: make(chan *workerPacket, config.ChanSize),
|
packetChan: make(chan *workerPacket, config.ChanSize),
|
||||||
logger: config.Logger,
|
logger: config.Logger,
|
||||||
|
macResolver: config.MACResolver,
|
||||||
tcpStreamFactory: tcpSF,
|
tcpStreamFactory: tcpSF,
|
||||||
tcpStreamPool: tcpStreamPool,
|
tcpStreamPool: tcpStreamPool,
|
||||||
tcpAssembler: tcpAssembler,
|
tcpAssembler: tcpAssembler,
|
||||||
@@ -120,7 +126,7 @@ func (w *worker) Run(ctx context.Context) {
|
|||||||
// Closed
|
// Closed
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
v, b := w.handle(wPkt.StreamID, wPkt.Packet)
|
v, b := w.handle(wPkt.StreamID, wPkt.Packet, wPkt.SrcMAC, wPkt.DstMAC)
|
||||||
_ = wPkt.SetVerdict(v, b)
|
_ = wPkt.SetVerdict(v, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,18 +139,21 @@ func (w *worker) UpdateRuleset(r ruleset.Ruleset) error {
|
|||||||
return w.udpStreamFactory.UpdateRuleset(r)
|
return w.udpStreamFactory.UpdateRuleset(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *worker) handle(streamID uint32, p gopacket.Packet) (io.Verdict, []byte) {
|
func (w *worker) handle(streamID uint32, p gopacket.Packet, srcMAC, dstMAC net.HardwareAddr) (io.Verdict, []byte) {
|
||||||
netLayer, trLayer := p.NetworkLayer(), p.TransportLayer()
|
netLayer, trLayer := p.NetworkLayer(), p.TransportLayer()
|
||||||
if netLayer == nil || trLayer == nil {
|
if netLayer == nil || trLayer == nil {
|
||||||
// Invalid packet
|
// Invalid packet
|
||||||
return io.VerdictAccept, nil
|
return io.VerdictAccept, nil
|
||||||
}
|
}
|
||||||
ipFlow := netLayer.NetworkFlow()
|
ipFlow := netLayer.NetworkFlow()
|
||||||
|
if len(srcMAC) == 0 && w.macResolver != nil {
|
||||||
|
srcMAC = w.macResolver.Resolve(net.IP(ipFlow.Src().Raw()))
|
||||||
|
}
|
||||||
switch tr := trLayer.(type) {
|
switch tr := trLayer.(type) {
|
||||||
case *layers.TCP:
|
case *layers.TCP:
|
||||||
return w.handleTCP(ipFlow, p.Metadata(), tr), nil
|
return w.handleTCP(ipFlow, srcMAC, dstMAC, p.Metadata(), tr), nil
|
||||||
case *layers.UDP:
|
case *layers.UDP:
|
||||||
v, modPayload := w.handleUDP(streamID, ipFlow, tr)
|
v, modPayload := w.handleUDP(streamID, ipFlow, srcMAC, dstMAC, tr)
|
||||||
if v == io.VerdictAcceptModify && modPayload != nil {
|
if v == io.VerdictAcceptModify && modPayload != nil {
|
||||||
tr.Payload = modPayload
|
tr.Payload = modPayload
|
||||||
_ = tr.SetNetworkLayerForChecksum(netLayer)
|
_ = tr.SetNetworkLayerForChecksum(netLayer)
|
||||||
@@ -167,18 +176,22 @@ func (w *worker) handle(streamID uint32, p gopacket.Packet) (io.Verdict, []byte)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *worker) handleTCP(ipFlow gopacket.Flow, pMeta *gopacket.PacketMetadata, tcp *layers.TCP) io.Verdict {
|
func (w *worker) handleTCP(ipFlow gopacket.Flow, srcMAC, dstMAC net.HardwareAddr, pMeta *gopacket.PacketMetadata, tcp *layers.TCP) io.Verdict {
|
||||||
ctx := &tcpContext{
|
ctx := &tcpContext{
|
||||||
PacketMetadata: pMeta,
|
PacketMetadata: pMeta,
|
||||||
Verdict: tcpVerdictAccept,
|
Verdict: tcpVerdictAccept,
|
||||||
|
SrcMAC: srcMAC,
|
||||||
|
DstMAC: dstMAC,
|
||||||
}
|
}
|
||||||
w.tcpAssembler.AssembleWithContext(ipFlow, tcp, ctx)
|
w.tcpAssembler.AssembleWithContext(ipFlow, tcp, ctx)
|
||||||
return io.Verdict(ctx.Verdict)
|
return io.Verdict(ctx.Verdict)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *worker) handleUDP(streamID uint32, ipFlow gopacket.Flow, udp *layers.UDP) (io.Verdict, []byte) {
|
func (w *worker) handleUDP(streamID uint32, ipFlow gopacket.Flow, srcMAC, dstMAC net.HardwareAddr, udp *layers.UDP) (io.Verdict, []byte) {
|
||||||
ctx := &udpContext{
|
ctx := &udpContext{
|
||||||
Verdict: udpVerdictAccept,
|
Verdict: udpVerdictAccept,
|
||||||
|
SrcMAC: srcMAC,
|
||||||
|
DstMAC: dstMAC,
|
||||||
}
|
}
|
||||||
w.udpStreamManager.MatchWithContext(streamID, ipFlow, udp, ctx)
|
w.udpStreamManager.MatchWithContext(streamID, ipFlow, udp, ctx)
|
||||||
return io.Verdict(ctx.Verdict), ctx.Packet
|
return io.Verdict(ctx.Verdict), ctx.Packet
|
||||||
|
|||||||
@@ -191,6 +191,10 @@ func streamInfoToExprEnv(info StreamInfo) map[string]interface{} {
|
|||||||
m := map[string]interface{}{
|
m := map[string]interface{}{
|
||||||
"id": info.ID,
|
"id": info.ID,
|
||||||
"proto": info.Protocol.String(),
|
"proto": info.Protocol.String(),
|
||||||
|
"mac": map[string]string{
|
||||||
|
"src": info.SrcMAC.String(),
|
||||||
|
"dst": info.DstMAC.String(),
|
||||||
|
},
|
||||||
"ip": map[string]string{
|
"ip": map[string]string{
|
||||||
"src": info.SrcIP.String(),
|
"src": info.SrcIP.String(),
|
||||||
"dst": info.DstIP.String(),
|
"dst": info.DstIP.String(),
|
||||||
@@ -211,7 +215,7 @@ func streamInfoToExprEnv(info StreamInfo) map[string]interface{} {
|
|||||||
|
|
||||||
func isBuiltInAnalyzer(name string) bool {
|
func isBuiltInAnalyzer(name string) bool {
|
||||||
switch name {
|
switch name {
|
||||||
case "id", "proto", "ip", "port":
|
case "id", "proto", "mac", "ip", "port":
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ const (
|
|||||||
type StreamInfo struct {
|
type StreamInfo struct {
|
||||||
ID int64
|
ID int64
|
||||||
Protocol Protocol
|
Protocol Protocol
|
||||||
|
SrcMAC, DstMAC net.HardwareAddr
|
||||||
SrcIP, DstIP net.IP
|
SrcIP, DstIP net.IP
|
||||||
SrcPort, DstPort uint16
|
SrcPort, DstPort uint16
|
||||||
Props analyzer.CombinedPropMap
|
Props analyzer.CombinedPropMap
|
||||||
|
|||||||
Reference in New Issue
Block a user