elazarl / goproxy

An HTTP proxy library for Go
BSD 3-Clause "New" or "Revised" License
6.06k stars 1.1k forks source link

ListenAndServeTLS causes goproxy to panic #434

Open g00nix opened 3 years ago

g00nix commented 3 years ago

I am running he goproxy as a HTTPS proxy:

func main() {
    proxy := goproxy.NewProxyHttpServer()
    listenAddress := os.Getenv("LISTEN_ADDRESS")
    if listenAddress == "" {
        log.Fatal("The LISTEN_ADDRESS env var is mandatory.")
    }
    log.Println("Starting to listen on", listenAddress)
    log.Println("HTTPS Failed:", http.ListenAndServeTLS(listenAddress, "/fullchain.pem", "/privkey.pem", proxy))
}

This works perfect till I curl small websites with curl. However if I add the proxy to a browser, i get a flood of panic messages in the log:

2021/03/20 16:16:19 http2: panic serving 172.17.0.1:50476: httpserver does not support hijacking
goroutine 123989 [running]:
net/http.(*http2serverConn).runHandler.func1(0xc00020c080, 0xc000336f8e, 0xc000528600)
    net/http/h2_bundle.go:5716 +0x193
panic(0x8f2ec0, 0xa43d00)
    runtime/panic.go:965 +0x1b9
github.com/elazarl/goproxy.(*ProxyHttpServer).handleHttps(0xc0001985a0, 0xa55890, 0xc00020c080, 0xc0000aff00)
    github.com/elazarl/goproxy@v0.0.0-20210110162100-a92cc753f88e/https.go:84 +0x18a7
github.com/elazarl/goproxy.(*ProxyHttpServer).ServeHTTP(0xc0001985a0, 0xa55890, 0xc00020c080, 0xc0000aff00)
    github.com/elazarl/goproxy@v0.0.0-20210110162100-a92cc753f88e/proxy.go:114 +0xc95
net/http.serverHandler.ServeHTTP(0xc0001661c0, 0xa55890, 0xc00020c080, 0xc0000aff00)
    net/http/server.go:2887 +0xa3
net/http.initALPNRequest.ServeHTTP(0xa56320, 0xc00017eea0, 0xc0001cca80, 0xc0001661c0, 0xa55890, 0xc00020c080, 0xc0000aff00)
    net/http/server.go:3459 +0x8d
net/http.(*http2serverConn).runHandler(0xc000528600, 0xc00020c080, 0xc0000aff00, 0xc0004907b0)
    net/http/h2_bundle.go:5723 +0x8b
created by net/http.(*http2serverConn).processHeaders
    net/http/h2_bundle.go:5453 +0x505
g00nix commented 3 years ago

I think this bug will appear on http2 websites. One solution would be to shut down http2 the same way you can do this on http.Server, by setting TLSNextProto to nil. The problem is that shutting http2 completely is not future proof. I found online solutions for TLS+http2 proxy, but not in Go. This is because most Go HTTPS proxies are based on Hijack which was not implemented for http2.

I have no idea at this point if I am wrong or not and if I should invest more time into this direction. If anybody has any ideas or advice on this topic, I am super interested.

jonreesman commented 8 months ago

Any update on this? Currently slogging through trying to force http1 but no matter what I do the server im forward proxying to decides h2.

elazarl commented 1 month ago

It seems go Hijack method doesn't work for h2, and we need some other solution. I'm not sure I'll have time to investigate, but will keep you posted.