From 83a69322fa7a529c238c194cd6215ae3f0c94b2f Mon Sep 17 00:00:00 2001 From: yusing Date: Thu, 18 Sep 2025 17:34:02 +0800 Subject: [PATCH] refactor(server): enhance server start options and support for proxy protocol --- agent/go.mod | 1 + agent/go.sum | 2 + agent/pkg/server/server.go | 2 +- go.mod | 1 + go.sum | 2 + internal/net/gphttp/server/server.go | 88 +++++++++++++++++++++++----- 6 files changed, 80 insertions(+), 16 deletions(-) diff --git a/agent/go.mod b/agent/go.mod index e7cf55d3..44eff438 100644 --- a/agent/go.mod +++ b/agent/go.mod @@ -71,6 +71,7 @@ require ( github.com/opencontainers/image-spec v1.1.1 // indirect github.com/oschwald/maxminddb-golang v1.13.1 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/pires/go-proxyproto v0.8.1 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect diff --git a/agent/go.sum b/agent/go.sum index f6f365bb..ad82ed39 100644 --- a/agent/go.sum +++ b/agent/go.sum @@ -128,6 +128,8 @@ github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5 github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaASJgp0= +github.com/pires/go-proxyproto v0.8.1/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= diff --git a/agent/pkg/server/server.go b/agent/pkg/server/server.go index 4b9e2b72..3ff04278 100644 --- a/agent/pkg/server/server.go +++ b/agent/pkg/server/server.go @@ -39,5 +39,5 @@ func StartAgentServer(parent task.Parent, opt Options) { TLSConfig: tlsConfig, } - server.Start(parent, agentServer, nil, &log.Logger) + server.Start(parent, agentServer, server.WithLogger(&log.Logger)) } diff --git a/go.mod b/go.mod index d652d704..52731b1a 100644 --- a/go.mod +++ b/go.mod @@ -213,6 +213,7 @@ require ( require ( github.com/gin-gonic/gin v1.10.1 + github.com/pires/go-proxyproto v0.8.1 github.com/yusing/ds v0.1.0 ) diff --git a/go.sum b/go.sum index 476f125d..b3880793 100644 --- a/go.sum +++ b/go.sum @@ -1424,6 +1424,8 @@ github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaASJgp0= +github.com/pires/go-proxyproto v0.8.1/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= diff --git a/internal/net/gphttp/server/server.go b/internal/net/gphttp/server/server.go index 5e9a391e..bd02cbcb 100644 --- a/internal/net/gphttp/server/server.go +++ b/internal/net/gphttp/server/server.go @@ -9,6 +9,7 @@ import ( "net/http" "time" + "github.com/pires/go-proxyproto" "github.com/quic-go/quic-go/http3" "github.com/rs/zerolog" "github.com/rs/zerolog/log" @@ -28,6 +29,7 @@ type Server struct { https *http.Server startTime time.Time acl *acl.Config + proxyProto bool l zerolog.Logger } @@ -39,6 +41,8 @@ type Options struct { CertProvider CertProvider Handler http.Handler ACL *acl.Config + + SupportProxyProtocol bool } type httpServer interface { @@ -86,6 +90,7 @@ func NewServer(opt Options) (s *Server) { https: httpsSer, l: logger, acl: opt.ACL, + proxyProto: opt.SupportProxyProtocol, } } @@ -105,7 +110,8 @@ func (s *Server) Start(parent task.Parent) { Handler: s.https.Handler, TLSConfig: http3.ConfigureTLSConfig(s.https.TLSConfig), } - Start(subtask, h3, s.acl, &s.l) + // TODO: support proxy protocol for HTTP/3 + Start(subtask, h3, WithACL(s.acl), WithLogger(&s.l)) if s.http != nil { s.http.Handler = advertiseHTTP3(s.http.Handler, h3) } @@ -113,16 +119,68 @@ func (s *Server) Start(parent task.Parent) { s.https.Handler = advertiseHTTP3(s.https.Handler, h3) } - Start(subtask, s.http, s.acl, &s.l) - Start(subtask, s.https, s.acl, &s.l) + Start(subtask, s.http, WithProxyProtocolSupport(s.proxyProto), WithACL(s.acl), WithLogger(&s.l)) + Start(subtask, s.https, WithProxyProtocolSupport(s.proxyProto), WithACL(s.acl), WithLogger(&s.l)) } -func Start[Server httpServer](parent task.Parent, srv Server, acl *acl.Config, logger *zerolog.Logger) (port int) { +type ServerStartOptions struct { + tcpWrappers []func(l net.Listener) net.Listener + udpWrappers []func(l net.PacketConn) net.PacketConn + logger *zerolog.Logger +} + +type ServerStartOption func(opts *ServerStartOptions) + +func WithTCPWrappers(wrappers ...func(l net.Listener) net.Listener) ServerStartOption { + return func(opts *ServerStartOptions) { + opts.tcpWrappers = wrappers + } +} + +func WithUDPWrappers(wrappers ...func(l net.PacketConn) net.PacketConn) ServerStartOption { + return func(opts *ServerStartOptions) { + opts.udpWrappers = wrappers + } +} + +func WithLogger(logger *zerolog.Logger) ServerStartOption { + return func(opts *ServerStartOptions) { + opts.logger = logger + } +} + +func WithACL(acl *acl.Config) ServerStartOption { + return func(opts *ServerStartOptions) { + if acl == nil { + return + } + opts.tcpWrappers = append(opts.tcpWrappers, acl.WrapTCP) + opts.udpWrappers = append(opts.udpWrappers, acl.WrapUDP) + } +} + +func WithProxyProtocolSupport(value bool) ServerStartOption { + // TODO: HTTP/3 (UDP) support + return func(opts *ServerStartOptions) { + if value { + opts.tcpWrappers = append(opts.tcpWrappers, func(l net.Listener) net.Listener { + return &proxyproto.Listener{Listener: l} + }) + } + } +} + +func Start[Server httpServer](parent task.Parent, srv Server, optFns ...ServerStartOption) (port int) { if srv == nil { return } - setDebugLogger(srv, logger) + var opts ServerStartOptions + for _, optFn := range optFns { + optFn(&opts) + } + + setDebugLogger(srv, opts.logger) proto := proto(srv) task := parent.Subtask(proto, true) @@ -137,40 +195,40 @@ func Start[Server httpServer](parent task.Parent, srv Server, acl *acl.Config, l } l, err := lc.Listen(task.Context(), "tcp", srv.Addr) if err != nil { - HandleError(logger, err, "failed to listen on port") + HandleError(opts.logger, err, "failed to listen on port") return } port = l.Addr().(*net.TCPAddr).Port if srv.TLSConfig != nil { l = tls.NewListener(l, srv.TLSConfig) } - if acl != nil { - l = acl.WrapTCP(l) + for _, wrapper := range opts.tcpWrappers { + l = wrapper(l) } serveFunc = getServeFunc(l, srv.Serve) task.OnCancel("stop", func() { - stop(srv, l, logger) + stop(srv, l, opts.logger) }) case *http3.Server: l, err := lc.ListenPacket(task.Context(), "udp", srv.Addr) if err != nil { - HandleError(logger, err, "failed to listen on port") + HandleError(opts.logger, err, "failed to listen on port") return } port = l.LocalAddr().(*net.UDPAddr).Port - if acl != nil { - l = acl.WrapUDP(l) + for _, wrapper := range opts.udpWrappers { + l = wrapper(l) } serveFunc = getServeFunc(l, srv.Serve) task.OnCancel("stop", func() { - stop(srv, l, logger) + stop(srv, l, opts.logger) }) } - logStarted(srv, logger) + logStarted(srv, opts.logger) go func() { err := convertError(serveFunc()) if err != nil { - HandleError(logger, err, "failed to serve "+proto+" server") + HandleError(opts.logger, err, "failed to serve "+proto+" server") } task.Finish(err) }()