defender: implement logging of events and bans
Signed-off-by: Anthrazz <25553648+Anthrazz@users.noreply.github.com>
This commit is contained in:
parent
d396c24ad4
commit
e187b77f29
4 changed files with 50 additions and 5 deletions
|
@ -103,6 +103,7 @@ The configuration file contains the following sections:
|
|||
- `observation_time`, integer. Defines the time window, in minutes, for tracking client errors. A host is banned if it has exceeded the defined threshold during the last observation time minutes. Default: `30`.
|
||||
- `entries_soft_limit`, integer. Ignored for `provider` driver. Default: `100`.
|
||||
- `entries_hard_limit`, integer. The number of banned IPs and host scores kept in memory will vary between the soft and hard limit for `memory` driver. If you use the `provider` driver, this setting will limit the number of entries to return when you ask for the entire host list from the defender. Default: `150`.
|
||||
- `log_events`, boolean. Set to true if defender events and banned IPs should be logged. Default: `false`.
|
||||
- `rate_limiters`, list of structs containing the rate limiters configuration. Take a look [here](./rate-limiting.md) for more details. Each struct has the following fields:
|
||||
- `average`, integer. Average defines the maximum rate allowed. 0 means disabled. Default: 0
|
||||
- `period`, integer. Period defines the period as milliseconds. The rate is actually defined by dividing average by period Default: 1000 (1 second).
|
||||
|
|
|
@ -19,17 +19,18 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/drakkan/sftpgo/v2/internal/dataprovider"
|
||||
"github.com/drakkan/sftpgo/v2/internal/logger"
|
||||
)
|
||||
|
||||
// HostEvent is the enumerable for the supported host events
|
||||
type HostEvent int
|
||||
type HostEvent string
|
||||
|
||||
// Supported host events
|
||||
const (
|
||||
HostEventLoginFailed HostEvent = iota
|
||||
HostEventUserNotFound
|
||||
HostEventNoLoginTried
|
||||
HostEventLimitExceeded
|
||||
HostEventLoginFailed HostEvent = "LoginFailed"
|
||||
HostEventUserNotFound = "UserNotFound"
|
||||
HostEventNoLoginTried = "NoLoginTried"
|
||||
HostEventLimitExceeded = "LimitExceeded"
|
||||
)
|
||||
|
||||
// Supported defender drivers
|
||||
|
@ -89,6 +90,8 @@ type DefenderConfig struct {
|
|||
// to return when you request for the entire host list from the defender
|
||||
EntriesSoftLimit int `json:"entries_soft_limit" mapstructure:"entries_soft_limit"`
|
||||
EntriesHardLimit int `json:"entries_hard_limit" mapstructure:"entries_hard_limit"`
|
||||
// LogEvents controls if Defender events should be logged
|
||||
LogEvents bool `json:"log_events" mapstructure:"log_events"`
|
||||
}
|
||||
|
||||
type baseDefender struct {
|
||||
|
@ -132,6 +135,42 @@ func (d *baseDefender) getScore(event HostEvent) int {
|
|||
return score
|
||||
}
|
||||
|
||||
func (d *baseDefender) logEvent(ip, protocol string, event HostEvent, totalScore int) {
|
||||
if !d.config.LogEvents {
|
||||
return
|
||||
}
|
||||
|
||||
// ignore events which do not change the host score
|
||||
eventScore := d.getScore(event)
|
||||
if eventScore == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
logger.GetLogger().Info().
|
||||
Timestamp().
|
||||
Str("sender", "defender").
|
||||
Str("client_ip", ip).
|
||||
Str("protocol", protocol).
|
||||
Str("event", string(event)).
|
||||
Int("increase_score_by", eventScore).
|
||||
Int("score", totalScore).
|
||||
Send()
|
||||
}
|
||||
|
||||
func (d *baseDefender) logBan(ip, protocol string) {
|
||||
if !d.config.LogEvents {
|
||||
return
|
||||
}
|
||||
|
||||
logger.GetLogger().Info().
|
||||
Timestamp().
|
||||
Str("sender", "defender").
|
||||
Str("client_ip", ip).
|
||||
Str("protocol", protocol).
|
||||
Str("event", "banned").
|
||||
Send()
|
||||
}
|
||||
|
||||
type hostEvent struct {
|
||||
dateTime time.Time
|
||||
score int
|
||||
|
|
|
@ -100,7 +100,9 @@ func (d *dbDefender) AddEvent(ip, protocol string, event HostEvent) {
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
d.baseDefender.logEvent(ip, protocol, event, host.Score)
|
||||
if host.Score > d.config.Threshold {
|
||||
d.baseDefender.logBan(ip, protocol)
|
||||
banTime := time.Now().Add(time.Duration(d.config.BanTime) * time.Minute)
|
||||
err = dataprovider.SetDefenderBanTime(ip, util.GetTimeAsMsSinceEpoch(banTime))
|
||||
if err == nil {
|
||||
|
|
|
@ -206,9 +206,11 @@ func (d *memoryDefender) AddEvent(ip, protocol string, event HostEvent) {
|
|||
idx++
|
||||
}
|
||||
}
|
||||
d.baseDefender.logEvent(ip, protocol, event, hs.TotalScore)
|
||||
|
||||
hs.Events = hs.Events[:idx]
|
||||
if hs.TotalScore >= d.config.Threshold {
|
||||
d.baseDefender.logBan(ip, protocol)
|
||||
d.banned[ip] = time.Now().Add(time.Duration(d.config.BanTime) * time.Minute)
|
||||
delete(d.hosts, ip)
|
||||
d.cleanupBanned()
|
||||
|
@ -222,6 +224,7 @@ func (d *memoryDefender) AddEvent(ip, protocol string, event HostEvent) {
|
|||
d.hosts[ip] = hs
|
||||
}
|
||||
} else {
|
||||
d.baseDefender.logEvent(ip, protocol, event, ev.score)
|
||||
d.hosts[ip] = hostScore{
|
||||
TotalScore: ev.score,
|
||||
Events: []hostEvent{ev},
|
||||
|
|
Loading…
Add table
Reference in a new issue