mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-07-18 16:59:53 +00:00
56 lines
1.9 KiB
Go
56 lines
1.9 KiB
Go
package bootstrap
|
|
|
|
import (
|
|
"fmt"
|
|
"log/slog"
|
|
"net"
|
|
"time"
|
|
|
|
"github.com/pires/go-proxyproto"
|
|
)
|
|
|
|
const proxyProtocolReadHeaderTimeout = 5 * time.Second
|
|
|
|
func newProxyProtocolListener(listener net.Listener, trustedProxies []string) (net.Listener, error) {
|
|
if len(trustedProxies) == 0 {
|
|
return listener, nil
|
|
}
|
|
|
|
// PROXY protocol transports client metadata on TCP connections before any TLS handshake
|
|
network := listener.Addr().Network()
|
|
if network != "tcp" && network != "tcp4" && network != "tcp6" {
|
|
return nil, fmt.Errorf("PROXY protocol requires a TCP listener, got %q", network)
|
|
}
|
|
|
|
// Require headers from configured network proxies and reject every other network peer
|
|
trustedProxyPolicy, err := proxyproto.TrustProxyHeaderFromRanges(trustedProxies)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to configure PROXY protocol trusted proxies: %w", err)
|
|
}
|
|
|
|
// We need to add another policy for loopback connections because healthcheck requests are made from the same host
|
|
// loopbackPolicy handles requests from trusted loopback like normal, but it also allows untrusted loopback connections to be accepted
|
|
// untrusted loopback connections aren't allowed to send PROXY headers though
|
|
loopbackPolicy, err := proxyproto.PolicyFromRanges(trustedProxies, proxyproto.USE, proxyproto.SKIP)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to configure PROXY protocol loopback proxies: %w", err)
|
|
}
|
|
|
|
// Create a policy which decides which of the two policies to use based on the upstream address
|
|
policy := func(options proxyproto.ConnPolicyOptions) (proxyproto.Policy, error) {
|
|
upstream, ok := options.Upstream.(*net.TCPAddr)
|
|
if ok && upstream.IP.IsLoopback() {
|
|
return loopbackPolicy(options)
|
|
}
|
|
|
|
return trustedProxyPolicy(options)
|
|
}
|
|
|
|
slog.Info("PROXY protocol enabled")
|
|
return &proxyproto.Listener{
|
|
Listener: listener,
|
|
ConnPolicy: policy,
|
|
ReadHeaderTimeout: proxyProtocolReadHeaderTimeout,
|
|
}, nil
|
|
}
|