Documentation
¶
Overview ¶
Package abuse matches connection destinations against IP-reputation blocklists, so the operator learns that an account is reaching known-bad infrastructure without the panel having to keep everyone's browsing history.
Only matches are ever recorded. That is the whole point: matches are rare, so they cost almost nothing to store and are worth keeping for weeks, whereas the traffic they are drawn from is high-cardinality and is never persisted at all.
Why IP only ¶
This package once matched domains too, against threat/piracy/gambling feeds. That was dropped because a domain can only be matched when the destination reaches the panel AS a domain, and on real traffic it usually does not: clients resolve DNS off the tunnel and encrypt the TLS SNI (ECH), so the access log records a bare IP. Measured on a live server it was 23 IPs to every 4 domains, and those 4 were connectivity checks. Three domain feeds cost ~12 MB of memory and a daily download to match almost nothing, so the destination is now matched as an address or not at all.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var Feeds = []Feed{ {Category: CatBadIP, URLs: []string{ "https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level1.netset", "https://cdn.jsdelivr.net/gh/firehol/blocklist-ipsets@master/firehol_level1.netset", }}, }
Feeds are the lists the panel ships with — IP reputation only, on purpose.
Domain feeds were shipped first and then dropped: a domain can only be matched when the destination reaches the panel AS a domain, and on real traffic it usually does not. Clients resolve DNS off the tunnel and encrypt the TLS SNI (ECH), so the access log records a bare IP; measured on a live server it was 23 IPs to every 4 domains, and those 4 were connectivity checks. Three domain lists cost ~12 MB of memory and a daily download to match almost nothing.
What survives is the one list that sees that traffic. FireHOL level 1 is the high-confidence, low-false-positive aggregate (spamhaus DROP, dshield, feodo/C2 trackers, …) — the tier FireHOL itself marks safe to block outright, curated to exclude CDNs and shared hosting, which is what an advisory abuse view needs.
The operator's own list is IP/CIDR too, for the same reason.
Functions ¶
func ParseCustom ¶
ParseCustom reads the operator's own list: one IP or CIDR per line, '#' comments. Lines that are not addresses (a hostname, a typo) are skipped rather than rejected — the field is free text and a bad line must not void the good ones.
Types ¶
type Category ¶
type Category string
Category is the kind of trouble a destination represents. These are the buckets the UI groups by and the operator reasons about.
The retired domain categories are still listed: rows written before the switch to IP-only carry them, and Title must keep rendering those rows correctly.
const ( // CatCustom is the operator's own list. Checked first so a local entry wins. CatCustom Category = "custom" // CatBadIP is the IP-reputation feed (attack/malware infrastructure) — the only // downloaded list, and the one that sees the bare-IP traffic everything else misses. CatBadIP Category = "badip" // Retired domain categories, kept so historical rows still render. CatMalware Category = "malware" CatPiracy Category = "piracy" CatGambling Category = "gambling" )
type Feed ¶
type Feed struct {
Category Category
// URLs are mirrors, tried in order. GitHub raw is sometimes DPI-degraded in RU,
// so a jsDelivr mirror follows — the same reason package geo carries two.
URLs []string
}
Feed is one downloadable category list.
type FileInfo ¶
type FileInfo struct {
Category string `json:"category"`
Title string `json:"title"`
Enabled bool `json:"enabled"`
Present bool `json:"present"` // a cached feed on disk, or a non-empty custom list
Entries int `json:"entries"` // entries currently loaded in the matcher
Size int64 `json:"size,omitempty"` // cached feed size (feeds only)
Updated int64 `json:"updated,omitempty"` // cached feed mtime (feeds only)
}
FileInfo is one category's state, for the settings UI.
type Matcher ¶
type Matcher struct {
// contains filtered or unexported fields
}
Matcher answers "is this destination on a list, and which one". Safe for concurrent use; reads take a read lock so the access-log path is not serialised against itself, and a feed reload swaps whole sets under the write lock.
A nil *Matcher is valid and matches nothing, so a panel that has never downloaded a feed behaves as if the feature is off rather than crashing the access-log reader.
func New ¶
func New() *Matcher
New returns an empty matcher that matches nothing until a list is set.
func (*Matcher) Clear ¶
Clear removes a category's set, so a disabled category matches nothing until it is loaded again.
func (*Matcher) Counts ¶
Counts reports how many entries each loaded category holds, for the settings UI.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store downloads, caches and loads the feeds into a Matcher.
func (*Store) Configure ¶
Configure applies operator settings — which categories are active and the custom list — and reloads the matcher from cache to match (no network). A disabled category is cleared from the matcher. Called at boot and on every settings save.
func (*Store) LoadCached ¶
func (s *Store) LoadCached()
LoadCached loads the enabled feeds' cached copies plus the custom list, without network. Called at boot so a panel that has run before starts matching immediately rather than being blind until the first download finishes.
func (*Store) Refresh ¶
Refresh downloads any feed whose cache is missing or stale, then reloads it. The operator's own list is never downloaded, only re-read.