From 82003f4270f299a90071f0697e20d25e09f76218 Mon Sep 17 00:00:00 2001 From: ginuerzh Date: Wed, 2 Jan 2019 21:33:17 +0800 Subject: [PATCH] add test cases for HTTP/HTTP2 probing resistance --- .testdata/probe_resist.txt | 1 + bypass_test.go | 43 +++++++++ common_test.go | 10 +- http2_test.go | 184 +++++++++++++++++++++++++++++++++++++ http_test.go | 180 +++++++++++++++++++++++++++++++++--- snapcraft.yaml | 4 +- 6 files changed, 405 insertions(+), 17 deletions(-) create mode 100644 .testdata/probe_resist.txt diff --git a/.testdata/probe_resist.txt b/.testdata/probe_resist.txt new file mode 100644 index 0000000..c57eff5 --- /dev/null +++ b/.testdata/probe_resist.txt @@ -0,0 +1 @@ +Hello World! \ No newline at end of file diff --git a/bypass_test.go b/bypass_test.go index 05dc069..52b1305 100644 --- a/bypass_test.go +++ b/bypass_test.go @@ -211,6 +211,22 @@ var bypassReloadTests = []struct { bypassed: true, stopped: false, }, + { + r: bytes.NewBufferString("#reverse true\n#reload 10s\n192.168.0.0/16"), + reversed: false, + period: 0, + addr: "192.168.10.2", + bypassed: true, + stopped: true, + }, + { + r: bytes.NewBufferString("#reverse true\n#reload 10s\n192.168.1.0/24"), + reversed: false, + period: 0, + addr: "192.168.10.2", + bypassed: false, + stopped: true, + }, { r: bytes.NewBufferString("reverse false\nreload 10s\n192.168.1.1\n#example.com"), reversed: false, @@ -227,6 +243,30 @@ var bypassReloadTests = []struct { bypassed: true, stopped: true, }, + { + r: bytes.NewBufferString("#reverse true\n#reload 10s\nexample.com"), + reversed: false, + period: 0, + addr: "example.com", + bypassed: true, + stopped: true, + }, + { + r: bytes.NewBufferString("#reverse true\n#reload 10s\n.example.com"), + reversed: false, + period: 0, + addr: "example.com", + bypassed: true, + stopped: true, + }, + { + r: bytes.NewBufferString("#reverse true\n#reload 10s\n*.example.com"), + reversed: false, + period: 0, + addr: "example.com", + bypassed: false, + stopped: true, + }, } func TestByapssReload(t *testing.T) { @@ -235,6 +275,8 @@ func TestByapssReload(t *testing.T) { if err := bp.Reload(tc.r); err != nil { t.Error(err) } + t.Log(bp.String()) + if bp.Reversed() != tc.reversed { t.Errorf("#%d test failed: reversed value should be %v, got %v", i, tc.reversed, bp.reversed) @@ -251,6 +293,7 @@ func TestByapssReload(t *testing.T) { if bp.Period() >= 0 { t.Errorf("period of the stopped reloader should be minus value") } + bp.Stop() } if bp.Stopped() != tc.stopped { t.Errorf("#%d test failed: stopped value should be %v, got %v", diff --git a/common_test.go b/common_test.go index 8221a81..0e8c348 100644 --- a/common_test.go +++ b/common_test.go @@ -16,8 +16,8 @@ import ( ) func init() { - // SetLogger(&LogLogger{}) - // Debug = true + SetLogger(&NopLogger{}) + Debug = true DialTimeout = 1000 * time.Millisecond HandshakeTimeout = 1000 * time.Millisecond ConnectTimeout = 1000 * time.Millisecond @@ -33,7 +33,11 @@ func init() { var ( httpTestHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - io.Copy(w, r.Body) + data, _ := ioutil.ReadAll(r.Body) + if len(data) == 0 { + data = []byte("Hello World!") + } + io.Copy(w, bytes.NewReader(data)) }) udpTestHandler = udpHandlerFunc(func(w io.Writer, r *udpRequest) { diff --git a/http2_test.go b/http2_test.go index 58c4784..6142fe7 100644 --- a/http2_test.go +++ b/http2_test.go @@ -1,9 +1,12 @@ package gost import ( + "bytes" "crypto/rand" "crypto/tls" "fmt" + "io/ioutil" + "net/http" "net/http/httptest" "net/url" "testing" @@ -920,3 +923,184 @@ func TestH2CForwardTunnel(t *testing.T) { t.Error(err) } } + +func TestHTTP2ProxyWithCodeProbeResist(t *testing.T) { + httpSrv := httptest.NewServer(httpTestHandler) + defer httpSrv.Close() + + ln, err := HTTP2Listener("", nil) + if err != nil { + t.Error(err) + } + + client := &Client{ + Connector: HTTP2Connector(nil), + Transporter: HTTP2Transporter(nil), + } + + server := &Server{ + Listener: ln, + Handler: HTTP2Handler( + UsersHandlerOption(url.UserPassword("admin", "123456")), + ProbeResistHandlerOption("code:400"), + ), + } + go server.Run() + defer server.Close() + + err = proxyRoundtrip(client, server, httpSrv.URL, nil) + if err == nil { + t.Error("should failed with status code 400") + } else if err.Error() != "400 Bad Request" { + t.Error("should failed with status code 400, got", err.Error()) + } +} + +func TestHTTP2ProxyWithWebProbeResist(t *testing.T) { + httpSrv := httptest.NewServer(httpTestHandler) + defer httpSrv.Close() + + ln, err := HTTP2Listener("", nil) + if err != nil { + t.Error(err) + } + + client := &Client{ + Connector: HTTP2Connector(nil), + Transporter: HTTP2Transporter(nil), + } + + server := &Server{ + Listener: ln, + Handler: HTTP2Handler( + UsersHandlerOption(url.UserPassword("admin", "123456")), + ProbeResistHandlerOption("web:"+httpSrv.URL), + ), + } + go server.Run() + defer server.Close() + + conn, err := proxyConn(client, server) + if err != nil { + t.Error(err) + } + defer conn.Close() + + conn, err = client.Connect(conn, "github.com:443") + if err != nil { + t.Error(err) + } + recv, _ := ioutil.ReadAll(conn) + if !bytes.Equal(recv, []byte("Hello World!")) { + t.Error("data not equal") + } +} + +func TestHTTP2ProxyWithHostProbeResist(t *testing.T) { + httpSrv := httptest.NewServer(httpTestHandler) + defer httpSrv.Close() + + sendData := make([]byte, 128) + rand.Read(sendData) + + ln, err := HTTP2Listener("", nil) + if err != nil { + t.Error(err) + } + + client := &Client{ + Connector: HTTP2Connector(nil), + Transporter: HTTP2Transporter(nil), + } + + u, err := url.Parse(httpSrv.URL) + if err != nil { + t.Error(err) + } + + server := &Server{ + Listener: ln, + Handler: HTTP2Handler( + UsersHandlerOption(url.UserPassword("admin", "123456")), + ProbeResistHandlerOption("host:"+u.Host), + ), + } + go server.Run() + defer server.Close() + + conn, err := proxyConn(client, server) + if err != nil { + t.Error(err) + } + defer conn.Close() + + cc, ok := conn.(*http2ClientConn) + if !ok { + t.Error("wrong connection type") + } + + req := &http.Request{ + Method: http.MethodConnect, + URL: &url.URL{Scheme: "https", Host: ln.Addr().String()}, + Header: make(http.Header), + Proto: "HTTP/2.0", + ProtoMajor: 2, + ProtoMinor: 0, + Body: ioutil.NopCloser(bytes.NewReader(sendData)), + Host: cc.addr, + ContentLength: -1, + } + req.Header.Set("Gost-Target", "github.com:443") + + resp, err := cc.client.Do(req) + if err != nil { + t.Error(err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + t.Error("got non-200 status:", resp.Status) + } + + recv, _ := ioutil.ReadAll(resp.Body) + if !bytes.Equal(sendData, recv) { + t.Error("data not equal") + } +} + +func TestHTTP2ProxyWithFileProbeResist(t *testing.T) { + ln, err := HTTP2Listener("", nil) + if err != nil { + t.Error(err) + } + + client := &Client{ + Connector: HTTP2Connector(nil), + Transporter: HTTP2Transporter(nil), + } + + server := &Server{ + Listener: ln, + Handler: HTTP2Handler( + UsersHandlerOption(url.UserPassword("admin", "123456")), + ProbeResistHandlerOption("file:.testdata/probe_resist.txt"), + ), + } + go server.Run() + defer server.Close() + + conn, err := proxyConn(client, server) + if err != nil { + t.Error(err) + } + defer conn.Close() + + conn, err = client.Connect(conn, "github.com:443") + if err != nil { + t.Error(err) + } + recv, _ := ioutil.ReadAll(conn) + if !bytes.Equal(recv, []byte("Hello World!")) { + t.Error("data not equal") + } +} diff --git a/http_test.go b/http_test.go index b5804ce..1fbb470 100644 --- a/http_test.go +++ b/http_test.go @@ -1,7 +1,11 @@ package gost import ( + "bytes" "crypto/rand" + "fmt" + "io/ioutil" + "net/http" "net/http/httptest" "net/url" "testing" @@ -59,19 +63,22 @@ func TestHTTPProxy(t *testing.T) { rand.Read(sendData) for i, tc := range httpProxyTests { - err := httpProxyRoundtrip(httpSrv.URL, sendData, tc.cliUser, tc.srvUsers) - if err == nil { - if tc.errStr != "" { - t.Errorf("#%d should failed with error %s", i, tc.errStr) + tc := tc + t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) { + err := httpProxyRoundtrip(httpSrv.URL, sendData, tc.cliUser, tc.srvUsers) + if err == nil { + if tc.errStr != "" { + t.Errorf("#%d should failed with error %s", i, tc.errStr) + } + } else { + if tc.errStr == "" { + t.Errorf("#%d got error %v", i, err) + } + if err.Error() != tc.errStr { + t.Errorf("#%d got error %v, want %v", i, err, tc.errStr) + } } - } else { - if tc.errStr == "" { - t.Errorf("#%d got error %v", i, err) - } - if err.Error() != tc.errStr { - t.Errorf("#%d got error %v, want %v", i, err, tc.errStr) - } - } + }) } } @@ -142,3 +149,152 @@ func BenchmarkHTTPProxyParallel(b *testing.B) { } }) } + +func TestHTTPProxyWithCodeProbeResist(t *testing.T) { + ln, err := TCPListener("") + if err != nil { + t.Error(err) + } + + server := &Server{ + Listener: ln, + Handler: HTTPHandler( + UsersHandlerOption(url.UserPassword("admin", "123456")), + ProbeResistHandlerOption("code:400"), + ), + } + go server.Run() + defer server.Close() + + resp, err := http.Get("http://" + ln.Addr().String()) + if err != nil { + t.Error(err) + } + defer resp.Body.Close() + + if resp.StatusCode != 400 { + t.Error("should failed with status code 400, got", resp.Status) + } +} + +func TestHTTPProxyWithWebProbeResist(t *testing.T) { + httpSrv := httptest.NewServer(httpTestHandler) + defer httpSrv.Close() + + ln, err := TCPListener("") + if err != nil { + t.Error(err) + } + + server := &Server{ + Listener: ln, + Handler: HTTPHandler( + UsersHandlerOption(url.UserPassword("admin", "123456")), + ProbeResistHandlerOption("web:"+httpSrv.URL), + ), + } + go server.Run() + defer server.Close() + + r, err := http.NewRequest("GET", "http://"+ln.Addr().String(), nil) + if err != nil { + t.Error(err) + } + resp, err := http.DefaultClient.Do(r) + if err != nil { + t.Error(err) + } + defer resp.Body.Close() + + if resp.StatusCode != 200 { + t.Error("got status:", resp.Status) + } + + recv, _ := ioutil.ReadAll(resp.Body) + if !bytes.Equal(recv, []byte("Hello World!")) { + t.Error("data not equal") + } +} + +func TestHTTPProxyWithHostProbeResist(t *testing.T) { + httpSrv := httptest.NewServer(httpTestHandler) + defer httpSrv.Close() + + sendData := make([]byte, 128) + rand.Read(sendData) + + ln, err := TCPListener("") + if err != nil { + t.Error(err) + } + + u, err := url.Parse(httpSrv.URL) + if err != nil { + t.Error(err) + } + + server := &Server{ + Listener: ln, + Handler: HTTPHandler( + UsersHandlerOption(url.UserPassword("admin", "123456")), + ProbeResistHandlerOption("host:"+u.Host), + ), + } + go server.Run() + defer server.Close() + + r, err := http.NewRequest("GET", "http://"+ln.Addr().String(), bytes.NewReader(sendData)) + if err != nil { + t.Error(err) + } + resp, err := http.DefaultClient.Do(r) + if err != nil { + t.Error(err) + } + defer resp.Body.Close() + + if resp.StatusCode != 200 { + t.Error("got status:", resp.Status) + } + + recv, _ := ioutil.ReadAll(resp.Body) + if !bytes.Equal(sendData, recv) { + t.Error("data not equal") + } +} + +func TestHTTPProxyWithFileProbeResist(t *testing.T) { + ln, err := TCPListener("") + if err != nil { + t.Error(err) + } + + server := &Server{ + Listener: ln, + Handler: HTTPHandler( + UsersHandlerOption(url.UserPassword("admin", "123456")), + ProbeResistHandlerOption("file:.testdata/probe_resist.txt"), + ), + } + go server.Run() + defer server.Close() + + r, err := http.NewRequest("GET", "http://"+ln.Addr().String(), nil) + if err != nil { + t.Error(err) + } + resp, err := http.DefaultClient.Do(r) + if err != nil { + t.Error(err) + } + defer resp.Body.Close() + + if resp.StatusCode != 200 { + t.Error("got status:", resp.Status) + } + + recv, _ := ioutil.ReadAll(resp.Body) + if !bytes.Equal(recv, []byte("Hello World!")) { + t.Error("data not equal, got:", string(recv)) + } +} diff --git a/snapcraft.yaml b/snapcraft.yaml index dd3a1de..d970183 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -1,5 +1,5 @@ name: gost -version: '2.6' +version: '2.7' summary: GO Simple Tunnel description: | A simple tunnel written in golang @@ -14,7 +14,7 @@ apps: parts: go: - source-tag: go1.10 + source-tag: go1.11 gost: after: [go] source: .