Fix: http proxy Upgrade behavior (#2097)

This commit is contained in:
Kr328
2022-04-25 19:50:20 +08:00
committed by Meta Gowork
parent ffb49ba4c5
commit cca3a1a934
5 changed files with 108 additions and 41 deletions

View File

@ -19,12 +19,7 @@ func HandleConn(c net.Conn, in chan<- C.ConnContext, cache *cache.Cache[string,
client := newClient(c.RemoteAddr(), in)
defer client.CloseIdleConnections()
var conn *N.BufferedConn
if bufConn, ok := c.(*N.BufferedConn); ok {
conn = bufConn
} else {
conn = N.NewBufferedConn(c)
}
conn := N.NewBufferedConn(c)
keepAlive := true
trusted := cache == nil // disable authenticate if cache is nil
@ -66,6 +61,12 @@ func HandleConn(c net.Conn, in chan<- C.ConnContext, cache *cache.Cache[string,
request.RequestURI = ""
if isUpgradeRequest(request) {
handleUpgrade(conn, request, in)
return // hijack connection
}
removeHopByHopHeaders(request.Header)
removeExtraHTTPHostPort(request)

61
listener/http/upgrade.go Normal file
View File

@ -0,0 +1,61 @@
package http
import (
"net"
"net/http"
"strings"
"github.com/Dreamacro/clash/adapter/inbound"
N "github.com/Dreamacro/clash/common/net"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/transport/socks5"
)
func isUpgradeRequest(req *http.Request) bool {
return strings.EqualFold(req.Header.Get("Connection"), "Upgrade")
}
func handleUpgrade(conn net.Conn, request *http.Request, in chan<- C.ConnContext) {
defer conn.Close()
removeProxyHeaders(request.Header)
removeExtraHTTPHostPort(request)
address := request.Host
if _, _, err := net.SplitHostPort(address); err != nil {
address = net.JoinHostPort(address, "80")
}
dstAddr := socks5.ParseAddr(address)
if dstAddr == nil {
return
}
left, right := net.Pipe()
in <- inbound.NewHTTP(dstAddr, conn.RemoteAddr(), right)
bufferedLeft := N.NewBufferedConn(left)
defer bufferedLeft.Close()
err := request.Write(bufferedLeft)
if err != nil {
return
}
resp, err := http.ReadResponse(bufferedLeft.Reader(), request)
if err != nil {
return
}
removeProxyHeaders(resp.Header)
err = resp.Write(conn)
if err != nil {
return
}
if resp.StatusCode == http.StatusSwitchingProtocols {
N.Relay(bufferedLeft, conn)
}
}

View File

@ -8,15 +8,21 @@ import (
"strings"
)
// removeHopByHopHeaders remove Proxy-* headers
func removeProxyHeaders(header http.Header) {
header.Del("Proxy-Connection")
header.Del("Proxy-Authenticate")
header.Del("Proxy-Authorization")
}
// removeHopByHopHeaders remove hop-by-hop header
func removeHopByHopHeaders(header http.Header) {
// Strip hop-by-hop header based on RFC:
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1
// https://www.mnot.net/blog/2011/07/11/what_proxies_must_do
header.Del("Proxy-Connection")
header.Del("Proxy-Authenticate")
header.Del("Proxy-Authorization")
removeProxyHeaders(header)
header.Del("TE")
header.Del("Trailers")
header.Del("Transfer-Encoding")