From c4241a0415f87ea1607323a0d40e7ade1b5190c5 Mon Sep 17 00:00:00 2001 From: Simone Basso Date: Tue, 28 Nov 2023 15:59:45 +0100 Subject: [PATCH] feat(webconnectivityqa): add more QA tests (#1397) This diff adds more QA tests extracted from https://github.com/ooni/probe-cli/pull/1392. Part of https://github.com/ooni/probe/issues/2634. --- internal/cmd/qatool/main_test.go | 3 ++ .../webconnectivityqa/dnsblocking.go | 24 ++++++++++++ .../webconnectivityqa/dnsblocking_test.go | 20 ++++++++++ .../webconnectivityqa/httpblocking.go | 37 +++++++++++++++++++ .../webconnectivityqa/httpblocking_test.go | 33 +++++++++++++++++ .../experiment/webconnectivityqa/success.go | 4 +- .../experiment/webconnectivityqa/testcase.go | 7 +++- 7 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 internal/experiment/webconnectivityqa/httpblocking.go create mode 100644 internal/experiment/webconnectivityqa/httpblocking_test.go diff --git a/internal/cmd/qatool/main_test.go b/internal/cmd/qatool/main_test.go index b1f231410c..de2bfdfe70 100644 --- a/internal/cmd/qatool/main_test.go +++ b/internal/cmd/qatool/main_test.go @@ -68,6 +68,9 @@ func TestMainSuccess(t *testing.T) { "xo/dnsBlockingAndroidDNSCacheNoData/measurement.json": true, "xo/dnsBlockingAndroidDNSCacheNoData/observations.json": true, "xo/dnsBlockingAndroidDNSCacheNoData/analysis.json": true, + "xo/dnsBlockingBOGON/analysis.json": true, + "xo/dnsBlockingBOGON/measurement.json": true, + "xo/dnsBlockingBOGON/observations.json": true, "xo/dnsBlockingNXDOMAIN/measurement.json": true, "xo/dnsBlockingNXDOMAIN/observations.json": true, "xo/dnsBlockingNXDOMAIN/analysis.json": true, diff --git a/internal/experiment/webconnectivityqa/dnsblocking.go b/internal/experiment/webconnectivityqa/dnsblocking.go index dc27caa9b6..e2bbbf1719 100644 --- a/internal/experiment/webconnectivityqa/dnsblocking.go +++ b/internal/experiment/webconnectivityqa/dnsblocking.go @@ -63,3 +63,27 @@ func dnsBlockingNXDOMAIN() *TestCase { }, } } + +// dnsBlockingBOGON is the case where there's DNS blocking by returning a bogon. +func dnsBlockingBOGON() *TestCase { + return &TestCase{ + Name: "dnsBlockingBOGON", + Flags: TestCaseFlagNoLTE, // We're not ready yet + Input: "https://www.example.com/", + Configure: func(env *netemx.QAEnv) { + env.ISPResolverConfig().RemoveRecord("www.example.com") + env.ISPResolverConfig().AddRecord("www.example.com", "", "10.10.34.35") + }, + ExpectErr: false, + ExpectTestKeys: &testKeys{ + HTTPExperimentFailure: "generic_timeout_error", + DNSExperimentFailure: nil, + DNSConsistency: "inconsistent", + XStatus: 4256, // StatusExperimentConnect | StatusAnomalyConnect | StatusAnomalyDNS + XDNSFlags: 1, // AnalysisDNSBogon + XBlockingFlags: 33, // analysisFlagDNSBlocking | analysisFlagSuccess + Accessible: false, + Blocking: "dns", + }, + } +} diff --git a/internal/experiment/webconnectivityqa/dnsblocking_test.go b/internal/experiment/webconnectivityqa/dnsblocking_test.go index 0f4b6adf6b..431f5f3a7d 100644 --- a/internal/experiment/webconnectivityqa/dnsblocking_test.go +++ b/internal/experiment/webconnectivityqa/dnsblocking_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/apex/log" + "github.com/google/go-cmp/cmp" "github.com/ooni/probe-cli/v3/internal/netemx" "github.com/ooni/probe-cli/v3/internal/netxlite" ) @@ -47,3 +48,22 @@ func TestDNSBlockingNXDOMAIN(t *testing.T) { } }) } + +func TestDNSBlockingBOGON(t *testing.T) { + env := netemx.MustNewScenario(netemx.InternetScenario) + defer env.Close() + + tc := dnsBlockingBOGON() + tc.Configure(env) + + env.Do(func() { + reso := netxlite.NewStdlibResolver(log.Log) + addrs, err := reso.LookupHost(context.Background(), "www.example.com") + if err != nil { + t.Fatal(err) + } + if diff := cmp.Diff([]string{"10.10.34.35"}, addrs); diff != "" { + t.Fatal(diff) + } + }) +} diff --git a/internal/experiment/webconnectivityqa/httpblocking.go b/internal/experiment/webconnectivityqa/httpblocking.go new file mode 100644 index 0000000000..0c15c99124 --- /dev/null +++ b/internal/experiment/webconnectivityqa/httpblocking.go @@ -0,0 +1,37 @@ +package webconnectivityqa + +import ( + "github.com/ooni/netem" + "github.com/ooni/probe-cli/v3/internal/netemx" +) + +// httpBlockingConnectionReset verifies the case where there is a connection reset +// when the host header is emitted on the wire in cleartext. +func httpBlockingConnectionReset() *TestCase { + return &TestCase{ + Name: "httpBlockingConnectionReset", + Flags: 0, + Input: "http://www.example.com/", + Configure: func(env *netemx.QAEnv) { + + env.DPIEngine().AddRule(&netem.DPIResetTrafficForString{ + Logger: env.Logger(), + ServerIPAddress: netemx.AddressWwwExampleCom, + ServerPort: 80, + String: "www.example.com", + }) + + }, + ExpectErr: false, + ExpectTestKeys: &testKeys{ + DNSConsistency: "consistent", + // TODO(bassosimone): it seems LTE QA does not check for the value of + // the HTTPExperimentFailure field, why? + HTTPExperimentFailure: "connection_reset", + XStatus: 8448, // StatusExperimentHTTP | StatusAnomalyReadWrite + XBlockingFlags: 8, // analysisFlagHTTPBlocking + Accessible: false, + Blocking: "http-failure", + }, + } +} diff --git a/internal/experiment/webconnectivityqa/httpblocking_test.go b/internal/experiment/webconnectivityqa/httpblocking_test.go new file mode 100644 index 0000000000..3bcd36a494 --- /dev/null +++ b/internal/experiment/webconnectivityqa/httpblocking_test.go @@ -0,0 +1,33 @@ +package webconnectivityqa + +import ( + "net/http" + "strings" + "testing" + + "github.com/apex/log" + "github.com/ooni/probe-cli/v3/internal/netemx" + "github.com/ooni/probe-cli/v3/internal/netxlite" +) + +func TestHTTPBlockingConnectionReset(t *testing.T) { + env := netemx.MustNewScenario(netemx.InternetScenario) + defer env.Close() + + tc := httpBlockingConnectionReset() + tc.Configure(env) + + env.Do(func() { + dialer := netxlite.NewDialerWithStdlibResolver(log.Log) + tlsDialer := netxlite.NewTLSDialer(dialer, netxlite.NewTLSHandshakerStdlib(log.Log)) + txp := netxlite.NewHTTPTransportWithOptions(log.Log, dialer, tlsDialer) + client := &http.Client{Transport: txp} + resp, err := client.Get("http://www.example.com/") + if err == nil || !strings.HasSuffix(err.Error(), "connection_reset") { + t.Fatal("unexpected err", err) + } + if resp != nil { + t.Fatal("expected nil resp") + } + }) +} diff --git a/internal/experiment/webconnectivityqa/success.go b/internal/experiment/webconnectivityqa/success.go index e2e628cbf7..1bd25bbaa4 100644 --- a/internal/experiment/webconnectivityqa/success.go +++ b/internal/experiment/webconnectivityqa/success.go @@ -1,7 +1,7 @@ package webconnectivityqa // successWithHTTP ensures we can successfully measure an HTTP URL. -func sucessWithHTTP() *TestCase { +func successWithHTTP() *TestCase { return &TestCase{ Name: "successWithHTTP", Flags: 0, @@ -24,7 +24,7 @@ func sucessWithHTTP() *TestCase { } // successWithHTTPS ensures we can successfully measure an HTTPS URL. -func sucessWithHTTPS() *TestCase { +func successWithHTTPS() *TestCase { return &TestCase{ Name: "successWithHTTPS", Flags: TestCaseFlagNoLTE, // it does not set any HTTP comparison value with HTTPS diff --git a/internal/experiment/webconnectivityqa/testcase.go b/internal/experiment/webconnectivityqa/testcase.go index 37ef5919db..0b0b0b7b02 100644 --- a/internal/experiment/webconnectivityqa/testcase.go +++ b/internal/experiment/webconnectivityqa/testcase.go @@ -46,11 +46,14 @@ func AllTestCases() []*TestCase { controlFailureWithSuccessfulHTTPSWebsite(), dnsBlockingAndroidDNSCacheNoData(), + dnsBlockingBOGON(), dnsBlockingNXDOMAIN(), dnsHijackingToProxyWithHTTPURL(), dnsHijackingToProxyWithHTTPSURL(), + httpBlockingConnectionReset(), + httpDiffWithConsistentDNS(), httpDiffWithInconsistentDNS(), @@ -64,8 +67,8 @@ func AllTestCases() []*TestCase { redirectWithConsistentDNSAndThenTimeoutForHTTP(), redirectWithConsistentDNSAndThenTimeoutForHTTPS(), - sucessWithHTTP(), - sucessWithHTTPS(), + successWithHTTP(), + successWithHTTPS(), tcpBlockingConnectTimeout(), tcpBlockingConnectionRefusedWithInconsistentDNS(),