88 lines
2.0 KiB
Go
88 lines
2.0 KiB
Go
package analyzer
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
"time"
|
|
|
|
"dip-ids/internal/config"
|
|
"dip-ids/internal/storage"
|
|
|
|
"github.com/google/gopacket"
|
|
)
|
|
|
|
// dosDetector обнаруживает DoS/DDoS атаки по превышению порога PPS.
|
|
// Алгоритм: считает количество пакетов от каждого источника
|
|
// за скользящее временное окно; при превышении порога — алерт.
|
|
type dosDetector struct {
|
|
mu sync.Mutex
|
|
cfg config.DoSConfig
|
|
tracker map[string][]time.Time // srcIP -> timestamps
|
|
alerted map[string]time.Time
|
|
}
|
|
|
|
func NewDoSDetector(cfg config.DoSConfig) Detector {
|
|
return &dosDetector{
|
|
cfg: cfg,
|
|
tracker: make(map[string][]time.Time),
|
|
alerted: make(map[string]time.Time),
|
|
}
|
|
}
|
|
|
|
func (d *dosDetector) Name() string { return "dos" }
|
|
|
|
func (d *dosDetector) Analyze(pkt gopacket.Packet) []storage.Alert {
|
|
if !d.cfg.Enabled {
|
|
return nil
|
|
}
|
|
|
|
netLayer := pkt.NetworkLayer()
|
|
if netLayer == nil {
|
|
return nil
|
|
}
|
|
|
|
srcIP := netLayer.NetworkFlow().Src().String()
|
|
dstIP := netLayer.NetworkFlow().Dst().String()
|
|
now := pkt.Metadata().Timestamp
|
|
if now.IsZero() {
|
|
now = time.Now()
|
|
}
|
|
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
|
|
window := time.Duration(d.cfg.WindowSeconds) * time.Second
|
|
cutoff := now.Add(-window)
|
|
|
|
d.tracker[srcIP] = append(d.tracker[srcIP], now)
|
|
d.tracker[srcIP] = filterTimes(d.tracker[srcIP], cutoff)
|
|
|
|
pps := len(d.tracker[srcIP])
|
|
if pps < d.cfg.PPSThreshold {
|
|
return nil
|
|
}
|
|
|
|
if last, ok := d.alerted[srcIP]; ok && now.Sub(last) < 10*time.Second {
|
|
return nil
|
|
}
|
|
d.alerted[srcIP] = now
|
|
|
|
return []storage.Alert{{
|
|
CreatedAt: now,
|
|
Type: "dos",
|
|
Severity: d.cfg.Severity,
|
|
SrcIP: srcIP,
|
|
DstIP: dstIP,
|
|
Protocol: "IP",
|
|
Description: fmt.Sprintf("DoS attack detected from %s: %d pkt/s (threshold: %d)", srcIP, pps, d.cfg.PPSThreshold),
|
|
Count: pps,
|
|
}}
|
|
}
|
|
|
|
func (d *dosDetector) Reset() {
|
|
d.mu.Lock()
|
|
defer d.mu.Unlock()
|
|
d.tracker = make(map[string][]time.Time)
|
|
d.alerted = make(map[string]time.Time)
|
|
}
|