Add command for removing IP addresses from the block list

- Introduced `block delete` command to remove IPs from the block list.
- Added `UnblockIP` method to support IP removal in the firewall.
- Updated internationalization files for delete command descriptions.
- Enhanced repository with `DeleteByIP` for targeted IP removal.
This commit is contained in:
2026-03-09 21:21:28 +05:00
parent a7e4c7d750
commit 221fdb8d3b
8 changed files with 163 additions and 6 deletions

View File

@@ -36,6 +36,12 @@ func CmdBlock() *cli.Command {
}, },
}, },
}, },
{
Name: "delete",
Usage: i18n.Lang.T("cmd.daemon.block.delete.Usage"),
Description: i18n.Lang.T("cmd.daemon.block.delete.Description"),
Action: cmdBlockDelete,
},
{ {
Name: "clear", Name: "clear",
Usage: i18n.Lang.T("cmd.daemon.block.clear.Usage"), Usage: i18n.Lang.T("cmd.daemon.block.clear.Usage"),
@@ -80,6 +86,37 @@ func cmdBlockAdd(_ context.Context, cmd *cli.Command) error {
return nil return nil
} }
func cmdBlockDelete(_ context.Context, cmd *cli.Command) error {
ip := net.ParseIP(cmd.Args().Get(0))
if ip == nil {
return errors.New("invalid ip address")
}
sock, err := newSocket()
if err != nil {
return errors.New(i18n.Lang.T("daemon is not running"))
}
defer func() {
_ = sock.Close()
}()
result, err := sock.SendCommand("block_delete_ip", map[string]string{
"ip": ip.String(),
})
if err != nil {
return err
}
if result != "ok" {
return errors.New(i18n.Lang.T("cmd.error", map[string]any{
"Error": result,
}))
}
fmt.Println(i18n.Lang.T("block_delete_ip_success"))
return nil
}
func cmdBlockClear(_ context.Context, _ *cli.Command) error { func cmdBlockClear(_ context.Context, _ *cli.Command) error {
sock, err := newSocket() sock, err := newSocket()
if err != nil { if err != nil {

View File

@@ -160,24 +160,43 @@ func (d *daemon) socketCommand(command string, args map[string]string, socket so
if args["ip"] == "" { if args["ip"] == "" {
return socket.Write("ip argument is required") return socket.Write("ip argument is required")
} }
ip := net.ParseIP(args["ip"]) ipAddr := net.ParseIP(args["ip"])
if ip == nil { if ipAddr == nil {
_ = socket.Write("invalid ip address") _ = socket.Write("invalid ip address")
return errors.New("invalid ip address") return errors.New("invalid ip address")
} }
port := args["port"] port := args["port"]
if port != "" { if port != "" {
if err := d.cmdBlockAddIPWithPort(ip, port, args); err != nil { if err := d.cmdBlockAddIPWithPort(ipAddr, port, args); err != nil {
return socket.Write("block add failed: " + err.Error()) _ = socket.Write("block add failed: " + err.Error())
return err
} }
} else { } else {
if err := d.cmdBlockAddIP(ip, args); err != nil { if err := d.cmdBlockAddIP(ipAddr, args); err != nil {
return socket.Write("block add failed: " + err.Error()) _ = socket.Write("block add failed: " + err.Error())
return err
} }
} }
return socket.Write("ok") return socket.Write("ok")
case "block_delete_ip":
if args["ip"] == "" {
return socket.Write("ip argument is required")
}
ipAddr := net.ParseIP(args["ip"])
if ipAddr == nil {
_ = socket.Write("invalid ip address")
return errors.New("invalid ip address")
}
if err := d.firewall.UnblockIP(ipAddr); err != nil {
_ = socket.Write("block delete failed: " + err.Error())
return err
}
return socket.Write("ok")
case "block_clear": case "block_clear":
if err := d.firewall.UnblockAllIPs(); err != nil { if err := d.firewall.UnblockAllIPs(); err != nil {
_ = socket.Write("block clear failed: " + err.Error()) _ = socket.Write("block clear failed: " + err.Error())

View File

@@ -3,6 +3,7 @@ package repository
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"net"
"time" "time"
"git.kor-elf.net/kor-elf-shield/kor-elf-shield/internal/daemon/db/entity" "git.kor-elf.net/kor-elf-shield/kor-elf-shield/internal/daemon/db/entity"
@@ -13,6 +14,7 @@ import (
type BlockingRepository interface { type BlockingRepository interface {
Add(blockedIP entity.Blocking) error Add(blockedIP entity.Blocking) error
List(callback func(entity.Blocking) error) error List(callback func(entity.Blocking) error) error
DeleteByIP(ip net.IP, callback func(entity.Blocking) error) error
DeleteExpired(limit int) (int, error) DeleteExpired(limit int) (int, error)
Clear() error Clear() error
} }
@@ -73,6 +75,44 @@ func (r *blocking) List(callback func(entity.Blocking) error) error {
}) })
} }
func (r *blocking) DeleteByIP(ip net.IP, callback func(entity.Blocking) error) error {
return r.db.Update(func(tx *bbolt.Tx) error {
bucket, err := tx.CreateBucketIfNotExists([]byte(r.bucket))
if err != nil {
return err
}
c := bucket.Cursor()
for k, v := c.First(); k != nil; {
blockedIP := entity.Blocking{}
err := json.Unmarshal(v, &blockedIP)
if err != nil {
return err
}
parsedBlockedIP := net.ParseIP(blockedIP.IP)
if parsedBlockedIP == nil || !parsedBlockedIP.Equal(ip) {
k, v = c.Next()
continue
}
if err := callback(blockedIP); err != nil {
return err
}
nextK, nextV := c.Next()
if err := bucket.Delete(k); err != nil {
return err
}
k = nextK
v = nextV
}
return nil
})
}
func (r *blocking) DeleteExpired(limit int) (int, error) { func (r *blocking) DeleteExpired(limit int) (int, error) {
if limit <= 0 { if limit <= 0 {
return 0, nil return 0, nil

View File

@@ -19,6 +19,7 @@ type API interface {
BlockIP(block BlockIP) (bool, error) BlockIP(block BlockIP) (bool, error)
BlockIPWithPorts(block BlockIPWithPorts) (bool, error) BlockIPWithPorts(block BlockIPWithPorts) (bool, error)
UnblockAllIPs() error UnblockAllIPs() error
UnblockIP(ip net.IP) error
ClearDBData() error ClearDBData() error
} }
@@ -171,6 +172,33 @@ func (b *blocking) BlockIPWithPorts(block BlockIPWithPorts) (bool, error) {
return true, nil return true, nil
} }
func (b *blocking) UnblockIP(ip net.IP) error {
err := b.blockingRepository.DeleteByIP(ip, func(e entity.Blocking) error {
if e.IsPorts() {
l4Ports, err := e.ToL4Ports()
if err != nil {
return err
}
return b.removeIPWithPorts(ip, l4Ports)
}
if err := b.blockListIP.DeleteIP(ip); err != nil {
if strings.Contains(err.Error(), "element does not exist") {
return nil
}
return err
}
return nil
})
if err != nil {
return err
}
return nil
}
func (b *blocking) UnblockAllIPs() error { func (b *blocking) UnblockAllIPs() error {
err := b.blockingRepository.List(func(e entity.Blocking) error { err := b.blockingRepository.List(func(e entity.Blocking) error {
ip := net.ParseIP(e.IP) ip := net.ParseIP(e.IP)
@@ -214,3 +242,16 @@ func (b *blocking) UnblockAllIPs() error {
func (b *blocking) ClearDBData() error { func (b *blocking) ClearDBData() error {
return b.blockingRepository.Clear() return b.blockingRepository.Clear()
} }
func (b *blocking) removeIPWithPorts(ip net.IP, l4Ports []types.L4Port) error {
for _, port := range l4Ports {
if err := b.blockListIPWithPort.DeleteIP(ip, port); err != nil {
if strings.Contains(err.Error(), "element does not exist") ||
strings.Contains(err.Error(), "Error: Could not process rule: No such file or directory") {
continue
}
return err
}
}
return nil
}

View File

@@ -2,6 +2,7 @@ package firewall
import ( import (
"fmt" "fmt"
"net"
"os" "os"
"git.kor-elf.net/kor-elf-shield/kor-elf-shield/internal/daemon/docker_monitor" "git.kor-elf.net/kor-elf-shield/kor-elf-shield/internal/daemon/docker_monitor"
@@ -31,6 +32,9 @@ type API interface {
// UnblockAllIPs Unblock all IP addresses. // UnblockAllIPs Unblock all IP addresses.
UnblockAllIPs() error UnblockAllIPs() error
// UnblockIP Unblock IP address.
UnblockIP(ip net.IP) error
// ClearDBData Clear all data from DB // ClearDBData Clear all data from DB
ClearDBData() error ClearDBData() error
@@ -129,6 +133,10 @@ func (f *firewall) UnblockAllIPs() error {
return f.blockingService.UnblockAllIPs() return f.blockingService.UnblockAllIPs()
} }
func (f *firewall) UnblockIP(ip net.IP) error {
return f.blockingService.UnblockIP(ip)
}
func (f *firewall) ClearDBData() error { func (f *firewall) ClearDBData() error {
return f.blockingService.ClearDBData() return f.blockingService.ClearDBData()
} }

View File

@@ -38,6 +38,10 @@
"cmd.daemon.block.add.FlagUsage.reason": "Reason for blocking.", "cmd.daemon.block.add.FlagUsage.reason": "Reason for blocking.",
"block_add_ip_success": "The IP address has been successfully added to the block list.", "block_add_ip_success": "The IP address has been successfully added to the block list.",
"cmd.daemon.block.delete.Usage": "Remove IP address from block list",
"cmd.daemon.block.delete.Description": "Remove an IP address from the block list. \nExample: \nkor-elf-shield block delete 192.168.1.1",
"block_delete_ip_success": "The IP address has been successfully removed from the block list.",
"Command error": "Command error", "Command error": "Command error",
"invalid log level": "The log level specified in the settings is invalid. It is currently set to: {{.Level}}. Valid values: {{.Levels}}", "invalid log level": "The log level specified in the settings is invalid. It is currently set to: {{.Level}}. Valid values: {{.Levels}}",
"invalid log encoding": "Invalid encoding setting. Currently set to: {{.Encoding}}. Valid values: {{.Encodings}}", "invalid log encoding": "Invalid encoding setting. Currently set to: {{.Encoding}}. Valid values: {{.Encodings}}",

View File

@@ -38,6 +38,10 @@
"cmd.daemon.block.add.FlagUsage.reason": "Блоктау себебі.", "cmd.daemon.block.add.FlagUsage.reason": "Блоктау себебі.",
"block_add_ip_success": "IP мекенжайы блоктау тізіміне сәтті қосылды.", "block_add_ip_success": "IP мекенжайы блоктау тізіміне сәтті қосылды.",
"cmd.daemon.block.delete.Usage": "IP мекенжайын блоктау тізімінен алып тастаңыз",
"cmd.daemon.block.delete.Description": "IP мекенжайын блоктау тізімінен алып тастаңыз. \nМысал: \nkor-elf-shield block delete 192.168.1.1",
"block_delete_ip_success": "IP мекенжайы блоктау тізімінен сәтті жойылды.",
"Command error": "Командалық қате", "Command error": "Командалық қате",
"invalid log level": "Параметрлерде көрсетілген журнал деңгейі жарамсыз. Ол қазір мына күйге орнатылған: {{.Level}}. Жарамды мәндер: {{.Levels}}", "invalid log level": "Параметрлерде көрсетілген журнал деңгейі жарамсыз. Ол қазір мына күйге орнатылған: {{.Level}}. Жарамды мәндер: {{.Levels}}",
"invalid log encoding": "Жарамсыз кодтау параметрі. Қазіргі уақытта орнатылған: {{.Encoding}}. Жарамды мәндер: {{.Encodings}}", "invalid log encoding": "Жарамсыз кодтау параметрі. Қазіргі уақытта орнатылған: {{.Encoding}}. Жарамды мәндер: {{.Encodings}}",

View File

@@ -38,6 +38,10 @@
"cmd.daemon.block.add.FlagUsage.reason": "Причина блокировки.", "cmd.daemon.block.add.FlagUsage.reason": "Причина блокировки.",
"block_add_ip_success": "IP адрес успешно добавлен в список заблокированных.", "block_add_ip_success": "IP адрес успешно добавлен в список заблокированных.",
"cmd.daemon.block.delete.Usage": "Удалить IP адрес из списка заблокированных",
"cmd.daemon.block.delete.Description": "Удалить IP адрес из списка заблокированных. \nПример: \nkor-elf-shield block delete 192.168.1.1",
"block_delete_ip_success": "IP адрес успешно удален из списка заблокированных.",
"Command error": "Ошибка команды", "Command error": "Ошибка команды",
"invalid log level": "В настройках указан не верный уровень log. Сейчас указан: {{.Level}}. Допустимые значения: {{.Levels}}", "invalid log level": "В настройках указан не верный уровень log. Сейчас указан: {{.Level}}. Допустимые значения: {{.Levels}}",
"invalid log encoding": "Неверная настройка encoding. Сейчас указан: {{.Encoding}}. Допустимые значения: {{.Encodings}}", "invalid log encoding": "Неверная настройка encoding. Сейчас указан: {{.Encoding}}. Допустимые значения: {{.Encodings}}",