Files
abrown38andClaude Opus 5.5 500bfc7bdd Ban lists: where Guard and fail2ban ban addresses
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>
2026-10-22 16:29:37 +01:00

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()
}