mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-11-11 06:18:27 +01:00
Reading the header in Accept let a silent peer stall the listener for everyone and let a malformed header surface as an accept error. The header now parses on first Read/RemoteAddr under a once, inside the connection's own goroutine lifecycle.
107 lines
2.5 KiB
Go
107 lines
2.5 KiB
Go
package util
|
|
|
|
import (
|
|
"bufio"
|
|
"io"
|
|
"net"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func acceptOne(t *testing.T, ln net.Listener) net.Conn {
|
|
t.Helper()
|
|
accept := make(chan net.Conn, 1)
|
|
go func() {
|
|
conn, err := ln.Accept()
|
|
if err == nil {
|
|
accept <- conn
|
|
}
|
|
}()
|
|
select {
|
|
case conn := <-accept:
|
|
return conn
|
|
case <-time.After(2 * time.Second):
|
|
t.Fatal("Accept blocked waiting for the peer to send data")
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func newPipePair(t *testing.T) (client, server net.Conn) {
|
|
t.Helper()
|
|
serverConn, client := net.Pipe()
|
|
ln := WrapProxyProtocolListener(&oneShotListener{conn: serverConn})
|
|
return client, acceptOne(t, ln)
|
|
}
|
|
|
|
type oneShotListener struct {
|
|
conn net.Conn
|
|
done bool
|
|
}
|
|
|
|
func (l *oneShotListener) Accept() (net.Conn, error) {
|
|
if l.done {
|
|
return nil, io.EOF
|
|
}
|
|
l.done = true
|
|
return l.conn, nil
|
|
}
|
|
func (l *oneShotListener) Close() error { return l.conn.Close() }
|
|
func (l *oneShotListener) Addr() net.Addr { return l.conn.LocalAddr() }
|
|
|
|
func TestProxyProtocolHeaderRewritesRemoteAddr(t *testing.T) {
|
|
client, server := newPipePair(t)
|
|
defer client.Close()
|
|
defer server.Close()
|
|
|
|
go func() {
|
|
_, _ = client.Write([]byte("PROXY TCP4 10.99.0.1 192.0.2.5 45678 8080\r\nGET / HTTP/1.0\r\n\r\n"))
|
|
}()
|
|
|
|
got, err := bufio.NewReader(server).ReadString('\n')
|
|
if err != nil {
|
|
t.Fatalf("read request line: %v", err)
|
|
}
|
|
if got != "GET / HTTP/1.0\r\n" {
|
|
t.Fatalf("request line = %q, want GET / HTTP/1.0", got)
|
|
}
|
|
if addr, ok := server.RemoteAddr().(*net.TCPAddr); !ok || addr.IP.String() != "10.99.0.1" || addr.Port != 45678 {
|
|
t.Fatalf("RemoteAddr = %v, want 10.99.0.1:45678", server.RemoteAddr())
|
|
}
|
|
}
|
|
|
|
func TestProxyProtocolAbsentKeepsRemoteAddr(t *testing.T) {
|
|
client, server := newPipePair(t)
|
|
defer client.Close()
|
|
defer server.Close()
|
|
|
|
go func() {
|
|
_, _ = client.Write([]byte("GET / HTTP/1.0\r\n\r\n"))
|
|
}()
|
|
|
|
got, err := bufio.NewReader(server).ReadString('\n')
|
|
if err != nil {
|
|
t.Fatalf("read request line: %v", err)
|
|
}
|
|
if got != "GET / HTTP/1.0\r\n" {
|
|
t.Fatalf("request line = %q, want GET / HTTP/1.0", got)
|
|
}
|
|
if server.RemoteAddr().String() != "pipe" {
|
|
t.Fatalf("RemoteAddr = %v, want underlying conn address", server.RemoteAddr())
|
|
}
|
|
}
|
|
|
|
func TestProxyProtocolTruncatedHeaderKeepsRemoteAddr(t *testing.T) {
|
|
client, server := newPipePair(t)
|
|
defer server.Close()
|
|
|
|
go func() {
|
|
_, _ = client.Write([]byte("PROXY TCP4 10.99.0.1"))
|
|
_ = client.Close()
|
|
}()
|
|
|
|
_, _ = server.Read(make([]byte, 64))
|
|
if server.RemoteAddr().String() != "pipe" {
|
|
t.Fatalf("RemoteAddr = %v, want underlying conn address", server.RemoteAddr())
|
|
}
|
|
}
|