Documentation
¶
Overview ¶
Package caddy_ipset provides a Caddy HTTP matcher module that matches requests based on client IP addresses against Linux ipset lists.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type IpsetMatcher ¶
type IpsetMatcher struct {
// Ipsets is a list of ipset names to match against
// If the client IP is in ANY of these ipsets, the matcher returns true
Ipsets []string `json:"ipsets,omitempty"`
// contains filtered or unexported fields
}
IpsetMatcher matches the client_ip against Linux ipset lists using native netlink communication. This enables efficient filtering against large, dynamic sets of IPs and CIDR ranges.
Requirements:
- Linux system with `ip_set` kernel module loaded
- CAP_NET_ADMIN capability, grant with: `sudo setcap cap_net_admin+ep /path/to/caddy`
- Existing ipset list, create with the `ipset` command
Supports both IPv4 and IPv6 ipsets, performing validation during initialization. Protocol mismatches (e.g., testing an IPv4 address against an IPv6 set) return false.
If multiple ipsets are configured, the matcher applies OR logic: it returns true if the IP is found in *any* of the provided sets.
Internally, it utilizes a buffered channel to pool netlink handles. This ensures high-performance concurrency while capping idle resources to prevent leaks.
The matcher integrates with Caddy's logging and metrics systems, providing detailed debug logs and Prometheus metrics for monitoring.
Example Caddyfile usage:
```
example.com {
@matcher {
ipset test-ipset-v4
ipset test-ipset-v6
}
handle @matcher {
respond "IP matches an ipset" 200
}
respond "IP does NOT match any of the ipsets" 403
}
```
Extended documentation can be found in [README.md](https://github.com/deovero/caddy-ipset/blob/main/README.md)
func (IpsetMatcher) CaddyModule ¶
func (IpsetMatcher) CaddyModule() caddy.ModuleInfo
CaddyModule returns the Caddy module information. It uses a value receiver (required by Caddy) so it can be called from a pointer.
noinspection GoMixedReceiverTypes
func (*IpsetMatcher) Cleanup ¶ added in v0.3.0
func (m *IpsetMatcher) Cleanup() error
Cleanup closes all netlink handles when the module is unloaded. This method is called by Caddy during graceful shutdown or module reload. It ensures proper cleanup of system resources.
func (*IpsetMatcher) MatchWithError ¶ added in v0.3.0
func (m *IpsetMatcher) MatchWithError(req *http.Request) (bool, error)
MatchWithError implements the caddyhttp.RequestMatcherWithError interface. The client IP is determined using Caddy's built-in detection which respects the trusted_proxies configuration.
IPv4-mapped IPv6 addresses (e.g., ::ffff:192.168.1.1) are treated as IPv4 addresses because `vishvananda/netlink` treats them as IPv4 addresses.
The matching process:
- Extracts the client_ip from the request
- Checks each configured ipsets in order
- For each ipset, checks if the IP family matches (optimization)
- Performs the ipset lookup via netlink
- Returns true if found in ANY ipset (OR logic)
Returns false + error if:
- The client IP is not found in the request context
- There is a problem with the netlink handle
- The client IP cannot be parsed
- An error occurs during ipset lookup
Returns false if:
- The IP is not found in any of the configured ipsets
Returns true if:
- the client's IP address is found in at least one configured ipset.
We don't want to silently ignore errors here because this has security implications.
We ignore context cancellation (e.g., client disconnects) to avoid logging an unnecessary error. It is not that expensive to complete testing the ipsets for a single request.
func (*IpsetMatcher) Provision ¶
func (m *IpsetMatcher) Provision(ctx caddy.Context) error
Provision sets up the matcher by validating the ipset configuration and establishing a persistent netlink connection to the kernel. This method is called by Caddy during module initialization.
It performs the following steps:
- Validates that at least one ipset name is configured
- Checks for CAP_NET_ADMIN capability (fails fast with clear error)
- For each ipset:
- Validates the ipset name format and length
- Verifies the ipset exists and is accessible
- Stores the ipset family (IPv4/IPv6) for optimization
Returns an error if:
- CAP_NET_ADMIN capability is not granted
- An ipset name is empty or too long
- Netlink handle creation fails
- The ipset doesn't exist or cannot be accessed
func (*IpsetMatcher) UnmarshalCaddyfile ¶
func (m *IpsetMatcher) UnmarshalCaddyfile(d *caddyfile.Dispenser) error
UnmarshalCaddyfile implements caddyfile.Unmarshaler. It parses the Caddyfile configuration for the ipset matcher.
Syntax:
```
ipset <name> ipset <name> <name> <name> ...
```
Example:
``` @blocked ipset blocklist-v4 ```
Multiple ipset directives in a matcher block:
```
@matcher {
ipset test-ipset-v4
ipset test-ipset-v6
}
```
This creates a single matcher that tests if the client IP is in ANY of the specified ipsets (OR logic).