package deconnector import ( "bufio" "fmt" "io" "net" "net/http" "net/url" ) func (d *Deconnector) handleTunnel(clientConn net.Conn, host string, upstreamURL *url.URL) { d.app.Logger().WithField("host", host).Info("Handling CONNECT tunnel") upstreamConn, err := d.dialer.Dial() if err != nil { d.app.Logger().WithError(err).Error("upstream dial failed") fmt.Fprintf(clientConn, "HTTP/1.1 502 Bad Gateway\r\n\r\n") return } defer upstreamConn.Close() connectLine := fmt.Sprintf( "CONNECT %s HTTP/1.1\r\nHost: %s\r\n\r\n", host, host, ) fmt.Fprint(upstreamConn, connectLine) resp, err := http.ReadResponse(bufio.NewReader(upstreamConn), nil) if err != nil || resp.StatusCode > 499 { d.app.Logger().WithError(err).Error("upstream CONNECT failed") fmt.Fprintf(clientConn, "HTTP/1.1 502 Bad Gateway\r\n\r\n") return } fmt.Fprintf(clientConn, "HTTP/1.1 200 Connection established\r\n\r\n") done := make(chan struct{}, 2) go func() { io.Copy(upstreamConn, clientConn); done <- struct{}{} }() go func() { io.Copy(clientConn, upstreamConn); done <- struct{}{} }() <-done }