Skip to content

net/http,x/crypto/ssh: Hijack hangs when underlying net.Conn doesn't support SetReadDeadline #67152

Open
@fasmide

Description

@fasmide

Go version

go version go1.22.2 linux/amd64

Output of go env in your module/workspace:

GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/home/fas/.cache/go-build'
GOENV='/home/fas/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/fas/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/fas/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/snap/go/10585'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/snap/go/10585/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.22.2'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/home/fas/github.com/fasmide/the-thing-about-websockets-and-ssh-tunnels/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build565532914=/tmp/go-build -gno-record-gcc-switches'

What did you do?

I was trying to have a web server forwarded through an SSH tunnel - I've made an example of this bug in fasmide/the-thing-about-websockets-and-ssh-tunnels

This all works out really well until web sockets are introduced.

This is because the http.response, which does Hijacking, tries to set its net.Conn's deadline to the past to have it unblock its current Read() - but x/crypto/ssh's implementation of net.Conn does not support this.

Furthermore, the http.response does not do any error checking when setting the deadline - so effectively the conn locks up without any indication to anyone about whats going on.

What did you see happen?

Using the example, one should find that using a local net.Listener — everything is fine; however, forwarding the listener through SSH tunnel's, the browser (both Chrome and Firefox) hangs indefinitely trying to connect.

Example of a working local listener:

the-thing-about-websockets-and-ssh-tunnels $  go run main.go -local
2024/05/03 10:44:29 *net.TCPListener listening on [::]:13337

When opening the webpage, look in the debugger for messages:
image

Example of a broken forwarded listener:

the-thing-about-websockets-and-ssh-tunnels $  go run main.go 127.0.0.1:22
2024/05/03 10:46:39 *ssh.tcpListener listening on 127.0.0.1:13337

Now, when opening the same webpage, the websocket is stuck in (pending):
image

What did you expect to see?

I did not expect there to be any differences :)

I don't know if this bug is in net/http or x/crypto/ssh - but given that HTTP hijack'ing usually returns an error if it is unable to hijack a connection, I would imagine some error checking is to be expected in net/http when SetReadDeadline returns an error

Metadata

Metadata

Assignees

No one assigned

    Labels

    NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions