/
githubmirror
/
rclone
Обзор
Документация
Войти
/
githubmirror
/
rclone
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
lib/proxy/http_test.go
120 строк
3 KB
Nick Craig-Wood
lib/proxy: fix unbounded HTTP CONNECT headers causing OOM GHSA-xhf4-832v-7xcr CVE-PENDING
31 июл 2026, 15:21
31 июл 2026, 15:21
21d8cd3
Код
Авторство
О чём код?
package proxy import ( "bufio" "net" "net/url" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // startProxy starts a fake HTTP CONNECT proxy which reads the CONNECT // request then calls serve with the connection to send the response. func startProxy(t *testing.T, serve func(conn net.Conn)) *url.URL { listener, err := net.Listen("tcp", "127.0.0.1:0") require.NoError(t, err) t.Cleanup(func() { _ = listener.Close() }) go func() { conn, err := listener.Accept() if err != nil { return } defer func() { _ = conn.Close() }() // Read the CONNECT request up to the blank line br := bufio.NewReader(conn) for { line, err := br.ReadString('\n') if err != nil || line == "\r\n" || line == "\n" { break } } serve(conn) }() proxyURL, err := url.Parse("http://" + listener.Addr().String()) require.NoError(t, err) return proxyURL } func TestHTTPConnectDial(t *testing.T) { proxyURL := startProxy(t, func(conn net.Conn) { if _, err := conn.Write([]byte("HTTP/1.1 200 Connection established\r\n\r\n")); err != nil { return } // echo the tunnelled data back buf := make([]byte, 4) if _, err := conn.Read(buf); err != nil { return } _, _ = conn.Write(buf) }) conn, err := HTTPConnectDial("tcp", "example.com:1234", proxyURL, nil) require.NoError(t, err) defer func() { _ = conn.Close() }() _, err = conn.Write([]byte("ping")) require.NoError(t, err) buf := make([]byte, 4) _, err = conn.Read(buf) require.NoError(t, err) assert.Equal(t, "ping", string(buf)) } // Check that tunnel bytes the server sends immediately after the // CONNECT response (eg an SSH banner) are not lost. func TestHTTPConnectDialBuffered(t *testing.T) { proxyURL := startProxy(t, func(conn net.Conn) { // Send the response and the start of the tunnelled protocol in // a single write so they arrive in one read. _, _ = conn.Write([]byte("HTTP/1.1 200 Connection established\r\n\r\nSSH-2.0-banner\r\n")) }) conn, err := HTTPConnectDial("tcp", "example.com:1234", proxyURL, nil) require.NoError(t, err) defer func() { _ = conn.Close() }() buf := make([]byte, 16) n, err := conn.Read(buf) require.NoError(t, err) assert.Equal(t, "SSH-2.0-banner\r\n", string(buf[:n])) } // Check that a proxy sending an arbitrarily large response can't use // unbounded memory. func TestHTTPConnectDialTooLarge(t *testing.T) { proxyURL := startProxy(t, func(conn net.Conn) { _, err := conn.Write([]byte("HTTP/1.1 200 Connection established\r\nX-Fill: ")) if err != nil { return } // Stream more header than maxResponseBytes - writes will error // once the client gives up and closes the connection. chunk := []byte(strings.Repeat("x", 64*1024)) for written := 0; written <= 2<<20; written += len(chunk) { if _, err := conn.Write(chunk); err != nil { return } } }) conn, err := HTTPConnectDial("tcp", "example.com:1234", proxyURL, nil) require.Error(t, err) assert.Nil(t, conn) assert.Contains(t, err.Error(), "too large") } func TestHTTPConnectDialNon200(t *testing.T) { proxyURL := startProxy(t, func(conn net.Conn) { _, _ = conn.Write([]byte("HTTP/1.1 403 Forbidden\r\nContent-Length: 0\r\n\r\n")) }) conn, err := HTTPConnectDial("tcp", "example.com:1234", proxyURL, nil) require.Error(t, err) assert.Nil(t, conn) assert.Contains(t, err.Error(), "403") }