package main
import (
"log"
"net"
"time"
"github.com/cilium/ebpf"
"github.com/cilium/ebpf/link"
"github.com/cilium/ebpf/rlimit"
)
// Adjust these constants for your setup
const (
bpfObjectFile = "udp_flood_blocker.bpf.o"
interfaceName = "eth0" // e.g. "eth0", "ens5", etc. on Ubuntu
packetsPerSecThreshold = 10000 // example threshold
)
func main() {
// 1) Remove the memlock limit so eBPF maps can be created
if err := rlimit.RemoveMemlock(); err != nil {
log.Fatalf("failed to remove memlock limit: %v", err)
}
// 2) Load the compiled eBPF object from file
spec, err := ebpf.LoadCollectionSpec(bpfObjectFile)
if err != nil {
log.Fatalf("failed to load eBPF collection spec from %s: %v", bpfObjectFile, err)
}
// 3) Create a Collection from the spec (program + maps)
coll, err := ebpf.NewCollection(spec)
if err != nil {
log.Fatalf("failed to create eBPF collection: %v", err)
}
defer coll.Close()
// 4) Get the XDP program from the collection
prog, ok := coll.Programs["detect_and_block_udp"]
if !ok {
log.Fatalf("program 'detect_and_block_udp' not found in %s", bpfObjectFile)
}
// 5) Attach the XDP program to the given network interface
ifIndex := resolveInterfaceIndex(interfaceName)
linkXDP, err := link.AttachXDP(link.XDPOptions{
Program: prog,
Interface: ifIndex,
Flags: link.XDPGenericMode, // or link.XDPDriverMode if supported
})
if err != nil {
log.Fatalf("failed to attach XDP to interface %s: %v", interfaceName, err)
}
defer linkXDP.Close()
log.Printf("XDP program attached to interface %s (ifIndex=%d)", interfaceName, ifIndex)
// 6) Retrieve eBPF maps from the collection
udpCountMap, ok := coll.Maps["udp_count"]
if !ok {
log.Fatalf("map 'udp_count' not found in the collection")
}
blockStateMap, ok := coll.Maps["block_state"]
if !ok {
log.Fatalf("map 'block_state' not found in the collection")
}
// Initialize block_state to 0 (allow)
zeroKey := uint32(0)
zeroVal := uint32(0)
if err := blockStateMap.Update(&zeroKey, &zeroVal, ebpf.UpdateAny); err != nil {
log.Fatalf("failed to initialize block_state: %v", err)
}
// We'll track how many UDP packets we see each second
var oldCount, newCount uint64
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
for range ticker.C {
// Read the current count from the eBPF map
if err := udpCountMap.Lookup(&zeroKey, &newCount); err != nil {
log.Printf("lookup failed: %v", err)
continue
}
diff := newCount - oldCount
oldCount = newCount
if diff > packetsPerSecThreshold {
// Exceeded threshold => block further UDP
log.Printf("[ALERT] High UDP rate: %d pkts/sec => blocking...", diff)
blockVal := uint32(1)
if err := blockStateMap.Update(&zeroKey, &blockVal, ebpf.UpdateAny); err != nil {
log.Printf("failed to set block_state: %v", err)
}
} else {
// If you want automatic unblocking, uncomment:
/*
blockVal := uint32(0)
blockStateMap.Update(&zeroKey, &blockVal, ebpf.UpdateAny)
*/
log.Printf("UDP packets last second: %d", diff)
}
}
}
// resolveInterfaceIndex fetches the index of an interface by name
func resolveInterfaceIndex(ifaceName string) int {
iface, err := net.InterfaceByName(ifaceName)
if err != nil {
log.Fatalf("cannot find interface %q: %v", ifaceName, err)
}
return iface.Index
}
Comments
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|👍
/👎
0 B
|👍
/👎