fix: judge creator, daemon logic
All checks were successful
CI.yml / build (push) Successful in 1m45s
All checks were successful
CI.yml / build (push) Successful in 1m45s
feat: first version for alpha test daemon on server fix: add second template for fix bug with slice Fix: add chek if path exists Fix: template one more time feat: Add file db on init command feat: add create dit feat: Add to init command create table to db feat: Add new logs for debug on server feat: Add CD, first release version chore:fix cd fix: change artifact ver from v4->v2 fix: ci one more time fix: ci
This commit is contained in:
82
.gitea/workflows/CD.yml
Normal file
82
.gitea/workflows/CD.yml
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
name: CD - BanForge Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Create Release
|
||||||
|
env:
|
||||||
|
TOKEN: ${{ secrets.TOKEN }}
|
||||||
|
run: |
|
||||||
|
TAG="${{ gitea.ref_name }}"
|
||||||
|
REPO="${{ gitea.repository }}"
|
||||||
|
SERVER="${{ gitea.server_url }}"
|
||||||
|
|
||||||
|
curl -X POST \
|
||||||
|
-H "Authorization: token $TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"tag_name": "'$TAG'",
|
||||||
|
"name": "Release '$TAG'",
|
||||||
|
"body": "# BanForge '$TAG'\n\nIntrusion Prevention System",
|
||||||
|
"draft": false,
|
||||||
|
"prerelease": false
|
||||||
|
}' \
|
||||||
|
"$SERVER/api/v1/repos/$REPO/releases"
|
||||||
|
|
||||||
|
build:
|
||||||
|
needs: release
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- goos: linux
|
||||||
|
arch: amd64
|
||||||
|
- goos: linux
|
||||||
|
arch: arm64
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- uses: actions/setup-go@v6
|
||||||
|
with:
|
||||||
|
go-version: '1.25'
|
||||||
|
cache: false
|
||||||
|
|
||||||
|
- run: go mod tidy
|
||||||
|
|
||||||
|
- run: go test ./...
|
||||||
|
|
||||||
|
- name: Build ${{ matrix.goos }}-${{ matrix.arch }}
|
||||||
|
env:
|
||||||
|
GOOS: ${{ matrix.goos }}
|
||||||
|
GOARCH: ${{ matrix.arch }}
|
||||||
|
run: go build -o banforge-${{ matrix.goos }}-${{ matrix.arch }} ./cmd/banforge
|
||||||
|
|
||||||
|
- name: Upload to release
|
||||||
|
env:
|
||||||
|
TOKEN: ${{ secrets.TOKEN }}
|
||||||
|
run: |
|
||||||
|
TAG="${{ gitea.ref_name }}"
|
||||||
|
REPO="${{ gitea.repository }}"
|
||||||
|
SERVER="${{ gitea.server_url }}"
|
||||||
|
|
||||||
|
curl -X POST \
|
||||||
|
-H "Authorization: token $TOKEN" \
|
||||||
|
-H "Content-Type: application/octet-stream" \
|
||||||
|
--data-binary "@banforge-${{ matrix.goos }}-${{ matrix.arch }}" \
|
||||||
|
"$SERVER/api/v1/repos/$REPO/releases/tags/$TAG/assets?name=banforge-${{ matrix.goos }}-${{ matrix.arch }}"
|
||||||
|
|
||||||
@@ -3,12 +3,14 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/d3m0k1d/BanForge/internal/blocker"
|
||||||
"github.com/d3m0k1d/BanForge/internal/config"
|
"github.com/d3m0k1d/BanForge/internal/config"
|
||||||
_ "github.com/d3m0k1d/BanForge/internal/judge"
|
"github.com/d3m0k1d/BanForge/internal/judge"
|
||||||
"github.com/d3m0k1d/BanForge/internal/logger"
|
"github.com/d3m0k1d/BanForge/internal/logger"
|
||||||
"github.com/d3m0k1d/BanForge/internal/parser"
|
"github.com/d3m0k1d/BanForge/internal/parser"
|
||||||
_ "github.com/d3m0k1d/BanForge/internal/storage"
|
"github.com/d3m0k1d/BanForge/internal/storage"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -25,26 +27,80 @@ var initCmd = &cobra.Command{
|
|||||||
Short: "Initialize BanForge",
|
Short: "Initialize BanForge",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
fmt.Println("Initializing BanForge...")
|
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)
|
err := os.Mkdir("/var/log/banforge", 0750)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
err = os.Mkdir("/etc/banforge", 0750)
|
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 {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
err = config.CreateConf()
|
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 {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
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()
|
err = config.FindFirewall()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
os.Exit(1)
|
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!")
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,23 +110,86 @@ var daemonCmd = &cobra.Command{
|
|||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
log := logger.New(false)
|
log := logger.New(false)
|
||||||
log.Info("Starting BanForge daemon")
|
log.Info("Starting BanForge daemon")
|
||||||
//db, err := storage.NewDB()
|
db, err := storage.NewDB()
|
||||||
//if err != nil {
|
if err != nil {
|
||||||
//log.Error("Failed to create database", "error", err)
|
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()
|
cfg, err := config.LoadConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to load config", "error", err)
|
log.Error("Failed to load config", "error", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
for service := range cfg.Service {
|
var b blocker.BlockerEngine
|
||||||
if cfg.Service[service].Enabled && cfg.Service[service].Name != "nginx" {
|
fw := cfg.Firewall.Name
|
||||||
pars, err := parser.NewScanner(cfg.Service[service].LogPath)
|
switch fw {
|
||||||
|
case "ufw":
|
||||||
|
b = blocker.NewUfw(log)
|
||||||
|
case "iptables":
|
||||||
|
b = blocker.NewIptables(log, cfg.Firewall.Config)
|
||||||
|
case "nftables":
|
||||||
|
b = blocker.NewNftables(log, cfg.Firewall.Config)
|
||||||
|
case "firewalld":
|
||||||
|
b = blocker.NewFirewalld(log)
|
||||||
|
default:
|
||||||
|
log.Error("Unknown firewall", "firewall", fw)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
r, err := config.LoadRuleConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to create parser", "error", err)
|
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 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 {}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,6 +198,7 @@ func Init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Execute() {
|
func Execute() {
|
||||||
|
rootCmd.AddCommand(daemonCmd)
|
||||||
rootCmd.AddCommand(initCmd)
|
rootCmd.AddCommand(initCmd)
|
||||||
if err := rootCmd.Execute(); err != nil {
|
if err := rootCmd.Execute(); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -4,11 +4,11 @@ go 1.25.5
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v1.6.0
|
github.com/BurntSushi/toml v1.6.0
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.33
|
||||||
github.com/spf13/cobra v1.10.2
|
github.com/spf13/cobra v1.10.2
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/mattn/go-sqlite3 v1.14.33 // indirect
|
|
||||||
github.com/spf13/pflag v1.0.10 // indirect
|
github.com/spf13/pflag v1.0.10 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -50,6 +50,14 @@ func CreateConf() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create rules file: %w", err)
|
return fmt.Errorf("failed to create rules file: %w", err)
|
||||||
}
|
}
|
||||||
|
file, err = os.Create("/var/lib/banforge/storage.db")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create database file: %w", err)
|
||||||
|
}
|
||||||
|
err = os.Chmod("/var/lib/banforge/storage.db", 0600)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to set permissions: %w", err)
|
||||||
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
err = file.Close()
|
err = file.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -9,8 +9,16 @@ name = ""
|
|||||||
config = "/etc/nftables.conf"
|
config = "/etc/nftables.conf"
|
||||||
ban_time = 1200
|
ban_time = 1200
|
||||||
|
|
||||||
[service]
|
[[service]]
|
||||||
name = "nginx"
|
name = "nginx"
|
||||||
log_path = "/var/log/nginx/access.log"
|
log_path = "/var/log/nginx/access.log"
|
||||||
enabled = true
|
enabled = true
|
||||||
|
|
||||||
|
[[service]]
|
||||||
|
name = "nginx"
|
||||||
|
log_path = "/var/log/nginx/access.log"
|
||||||
|
enabled = false
|
||||||
|
|
||||||
`
|
`
|
||||||
|
|
||||||
|
// TODO: fix types for use 1 or any services"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package Judge
|
package judge
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -16,11 +16,12 @@ type Judge struct {
|
|||||||
rulesByService map[string][]config.Rule
|
rulesByService map[string][]config.Rule
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(db *storage.DB) *Judge {
|
func New(db *storage.DB, b blocker.BlockerEngine) *Judge {
|
||||||
return &Judge{
|
return &Judge{
|
||||||
db: db,
|
db: db,
|
||||||
logger: logger.New(false),
|
logger: logger.New(false),
|
||||||
rulesByService: make(map[string][]config.Rule),
|
rulesByService: make(map[string][]config.Rule),
|
||||||
|
Blocker: b,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ func (p *NginxParser) Parse(eventCh <-chan Event, resultCh chan<- *storage.LogEn
|
|||||||
Method: method,
|
Method: method,
|
||||||
IsViewed: false,
|
IsViewed: false,
|
||||||
}
|
}
|
||||||
|
p.logger.Info("Parsed nginx log entry", "ip", matches[1], "path", path, "status", status, "method", method)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ func (s *Scanner) Start() {
|
|||||||
s.ch <- Event{
|
s.ch <- Event{
|
||||||
Data: s.scanner.Text(),
|
Data: s.scanner.Text(),
|
||||||
}
|
}
|
||||||
|
s.logger.Info("Scanner event", "data", s.scanner.Text())
|
||||||
} else {
|
} else {
|
||||||
if err := s.scanner.Err(); err != nil {
|
if err := s.scanner.Err(); err != nil {
|
||||||
s.logger.Error("Scanner error")
|
s.logger.Error("Scanner error")
|
||||||
|
|||||||
Reference in New Issue
Block a user