Add blocking package for IP blocking management
- Introduced `blocking` implementation with methods for managing blocked IPs. - Added `NftReload` for reloading block lists into the firewall. - Created `BlockIP` to block specific IPs with expiration and logging support. - Implemented `ClearDBData` for clearing database blocking entries.
This commit is contained in:
116
internal/daemon/firewall/blocking/blocking.go
Normal file
116
internal/daemon/firewall/blocking/blocking.go
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
package blocking
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"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/repository"
|
||||||
|
"git.kor-elf.net/kor-elf-shield/kor-elf-shield/internal/daemon/firewall/chain/block"
|
||||||
|
"git.kor-elf.net/kor-elf-shield/kor-elf-shield/internal/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type API interface {
|
||||||
|
NftReload(blockListIP block.ListIP) error
|
||||||
|
BlockIP(blockIP BlockIP) (bool, error)
|
||||||
|
ClearDBData() error
|
||||||
|
}
|
||||||
|
|
||||||
|
type blocking struct {
|
||||||
|
blockingRepository repository.BlockingRepository
|
||||||
|
blockListIP block.ListIP
|
||||||
|
logger log.Logger
|
||||||
|
|
||||||
|
mu sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
type BlockIP struct {
|
||||||
|
IP net.IP
|
||||||
|
TimeSeconds uint32
|
||||||
|
Reason string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(blockingRepository repository.BlockingRepository, logger log.Logger) API {
|
||||||
|
return &blocking{
|
||||||
|
blockingRepository: blockingRepository,
|
||||||
|
logger: logger,
|
||||||
|
mu: sync.Mutex{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *blocking) NftReload(blockListIP block.ListIP) error {
|
||||||
|
b.mu.Lock()
|
||||||
|
b.blockListIP = blockListIP
|
||||||
|
b.mu.Unlock()
|
||||||
|
|
||||||
|
isExpiredEntries := false
|
||||||
|
nowUnix := time.Now().Unix()
|
||||||
|
err := b.blockingRepository.List(func(e entity.Blocking) error {
|
||||||
|
ip := net.ParseIP(e.IP)
|
||||||
|
if ip == nil {
|
||||||
|
b.logger.Error(fmt.Sprintf("Failed to parse IP address: %s", e.IP))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
banSeconds := uint32(0)
|
||||||
|
if e.ExpireAtUnix > 0 {
|
||||||
|
if e.ExpireAtUnix < nowUnix {
|
||||||
|
isExpiredEntries = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
banSeconds = uint32(e.ExpireAtUnix - nowUnix)
|
||||||
|
fmt.Printf("Now %s ExpireAtUnix %d banSeconds %d\n", time.Now().Format(time.RFC3339), e.ExpireAtUnix, banSeconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := b.blockListIP.AddIP(ip, banSeconds); err != nil {
|
||||||
|
b.logger.Error(fmt.Sprintf("Failed to add IP %s to block list: %s", ip.String(), err))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if isExpiredEntries {
|
||||||
|
go func() {
|
||||||
|
deleteCount, err := b.blockingRepository.DeleteExpired(100)
|
||||||
|
if err != nil {
|
||||||
|
b.logger.Error(fmt.Sprintf("Failed to delete expired entries from database: %s", err))
|
||||||
|
}
|
||||||
|
b.logger.Debug(fmt.Sprintf("Deleted %d expired entries from database", deleteCount))
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *blocking) BlockIP(blockIP BlockIP) (bool, error) {
|
||||||
|
if blockIP.IP.IsLoopback() {
|
||||||
|
return false, fmt.Errorf("loopback IP address %s cannot be blocked", blockIP.IP.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := b.blockListIP.AddIP(blockIP.IP, blockIP.TimeSeconds); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
expireAtUnix := int64(0)
|
||||||
|
if blockIP.TimeSeconds > 0 {
|
||||||
|
expire := time.Now().Add(time.Duration(int64(blockIP.TimeSeconds)) * time.Second)
|
||||||
|
expireAtUnix = expire.Unix()
|
||||||
|
}
|
||||||
|
data := entity.Blocking{
|
||||||
|
IP: blockIP.IP.String(),
|
||||||
|
ExpireAtUnix: expireAtUnix,
|
||||||
|
Reason: blockIP.Reason,
|
||||||
|
}
|
||||||
|
if err := b.blockingRepository.Add(data); err != nil {
|
||||||
|
return true, fmt.Errorf("the IP is blocked, but not recorded in the database. Failed to add IP %s to database: %w", blockIP.IP.String(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *blocking) ClearDBData() error {
|
||||||
|
return b.blockingRepository.Clear()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user