diff --git a/ekko/ekko.go b/ekko/ekko.go index 623a0b8..d3381f2 100644 --- a/ekko/ekko.go +++ b/ekko/ekko.go @@ -163,6 +163,7 @@ func (ek *Ekko) setup(ctx context.Context) (*echo.Echo, error) { echo.TrustLinkLocal(false), echo.TrustPrivateNet(true), } + trustOptions = append(trustOptions, ek.extraTrustOptions...) e.IPExtractor = echo.ExtractIPFromXFFHeader(trustOptions...) if ek.otelmiddleware == nil { diff --git a/ekko/options.go b/ekko/options.go index 82a83e3..45ff13d 100644 --- a/ekko/options.go +++ b/ekko/options.go @@ -13,13 +13,14 @@ import ( // It encapsulates server configuration, middleware options, and lifecycle management // for NTP Pool web services. Use New() with functional options to configure. type Ekko struct { - name string - prom prometheus.Registerer - port int - routeFn func(e *echo.Echo) error - logFilters []slogecho.Filter - otelmiddleware echo.MiddlewareFunc - gzipConfig *middleware.GzipConfig + name string + prom prometheus.Registerer + port int + routeFn func(e *echo.Echo) error + logFilters []slogecho.Filter + otelmiddleware echo.MiddlewareFunc + gzipConfig *middleware.GzipConfig + extraTrustOptions []echo.TrustOption writeTimeout time.Duration readHeaderTimeout time.Duration @@ -92,6 +93,16 @@ func WithReadHeaderTimeout(t time.Duration) func(*Ekko) { } } +// WithTrustOptions appends additional trust options to the default IP extraction +// configuration. These options are applied after the built-in trust settings +// (loopback trusted, link-local untrusted, private networks trusted) when +// extracting client IPs from the X-Forwarded-For header. +func WithTrustOptions(opts ...echo.TrustOption) func(*Ekko) { + return func(ek *Ekko) { + ek.extraTrustOptions = append(ek.extraTrustOptions, opts...) + } +} + // WithGzipConfig provides custom gzip compression configuration. // By default, gzip compression is enabled with standard settings. // Use this option to customize compression level, skip patterns, or disable compression.