From 8b492b41215603f50598bddd02f1f4e5efd2b4b9 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 29 Aug 2023 16:27:30 -0700 Subject: [PATCH] net/wsconn: accept a remote addr string and plumb it through This makes wsconn.Conns somewhat present reasonably when they are the client of an http.Request, rather than just put a placeholder in that field. Updates tailscale/corp#13777 Signed-off-by: David Anderson --- cmd/derper/websocket.go | 2 +- control/controlhttp/client_js.go | 2 +- control/controlhttp/server.go | 2 +- derp/derphttp/websocket.go | 2 +- net/wsconn/wsconn.go | 27 ++++++++++++++++++++------- 5 files changed, 24 insertions(+), 11 deletions(-) diff --git a/cmd/derper/websocket.go b/cmd/derper/websocket.go index 3f0c4bd0e..83ab38876 100644 --- a/cmd/derper/websocket.go +++ b/cmd/derper/websocket.go @@ -50,7 +50,7 @@ func addWebSocketSupport(s *derp.Server, base http.Handler) http.Handler { return } counterWebSocketAccepts.Add(1) - wc := wsconn.NetConn(r.Context(), c, websocket.MessageBinary) + wc := wsconn.NetConn(r.Context(), c, websocket.MessageBinary, r.RemoteAddr) brw := bufio.NewReadWriter(bufio.NewReader(wc), bufio.NewWriter(wc)) s.Accept(r.Context(), wc, brw, r.RemoteAddr) }) diff --git a/control/controlhttp/client_js.go b/control/controlhttp/client_js.go index 5a4b4d08b..7ad596366 100644 --- a/control/controlhttp/client_js.go +++ b/control/controlhttp/client_js.go @@ -51,7 +51,7 @@ func (d *Dialer) Dial(ctx context.Context) (*ClientConn, error) { if err != nil { return nil, err } - netConn := wsconn.NetConn(context.Background(), wsConn, websocket.MessageBinary) + netConn := wsconn.NetConn(context.Background(), wsConn, websocket.MessageBinary, wsURL.String()) cbConn, err := cont(ctx, netConn) if err != nil { netConn.Close() diff --git a/control/controlhttp/server.go b/control/controlhttp/server.go index d49e32c1d..ee469fabd 100644 --- a/control/controlhttp/server.go +++ b/control/controlhttp/server.go @@ -146,7 +146,7 @@ func acceptWebsocket(ctx context.Context, w http.ResponseWriter, r *http.Request return nil, fmt.Errorf("decoding base64 handshake parameter: %v", err) } - conn := wsconn.NetConn(ctx, c, websocket.MessageBinary) + conn := wsconn.NetConn(ctx, c, websocket.MessageBinary, r.RemoteAddr) nc, err := controlbase.Server(ctx, conn, private, init) if err != nil { conn.Close() diff --git a/derp/derphttp/websocket.go b/derp/derphttp/websocket.go index 730f975ff..08e401854 100644 --- a/derp/derphttp/websocket.go +++ b/derp/derphttp/websocket.go @@ -27,6 +27,6 @@ func dialWebsocket(ctx context.Context, urlStr string) (net.Conn, error) { return nil, err } log.Printf("websocket: connected to %v", urlStr) - netConn := wsconn.NetConn(context.Background(), c, websocket.MessageBinary) + netConn := wsconn.NetConn(context.Background(), c, websocket.MessageBinary, urlStr) return netConn, nil } diff --git a/net/wsconn/wsconn.go b/net/wsconn/wsconn.go index 697b66ddd..2d708ac53 100644 --- a/net/wsconn/wsconn.go +++ b/net/wsconn/wsconn.go @@ -48,10 +48,18 @@ import ( // // A received StatusNormalClosure or StatusGoingAway close frame will be translated to // io.EOF when reading. -func NetConn(ctx context.Context, c *websocket.Conn, msgType websocket.MessageType) net.Conn { +// +// The given remoteAddr will be the value of the returned conn's +// RemoteAddr().String(). For best compatibility with consumers of +// conns, the string should be an ip:port if available, but in the +// absence of that it can be any string that describes the remote +// endpoint, or the empty string to makes RemoteAddr() return a place +// holder value. +func NetConn(ctx context.Context, c *websocket.Conn, msgType websocket.MessageType, remoteAddr string) net.Conn { nc := &netConn{ - c: c, - msgType: msgType, + c: c, + msgType: msgType, + remoteAddr: remoteAddr, } var writeCancel context.CancelFunc @@ -82,8 +90,9 @@ func NetConn(ctx context.Context, c *websocket.Conn, msgType websocket.MessageTy } type netConn struct { - c *websocket.Conn - msgType websocket.MessageType + c *websocket.Conn + msgType websocket.MessageType + remoteAddr string writeTimer *time.Timer writeContext context.Context @@ -167,6 +176,7 @@ func (c *netConn) Read(p []byte) (int, error) { } type websocketAddr struct { + addr string } func (a websocketAddr) Network() string { @@ -174,15 +184,18 @@ func (a websocketAddr) Network() string { } func (a websocketAddr) String() string { + if a.addr != "" { + return a.addr + } return "websocket/unknown-addr" } func (c *netConn) RemoteAddr() net.Addr { - return websocketAddr{} + return websocketAddr{c.remoteAddr} } func (c *netConn) LocalAddr() net.Addr { - return websocketAddr{} + return websocketAddr{""} } func (c *netConn) SetDeadline(t time.Time) error {