331 lines
7.4 KiB
Go
331 lines
7.4 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/d3m0k1d/BanForge/internal/blocker"
|
|
"github.com/d3m0k1d/BanForge/internal/config"
|
|
"github.com/d3m0k1d/BanForge/internal/judge"
|
|
"github.com/d3m0k1d/BanForge/internal/logger"
|
|
"github.com/d3m0k1d/BanForge/internal/parser"
|
|
"github.com/d3m0k1d/BanForge/internal/storage"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
var (
|
|
ip string
|
|
name string
|
|
service string
|
|
path string
|
|
status string
|
|
method string
|
|
)
|
|
|
|
var rootCmd = &cobra.Command{
|
|
Use: "banforge",
|
|
Short: "IPS log-based written on Golang",
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
|
|
},
|
|
}
|
|
|
|
var initCmd = &cobra.Command{
|
|
Use: "init",
|
|
Short: "Initialize BanForge",
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
fmt.Println("Initializing BanForge...")
|
|
|
|
if _, err := os.Stat("/var/log/banforge"); err == nil {
|
|
fmt.Println("/var/log/banforge already exists, skipping...")
|
|
} else if os.IsNotExist(err) {
|
|
err := os.Mkdir("/var/log/banforge", 0750)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
fmt.Println("Created /var/log/banforge")
|
|
} else {
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
if _, err := os.Stat("/var/lib/banforge"); err == nil {
|
|
fmt.Println("/var/lib/banforge already exists, skipping...")
|
|
} else if os.IsNotExist(err) {
|
|
err := os.Mkdir("/var/lib/banforge", 0750)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
fmt.Println("Created /var/lib/banforge")
|
|
} else {
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
if _, err := os.Stat("/etc/banforge"); err == nil {
|
|
fmt.Println("/etc/banforge already exists, skipping...")
|
|
} else if os.IsNotExist(err) {
|
|
err := os.Mkdir("/etc/banforge", 0750)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
fmt.Println("Created /etc/banforge")
|
|
} else {
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
err := config.CreateConf()
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
fmt.Println("Config created")
|
|
|
|
err = config.FindFirewall()
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
db, err := storage.NewDB()
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
err = db.CreateTable()
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
defer func() {
|
|
err = db.Close()
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
}()
|
|
fmt.Println("Firewall detected and configured")
|
|
|
|
fmt.Println("BanForge initialized successfully!")
|
|
},
|
|
}
|
|
|
|
var daemonCmd = &cobra.Command{
|
|
Use: "daemon",
|
|
Short: "Run BanForge daemon process",
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
log := logger.New(false)
|
|
log.Info("Starting BanForge daemon")
|
|
db, err := storage.NewDB()
|
|
if err != nil {
|
|
log.Error("Failed to create database", "error", err)
|
|
os.Exit(1)
|
|
}
|
|
defer func() {
|
|
err = db.Close()
|
|
if err != nil {
|
|
log.Error("Failed to close database connection", "error", err)
|
|
}
|
|
}()
|
|
cfg, err := config.LoadConfig()
|
|
if err != nil {
|
|
log.Error("Failed to load config", "error", err)
|
|
os.Exit(1)
|
|
}
|
|
var b blocker.BlockerEngine
|
|
fw := cfg.Firewall.Name
|
|
b = blocker.GetBlocker(fw, cfg.Firewall.Config)
|
|
r, err := config.LoadRuleConfig()
|
|
if err != nil {
|
|
log.Error("Failed to load rules", "error", err)
|
|
os.Exit(1)
|
|
}
|
|
j := judge.New(db, b)
|
|
j.LoadRules(r)
|
|
go func() {
|
|
ticker := time.NewTicker(5 * time.Second)
|
|
defer ticker.Stop()
|
|
for range ticker.C {
|
|
if err := j.ProcessUnviewed(); err != nil {
|
|
log.Error("Failed to process unviewed", "error", err)
|
|
}
|
|
}
|
|
}()
|
|
|
|
for _, svc := range cfg.Service {
|
|
log.Info("Processing service", "name", svc.Name, "enabled", svc.Enabled, "path", svc.LogPath)
|
|
|
|
if !svc.Enabled {
|
|
log.Info("Service disabled, skipping", "name", svc.Name)
|
|
continue
|
|
}
|
|
|
|
if svc.Name != "nginx" {
|
|
log.Info("Only nginx supported, skipping", "name", svc.Name)
|
|
continue
|
|
}
|
|
|
|
log.Info("Starting parser for service", "name", svc.Name, "path", svc.LogPath)
|
|
|
|
pars, err := parser.NewScanner(svc.LogPath)
|
|
if err != nil {
|
|
log.Error("Failed to create scanner", "service", svc.Name, "error", err)
|
|
continue
|
|
}
|
|
|
|
go pars.Start()
|
|
go func(p *parser.Scanner, serviceName string) {
|
|
log.Info("Starting nginx parser", "service", serviceName)
|
|
ng := parser.NewNginxParser()
|
|
resultCh := make(chan *storage.LogEntry, 100)
|
|
ng.Parse(p.Events(), resultCh)
|
|
go storage.Write(db, resultCh)
|
|
}(pars, svc.Name)
|
|
}
|
|
|
|
select {}
|
|
},
|
|
}
|
|
|
|
var UnbanCmd = &cobra.Command{
|
|
Use: "unban",
|
|
Short: "Unban IP",
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
cfg, err := config.LoadConfig()
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
fw := cfg.Firewall.Name
|
|
b := blocker.GetBlocker(fw, cfg.Firewall.Config)
|
|
if ip == "" {
|
|
fmt.Println("IP can't be empty")
|
|
os.Exit(1)
|
|
}
|
|
if net.ParseIP(ip) == nil {
|
|
fmt.Println("Invalid IP")
|
|
os.Exit(1)
|
|
}
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
err = b.Unban(ip)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
fmt.Println("IP unblocked successfully!")
|
|
},
|
|
}
|
|
|
|
var BanCmd = &cobra.Command{
|
|
Use: "ban",
|
|
Short: "Ban IP",
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
|
|
cfg, err := config.LoadConfig()
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
fw := cfg.Firewall.Name
|
|
b := blocker.GetBlocker(fw, cfg.Firewall.Config)
|
|
if ip == "" {
|
|
fmt.Println("IP can't be empty")
|
|
os.Exit(1)
|
|
}
|
|
if net.ParseIP(ip) == nil {
|
|
fmt.Println("Invalid IP")
|
|
os.Exit(1)
|
|
}
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
err = b.Ban(ip)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
fmt.Println("IP unblocked successfully!")
|
|
},
|
|
}
|
|
|
|
// Rule block
|
|
var ruleCmd = &cobra.Command{
|
|
Use: "rule",
|
|
Short: "Manage rules",
|
|
}
|
|
|
|
var addCmd = &cobra.Command{
|
|
Use: "add",
|
|
Short: "CLI interface for add new rule to file /etc/banforge/rules.toml",
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
if name == "" {
|
|
fmt.Printf("Rule name can't be empty\n")
|
|
os.Exit(1)
|
|
}
|
|
if service == "" && path == "" && status == "" && method == "" {
|
|
fmt.Printf("At least 1 rule field must be filled in.")
|
|
os.Exit(1)
|
|
}
|
|
|
|
err := config.NewRule(name, service, path, status, method)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
fmt.Println("Rule added successfully!")
|
|
},
|
|
}
|
|
|
|
var listCmd = &cobra.Command{
|
|
Use: "list",
|
|
Short: "List rules",
|
|
Run: func(cmd *cobra.Command, args []string) {
|
|
r, err := config.LoadRuleConfig()
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
for _, rule := range r {
|
|
fmt.Printf("Name: %s\nService: %s\nPath: %s\nStatus: %s\nMethod: %s\n\n", rule.Name, rule.ServiceName, rule.Path, rule.Status, rule.Method)
|
|
}
|
|
},
|
|
}
|
|
|
|
func Init() {
|
|
|
|
}
|
|
|
|
func Execute() {
|
|
rootCmd.AddCommand(daemonCmd)
|
|
rootCmd.AddCommand(initCmd)
|
|
rootCmd.AddCommand(ruleCmd)
|
|
rootCmd.AddCommand(BanCmd)
|
|
rootCmd.AddCommand(UnbanCmd)
|
|
UnbanCmd.Flags().StringVarP(&ip, "ip", "i", "", "ip to unban")
|
|
BanCmd.Flags().StringVarP(&ip, "ip", "i", "", "ip to ban")
|
|
// Rule comand block
|
|
ruleCmd.AddCommand(addCmd)
|
|
ruleCmd.AddCommand(listCmd)
|
|
addCmd.Flags().StringVarP(&name, "name", "n", "", "rule name (required)")
|
|
addCmd.Flags().StringVarP(&service, "service", "s", "", "service name")
|
|
addCmd.Flags().StringVarP(&path, "path", "p", "", "request path")
|
|
addCmd.Flags().StringVarP(&status, "status", "c", "", "HTTP status code")
|
|
addCmd.Flags().StringVarP(&method, "method", "m", "", "HTTP method")
|
|
if err := rootCmd.Execute(); err != nil {
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
Execute()
|
|
}
|