Make webhook configurable
This commit is contained in:
16
config.ini
Normal file
16
config.ini
Normal file
@@ -0,0 +1,16 @@
|
||||
[General]
|
||||
; Path to the named pipe (FIFO) for sFlow data
|
||||
PipePath = /tmp/sflow-abuse
|
||||
; Webhook URL for sending alerts
|
||||
WebhookURL = "x"
|
||||
|
||||
[Monitoring]
|
||||
; List of ports to monitor (comma-separated)
|
||||
MonitoredPorts = 25,587
|
||||
|
||||
[Thresholds]
|
||||
; Time threshold for counting events (in seconds)
|
||||
TimeThreshold = 10
|
||||
|
||||
; Packet count threshold for sending an alert
|
||||
PacketCountThreshold = 100
|
||||
4
go.mod
4
go.mod
@@ -1,3 +1,7 @@
|
||||
module sflow-abuse
|
||||
|
||||
go 1.20
|
||||
|
||||
require github.com/go-ini/ini v1.67.0
|
||||
|
||||
require github.com/stretchr/testify v1.8.4 // indirect
|
||||
|
||||
55
main.go
55
main.go
@@ -7,11 +7,13 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
"sflow-abuse/src"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/go-ini/ini"
|
||||
)
|
||||
|
||||
// Function to check if an IP address is within any of the specified subnets.
|
||||
func isIPInSubnets(ip string, subnets []string, ignored []string) bool {
|
||||
addr := net.ParseIP(ip)
|
||||
if addr == nil {
|
||||
@@ -34,12 +36,36 @@ func isIPInSubnets(ip string, subnets []string, ignored []string) bool {
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Define the path for the named pipe (FIFO).
|
||||
pipePath := "/tmp/sflow-abuse"
|
||||
cfg, err := ini.Load("config.ini")
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to read configuration file: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Read the values from the sections
|
||||
generalSection := cfg.Section("General")
|
||||
pipePath := generalSection.Key("PipePath").String()
|
||||
|
||||
monitoringSection := cfg.Section("Monitoring")
|
||||
monitoredPorts := monitoringSection.Key("MonitoredPorts").String()
|
||||
// Split the comma-separated ports into a slice
|
||||
monitoredPortSlice := strings.Split(monitoredPorts, ",")
|
||||
|
||||
thresholdsSection := cfg.Section("Thresholds")
|
||||
timeThreshold, err := thresholdsSection.Key("TimeThreshold").Int()
|
||||
if err != nil {
|
||||
fmt.Printf("Invalid TimeThreshold: %v\n", err)
|
||||
return
|
||||
}
|
||||
packetCountThreshold, err := thresholdsSection.Key("PacketCountThreshold").Int()
|
||||
if err != nil {
|
||||
fmt.Printf("Invalid PacketCountThreshold: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Create the named pipe (FIFO) if it doesn't exist.
|
||||
if _, err := os.Stat(pipePath); os.IsNotExist(err) {
|
||||
if err := syscall.Mkfifo(pipePath, 0666); err != nil {
|
||||
if err := syscall.Mkfifo(pipePath, 0660); err != nil {
|
||||
fmt.Printf("Error creating named pipe: %v\n", err)
|
||||
return
|
||||
}
|
||||
@@ -77,11 +103,12 @@ func main() {
|
||||
|
||||
// Print the subnets that will be used for filtering.
|
||||
fmt.Printf("Loaded %d subnets: %v\n", len(subnets), subnets)
|
||||
fmt.Printf("Loaded %d monitored ports: %v\n", len(monitoredPortSlice), monitoredPortSlice)
|
||||
fmt.Printf("Loaded %d ignored subnets: %v\n", len(ignored), ignored)
|
||||
|
||||
// Create an instance of EventCounter to track events.
|
||||
eventCounter := src.NewEventCounter(10*time.Second, src.HandleAlert)
|
||||
go eventCounter.StartMonitoring()
|
||||
eventCounter := src.NewEventCounter(time.Duration(timeThreshold)*time.Second, src.HandleAlert)
|
||||
go eventCounter.StartMonitoring(packetCountThreshold)
|
||||
|
||||
// Open the named pipe for reading.
|
||||
pipeFile, err := os.OpenFile(pipePath, os.O_RDONLY, os.ModeNamedPipe)
|
||||
@@ -111,17 +138,29 @@ func main() {
|
||||
if len(row) >= 16 {
|
||||
if net.ParseIP(row[9]) != nil {
|
||||
sourceIP := row[9]
|
||||
// Check if the source IP is within any of the specified subnets.
|
||||
if isIPInSubnets(sourceIP, subnets, ignored) {
|
||||
destinationPort := row[15]
|
||||
|
||||
// Check if the destination port is in the list of monitored ports.
|
||||
if containsPort(monitoredPortSlice, destinationPort) {
|
||||
// Check if the source IP is within any of the specified subnets.
|
||||
if isIPInSubnets(sourceIP, subnets, ignored) {
|
||||
// Count the event for the source IP and port combination.
|
||||
eventCounter.CountEvent(sourceIP, destinationPort)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stop the event monitoring when finished.
|
||||
eventCounter.StopMonitoring()
|
||||
}
|
||||
|
||||
func containsPort(ports []string, port string) bool {
|
||||
for _, p := range ports {
|
||||
if p == port {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -4,12 +4,10 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/go-ini/ini"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// WebhookURL is the URL of the Discord webhook.
|
||||
const WebhookURL = "https://discord.com/api/webhooks/1116824798421594233/ARw2KQvPPIt2wLlw4Ssp98o0VWkjr-FdZ2kpFono8zu5UC-N1Uyysy73wbL_DvYJutya"
|
||||
|
||||
// AlertData represents the data to be sent in the alert.
|
||||
type AlertData struct {
|
||||
Embeds []Embed `json:"embeds"`
|
||||
@@ -24,6 +22,16 @@ type Embed struct {
|
||||
|
||||
// SendAlert sends an alert to the specified Discord webhook.
|
||||
func SendAlert(alert string) error {
|
||||
cfg, err := ini.Load("config.ini")
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to read configuration file: %v\n", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
// WebhookURL is the URL of the Discord webhook.
|
||||
generalSection := cfg.Section("General")
|
||||
WebhookURL := generalSection.Key("WebhookURL").String()
|
||||
|
||||
url := WebhookURL
|
||||
|
||||
alertData := AlertData{
|
||||
|
||||
@@ -34,12 +34,12 @@ func (ec *EventCounter) CountEvent(ip, port string) {
|
||||
ec.mutex.Unlock()
|
||||
}
|
||||
|
||||
// StartMonitoring starts the event monitoring and alerts.
|
||||
func (ec *EventCounter) StartMonitoring() {
|
||||
// StartMonitoring starts the event monitoring and alerts with a specified threshold.
|
||||
func (ec *EventCounter) StartMonitoring(threshold int) {
|
||||
for range ec.resetTimer.C {
|
||||
ec.mutex.Lock()
|
||||
for key, count := range ec.counts {
|
||||
if count >= 10 {
|
||||
if count >= threshold {
|
||||
ip, port := parseKey(key)
|
||||
ec.alertHandler(ip, port, count)
|
||||
}
|
||||
@@ -68,6 +68,6 @@ func (ec *EventCounter) StopMonitoring() {
|
||||
|
||||
// HandleAlert is a placeholder for alert handling logic.
|
||||
func HandleAlert(ip, port string, count int) {
|
||||
SendAlert(fmt.Sprintf("Alert: Source IP %s, Port %s exceeded the threshold with a count of %d\n", ip, port, count))
|
||||
SendAlert(fmt.Sprintf("Source IP %s, Port %s exceeded the threshold with a count of %d\n", ip, port, count))
|
||||
fmt.Printf("Alert: Source IP %s, Port %s exceeded the threshold with a count of %d\n", ip, port, count)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user