diff options
author | Matthew Holt <[email protected]> | 2022-09-30 13:29:33 -0600 |
---|---|---|
committer | Matthew Holt <[email protected]> | 2022-09-30 13:29:33 -0600 |
commit | 9873ff9918224f56604048ea0ed3d3ae3953939e (patch) | |
tree | cde9d321ddd60339e8cf1e9872072f75d537e3f6 /modules/caddyhttp/replacer.go | |
parent | 5e52bbb1369b7444700427539e4dd532ed13ac6d (diff) | |
download | caddy-9873ff9918224f56604048ea0ed3d3ae3953939e.tar.gz caddy-9873ff9918224f56604048ea0ed3d3ae3953939e.zip |
caddyhttp: Remote IP prefix placeholders
See https://github.com/mholt/caddy-ratelimit/issues/12
Diffstat (limited to 'modules/caddyhttp/replacer.go')
-rw-r--r-- | modules/caddyhttp/replacer.go | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/modules/caddyhttp/replacer.go b/modules/caddyhttp/replacer.go index e15464997..9ea5f7729 100644 --- a/modules/caddyhttp/replacer.go +++ b/modules/caddyhttp/replacer.go @@ -31,6 +31,7 @@ import ( "io" "net" "net/http" + "net/netip" "net/textproto" "net/url" "path" @@ -196,6 +197,37 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo return or.URL.RawQuery, true } + // remote IP range/prefix (e.g. keep top 24 bits of 1.2.3.4 => "1.2.3.0/24") + // syntax: "/V4,V6" where V4 = IPv4 bits, and V6 = IPv6 bits; if no comma, then same bit length used for both + // (EXPERIMENTAL) + if strings.HasPrefix(key, "http.request.remote.host/") { + host, _, err := net.SplitHostPort(req.RemoteAddr) + if err != nil { + host = req.RemoteAddr // assume no port, I guess? + } + addr, err := netip.ParseAddr(host) + if err != nil { + return host, true // not an IP address + } + // extract the bits from the end of the placeholder (start after "/") then split on "," + bitsBoth := key[strings.Index(key, "/")+1:] + ipv4BitsStr, ipv6BitsStr, cutOK := strings.Cut(bitsBoth, ",") + bitsStr := ipv4BitsStr + if addr.Is6() && cutOK { + bitsStr = ipv6BitsStr + } + // convert to integer then compute prefix + bits, err := strconv.Atoi(bitsStr) + if err != nil { + return "", true + } + prefix, err := addr.Prefix(bits) + if err != nil { + return "", true + } + return prefix.String(), true + } + // hostname labels if strings.HasPrefix(key, reqHostLabelsReplPrefix) { idxStr := key[len(reqHostLabelsReplPrefix):] |