Files
common/xff/fastlyxff/xff.go
Ask Bjørn Hansen 1b9e566892 refactor(xff): split into generic, echo, and fastly packages
Extract generic trusted proxy handling into xff/ (stdlib only),
Echo framework adapter into xff/echo/, and slim xff/fastlyxff/
down to Fastly JSON loading.

Key changes:
- xff/ uses netip.Prefix for efficient IP matching
- Fix XFF extraction to walk right-to-left per MDN spec
- Remove echo dependency from core xff package
- fastlyxff.New() now returns *xff.TrustedProxies
2026-03-21 18:41:28 -07:00

54 lines
1.3 KiB
Go

// Package fastlyxff loads Fastly CDN IP ranges and returns a generic
// [xff.TrustedProxies] for trusted proxy handling.
//
// Fastly publishes their edge server IP ranges in a JSON format:
//
// {
// "addresses": ["23.235.32.0/20", "43.249.72.0/22", ...],
// "ipv6_addresses": ["2a04:4e40::/32", "2a04:4e42::/32", ...]
// }
//
// # Usage
//
// tp, err := fastlyxff.New("fastly.json")
// if err != nil {
// return err
// }
// // Use tp.HTTPMiddleware(), tp.ExtractRealIP(r), etc.
// // For Echo framework, use the xff/echo package:
// // opts, err := xffecho.TrustOptions(tp)
package fastlyxff
import (
"encoding/json"
"os"
"go.ntppool.org/common/xff"
)
// fastlyIPRanges matches the JSON format published by Fastly for their
// edge server IP ranges.
type fastlyIPRanges struct {
IPv4 []string `json:"addresses"`
IPv6 []string `json:"ipv6_addresses"`
}
// New loads Fastly IP ranges from a JSON file and returns a [xff.TrustedProxies].
func New(fileName string) (*xff.TrustedProxies, error) {
b, err := os.ReadFile(fileName)
if err != nil {
return nil, err
}
var ranges fastlyIPRanges
if err := json.Unmarshal(b, &ranges); err != nil {
return nil, err
}
cidrs := make([]string, 0, len(ranges.IPv4)+len(ranges.IPv6))
cidrs = append(cidrs, ranges.IPv4...)
cidrs = append(cidrs, ranges.IPv6...)
return xff.NewFromCIDRs(cidrs)
}