A program bans an address (every port, or a protocol's ports) for a time; the ban list says what it is kept from: the firewall, some hosts behind it, or everything. Bans drop ahead of every rule, close the address's connections, group IPv6 by /64, are kept in the database across restarts and audited. Never banned: the inside, the firewall's own addresses, the caller, the list's never. bans grant (bans:write:LIST), hc banlist/bans/ban/unban, Traffic -> Bans, a fail2ban action in contrib/, and failed logins and refused tokens logged for Guard and fail2ban. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
54 lines
1.6 KiB
Go
54 lines
1.6 KiB
Go
package model
|
|
|
|
import (
|
|
"net/netip"
|
|
"time"
|
|
)
|
|
|
|
// Ban is an address a ban list keeps out (docs/bans.md): of every port,
|
|
// or of one protocol and port. Bans are kept apart from the
|
|
// configuration, like a dynamic set's entries: not in the history, and
|
|
// not on probation.
|
|
type Ban struct {
|
|
ID int64 `json:"id"`
|
|
ListID int64 `json:"list_id"`
|
|
List string `json:"list"`
|
|
// Address is what is banned: an address, or an IPv6 prefix of the
|
|
// list's grouping ("2001:db8:1:2::/64").
|
|
Address string `json:"address"`
|
|
Protocol string `json:"protocol,omitempty"` // tcp or udp; "" every port
|
|
Port int `json:"port,omitempty"`
|
|
// Expires is when the ban ends (nil: it doesn't); Timeout the
|
|
// seconds it has left then.
|
|
Expires *time.Time `json:"expires,omitempty"`
|
|
Timeout int `json:"timeout,omitempty"`
|
|
Created time.Time `json:"created"`
|
|
// Who banned it (the user or token's name), Source the program's own
|
|
// name for why ("guard/ssh", "fail2ban/sshd"), Reason free text (a
|
|
// log line).
|
|
Who string `json:"who"`
|
|
Source string `json:"source,omitempty"`
|
|
Reason string `json:"reason,omitempty"`
|
|
}
|
|
|
|
// Prefix is the banned address as a prefix.
|
|
func (b *Ban) Prefix() (netip.Prefix, error) {
|
|
if p, err := netip.ParsePrefix(b.Address); err == nil {
|
|
return p, nil
|
|
}
|
|
a, err := netip.ParseAddr(b.Address)
|
|
if err != nil {
|
|
return netip.Prefix{}, err
|
|
}
|
|
return netip.PrefixFrom(a, a.BitLen()), nil
|
|
}
|
|
|
|
// BanAddress writes a banned prefix: an address alone when it is one
|
|
// address, else the prefix.
|
|
func BanAddress(p netip.Prefix) string {
|
|
if p.IsSingleIP() {
|
|
return p.Addr().String()
|
|
}
|
|
return p.String()
|
|
}
|