From afcf4a525259b4efc031fe21ed80287f3a0ea584 Mon Sep 17 00:00:00 2001 From: ginuerzh Date: Tue, 15 Jul 2025 19:59:10 +0800 Subject: [PATCH] parse real client IP --- connector/socks/v5/conn.go | 22 +++++++++---------- connector/socks/v5/connector.go | 9 ++++---- connector/socks/v5/metadata.go | 11 +--------- handler/http/handler.go | 5 +++++ handler/http/metadata.go | 5 ++++- handler/socks/v5/bind.go | 3 +++ handler/socks/v5/mbind.go | 3 +++ handler/socks/v5/metadata.go | 2 ++ handler/socks/v5/udp.go | 28 ++++++++++++++--------- handler/tunnel/handler.go | 10 +++++++++ internal/util/wt/conn.go | 17 ++++++++++++-- limiter/traffic/wrapper/conn.go | 7 ++++++ listener/grpc/server.go | 39 +++++++++++++++++++++++++++++++++ listener/http2/conn.go | 17 +++++++++----- listener/http2/h2/conn.go | 5 +++++ listener/http2/h2/listener.go | 8 +++++++ listener/http2/listener.go | 6 +++++ listener/http3/conn.go | 16 ++++++++------ listener/http3/listener.go | 6 +++++ listener/http3/wt/listener.go | 18 ++++++++++++--- listener/mws/listener.go | 30 ++++++++++++++++++++----- listener/ws/listener.go | 25 ++++++++++----------- metrics/wrapper/conn.go | 7 ++++++ observer/stats/wrapper/conn.go | 7 ++++++ 24 files changed, 232 insertions(+), 74 deletions(-) diff --git a/connector/socks/v5/conn.go b/connector/socks/v5/conn.go index 933a1f23..c5562d82 100644 --- a/connector/socks/v5/conn.go +++ b/connector/socks/v5/conn.go @@ -2,10 +2,10 @@ package v5 import ( "bytes" + "math" "net" "time" - "github.com/go-gost/core/common/bufpool" "github.com/go-gost/core/logger" "github.com/go-gost/gosocks5" ) @@ -25,18 +25,17 @@ func (c *bindConn) RemoteAddr() net.Addr { } type udpRelayConn struct { - udpConn *net.UDPConn - tcpConn net.Conn - taddr net.Addr - bufferSize int - logger logger.Logger + udpConn *net.UDPConn + tcpConn net.Conn + taddr net.Addr + rbuf [math.MaxUint16]byte + wbuf [math.MaxInt16]byte + logger logger.Logger } func (c *udpRelayConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) { - buf := bufpool.Get(c.bufferSize) - defer bufpool.Put(buf) - - nn, err := c.udpConn.Read(buf) + buf := c.rbuf[:] + nn, err := c.udpConn.Read(buf[:]) if err != nil { return } @@ -82,8 +81,7 @@ func (c *udpRelayConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { Data: b, } - buf := bufpool.Get(c.bufferSize) - defer bufpool.Put(buf) + buf := c.wbuf[:] nn, err := dgram.WriteTo(bytes.NewBuffer(buf[:0])) if err != nil { diff --git a/connector/socks/v5/connector.go b/connector/socks/v5/connector.go index 4d09591a..5975a316 100644 --- a/connector/socks/v5/connector.go +++ b/connector/socks/v5/connector.go @@ -225,10 +225,9 @@ func (c *socks5Connector) relayUDP(ctx context.Context, conn net.Conn, addr net. } return &udpRelayConn{ - udpConn: cc.(*net.UDPConn), - tcpConn: conn, - taddr: addr, - bufferSize: c.md.udpBufferSize, - logger: log, + udpConn: cc.(*net.UDPConn), + tcpConn: conn, + taddr: addr, + logger: log, }, nil } diff --git a/connector/socks/v5/metadata.go b/connector/socks/v5/metadata.go index c73a69d9..50556347 100644 --- a/connector/socks/v5/metadata.go +++ b/connector/socks/v5/metadata.go @@ -4,19 +4,14 @@ import ( "time" mdata "github.com/go-gost/core/metadata" - mdutil "github.com/go-gost/x/metadata/util" "github.com/go-gost/x/internal/util/mux" -) - -const ( - defaultUDPBufferSize = 4096 + mdutil "github.com/go-gost/x/metadata/util" ) type metadata struct { connectTimeout time.Duration noTLS bool relay string - udpBufferSize int udpTimeout time.Duration muxCfg *mux.Config } @@ -25,10 +20,6 @@ func (c *socks5Connector) parseMetadata(md mdata.Metadata) (err error) { c.md.connectTimeout = mdutil.GetDuration(md, "timeout") c.md.noTLS = mdutil.GetBool(md, "notls") c.md.relay = mdutil.GetString(md, "relay") - c.md.udpBufferSize = mdutil.GetInt(md, "udp.bufferSize", "udpBufferSize") - if c.md.udpBufferSize <= 0 { - c.md.udpBufferSize = defaultUDPBufferSize - } c.md.udpTimeout = mdutil.GetDuration(md, "udp.timeout") c.md.muxCfg = &mux.Config{ diff --git a/handler/http/handler.go b/handler/http/handler.go index 9a074041..bdcfc72c 100644 --- a/handler/http/handler.go +++ b/handler/http/handler.go @@ -665,6 +665,11 @@ func (h *httpHandler) dial(ctx context.Context, network, addr string) (conn net. conn, err = h.options.Router.Dial(ctxvalue.ContextWithBuffer(ctx, &buf), network, addr) if ro := ctx_internal.RecorderObjectFromContext(ctx); ro != nil { ro.Route = buf.String() + + if conn != nil { + ro.Src = conn.LocalAddr().String() + ro.Dst = conn.RemoteAddr().String() + } } return diff --git a/handler/http/metadata.go b/handler/http/metadata.go index d1ed5654..e704e07d 100644 --- a/handler/http/metadata.go +++ b/handler/http/metadata.go @@ -49,9 +49,12 @@ type metadata struct { func (h *httpHandler) parseMetadata(md mdata.Metadata) error { h.md.readTimeout = mdutil.GetDuration(md, "readTimeout") - if h.md.readTimeout <= 0 { + if h.md.readTimeout == 0 { h.md.readTimeout = 15 * time.Second } + if h.md.readTimeout < 0 { + h.md.readTimeout = 0 + } if m := mdutil.GetStringMapString(md, "http.header", "header"); len(m) > 0 { hd := http.Header{} diff --git a/handler/socks/v5/bind.go b/handler/socks/v5/bind.go index b22cea84..d4d610a3 100644 --- a/handler/socks/v5/bind.go +++ b/handler/socks/v5/bind.go @@ -87,6 +87,9 @@ func (h *socks5Handler) bindLocal(ctx context.Context, conn net.Conn, network, a // Issue: may not reachable when host has multi-interface socksAddr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String()) + if h.md.publicAddr != "" { + socksAddr.Host = h.md.publicAddr + } socksAddr.Type = 0 reply := gosocks5.NewReply(gosocks5.Succeeded, &socksAddr) log.Trace(reply) diff --git a/handler/socks/v5/mbind.go b/handler/socks/v5/mbind.go index b3c56489..6492787b 100644 --- a/handler/socks/v5/mbind.go +++ b/handler/socks/v5/mbind.go @@ -88,6 +88,9 @@ func (h *socks5Handler) muxBindLocal(ctx context.Context, conn net.Conn, network // Issue: may not reachable when host has multi-interface socksAddr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String()) + if h.md.publicAddr != "" { + socksAddr.Host = h.md.publicAddr + } socksAddr.Type = 0 reply := gosocks5.NewReply(gosocks5.Succeeded, &socksAddr) log.Trace(reply) diff --git a/handler/socks/v5/metadata.go b/handler/socks/v5/metadata.go index a8c264ef..34b6d994 100644 --- a/handler/socks/v5/metadata.go +++ b/handler/socks/v5/metadata.go @@ -14,6 +14,7 @@ import ( ) type metadata struct { + publicAddr string readTimeout time.Duration noTLS bool enableBind bool @@ -40,6 +41,7 @@ type metadata struct { } func (h *socks5Handler) parseMetadata(md mdata.Metadata) (err error) { + h.md.publicAddr = mdutil.GetString(md, "socks.publicAddr", "publicAddr") h.md.readTimeout = mdutil.GetDuration(md, "readTimeout") if h.md.readTimeout <= 0 { h.md.readTimeout = 15 * time.Second diff --git a/handler/socks/v5/udp.go b/handler/socks/v5/udp.go index 0bff79ad..d46d058f 100644 --- a/handler/socks/v5/udp.go +++ b/handler/socks/v5/udp.go @@ -17,6 +17,7 @@ import ( "github.com/go-gost/x/internal/net/udp" "github.com/go-gost/x/internal/util/socks" traffic_wrapper "github.com/go-gost/x/limiter/traffic/wrapper" + metrics "github.com/go-gost/x/metrics/wrapper" xstats "github.com/go-gost/x/observer/stats" stats_wrapper "github.com/go-gost/x/observer/stats/wrapper" xrecorder "github.com/go-gost/x/recorder" @@ -37,8 +38,8 @@ func (h *socks5Handler) handleUDP(ctx context.Context, conn net.Conn, ro *xrecor lc := xnet.ListenConfig{ Netns: h.options.Netns, } - laddr := &net.UDPAddr{IP: conn.LocalAddr().(*net.TCPAddr).IP, Port: 0} // use out-going interface's IP - cc, err := lc.ListenPacket(ctx, "udp", laddr.String()) + + cc, err := lc.ListenPacket(ctx, "udp", "") if err != nil { log.Error(err) reply := gosocks5.NewReply(gosocks5.Failure, nil) @@ -56,6 +57,12 @@ func (h *socks5Handler) handleUDP(ctx context.Context, conn net.Conn, ro *xrecor saddr := gosocks5.Addr{} saddr.ParseFrom(cc.LocalAddr().String()) + + saddr.Host, _, _ = net.SplitHostPort(conn.LocalAddr().String()) + if v := net.ParseIP(h.md.publicAddr); v != nil { + saddr.Host = h.md.publicAddr + } + saddr.Type = 0 reply := gosocks5.NewReply(gosocks5.Succeeded, &saddr) log.Trace(reply) if err := reply.Write(conn); err != nil { @@ -81,16 +88,17 @@ func (h *socks5Handler) handleUDP(ctx context.Context, conn net.Conn, ro *xrecor log.Error(err) return err } - - pStats := xstats.Stats{} - cc = stats_wrapper.WrapPacketConn(cc, &pStats) - - defer func() { - ro.InputBytes = pStats.Get(stats.KindInputBytes) - ro.OutputBytes = pStats.Get(stats.KindOutputBytes) - }() + pc = metrics.WrapPacketConn(ro.Service, pc) { + pStats := xstats.Stats{} + cc = stats_wrapper.WrapPacketConn(cc, &pStats) + + defer func() { + ro.InputBytes = pStats.Get(stats.KindInputBytes) + ro.OutputBytes = pStats.Get(stats.KindOutputBytes) + }() + clientID := ctxvalue.ClientIDFromContext(ctx) cc = traffic_wrapper.WrapPacketConn( cc, diff --git a/handler/tunnel/handler.go b/handler/tunnel/handler.go index 45e34b31..53a98c4d 100644 --- a/handler/tunnel/handler.go +++ b/handler/tunnel/handler.go @@ -186,10 +186,20 @@ func (h *tunnelHandler) initEntrypoint() (err error) { func (h *tunnelHandler) Handle(ctx context.Context, conn net.Conn, opts ...handler.HandleOption) (err error) { start := time.Now() + + clientIP := conn.RemoteAddr().String() + if clientAddr := ctxvalue.ClientAddrFromContext(ctx); clientAddr != "" { + clientIP = string(clientAddr) + } + if h, _, _ := net.SplitHostPort(clientIP); h != "" { + clientIP = h + } + log := h.log.WithFields(map[string]any{ "remote": conn.RemoteAddr().String(), "local": conn.LocalAddr().String(), "sid": ctxvalue.SidFromContext(ctx), + "client": clientIP, }) log.Infof("%s <> %s", conn.RemoteAddr(), conn.LocalAddr()) diff --git a/internal/util/wt/conn.go b/internal/util/wt/conn.go index 92f5de03..5ac5a43a 100644 --- a/internal/util/wt/conn.go +++ b/internal/util/wt/conn.go @@ -8,8 +8,9 @@ import ( ) type conn struct { - session *wt.Session - stream *wt.Stream + session *wt.Session + stream *wt.Stream + clientAddr net.Addr } func Conn(session *wt.Session, stream *wt.Stream) net.Conn { @@ -19,6 +20,14 @@ func Conn(session *wt.Session, stream *wt.Stream) net.Conn { } } +func ConnWithClientAddr(session *wt.Session, stream *wt.Stream, clientAddr net.Addr) net.Conn { + return &conn{ + session: session, + stream: stream, + clientAddr: clientAddr, + } +} + func (c *conn) Read(b []byte) (n int, err error) { return c.stream.Read(b) } @@ -39,6 +48,10 @@ func (c *conn) RemoteAddr() net.Addr { return c.session.RemoteAddr() } +func (c *conn) ClientAddr() net.Addr { + return c.clientAddr +} + func (c *conn) SetDeadline(t time.Time) error { return c.stream.SetDeadline(t) } diff --git a/limiter/traffic/wrapper/conn.go b/limiter/traffic/wrapper/conn.go index 07979661..ae38022a 100644 --- a/limiter/traffic/wrapper/conn.go +++ b/limiter/traffic/wrapper/conn.go @@ -106,6 +106,13 @@ func (c *limitConn) Metadata() metadata.Metadata { return nil } +func (c *limitConn) ClientAddr() net.Addr { + if sc, ok := c.Conn.(xnet.ClientAddr); ok { + return sc.ClientAddr() + } + return nil +} + type packetConn struct { net.PacketConn limiter traffic.TrafficLimiter diff --git a/listener/grpc/server.go b/listener/grpc/server.go index 18cec57b..112b9fa4 100644 --- a/listener/grpc/server.go +++ b/listener/grpc/server.go @@ -4,10 +4,12 @@ import ( "errors" "io" "net" + "strings" "time" "github.com/go-gost/core/logger" pb "github.com/go-gost/x/internal/util/grpc/proto" + mdata "google.golang.org/grpc/metadata" "google.golang.org/grpc/peer" ) @@ -28,6 +30,11 @@ func (s *server) Tunnel(srv pb.GostTunel_TunnelServer) error { if p, ok := peer.FromContext(srv.Context()); ok { c.remoteAddr = p.Addr } + if md, ok := mdata.FromIncomingContext(srv.Context()); ok { + if cip := getClientIP(md); cip != nil { + c.clientAddr = &net.IPAddr{IP: cip} + } + } select { case s.cqueue <- c: @@ -41,11 +48,39 @@ func (s *server) Tunnel(srv pb.GostTunel_TunnelServer) error { return nil } +func getClientIP(md mdata.MD) net.IP { + if md == nil { + return nil + } + var cip string + // cloudflare CDN + if v := md.Get("CF-Connecting-IP"); len(v) > 0 { + cip = v[0] + } + if cip == "" { + if v := md.Get("X-Forwarded-For"); len(v) > 0 { + ss := strings.Split(v[0], ",") + if len(ss) > 0 && ss[0] != "" { + cip = ss[0] + } + + } + } + if cip == "" { + if v := md.Get("X-Real-Ip"); len(v) > 0 { + cip = v[0] + } + } + + return net.ParseIP(cip) +} + type conn struct { s pb.GostTunel_TunnelServer rb []byte localAddr net.Addr remoteAddr net.Addr + clientAddr net.Addr closed chan struct{} } @@ -111,6 +146,10 @@ func (c *conn) RemoteAddr() net.Addr { return c.remoteAddr } +func (c *conn) ClientAddr() net.Addr { + return c.clientAddr +} + func (c *conn) SetDeadline(t time.Time) error { return &net.OpError{Op: "set", Net: "grpc", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} } diff --git a/listener/http2/conn.go b/listener/http2/conn.go index 15f56f2a..6aa59b51 100644 --- a/listener/http2/conn.go +++ b/listener/http2/conn.go @@ -11,12 +11,13 @@ import ( // a dummy HTTP2 server conn used by HTTP2 handler type conn struct { - md mdata.Metadata - r *http.Request - w http.ResponseWriter - laddr net.Addr - raddr net.Addr - closed chan struct{} + md mdata.Metadata + r *http.Request + w http.ResponseWriter + laddr net.Addr + raddr net.Addr + clientAddr net.Addr + closed chan struct{} } func (c *conn) Read(b []byte) (n int, err error) { @@ -44,6 +45,10 @@ func (c *conn) RemoteAddr() net.Addr { return c.raddr } +func (c *conn) ClientAddr() net.Addr { + return c.clientAddr +} + func (c *conn) SetDeadline(t time.Time) error { return &net.OpError{Op: "set", Net: "http2", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} } diff --git a/listener/http2/h2/conn.go b/listener/http2/h2/conn.go index 10f8d4c7..f4b4ce03 100644 --- a/listener/http2/h2/conn.go +++ b/listener/http2/h2/conn.go @@ -14,6 +14,7 @@ type conn struct { w io.Writer remoteAddr net.Addr localAddr net.Addr + clientAddr net.Addr closed chan struct{} } @@ -49,6 +50,10 @@ func (c *conn) RemoteAddr() net.Addr { return c.remoteAddr } +func (c *conn) ClientAddr() net.Addr { + return c.clientAddr +} + func (c *conn) SetDeadline(t time.Time) error { return &net.OpError{Op: "set", Net: "http2", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} } diff --git a/listener/http2/h2/listener.go b/listener/http2/h2/listener.go index 1aa32405..7c7f11f4 100644 --- a/listener/http2/h2/listener.go +++ b/listener/http2/h2/listener.go @@ -15,6 +15,7 @@ import ( md "github.com/go-gost/core/metadata" admission "github.com/go-gost/x/admission/wrapper" xnet "github.com/go-gost/x/internal/net" + xhttp "github.com/go-gost/x/internal/net/http" "github.com/go-gost/x/internal/net/proxyproto" climiter "github.com/go-gost/x/limiter/conn/wrapper" limiter_wrapper "github.com/go-gost/x/limiter/traffic/wrapper" @@ -198,11 +199,18 @@ func (l *h2Listener) upgrade(w http.ResponseWriter, r *http.Request) (*conn, err Port: 0, } } + + var clientAddr net.Addr + if clientIP := xhttp.GetClientIP(r); clientIP != nil { + clientAddr = &net.IPAddr{IP: clientIP} + } + return &conn{ r: r.Body, w: flushWriter{w}, localAddr: l.addr, remoteAddr: remoteAddr, + clientAddr: clientAddr, closed: make(chan struct{}), }, nil } diff --git a/listener/http2/listener.go b/listener/http2/listener.go index 31973b3a..e0d38840 100644 --- a/listener/http2/listener.go +++ b/listener/http2/listener.go @@ -13,6 +13,7 @@ import ( md "github.com/go-gost/core/metadata" admission "github.com/go-gost/x/admission/wrapper" xnet "github.com/go-gost/x/internal/net" + xhttp "github.com/go-gost/x/internal/net/http" "github.com/go-gost/x/internal/net/proxyproto" climiter "github.com/go-gost/x/limiter/conn/wrapper" limiter_wrapper "github.com/go-gost/x/limiter/traffic/wrapper" @@ -148,6 +149,11 @@ func (l *http2Listener) handleFunc(w http.ResponseWriter, r *http.Request) { "w": w, }), } + + if clientIP := xhttp.GetClientIP(r); clientIP != nil { + conn.clientAddr = &net.IPAddr{IP: clientIP} + } + select { case l.cqueue <- conn: default: diff --git a/listener/http3/conn.go b/listener/http3/conn.go index a6183bd6..4a71b998 100644 --- a/listener/http3/conn.go +++ b/listener/http3/conn.go @@ -3,7 +3,6 @@ package http3 import ( "errors" "net" - "net/http" "time" mdata "github.com/go-gost/core/metadata" @@ -11,12 +10,11 @@ import ( // a dummy HTTP3 server conn used by HTTP3 handler type conn struct { - md mdata.Metadata - r *http.Request - w http.ResponseWriter - laddr net.Addr - raddr net.Addr - closed chan struct{} + md mdata.Metadata + laddr net.Addr + raddr net.Addr + clientAddr net.Addr + closed chan struct{} } func (c *conn) Read(b []byte) (n int, err error) { @@ -44,6 +42,10 @@ func (c *conn) RemoteAddr() net.Addr { return c.raddr } +func (c *conn) ClientAddr() net.Addr { + return c.clientAddr +} + func (c *conn) SetDeadline(t time.Time) error { return &net.OpError{Op: "set", Net: "http3", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} } diff --git a/listener/http3/listener.go b/listener/http3/listener.go index aa1bb410..02d1fdce 100644 --- a/listener/http3/listener.go +++ b/listener/http3/listener.go @@ -9,6 +9,7 @@ import ( "github.com/go-gost/core/logger" md "github.com/go-gost/core/metadata" xnet "github.com/go-gost/x/internal/net" + xhttp "github.com/go-gost/x/internal/net/http" mdx "github.com/go-gost/x/metadata" "github.com/go-gost/x/registry" "github.com/quic-go/quic-go" @@ -134,6 +135,11 @@ func (l *http3Listener) handleFunc(w http.ResponseWriter, r *http.Request) { "w": w, }), } + + if clientIP := xhttp.GetClientIP(r); clientIP != nil { + conn.clientAddr = &net.IPAddr{IP: clientIP} + } + select { case l.cqueue <- conn: default: diff --git a/listener/http3/wt/listener.go b/listener/http3/wt/listener.go index 4ba93af3..3cb144a1 100644 --- a/listener/http3/wt/listener.go +++ b/listener/http3/wt/listener.go @@ -11,6 +11,7 @@ import ( md "github.com/go-gost/core/metadata" admission "github.com/go-gost/x/admission/wrapper" xnet "github.com/go-gost/x/internal/net" + xhttp "github.com/go-gost/x/internal/net/http" wt_util "github.com/go-gost/x/internal/util/wt" traffic_limiter "github.com/go-gost/x/limiter/traffic" limiter_wrapper "github.com/go-gost/x/limiter/traffic/wrapper" @@ -153,9 +154,15 @@ func (l *wtListener) Close() (err error) { } func (l *wtListener) upgrade(w http.ResponseWriter, r *http.Request) { + clientIP := xhttp.GetClientIP(r) + cip := "" + if clientIP != nil { + cip = clientIP.String() + } log := l.logger.WithFields(map[string]any{ "local": l.addr.String(), "remote": r.RemoteAddr, + "client": cip, }) if l.logger.IsLevelEnabled(logger.TraceLevel) { dump, _ := httputil.DumpRequest(r, false) @@ -169,10 +176,15 @@ func (l *wtListener) upgrade(w http.ResponseWriter, r *http.Request) { return } - l.mux(s, log) + var clientAddr net.Addr + if clientIP != nil { + clientAddr = &net.IPAddr{IP: clientIP} + } + + l.mux(s, clientAddr, log) } -func (l *wtListener) mux(s *wt.Session, log logger.Logger) (err error) { +func (l *wtListener) mux(s *wt.Session, clientAddr net.Addr, log logger.Logger) (err error) { defer func() { if err != nil { s.CloseWithError(1, err.Error()) @@ -190,7 +202,7 @@ func (l *wtListener) mux(s *wt.Session, log logger.Logger) (err error) { } select { - case l.cqueue <- wt_util.Conn(s, stream): + case l.cqueue <- wt_util.ConnWithClientAddr(s, stream, clientAddr): default: stream.Close() l.logger.Warnf("connection queue is full, stream %v discarded", stream.StreamID()) diff --git a/listener/mws/listener.go b/listener/mws/listener.go index 6626f069..54643544 100644 --- a/listener/mws/listener.go +++ b/listener/mws/listener.go @@ -14,6 +14,7 @@ import ( md "github.com/go-gost/core/metadata" admission "github.com/go-gost/x/admission/wrapper" xnet "github.com/go-gost/x/internal/net" + xhttp "github.com/go-gost/x/internal/net/http" "github.com/go-gost/x/internal/net/proxyproto" "github.com/go-gost/x/internal/util/mux" ws_util "github.com/go-gost/x/internal/util/ws" @@ -162,26 +163,36 @@ func (l *mwsListener) Addr() net.Addr { } func (l *mwsListener) upgrade(w http.ResponseWriter, r *http.Request) { + clientIP := xhttp.GetClientIP(r) + cip := "" + if clientIP != nil { + cip = clientIP.String() + } log := l.logger.WithFields(map[string]any{ "local": l.addr.String(), "remote": r.RemoteAddr, + "client": cip, }) - if l.logger.IsLevelEnabled(logger.TraceLevel) { + if log.IsLevelEnabled(logger.TraceLevel) { dump, _ := httputil.DumpRequest(r, false) log.Trace(string(dump)) } conn, err := l.upgrader.Upgrade(w, r, l.md.header) if err != nil { - w.WriteHeader(http.StatusInternalServerError) log.Error(err) return } - l.mux(ws_util.Conn(conn), log) + var clientAddr net.Addr + if clientIP != nil { + clientAddr = &net.IPAddr{IP: clientIP} + } + + l.mux(ws_util.Conn(conn), clientAddr, log) } -func (l *mwsListener) mux(conn net.Conn, log logger.Logger) { +func (l *mwsListener) mux(conn net.Conn, clientAddr net.Addr, log logger.Logger) { defer conn.Close() session, err := mux.ServerSession(conn, l.md.muxCfg) @@ -199,10 +210,19 @@ func (l *mwsListener) mux(conn net.Conn, log logger.Logger) { } select { - case l.cqueue <- stream: + case l.cqueue <- &connWithClientAddr{Conn: stream, clientAddr: clientAddr}: default: stream.Close() log.Warnf("connection queue is full, client %s discarded", stream.RemoteAddr()) } } } + +type connWithClientAddr struct { + net.Conn + clientAddr net.Addr +} + +func (c *connWithClientAddr) ClientAddr() net.Addr { + return c.clientAddr +} diff --git a/listener/ws/listener.go b/listener/ws/listener.go index fb93bdeb..57d99ee7 100644 --- a/listener/ws/listener.go +++ b/listener/ws/listener.go @@ -159,24 +159,23 @@ func (l *wsListener) Addr() net.Addr { func (l *wsListener) upgrade(w http.ResponseWriter, r *http.Request) { clientIP := xhttp.GetClientIP(r) - if l.logger.IsLevelEnabled(logger.TraceLevel) { - sip := "" - if clientIP != nil { - sip = clientIP.String() - } - log := l.logger.WithFields(map[string]any{ - "local": l.addr.String(), - "remote": r.RemoteAddr, - "clientIP": sip, - }) + cip := "" + if clientIP != nil { + cip = clientIP.String() + } + log := l.logger.WithFields(map[string]any{ + "local": l.addr.String(), + "remote": r.RemoteAddr, + "client": cip, + }) + if log.IsLevelEnabled(logger.TraceLevel) { dump, _ := httputil.DumpRequest(r, false) log.Trace(string(dump)) } conn, err := l.upgrader.Upgrade(w, r, l.md.header) if err != nil { - l.logger.Error(err) - w.WriteHeader(http.StatusInternalServerError) + log.Error(err) return } @@ -189,6 +188,6 @@ func (l *wsListener) upgrade(w http.ResponseWriter, r *http.Request) { case l.cqueue <- ws_util.ConnWithClientAddr(conn, clientAddr): default: conn.Close() - l.logger.Warnf("connection queue is full, client %s discarded", conn.RemoteAddr()) + log.Warnf("connection queue is full, client %s discarded", conn.RemoteAddr()) } } diff --git a/metrics/wrapper/conn.go b/metrics/wrapper/conn.go index d1f12085..a88a8e65 100644 --- a/metrics/wrapper/conn.go +++ b/metrics/wrapper/conn.go @@ -80,6 +80,13 @@ func (c *serverConn) Metadata() metadata.Metadata { return nil } +func (c *serverConn) ClientAddr() net.Addr { + if sc, ok := c.Conn.(xnet.ClientAddr); ok { + return sc.ClientAddr() + } + return nil +} + type packetConn struct { net.PacketConn service string diff --git a/observer/stats/wrapper/conn.go b/observer/stats/wrapper/conn.go index 9f28115b..efef5eb4 100644 --- a/observer/stats/wrapper/conn.go +++ b/observer/stats/wrapper/conn.go @@ -82,6 +82,13 @@ func (c *conn) Metadata() metadata.Metadata { return nil } +func (c *conn) ClientAddr() net.Addr { + if sc, ok := c.Conn.(xnet.ClientAddr); ok { + return sc.ClientAddr() + } + return nil +} + type packetConn struct { net.PacketConn stats stats.Stats