proxyproto: add UDP session tracking for Spectrum PPv2 (#7967)

This commit is contained in:
Minghang Chen
2026-03-28 15:06:36 -07:00
committed by GitHub
parent 12d9457e71
commit 34acf8353f
10 changed files with 398 additions and 19 deletions

View File

@@ -73,6 +73,22 @@ type Config struct {
// If nil, PROXY protocol is disabled.
ProxyProtoConnPolicy proxyproto.ConnPolicyFunc
// ProxyProtoUDPSessionTrackingTTL enables per-UDP-session source address
// caching on the PacketConn listener when set to a positive duration.
// The first datagram of a Cloudflare Spectrum PPv2 session (which contains
// only the PROXY Protocol header and no DNS payload) is used to populate a
// short-lived cache keyed by the Spectrum-side remote address. Subsequent
// datagrams from the same remote address that carry no PROXY Protocol header
// are associated with the cached real client address for up to this duration
// (refreshed on each matching packet). A zero or negative value disables
// session tracking. Has no effect unless ProxyProtoConnPolicy is also set.
ProxyProtoUDPSessionTrackingTTL time.Duration
// ProxyProtoUDPSessionTrackingMaxSessions is the maximum number of concurrent
// UDP sessions held in the LRU cache. Zero means use the default (udpSessionMaxEntries).
// Has no effect unless ProxyProtoUDPSessionTrackingTTL is positive.
ProxyProtoUDPSessionTrackingMaxSessions int
// MaxGRPCStreams defines the maximum number of concurrent streams per gRPC connection.
// This is nil if not specified, allowing for a default to be used.
MaxGRPCStreams *int

View File

@@ -39,7 +39,9 @@ type Server struct {
ReadTimeout time.Duration // Read timeout for TCP
WriteTimeout time.Duration // Write timeout for TCP
connPolicy proxyproto.ConnPolicyFunc // Proxy Protocol connection policy function
connPolicy proxyproto.ConnPolicyFunc // Proxy Protocol connection policy function
udpSessionTrackingTTL time.Duration // TTL for UDP PPv2 session tracking (0 = disabled)
udpSessionTrackingMaxSessions int // LRU cap for UDP session tracking (0 = default)
server [2]*dns.Server // 0 is a net.Listener, 1 is a net.PacketConn (a *UDPConn) in our case.
m sync.Mutex // protects the servers
@@ -130,6 +132,12 @@ func NewServer(addr string, group []*Config) (*Server, error) {
if site.ProxyProtoConnPolicy != nil {
s.connPolicy = site.ProxyProtoConnPolicy
}
if site.ProxyProtoUDPSessionTrackingTTL > 0 {
s.udpSessionTrackingTTL = site.ProxyProtoUDPSessionTrackingTTL
}
if site.ProxyProtoUDPSessionTrackingMaxSessions > 0 {
s.udpSessionTrackingMaxSessions = site.ProxyProtoUDPSessionTrackingMaxSessions
}
}
if !s.debug {
@@ -206,7 +214,7 @@ func (s *Server) ListenPacket() (net.PacketConn, error) {
return nil, err
}
if s.connPolicy != nil {
p = &cproxyproto.PacketConn{PacketConn: p, ConnPolicy: s.connPolicy}
p = &cproxyproto.PacketConn{PacketConn: p, ConnPolicy: s.connPolicy, UDPSessionTrackingTTL: s.udpSessionTrackingTTL, UDPSessionTrackingMaxSessions: s.udpSessionTrackingMaxSessions}
}
return p, nil
}