package integration_tests import ( "context" "crypto/tls" "net" "net/http" "net/url" "strings" "testing" "time" "github.com/apernet/hysteria/core/internal/protocol" "github.com/apernet/hysteria/core/server" "github.com/quic-go/quic-go" "github.com/quic-go/quic-go/http3" ) // TestServerMasquerade is a test to ensure that the server behaves as a normal // HTTP/3 server when dealing with an unauthenticated client. This is mainly to // confirm that the server does not expose itself to active probers. func TestServerMasquerade(t *testing.T) { // Create server udpAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 14514} udpConn, err := net.ListenUDP("udp", udpAddr) if err != nil { t.Fatal("error creating server:", err) } s, err := server.NewServer(&server.Config{ TLSConfig: serverTLSConfig(), Conn: udpConn, Authenticator: &pwAuthenticator{ Password: "password", ID: "nobody", }, }) if err != nil { t.Fatal("error creating server:", err) } defer s.Close() go s.Serve() // QUIC connection & RoundTripper var conn quic.EarlyConnection rt := &http3.RoundTripper{ EnableDatagrams: true, TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, }, Dial: func(ctx context.Context, _ string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) { qc, err := quic.DialAddrEarly(ctx, udpAddr.String(), tlsCfg, cfg) if err != nil { return nil, err } conn = qc return qc, nil }, } defer rt.Close() // This will close the QUIC connection // Send the bogus request // We expect 404 (from the default handler) req := &http.Request{ Method: http.MethodPost, URL: &url.URL{ Scheme: "https", Host: protocol.URLHost, Path: protocol.URLPath, }, Header: make(http.Header), } resp, err := rt.RoundTrip(req) if err != nil { t.Fatal("error sending request:", err) } if resp.StatusCode != http.StatusNotFound { t.Fatalf("expected status %d, got %d", http.StatusNotFound, resp.StatusCode) } for k := range resp.Header { // Make sure no strange headers are sent if strings.Contains(k, "Hysteria") { t.Fatal("expected no Hysteria headers, got", k) } } buf := make([]byte, 1024) // We send a TCP request anyway, see if we get a response tcpStream, err := conn.OpenStream() if err != nil { t.Fatal("error opening stream:", err) } defer tcpStream.Close() err = protocol.WriteTCPRequest(tcpStream, "www.google.com:443") if err != nil { t.Fatal("error sending request:", err) } // We should receive nothing _ = tcpStream.SetReadDeadline(time.Now().Add(2 * time.Second)) n, err := tcpStream.Read(buf) if n != 0 { t.Fatal("expected no response, got", n) } if nErr, ok := err.(net.Error); !ok || !nErr.Timeout() { t.Fatal("expected timeout, got", err) } }