Compare commits
7 Commits
v0.4.1
...
820c9410a1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
820c9410a1 | ||
|
|
6f261803a7 | ||
|
|
aacc98668f | ||
|
|
9519eedf4f | ||
|
|
b8b9b227a9 | ||
|
|
08d3214f22 | ||
|
|
6ebda76738 |
@@ -112,6 +112,11 @@ var DaemonCmd = &cobra.Command{
|
||||
ssh := parser.NewSshdParser()
|
||||
ssh.Parse(p.Events(), entryCh)
|
||||
}
|
||||
if svc.Name == "apache" {
|
||||
log.Info("Starting apache parser", "service", serviceName)
|
||||
ap := parser.NewApacheParser()
|
||||
ap.Parse(p.Events(), entryCh)
|
||||
}
|
||||
}(pars, svc.Name)
|
||||
continue
|
||||
}
|
||||
@@ -131,14 +136,18 @@ var DaemonCmd = &cobra.Command{
|
||||
if svc.Name == "nginx" {
|
||||
log.Info("Starting nginx parser", "service", serviceName)
|
||||
ng := parser.NewNginxParser()
|
||||
ng.Parse(p.Events(), resultCh)
|
||||
ng.Parse(p.Events(), entryCh)
|
||||
|
||||
}
|
||||
if svc.Name == "ssh" {
|
||||
log.Info("Starting ssh parser", "service", serviceName)
|
||||
ssh := parser.NewSshdParser()
|
||||
ssh.Parse(p.Events(), resultCh)
|
||||
|
||||
ssh.Parse(p.Events(), entryCh)
|
||||
}
|
||||
if svc.Name == "apache" {
|
||||
log.Info("Starting apache parser", "service", serviceName)
|
||||
ap := parser.NewApacheParser()
|
||||
ap.Parse(p.Events(), entryCh)
|
||||
}
|
||||
|
||||
}(pars, svc.Name)
|
||||
|
||||
@@ -12,7 +12,9 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ttl_fw string
|
||||
ttl_fw string
|
||||
port int
|
||||
protocol string
|
||||
)
|
||||
var UnbanCmd = &cobra.Command{
|
||||
Use: "unban",
|
||||
@@ -114,6 +116,65 @@ var BanCmd = &cobra.Command{
|
||||
},
|
||||
}
|
||||
|
||||
var PortCmd = &cobra.Command{
|
||||
Use: "port",
|
||||
Short: "Ports commands",
|
||||
}
|
||||
|
||||
var PortOpenCmd = &cobra.Command{
|
||||
Use: "open",
|
||||
Short: "Open ports on firewall",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if protocol == "" {
|
||||
fmt.Println("Protocol can't be empty")
|
||||
os.Exit(1)
|
||||
}
|
||||
cfg, err := config.LoadConfig()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fw := cfg.Firewall.Name
|
||||
b := blocker.GetBlocker(fw, cfg.Firewall.Config)
|
||||
err = b.PortOpen(port, protocol)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println("Port opened successfully!")
|
||||
},
|
||||
}
|
||||
|
||||
var PortCloseCmd = &cobra.Command{
|
||||
Use: "close",
|
||||
Short: "Close ports on firewall",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if protocol == "" {
|
||||
fmt.Println("Protocol can't be empty")
|
||||
os.Exit(1)
|
||||
}
|
||||
cfg, err := config.LoadConfig()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fw := cfg.Firewall.Name
|
||||
b := blocker.GetBlocker(fw, cfg.Firewall.Config)
|
||||
err = b.PortClose(port, protocol)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println("Port closed successfully!")
|
||||
},
|
||||
}
|
||||
|
||||
func FwRegister() {
|
||||
BanCmd.Flags().StringVarP(&ttl_fw, "ttl", "t", "", "ban time")
|
||||
PortCmd.AddCommand(PortOpenCmd)
|
||||
PortCmd.AddCommand(PortCloseCmd)
|
||||
PortOpenCmd.Flags().IntVarP(&port, "port", "p", 0, "port number")
|
||||
PortOpenCmd.Flags().StringVarP(&protocol, "protocol", "c", "", "protocol")
|
||||
PortCloseCmd.Flags().IntVarP(&port, "port", "p", 0, "port number")
|
||||
PortCloseCmd.Flags().StringVarP(&protocol, "protocol", "c", "", "protocol")
|
||||
}
|
||||
|
||||
17
cmd/banforge/command/version.go
Normal file
17
cmd/banforge/command/version.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var version = "0.4.3"
|
||||
|
||||
var VersionCmd = &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "BanForge version",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println("BanForge version:", version)
|
||||
},
|
||||
}
|
||||
@@ -13,7 +13,6 @@ var rootCmd = &cobra.Command{
|
||||
Use: "banforge",
|
||||
Short: "IPS log-based written on Golang",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
@@ -28,6 +27,8 @@ func Execute() {
|
||||
rootCmd.AddCommand(command.BanCmd)
|
||||
rootCmd.AddCommand(command.UnbanCmd)
|
||||
rootCmd.AddCommand(command.BanListCmd)
|
||||
rootCmd.AddCommand(command.VersionCmd)
|
||||
rootCmd.AddCommand(command.PortCmd)
|
||||
command.RuleRegister()
|
||||
command.FwRegister()
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
|
||||
21
docs/cli.md
21
docs/cli.md
@@ -11,6 +11,16 @@ banforge init
|
||||
**Description**
|
||||
This command creates the necessary directories and base configuration files
|
||||
required for the daemon to operate.
|
||||
|
||||
### version - Display BanForge version
|
||||
|
||||
```shell
|
||||
banforge version
|
||||
```
|
||||
|
||||
**Description**
|
||||
This command displays the current version of the BanForge software.
|
||||
|
||||
### daemon - Starts the BanForge daemon process
|
||||
|
||||
```shell
|
||||
@@ -32,6 +42,17 @@ banforge unban <ip>
|
||||
These commands provide an abstraction over your firewall. If you want to simplify the interface to your firewall, you can use these commands.
|
||||
|
||||
Flag -t or -ttl add bantime if not used default ban 1 year
|
||||
|
||||
### ports - Open and Close ports on firewall
|
||||
|
||||
```shell
|
||||
banforge open -port <port> -protocol <protocol>
|
||||
banforge close -port <port> -protocol <protocol>
|
||||
```
|
||||
|
||||
**Description**
|
||||
These commands provide an abstraction over your firewall. If you want to simplify the interface to your firewall, you can use these commands.
|
||||
|
||||
### list - Lists the IP addresses that are currently blocked
|
||||
```shell
|
||||
banforge list
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package blocker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
|
||||
"github.com/d3m0k1d/BanForge/internal/logger"
|
||||
)
|
||||
@@ -58,6 +60,66 @@ func (f *Firewalld) Unban(ip string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Firewalld) PortOpen(port int, protocol string) error {
|
||||
// #nosec G204 - handle is extracted from nftables output and validated
|
||||
if port >= 0 && port <= 65535 {
|
||||
if protocol != "tcp" && protocol != "udp" {
|
||||
f.logger.Error("invalid protocol")
|
||||
return fmt.Errorf("invalid protocol")
|
||||
}
|
||||
s := strconv.Itoa(port)
|
||||
cmd := exec.Command(
|
||||
"firewall-cmd",
|
||||
"--zone=public",
|
||||
"--add-port="+s+"/"+protocol,
|
||||
"--permanent",
|
||||
)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
f.logger.Error(err.Error())
|
||||
return err
|
||||
}
|
||||
f.logger.Info("Add port " + s + " " + string(output))
|
||||
output, err = exec.Command("firewall-cmd", "--reload").CombinedOutput()
|
||||
if err != nil {
|
||||
f.logger.Error(err.Error())
|
||||
return err
|
||||
}
|
||||
f.logger.Info("Reload " + string(output))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Firewalld) PortClose(port int, protocol string) error {
|
||||
// #nosec G204 - handle is extracted from nftables output and validated
|
||||
if port >= 0 && port <= 65535 {
|
||||
if protocol != "tcp" && protocol != "udp" {
|
||||
f.logger.Error("invalid protocol")
|
||||
return fmt.Errorf("invalid protocol")
|
||||
}
|
||||
s := strconv.Itoa(port)
|
||||
cmd := exec.Command(
|
||||
"firewall-cmd",
|
||||
"--zone=public",
|
||||
"--remove-port="+s+"/"+protocol,
|
||||
"--permanent",
|
||||
)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
f.logger.Error(err.Error())
|
||||
return err
|
||||
}
|
||||
f.logger.Info("Remove port " + s + " " + string(output))
|
||||
output, err = exec.Command("firewall-cmd", "--reload").CombinedOutput()
|
||||
if err != nil {
|
||||
f.logger.Error(err.Error())
|
||||
return err
|
||||
}
|
||||
f.logger.Info("Reload " + string(output))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Firewalld) Setup(config string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ type BlockerEngine interface {
|
||||
Ban(ip string) error
|
||||
Unban(ip string) error
|
||||
Setup(config string) error
|
||||
PortOpen(port int, protocol string) error
|
||||
PortClose(port int, protocol string) error
|
||||
}
|
||||
|
||||
func GetBlocker(fw string, config string) BlockerEngine {
|
||||
|
||||
@@ -2,6 +2,7 @@ package blocker
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"strconv"
|
||||
|
||||
"github.com/d3m0k1d/BanForge/internal/logger"
|
||||
)
|
||||
@@ -102,6 +103,64 @@ func (f *Iptables) Unban(ip string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Iptables) PortOpen(port int, protocol string) error {
|
||||
if port >= 0 && port <= 65535 {
|
||||
if protocol != "tcp" && protocol != "udp" {
|
||||
f.logger.Error("invalid protocol")
|
||||
return nil
|
||||
}
|
||||
s := strconv.Itoa(port)
|
||||
// #nosec G204 - managed by system adminstartor
|
||||
cmd := exec.Command("iptables", "-A", "INPUT", "-p", protocol, "--dport", s, "-j", "ACCEPT")
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
f.logger.Error(err.Error())
|
||||
return err
|
||||
}
|
||||
f.logger.Info("Add port " + s + " " + string(output))
|
||||
// #nosec G204 - f.config is validated above via validateConfigPath()
|
||||
cmd = exec.Command("iptables-save", "-f", f.config)
|
||||
output, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
f.logger.Error("failed to save config",
|
||||
"config_path", f.config,
|
||||
"error", err.Error(),
|
||||
"output", string(output))
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Iptables) PortClose(port int, protocol string) error {
|
||||
if port >= 0 && port <= 65535 {
|
||||
if protocol != "tcp" && protocol != "udp" {
|
||||
f.logger.Error("invalid protocol")
|
||||
return nil
|
||||
}
|
||||
s := strconv.Itoa(port)
|
||||
// #nosec G204 - managed by system adminstartor
|
||||
cmd := exec.Command("iptables", "-D", "INPUT", "-p", protocol, "--dport", s, "-j", "ACCEPT")
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
f.logger.Error(err.Error())
|
||||
return err
|
||||
}
|
||||
f.logger.Info("Add port " + s + " " + string(output))
|
||||
// #nosec G204 - f.config is validated above via validateConfigPath()
|
||||
cmd = exec.Command("iptables-save", "-f", f.config)
|
||||
output, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
f.logger.Error("failed to save config",
|
||||
"config_path", f.config,
|
||||
"error", err.Error(),
|
||||
"output", string(output))
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Iptables) Setup(config string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package blocker
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/d3m0k1d/BanForge/internal/logger"
|
||||
@@ -166,6 +167,81 @@ func (n *Nftables) findRuleHandle(ip string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (n *Nftables) PortOpen(port int, protocol string) error {
|
||||
if port >= 0 && port <= 65535 {
|
||||
if protocol != "tcp" && protocol != "udp" {
|
||||
n.logger.Error("invalid protocol")
|
||||
return fmt.Errorf("invalid protocol")
|
||||
}
|
||||
s := strconv.Itoa(port)
|
||||
// #nosec G204 - managed by system adminstartor
|
||||
cmd := exec.Command(
|
||||
"nft",
|
||||
"add",
|
||||
"rule",
|
||||
"inet",
|
||||
"banforge",
|
||||
"input",
|
||||
protocol,
|
||||
"dport",
|
||||
s,
|
||||
"accept",
|
||||
)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
n.logger.Error(err.Error())
|
||||
return err
|
||||
}
|
||||
n.logger.Info("Add port " + s + " " + string(output))
|
||||
err = saveNftablesConfig(n.config)
|
||||
if err != nil {
|
||||
n.logger.Error("failed to save config",
|
||||
"config_path", n.config,
|
||||
"error", err.Error())
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *Nftables) PortClose(port int, protocol string) error {
|
||||
if port >= 0 && port <= 65535 {
|
||||
if protocol != "tcp" && protocol != "udp" {
|
||||
n.logger.Error("invalid protocol")
|
||||
return fmt.Errorf("invalid protocol")
|
||||
}
|
||||
s := strconv.Itoa(port)
|
||||
// #nosec G204 - managed by system adminstartor
|
||||
cmd := exec.Command(
|
||||
"nft",
|
||||
"add",
|
||||
"rule",
|
||||
"inet",
|
||||
"banforge",
|
||||
"input",
|
||||
protocol,
|
||||
"dport",
|
||||
s,
|
||||
"drop",
|
||||
)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
n.logger.Error(err.Error())
|
||||
return err
|
||||
}
|
||||
n.logger.Info("Add port " + s + " " + string(output))
|
||||
err = saveNftablesConfig(n.config)
|
||||
if err != nil {
|
||||
n.logger.Error("failed to save config",
|
||||
"config_path", n.config,
|
||||
"error", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func saveNftablesConfig(configPath string) error {
|
||||
err := validateConfigPath(configPath)
|
||||
if err != nil {
|
||||
|
||||
@@ -3,6 +3,7 @@ package blocker
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
|
||||
"github.com/d3m0k1d/BanForge/internal/logger"
|
||||
)
|
||||
@@ -56,6 +57,44 @@ func (u *Ufw) Unban(ip string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *Ufw) PortOpen(port int, protocol string) error {
|
||||
if port >= 0 && port <= 65535 {
|
||||
if protocol != "tcp" && protocol != "udp" {
|
||||
u.logger.Error("invalid protocol")
|
||||
return fmt.Errorf("invalid protocol")
|
||||
}
|
||||
s := strconv.Itoa(port)
|
||||
// #nosec G204 - managed by system adminstartor
|
||||
cmd := exec.Command("ufw", "allow", s+"/"+protocol)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
u.logger.Error(err.Error())
|
||||
return err
|
||||
}
|
||||
u.logger.Info("Add port " + s + " " + string(output))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *Ufw) PortClose(port int, protocol string) error {
|
||||
if port >= 0 && port <= 65535 {
|
||||
if protocol != "tcp" && protocol != "udp" {
|
||||
u.logger.Error("invalid protocol")
|
||||
return nil
|
||||
}
|
||||
s := strconv.Itoa(port)
|
||||
// #nosec G204 - managed by system adminstartor
|
||||
cmd := exec.Command("ufw", "deny", s+"/"+protocol)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
u.logger.Error(err.Error())
|
||||
return err
|
||||
}
|
||||
u.logger.Info("Add port " + s + " " + string(output))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *Ufw) Setup(config string) error {
|
||||
if config != "" {
|
||||
fmt.Printf("Ufw dont support config file\n")
|
||||
|
||||
61
internal/parser/ApacheParser.go
Normal file
61
internal/parser/ApacheParser.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
|
||||
"github.com/d3m0k1d/BanForge/internal/logger"
|
||||
"github.com/d3m0k1d/BanForge/internal/storage"
|
||||
)
|
||||
|
||||
type ApacheParser struct {
|
||||
pattern *regexp.Regexp
|
||||
logger *logger.Logger
|
||||
}
|
||||
|
||||
func NewApacheParser() *ApacheParser {
|
||||
pattern := regexp.MustCompile(
|
||||
`^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s+-\s+-\s+\[(.*?)\]\s+"(\w+)\s+(.*?)\s+HTTP/[\d.]+"\s+(\d+)\s+(\d+|-)\s+"(.*?)"\s+"(.*?)"`,
|
||||
)
|
||||
// Groups:
|
||||
// 1: IP
|
||||
// 2: Timestamp
|
||||
// 3: Method (GET, POST, etc.)
|
||||
// 4: Path
|
||||
// 5: Status Code (200, 404, 403...)
|
||||
// 6: Response Size
|
||||
// 7: Referer
|
||||
// 8: User-Agent
|
||||
|
||||
return &ApacheParser{
|
||||
pattern: pattern,
|
||||
logger: logger.New(false),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ApacheParser) Parse(eventCh <-chan Event, resultCh chan<- *storage.LogEntry) {
|
||||
// Group 1: IP, Group 2: Timestamp, Group 3: Method, Group 4: Path, Group 5: Status
|
||||
for event := range eventCh {
|
||||
matches := p.pattern.FindStringSubmatch(event.Data)
|
||||
if matches == nil {
|
||||
continue
|
||||
}
|
||||
path := matches[4]
|
||||
status := matches[5]
|
||||
method := matches[3]
|
||||
|
||||
resultCh <- &storage.LogEntry{
|
||||
Service: "apache",
|
||||
IP: matches[1],
|
||||
Path: path,
|
||||
Status: status,
|
||||
Method: method,
|
||||
}
|
||||
p.logger.Info(
|
||||
"Parsed apache log entry",
|
||||
"ip", matches[1],
|
||||
"path", path,
|
||||
"status", status,
|
||||
"method", method,
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user