bug: fasthttpproxy dialers return nil DialFunc on error, causing panic (#2248) (#2279)

This commit is contained in:
Erik Dubbelboer
2026-06-06 17:28:48 +08:00
committed by GitHub
parent 4b198af059
commit 1899b234a1
5 changed files with 78 additions and 10 deletions
+9
View File
@@ -21,6 +21,15 @@ var (
tmpURL = &url.URL{Scheme: httpsScheme, Host: "example.com"}
)
func dialFuncOrError(dialFunc fasthttp.DialFunc, err error) fasthttp.DialFunc {
if err == nil {
return dialFunc
}
return func(addr string) (net.Conn, error) {
return nil, err
}
}
// Dialer embeds both fasthttp.TCPDialer and httpproxy.Config, allowing it
// to take advantage of the optimizations provided by fasthttp for dialing while also
// utilizing the finer-grained configuration options offered by httpproxy.
+59
View File
@@ -261,6 +261,65 @@ func TestHTTPProxyDialRejectsTargetAddrContainingNewlines(t *testing.T) {
}
}
func TestProxyDialerConstructorsReturnErroringDialFunc(t *testing.T) {
t.Setenv("HTTP_PROXY", "socket6://127.0.0.1:8080")
t.Setenv("HTTPS_PROXY", "socket6://127.0.0.1:8080")
t.Setenv("NO_PROXY", "")
tests := []struct {
name string
fn func() fasthttp.DialFunc
}{
{
name: "http",
fn: func() fasthttp.DialFunc {
return FasthttpHTTPDialer("socket6://127.0.0.1:8080")
},
},
{
name: "http dual stack",
fn: func() fasthttp.DialFunc {
return FasthttpHTTPDialerDualStack("socket6://127.0.0.1:8080")
},
},
{
name: "socks",
fn: func() fasthttp.DialFunc {
return FasthttpSocksDialer("socket6://127.0.0.1:8080")
},
},
{
name: "socks dual stack",
fn: func() fasthttp.DialFunc {
return FasthttpSocksDialerDualStack("socket6://127.0.0.1:8080")
},
},
{
name: "env",
fn: FasthttpProxyHTTPDialer,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dialFunc := tt.fn()
if dialFunc == nil {
t.Fatalf("unexpected nil dial func")
}
conn, err := dialFunc("example.com:80")
if conn != nil {
conn.Close()
}
if err == nil {
t.Fatalf("expected error")
}
if err.Error() != "proxy: unknown scheme: socket6" {
t.Fatalf("unexpected error: %v", err)
}
})
}
}
func startProxyServer(t *testing.T, ports []string, counts []atomic.Int64) (lns []net.Listener) {
for i, port := range ports {
ln, err := net.Listen("tcp", ":"+port)
+4 -4
View File
@@ -30,8 +30,8 @@ func FasthttpHTTPDialer(proxy string) fasthttp.DialFunc {
// }
func FasthttpHTTPDialerTimeout(proxy string, timeout time.Duration) fasthttp.DialFunc {
d := Dialer{Config: httpproxy.Config{HTTPProxy: proxy, HTTPSProxy: proxy}, Timeout: timeout, ConnectTimeout: timeout}
dialFunc, _ := d.GetDialFunc(false)
return dialFunc
dialFunc, err := d.GetDialFunc(false)
return dialFuncOrError(dialFunc, err)
}
// FasthttpHTTPDialerDualStack returns a fasthttp.DialFunc that dials using
@@ -60,6 +60,6 @@ func FasthttpHTTPDialerDualStackTimeout(proxy string, timeout time.Duration) fas
Config: httpproxy.Config{HTTPProxy: proxy, HTTPSProxy: proxy}, Timeout: timeout, ConnectTimeout: timeout,
DialDualStack: true,
}
dialFunc, _ := d.GetDialFunc(false)
return dialFunc
dialFunc, err := d.GetDialFunc(false)
return dialFuncOrError(dialFunc, err)
}
+2 -2
View File
@@ -34,6 +34,6 @@ func FasthttpProxyHTTPDialer() fasthttp.DialFunc {
// }
func FasthttpProxyHTTPDialerTimeout(timeout time.Duration) fasthttp.DialFunc {
d := Dialer{Timeout: timeout, ConnectTimeout: timeout}
dialFunc, _ := d.GetDialFunc(true)
return dialFunc
dialFunc, err := d.GetDialFunc(true)
return dialFuncOrError(dialFunc, err)
}
+4 -4
View File
@@ -15,8 +15,8 @@ import (
// }
func FasthttpSocksDialer(proxyAddr string) fasthttp.DialFunc {
d := Dialer{Config: httpproxy.Config{HTTPProxy: proxyAddr, HTTPSProxy: proxyAddr}}
dialFunc, _ := d.GetDialFunc(false)
return dialFunc
dialFunc, err := d.GetDialFunc(false)
return dialFuncOrError(dialFunc, err)
}
// FasthttpSocksDialerDualStack returns a fasthttp.DialFunc that dials using
@@ -29,6 +29,6 @@ func FasthttpSocksDialer(proxyAddr string) fasthttp.DialFunc {
// }
func FasthttpSocksDialerDualStack(proxyAddr string) fasthttp.DialFunc {
d := Dialer{Config: httpproxy.Config{HTTPProxy: proxyAddr, HTTPSProxy: proxyAddr}, DialDualStack: true}
dialFunc, _ := d.GetDialFunc(false)
return dialFunc
dialFunc, err := d.GetDialFunc(false)
return dialFuncOrError(dialFunc, err)
}