Files
dip-ids/internal/analyzer/arp.go
T
2026-04-12 22:26:26 +04:00

102 lines
2.4 KiB
Go

package analyzer
import (
"fmt"
"sync"
"time"
"dip-ids/internal/config"
"dip-ids/internal/storage"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
)
// arpSpoofDetector обнаруживает ARP-спуфинг.
// Алгоритм: ведёт таблицу соответствия IP→MAC; при обнаружении
// нового MAC для уже известного IP генерирует алерт.
type arpSpoofDetector struct {
mu sync.Mutex
cfg config.ARPSpoofConfig
ipToMAC map[string]string // IP -> MAC
alerted map[string]time.Time
}
func NewARPSpoofDetector(cfg config.ARPSpoofConfig) Detector {
return &arpSpoofDetector{
cfg: cfg,
ipToMAC: make(map[string]string),
alerted: make(map[string]time.Time),
}
}
func (d *arpSpoofDetector) Name() string { return "arp_spoof" }
func (d *arpSpoofDetector) Analyze(pkt gopacket.Packet) []storage.Alert {
if !d.cfg.Enabled {
return nil
}
arpLayer := pkt.Layer(layers.LayerTypeARP)
if arpLayer == nil {
return nil
}
arp := arpLayer.(*layers.ARP)
// Обрабатываем только ARP Reply (op=2) и Gratuitous ARP
if arp.Operation != layers.ARPReply {
return nil
}
srcIP := fmt.Sprintf("%d.%d.%d.%d", arp.SourceProtAddress[0], arp.SourceProtAddress[1],
arp.SourceProtAddress[2], arp.SourceProtAddress[3])
srcMAC := fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x",
arp.SourceHwAddress[0], arp.SourceHwAddress[1], arp.SourceHwAddress[2],
arp.SourceHwAddress[3], arp.SourceHwAddress[4], arp.SourceHwAddress[5])
now := pkt.Metadata().Timestamp
if now.IsZero() {
now = time.Now()
}
d.mu.Lock()
defer d.mu.Unlock()
knownMAC, exists := d.ipToMAC[srcIP]
if !exists {
d.ipToMAC[srcIP] = srcMAC
return nil
}
if knownMAC == srcMAC {
return nil
}
// MAC изменился — ARP спуфинг
key := srcIP
if last, ok := d.alerted[key]; ok && now.Sub(last) < 60*time.Second {
return nil
}
d.alerted[key] = now
// Обновляем таблицу
d.ipToMAC[srcIP] = srcMAC
return []storage.Alert{{
CreatedAt: now,
Type: "arp_spoof",
Severity: d.cfg.Severity,
SrcIP: srcIP,
Protocol: "ARP",
Description: fmt.Sprintf("ARP spoofing: IP %s changed MAC from %s to %s", srcIP, knownMAC, srcMAC),
Count: 1,
}}
}
func (d *arpSpoofDetector) Reset() {
d.mu.Lock()
defer d.mu.Unlock()
d.ipToMAC = make(map[string]string)
d.alerted = make(map[string]time.Time)
}