From 2e0118d1a65362f8fa03b2b89da1bdf87121f475 Mon Sep 17 00:00:00 2001 From: Simone Basso Date: Sun, 5 Sep 2021 14:49:38 +0200 Subject: [PATCH] refactor(netxlite): hide details without breaking the rest of the tree (#454) ## Description This PR continues the refactoring of `netx` under the following principles: 1. do not break the rest of the tree and do not engage in extensive tree-wide refactoring yet 2. move under `netxlite` clearly related subpackages (e.g., `iox`, `netxmocks`) 3. move into `internal/netxlite/internal` stuff that is clearly private of `netxlite` 4. hide implementation details in `netxlite` pending new factories 5. refactor `tls` code in `netxlite` to clearly separate `crypto/tls` code from `utls` code After each commit, I run `go test -short -race ./...` locally. Each individual commit explains what it does. I will squash, but this operation will preserve the original commit titles, so this will give further insight on each step. ## Commits * refactor: rename netxmocks -> netxlite/mocks Part of https://github.com/ooni/probe/issues/1591 * refactor: rename quicx -> netxlite/quicx See https://github.com/ooni/probe/issues/1591 * refactor: rename iox -> netxlite/iox Regenerate sources and make sure the tests pass. See https://github.com/ooni/probe/issues/1591. * refactor(iox): move MockableReader to netxlite/mocks See https://github.com/ooni/probe/issues/1591 * refactor(netxlite): generator is an implementation detail See https://github.com/ooni/probe/issues/1591 * refactor(netxlite): separate tls and utls code See https://github.com/ooni/probe/issues/1591 * refactor(netxlite): hide most types but keep old names as legacy With this change we avoid breaking the rest of the tree, but we start hiding some implementation details a bit. Factories will follow. See https://github.com/ooni/probe/issues/1591 --- CONTRIBUTING.md | 4 +- cmd/ooniprobe/internal/config/parser_test.go | 2 +- cmd/ooniprobe/internal/database/database.go | 2 +- internal/bytecounter/conn_test.go | 6 +- internal/cmd/jafar/badproxy/badproxy.go | 2 +- .../cmd/jafar/httpproxy/httpproxy_test.go | 2 +- internal/cmd/jafar/iptables/iptables_linux.go | 1 + .../jafar/iptables/iptables_unsupported.go | 1 + .../cmd/jafar/uncensored/uncensored_test.go | 2 +- internal/cmd/oohelper/internal/client.go | 2 +- internal/cmd/oohelper/internal/fake_test.go | 2 +- .../internal/webconnectivity/fake_test.go | 2 +- .../internal/webconnectivity/http.go | 2 +- .../webconnectivity/webconnectivity.go | 2 +- .../webconnectivity/webconnectivity_test.go | 2 +- .../oohelperd/internal/websteps/websteps.go | 2 +- .../internal/websteps/websteps_test.go | 2 +- internal/engine/experiment/dash/dash.go | 2 +- internal/engine/experiment/hhfm/fake_test.go | 2 +- internal/engine/experiment/hhfm/hhfm.go | 2 +- internal/engine/experiment/ndt7/download.go | 2 +- .../engine/experiment/urlgetter/runner.go | 2 +- .../engine/experiment/websteps/websteps.go | 2 +- internal/engine/geolocate/fake_test.go | 2 +- internal/engine/httpx/fake_test.go | 2 +- internal/engine/httpx/jsonapi.go | 2 +- .../engine/legacy/netx/emitterdialer_test.go | 8 +- internal/engine/legacy/netx/http_test.go | 2 +- .../netx/oldhttptransport/bodytracer_test.go | 2 +- .../oldhttptransport/httptransport_test.go | 2 +- .../netx/oldhttptransport/tracetripper.go | 2 +- .../oldhttptransport/tracetripper_test.go | 2 +- .../legacy/netxlogger/netxlogger_test.go | 2 +- .../legacy/oonitemplates/oonitemplates.go | 2 +- .../engine/netx/dialer/bytecounter_test.go | 6 +- internal/engine/netx/dialer/proxy_test.go | 6 +- internal/engine/netx/dialer/saver_test.go | 10 +- .../engine/netx/dialer/shaping_disabled.go | 1 + .../engine/netx/dialer/shaping_enabled.go | 1 + internal/engine/netx/fake_test.go | 2 +- .../netx/httptransport/bytecounter_test.go | 2 +- .../engine/netx/httptransport/fake_test.go | 2 +- internal/engine/netx/httptransport/saver.go | 2 +- .../engine/netx/httptransport/saver_test.go | 2 +- internal/engine/netx/integration_test.go | 2 +- internal/engine/netx/quicdialer/system.go | 2 +- .../engine/netx/quicdialer/system_test.go | 6 +- internal/engine/netx/resolver/dnsoverhttps.go | 2 +- .../engine/probeservices/collector_test.go | 2 +- .../probeservices/probeservices_test.go | 2 +- internal/engine/session_integration_test.go | 2 +- internal/engine/session_nopsiphon.go | 1 + internal/engine/session_nopsiphon_test.go | 1 + internal/engine/session_psiphon.go | 3 +- internal/engine/session_psiphon_test.go | 1 + internal/errorsx/dialer_test.go | 18 +- internal/errorsx/errno.go | 2 +- internal/errorsx/errno_test.go | 2 +- internal/errorsx/errno_unix.go | 2 +- internal/errorsx/errno_windows.go | 2 +- internal/errorsx/quic.go | 2 +- internal/errorsx/quic_test.go | 18 +- internal/errorsx/resolver_test.go | 8 +- internal/errorsx/tls_test.go | 6 +- internal/fsx/example_test.go | 2 +- internal/mlablocate/mlablocate.go | 2 +- internal/mlablocatev2/fake_test.go | 2 +- internal/mlablocatev2/mlablocatev2.go | 2 +- internal/netxlite/certifi.go | 190 ++++---- internal/netxlite/dialer.go | 24 +- internal/netxlite/dialer_test.go | 34 +- internal/netxlite/http.go | 12 +- internal/netxlite/http3_test.go | 6 +- internal/netxlite/http_test.go | 32 +- .../netxlite/{ => internal}/generator/main.go | 4 +- internal/{ => netxlite}/iox/example_test.go | 2 +- internal/{ => netxlite}/iox/iox.go | 13 - internal/{ => netxlite}/iox/iox_test.go | 10 +- internal/netxlite/legacy.go | 22 + .../{netxmocks => netxlite/mocks}/conn.go | 2 +- .../mocks}/conn_test.go | 2 +- .../{netxmocks => netxlite/mocks}/dialer.go | 2 +- .../mocks}/dialer_test.go | 2 +- internal/netxlite/mocks/doc.go | 2 + .../{netxmocks => netxlite/mocks}/http.go | 2 +- .../mocks}/http_test.go | 2 +- .../{netxmocks => netxlite/mocks}/quic.go | 4 +- .../mocks}/quic_test.go | 4 +- internal/netxlite/mocks/reader.go | 16 + internal/netxlite/mocks/reader_test.go | 23 + .../{netxmocks => netxlite/mocks}/resolver.go | 2 +- .../mocks}/resolver_test.go | 2 +- .../{netxmocks => netxlite/mocks}/tlsconn.go | 2 +- .../mocks}/tlsconn_test.go | 2 +- .../mocks}/tlshandshaker.go | 2 +- .../mocks}/tlshandshaker_test.go | 2 +- internal/netxlite/quic.go | 42 +- internal/netxlite/quic_test.go | 70 +-- internal/{ => netxlite}/quicx/quicx.go | 2 +- internal/netxlite/resolver.go | 36 +- internal/netxlite/resolver_test.go | 30 +- internal/netxlite/tls.go | 273 ++++++++++++ internal/netxlite/tls_test.go | 409 ++++++++++++++++++ internal/netxlite/tlsconn.go | 18 - internal/netxlite/tlsdialer.go | 64 --- internal/netxlite/tlsdialer_test.go | 145 ------- internal/netxlite/tlshandshaker.go | 148 ------- internal/netxlite/tlshandshaker_test.go | 198 --------- internal/netxlite/tlsx.go | 101 ----- internal/netxlite/tlsx_test.go | 105 ----- internal/netxlite/utls.go | 46 ++ internal/netxlite/utls_test.go | 28 ++ internal/netxmocks/doc.go | 2 - internal/ooapi/apis.go | 2 +- internal/ooapi/apis_test.go | 4 +- internal/ooapi/caching.go | 2 +- internal/ooapi/caching_test.go | 2 +- internal/ooapi/callers.go | 2 +- internal/ooapi/clientcall.go | 2 +- internal/ooapi/clientcall_test.go | 4 +- internal/ooapi/cloners.go | 2 +- internal/ooapi/fake_test.go | 2 +- internal/ooapi/fakeapi_test.go | 2 +- internal/ooapi/internal/generator/apistest.go | 2 +- .../internal/generator/clientcalltest.go | 2 +- .../ooapi/internal/generator/responses.go | 2 +- internal/ooapi/login.go | 2 +- internal/ooapi/login_test.go | 2 +- internal/ooapi/loginhandler_test.go | 2 +- internal/ooapi/requests.go | 2 +- internal/ooapi/responses.go | 4 +- internal/ooapi/swagger_test.go | 4 +- internal/ooapi/swaggerdiff_test.go | 2 +- internal/ptx/obfs4_test.go | 8 +- internal/ptx/ptx.go | 2 +- internal/ptx/ptx_test.go | 10 +- internal/ptx/snowflake_test.go | 6 +- 137 files changed, 1244 insertions(+), 1173 deletions(-) rename internal/netxlite/{ => internal}/generator/main.go (93%) rename internal/{ => netxlite}/iox/example_test.go (84%) rename internal/{ => netxlite}/iox/iox.go (82%) rename internal/{ => netxlite}/iox/iox_test.go (95%) rename internal/{netxmocks => netxlite/mocks}/conn.go (98%) rename internal/{netxmocks => netxlite/mocks}/conn_test.go (99%) rename internal/{netxmocks => netxlite/mocks}/dialer.go (95%) rename internal/{netxmocks => netxlite/mocks}/dialer_test.go (96%) create mode 100644 internal/netxlite/mocks/doc.go rename internal/{netxmocks => netxlite/mocks}/http.go (96%) rename internal/{netxmocks => netxlite/mocks}/http_test.go (97%) rename internal/{netxmocks => netxlite/mocks}/quic.go (98%) rename internal/{netxmocks => netxlite/mocks}/quic_test.go (99%) create mode 100644 internal/netxlite/mocks/reader.go create mode 100644 internal/netxlite/mocks/reader_test.go rename internal/{netxmocks => netxlite/mocks}/resolver.go (96%) rename internal/{netxmocks => netxlite/mocks}/resolver_test.go (97%) rename internal/{netxmocks => netxlite/mocks}/tlsconn.go (96%) rename internal/{netxmocks => netxlite/mocks}/tlsconn_test.go (97%) rename internal/{netxmocks => netxlite/mocks}/tlshandshaker.go (96%) rename internal/{netxmocks => netxlite/mocks}/tlshandshaker_test.go (97%) rename internal/{ => netxlite}/quicx/quicx.go (95%) create mode 100644 internal/netxlite/tls.go create mode 100644 internal/netxlite/tls_test.go delete mode 100644 internal/netxlite/tlsconn.go delete mode 100644 internal/netxlite/tlsdialer.go delete mode 100644 internal/netxlite/tlsdialer_test.go delete mode 100644 internal/netxlite/tlshandshaker.go delete mode 100644 internal/netxlite/tlshandshaker_test.go delete mode 100644 internal/netxlite/tlsx.go delete mode 100644 internal/netxlite/tlsx_test.go create mode 100644 internal/netxlite/utls.go create mode 100644 internal/netxlite/utls_test.go delete mode 100644 internal/netxmocks/doc.go diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 626d40b..5a79986 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -65,8 +65,8 @@ run `go mod tidy` to minimize such changes. - use `./internal/fsx.OpenFile` when you need to open a file -- use `./internal/iox.ReadAllContext` instead of `io.ReadAll` -and `./internal/iox.CopyContext` instead of `io.Copy` +- use `./internal/netxlite/iox.ReadAllContext` instead of `io.ReadAll` +and `./internal/netxlite/iox.CopyContext` instead of `io.Copy` ## Code testing requirements diff --git a/cmd/ooniprobe/internal/config/parser_test.go b/cmd/ooniprobe/internal/config/parser_test.go index 05579a0..0399f15 100644 --- a/cmd/ooniprobe/internal/config/parser_test.go +++ b/cmd/ooniprobe/internal/config/parser_test.go @@ -8,7 +8,7 @@ import ( "os" "testing" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) func getShasum(path string) (string, error) { diff --git a/cmd/ooniprobe/internal/database/database.go b/cmd/ooniprobe/internal/database/database.go index 2589a8c..0673156 100644 --- a/cmd/ooniprobe/internal/database/database.go +++ b/cmd/ooniprobe/internal/database/database.go @@ -6,7 +6,7 @@ import ( "embed" "github.com/apex/log" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" migrate "github.com/rubenv/sql-migrate" "upper.io/db.v3/lib/sqlbuilder" "upper.io/db.v3/sqlite" diff --git a/internal/bytecounter/conn_test.go b/internal/bytecounter/conn_test.go index 88bc67a..0b254bb 100644 --- a/internal/bytecounter/conn_test.go +++ b/internal/bytecounter/conn_test.go @@ -4,12 +4,12 @@ import ( "errors" "testing" - "github.com/ooni/probe-cli/v3/internal/netxmocks" + "github.com/ooni/probe-cli/v3/internal/netxlite/mocks" ) func TestConnWorksOnSuccess(t *testing.T) { counter := New() - underlying := &netxmocks.Conn{ + underlying := &mocks.Conn{ MockRead: func(b []byte) (int, error) { return 10, nil }, @@ -39,7 +39,7 @@ func TestConnWorksOnFailure(t *testing.T) { readError := errors.New("read error") writeError := errors.New("write error") counter := New() - underlying := &netxmocks.Conn{ + underlying := &mocks.Conn{ MockRead: func(b []byte) (int, error) { return 0, readError }, diff --git a/internal/cmd/jafar/badproxy/badproxy.go b/internal/cmd/jafar/badproxy/badproxy.go index 2eebb3f..4c85ada 100644 --- a/internal/cmd/jafar/badproxy/badproxy.go +++ b/internal/cmd/jafar/badproxy/badproxy.go @@ -16,7 +16,7 @@ import ( "time" "github.com/google/martian/v3/mitm" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) // CensoringProxy is a proxy that does not behave correctly. diff --git a/internal/cmd/jafar/httpproxy/httpproxy_test.go b/internal/cmd/jafar/httpproxy/httpproxy_test.go index a701ce1..b24654b 100644 --- a/internal/cmd/jafar/httpproxy/httpproxy_test.go +++ b/internal/cmd/jafar/httpproxy/httpproxy_test.go @@ -8,7 +8,7 @@ import ( "testing" "github.com/ooni/probe-cli/v3/internal/cmd/jafar/uncensored" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) func TestPass(t *testing.T) { diff --git a/internal/cmd/jafar/iptables/iptables_linux.go b/internal/cmd/jafar/iptables/iptables_linux.go index 1cd034d..b994dc2 100644 --- a/internal/cmd/jafar/iptables/iptables_linux.go +++ b/internal/cmd/jafar/iptables/iptables_linux.go @@ -1,3 +1,4 @@ +//go:build linux // +build linux package iptables diff --git a/internal/cmd/jafar/iptables/iptables_unsupported.go b/internal/cmd/jafar/iptables/iptables_unsupported.go index 0ffd0c8..216f719 100644 --- a/internal/cmd/jafar/iptables/iptables_unsupported.go +++ b/internal/cmd/jafar/iptables/iptables_unsupported.go @@ -1,3 +1,4 @@ +//go:build !linux // +build !linux package iptables diff --git a/internal/cmd/jafar/uncensored/uncensored_test.go b/internal/cmd/jafar/uncensored/uncensored_test.go index 731318c..4ce05cc 100644 --- a/internal/cmd/jafar/uncensored/uncensored_test.go +++ b/internal/cmd/jafar/uncensored/uncensored_test.go @@ -7,7 +7,7 @@ import ( "net/url" "testing" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) func TestGood(t *testing.T) { diff --git a/internal/cmd/oohelper/internal/client.go b/internal/cmd/oohelper/internal/client.go index 0f9fd23..d8de90a 100644 --- a/internal/cmd/oohelper/internal/client.go +++ b/internal/cmd/oohelper/internal/client.go @@ -14,7 +14,7 @@ import ( "github.com/ooni/probe-cli/v3/internal/engine/experiment/webconnectivity" "github.com/ooni/probe-cli/v3/internal/engine/httpheader" "github.com/ooni/probe-cli/v3/internal/engine/netx" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" "github.com/ooni/probe-cli/v3/internal/runtimex" "github.com/ooni/probe-cli/v3/internal/version" ) diff --git a/internal/cmd/oohelper/internal/fake_test.go b/internal/cmd/oohelper/internal/fake_test.go index df7987b..0b5382f 100644 --- a/internal/cmd/oohelper/internal/fake_test.go +++ b/internal/cmd/oohelper/internal/fake_test.go @@ -9,7 +9,7 @@ import ( "github.com/ooni/probe-cli/v3/internal/atomicx" "github.com/ooni/probe-cli/v3/internal/engine/netx" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) type FakeResolver struct { diff --git a/internal/cmd/oohelperd/internal/webconnectivity/fake_test.go b/internal/cmd/oohelperd/internal/webconnectivity/fake_test.go index 177c40c..9787499 100644 --- a/internal/cmd/oohelperd/internal/webconnectivity/fake_test.go +++ b/internal/cmd/oohelperd/internal/webconnectivity/fake_test.go @@ -9,7 +9,7 @@ import ( "github.com/ooni/probe-cli/v3/internal/atomicx" "github.com/ooni/probe-cli/v3/internal/engine/netx" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) type FakeResolver struct { diff --git a/internal/cmd/oohelperd/internal/webconnectivity/http.go b/internal/cmd/oohelperd/internal/webconnectivity/http.go index 6a84e5f..673c6e2 100644 --- a/internal/cmd/oohelperd/internal/webconnectivity/http.go +++ b/internal/cmd/oohelperd/internal/webconnectivity/http.go @@ -8,7 +8,7 @@ import ( "sync" "github.com/ooni/probe-cli/v3/internal/engine/experiment/webconnectivity" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) // CtrlHTTPResponse is the result of the HTTP check performed by diff --git a/internal/cmd/oohelperd/internal/webconnectivity/webconnectivity.go b/internal/cmd/oohelperd/internal/webconnectivity/webconnectivity.go index 3e18b57..5d35af6 100644 --- a/internal/cmd/oohelperd/internal/webconnectivity/webconnectivity.go +++ b/internal/cmd/oohelperd/internal/webconnectivity/webconnectivity.go @@ -7,7 +7,7 @@ import ( "net/http" "github.com/ooni/probe-cli/v3/internal/engine/netx" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" "github.com/ooni/probe-cli/v3/internal/runtimex" "github.com/ooni/probe-cli/v3/internal/version" ) diff --git a/internal/cmd/oohelperd/internal/webconnectivity/webconnectivity_test.go b/internal/cmd/oohelperd/internal/webconnectivity/webconnectivity_test.go index 4b9770c..c03e18f 100644 --- a/internal/cmd/oohelperd/internal/webconnectivity/webconnectivity_test.go +++ b/internal/cmd/oohelperd/internal/webconnectivity/webconnectivity_test.go @@ -10,8 +10,8 @@ import ( "strings" "testing" - "github.com/ooni/probe-cli/v3/internal/iox" "github.com/ooni/probe-cli/v3/internal/netxlite" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) const simplerequest = `{ diff --git a/internal/cmd/oohelperd/internal/websteps/websteps.go b/internal/cmd/oohelperd/internal/websteps/websteps.go index ee7f899..1a3d6fe 100644 --- a/internal/cmd/oohelperd/internal/websteps/websteps.go +++ b/internal/cmd/oohelperd/internal/websteps/websteps.go @@ -13,7 +13,7 @@ import ( "net/http" "github.com/ooni/probe-cli/v3/internal/engine/netx/archival" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" "github.com/ooni/probe-cli/v3/internal/runtimex" "github.com/ooni/probe-cli/v3/internal/version" ) diff --git a/internal/cmd/oohelperd/internal/websteps/websteps_test.go b/internal/cmd/oohelperd/internal/websteps/websteps_test.go index 00f802d..e00596d 100644 --- a/internal/cmd/oohelperd/internal/websteps/websteps_test.go +++ b/internal/cmd/oohelperd/internal/websteps/websteps_test.go @@ -10,7 +10,7 @@ import ( "testing" "time" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) const requestnoredirect = `{ diff --git a/internal/engine/experiment/dash/dash.go b/internal/engine/experiment/dash/dash.go index 4cb6869..698dfbd 100644 --- a/internal/engine/experiment/dash/dash.go +++ b/internal/engine/experiment/dash/dash.go @@ -19,7 +19,7 @@ import ( "github.com/ooni/probe-cli/v3/internal/engine/netx/trace" "github.com/ooni/probe-cli/v3/internal/errorsx" "github.com/ooni/probe-cli/v3/internal/humanize" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) const ( diff --git a/internal/engine/experiment/hhfm/fake_test.go b/internal/engine/experiment/hhfm/fake_test.go index ee0c7b8..0c7e3c6 100644 --- a/internal/engine/experiment/hhfm/fake_test.go +++ b/internal/engine/experiment/hhfm/fake_test.go @@ -6,7 +6,7 @@ import ( "net/http" "time" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) type FakeDialer struct { diff --git a/internal/engine/experiment/hhfm/hhfm.go b/internal/engine/experiment/hhfm/hhfm.go index 3283c63..c6fdffb 100644 --- a/internal/engine/experiment/hhfm/hhfm.go +++ b/internal/engine/experiment/hhfm/hhfm.go @@ -20,7 +20,7 @@ import ( "github.com/ooni/probe-cli/v3/internal/engine/netx/archival" "github.com/ooni/probe-cli/v3/internal/engine/netx/dialer" "github.com/ooni/probe-cli/v3/internal/errorsx" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" "github.com/ooni/probe-cli/v3/internal/randx" ) diff --git a/internal/engine/experiment/ndt7/download.go b/internal/engine/experiment/ndt7/download.go index 1789aa2..98dc204 100644 --- a/internal/engine/experiment/ndt7/download.go +++ b/internal/engine/experiment/ndt7/download.go @@ -7,7 +7,7 @@ import ( "time" "github.com/gorilla/websocket" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) type downloadManager struct { diff --git a/internal/engine/experiment/urlgetter/runner.go b/internal/engine/experiment/urlgetter/runner.go index be34093..4f9f939 100644 --- a/internal/engine/experiment/urlgetter/runner.go +++ b/internal/engine/experiment/urlgetter/runner.go @@ -12,7 +12,7 @@ import ( "github.com/ooni/probe-cli/v3/internal/engine/httpheader" "github.com/ooni/probe-cli/v3/internal/engine/netx" "github.com/ooni/probe-cli/v3/internal/errorsx" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" "github.com/ooni/probe-cli/v3/internal/runtimex" ) diff --git a/internal/engine/experiment/websteps/websteps.go b/internal/engine/experiment/websteps/websteps.go index 676fd3e..7bba6e6 100644 --- a/internal/engine/experiment/websteps/websteps.go +++ b/internal/engine/experiment/websteps/websteps.go @@ -66,7 +66,7 @@ func (m Measurer) ExperimentVersion() string { // SupportedQUICVersions are the H3 over QUIC versions we currently support var SupportedQUICVersions = map[string]bool{ - "h3": true, + "h3": true, } var ( diff --git a/internal/engine/geolocate/fake_test.go b/internal/engine/geolocate/fake_test.go index 93c8589..16c5487 100644 --- a/internal/engine/geolocate/fake_test.go +++ b/internal/engine/geolocate/fake_test.go @@ -4,7 +4,7 @@ import ( "net/http" "time" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) type FakeTransport struct { diff --git a/internal/engine/httpx/fake_test.go b/internal/engine/httpx/fake_test.go index a5c94ea..60ef9bd 100644 --- a/internal/engine/httpx/fake_test.go +++ b/internal/engine/httpx/fake_test.go @@ -4,7 +4,7 @@ import ( "net/http" "time" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) type FakeTransport struct { diff --git a/internal/engine/httpx/jsonapi.go b/internal/engine/httpx/jsonapi.go index 0845295..8e6ce42 100644 --- a/internal/engine/httpx/jsonapi.go +++ b/internal/engine/httpx/jsonapi.go @@ -10,7 +10,7 @@ import ( "net/http" "net/url" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) // Logger is the definition of Logger used by this package. diff --git a/internal/engine/legacy/netx/emitterdialer_test.go b/internal/engine/legacy/netx/emitterdialer_test.go index 485b935..155d632 100644 --- a/internal/engine/legacy/netx/emitterdialer_test.go +++ b/internal/engine/legacy/netx/emitterdialer_test.go @@ -10,7 +10,7 @@ import ( "github.com/ooni/probe-cli/v3/internal/engine/legacy/netx/handlers" "github.com/ooni/probe-cli/v3/internal/engine/legacy/netx/modelx" - "github.com/ooni/probe-cli/v3/internal/netxmocks" + "github.com/ooni/probe-cli/v3/internal/netxlite/mocks" ) func TestEmitterFailure(t *testing.T) { @@ -20,7 +20,7 @@ func TestEmitterFailure(t *testing.T) { Beginning: time.Now(), Handler: saver, }) - d := EmitterDialer{Dialer: &netxmocks.Dialer{ + d := EmitterDialer{Dialer: &mocks.Dialer{ MockDialContext: func(ctx context.Context, network string, address string) (net.Conn, error) { return nil, io.EOF }, @@ -69,9 +69,9 @@ func TestEmitterSuccess(t *testing.T) { Beginning: time.Now(), Handler: saver, }) - d := EmitterDialer{Dialer: &netxmocks.Dialer{ + d := EmitterDialer{Dialer: &mocks.Dialer{ MockDialContext: func(ctx context.Context, network string, address string) (net.Conn, error) { - return &netxmocks.Conn{ + return &mocks.Conn{ MockRead: func(b []byte) (int, error) { return 0, io.EOF }, diff --git a/internal/engine/legacy/netx/http_test.go b/internal/engine/legacy/netx/http_test.go index 9b163db..8de5267 100644 --- a/internal/engine/legacy/netx/http_test.go +++ b/internal/engine/legacy/netx/http_test.go @@ -14,7 +14,7 @@ import ( "github.com/ooni/probe-cli/v3/internal/engine/legacy/netx" "github.com/ooni/probe-cli/v3/internal/errorsx" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) func dowithclient(t *testing.T, client *netx.HTTPClient) { diff --git a/internal/engine/legacy/netx/oldhttptransport/bodytracer_test.go b/internal/engine/legacy/netx/oldhttptransport/bodytracer_test.go index a33d71b..e0b9406 100644 --- a/internal/engine/legacy/netx/oldhttptransport/bodytracer_test.go +++ b/internal/engine/legacy/netx/oldhttptransport/bodytracer_test.go @@ -5,7 +5,7 @@ import ( "net/http" "testing" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) func TestBodyTracerSuccess(t *testing.T) { diff --git a/internal/engine/legacy/netx/oldhttptransport/httptransport_test.go b/internal/engine/legacy/netx/oldhttptransport/httptransport_test.go index 835dc3d..40b67ab 100644 --- a/internal/engine/legacy/netx/oldhttptransport/httptransport_test.go +++ b/internal/engine/legacy/netx/oldhttptransport/httptransport_test.go @@ -5,7 +5,7 @@ import ( "net/http" "testing" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) func TestGood(t *testing.T) { diff --git a/internal/engine/legacy/netx/oldhttptransport/tracetripper.go b/internal/engine/legacy/netx/oldhttptransport/tracetripper.go index a8fe33c..f074d9a 100644 --- a/internal/engine/legacy/netx/oldhttptransport/tracetripper.go +++ b/internal/engine/legacy/netx/oldhttptransport/tracetripper.go @@ -13,7 +13,7 @@ import ( "github.com/ooni/probe-cli/v3/internal/atomicx" "github.com/ooni/probe-cli/v3/internal/engine/legacy/netx/modelx" "github.com/ooni/probe-cli/v3/internal/errorsx" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) // TraceTripper performs single HTTP transactions. diff --git a/internal/engine/legacy/netx/oldhttptransport/tracetripper_test.go b/internal/engine/legacy/netx/oldhttptransport/tracetripper_test.go index 990bc4a..24f5856 100644 --- a/internal/engine/legacy/netx/oldhttptransport/tracetripper_test.go +++ b/internal/engine/legacy/netx/oldhttptransport/tracetripper_test.go @@ -13,7 +13,7 @@ import ( "github.com/miekg/dns" "github.com/ooni/probe-cli/v3/internal/engine/legacy/netx/modelx" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) func TestTraceTripperSuccess(t *testing.T) { diff --git a/internal/engine/legacy/netxlogger/netxlogger_test.go b/internal/engine/legacy/netxlogger/netxlogger_test.go index 3bf64ba..fc40578 100644 --- a/internal/engine/legacy/netxlogger/netxlogger_test.go +++ b/internal/engine/legacy/netxlogger/netxlogger_test.go @@ -10,7 +10,7 @@ import ( "github.com/apex/log/handlers/discard" "github.com/ooni/probe-cli/v3/internal/engine/legacy/netx" "github.com/ooni/probe-cli/v3/internal/engine/legacy/netx/modelx" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) func TestGood(t *testing.T) { diff --git a/internal/engine/legacy/oonitemplates/oonitemplates.go b/internal/engine/legacy/oonitemplates/oonitemplates.go index 432c014..0daace8 100644 --- a/internal/engine/legacy/oonitemplates/oonitemplates.go +++ b/internal/engine/legacy/oonitemplates/oonitemplates.go @@ -24,7 +24,7 @@ import ( "github.com/ooni/probe-cli/v3/internal/engine/legacy/netx" "github.com/ooni/probe-cli/v3/internal/engine/legacy/netx/handlers" "github.com/ooni/probe-cli/v3/internal/engine/legacy/netx/modelx" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" "github.com/ooni/probe-cli/v3/internal/runtimex" "gitlab.com/yawning/obfs4.git/transports" obfs4base "gitlab.com/yawning/obfs4.git/transports/base" diff --git a/internal/engine/netx/dialer/bytecounter_test.go b/internal/engine/netx/dialer/bytecounter_test.go index e2937b3..23c39eb 100644 --- a/internal/engine/netx/dialer/bytecounter_test.go +++ b/internal/engine/netx/dialer/bytecounter_test.go @@ -9,8 +9,8 @@ import ( "testing" "github.com/ooni/probe-cli/v3/internal/bytecounter" - "github.com/ooni/probe-cli/v3/internal/iox" - "github.com/ooni/probe-cli/v3/internal/netxmocks" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/mocks" ) func dorequest(ctx context.Context, url string) error { @@ -76,7 +76,7 @@ func TestByteCounterNoHandlers(t *testing.T) { } func TestByteCounterConnectFailure(t *testing.T) { - dialer := &byteCounterDialer{Dialer: &netxmocks.Dialer{ + dialer := &byteCounterDialer{Dialer: &mocks.Dialer{ MockDialContext: func(ctx context.Context, network string, address string) (net.Conn, error) { return nil, io.EOF }, diff --git a/internal/engine/netx/dialer/proxy_test.go b/internal/engine/netx/dialer/proxy_test.go index e91bb80..c67ff62 100644 --- a/internal/engine/netx/dialer/proxy_test.go +++ b/internal/engine/netx/dialer/proxy_test.go @@ -8,13 +8,13 @@ import ( "net/url" "testing" - "github.com/ooni/probe-cli/v3/internal/netxmocks" + "github.com/ooni/probe-cli/v3/internal/netxlite/mocks" ) func TestProxyDialerDialContextNoProxyURL(t *testing.T) { expected := errors.New("mocked error") d := &proxyDialer{ - Dialer: &netxmocks.Dialer{ + Dialer: &mocks.Dialer{ MockDialContext: func(ctx context.Context, network string, address string) (net.Conn, error) { return nil, expected }, @@ -45,7 +45,7 @@ func TestProxyDialerDialContextInvalidScheme(t *testing.T) { func TestProxyDialerDialContextWithEOF(t *testing.T) { const expect = "10.0.0.1:9050" d := &proxyDialer{ - Dialer: &netxmocks.Dialer{ + Dialer: &mocks.Dialer{ MockDialContext: func(ctx context.Context, network string, address string) (net.Conn, error) { if address != expect { return nil, errors.New("unexpected address") diff --git a/internal/engine/netx/dialer/saver_test.go b/internal/engine/netx/dialer/saver_test.go index 86d0853..a09f419 100644 --- a/internal/engine/netx/dialer/saver_test.go +++ b/internal/engine/netx/dialer/saver_test.go @@ -10,14 +10,14 @@ import ( "github.com/ooni/probe-cli/v3/internal/engine/netx/trace" "github.com/ooni/probe-cli/v3/internal/errorsx" - "github.com/ooni/probe-cli/v3/internal/netxmocks" + "github.com/ooni/probe-cli/v3/internal/netxlite/mocks" ) func TestSaverDialerFailure(t *testing.T) { expected := errors.New("mocked error") saver := &trace.Saver{} dlr := &saverDialer{ - Dialer: &netxmocks.Dialer{ + Dialer: &mocks.Dialer{ MockDialContext: func(ctx context.Context, network string, address string) (net.Conn, error) { return nil, expected }, @@ -59,7 +59,7 @@ func TestSaverConnDialerFailure(t *testing.T) { expected := errors.New("mocked error") saver := &trace.Saver{} dlr := &saverConnDialer{ - Dialer: &netxmocks.Dialer{ + Dialer: &mocks.Dialer{ MockDialContext: func(ctx context.Context, network string, address string) (net.Conn, error) { return nil, expected }, @@ -79,9 +79,9 @@ func TestSaverConnDialerSuccess(t *testing.T) { saver := &trace.Saver{} dlr := &saverConnDialer{ Dialer: &saverDialer{ - Dialer: &netxmocks.Dialer{ + Dialer: &mocks.Dialer{ MockDialContext: func(ctx context.Context, network string, address string) (net.Conn, error) { - return &netxmocks.Conn{ + return &mocks.Conn{ MockRead: func(b []byte) (int, error) { return 0, io.EOF }, diff --git a/internal/engine/netx/dialer/shaping_disabled.go b/internal/engine/netx/dialer/shaping_disabled.go index 1562921..6da82b3 100644 --- a/internal/engine/netx/dialer/shaping_disabled.go +++ b/internal/engine/netx/dialer/shaping_disabled.go @@ -1,3 +1,4 @@ +//go:build !shaping // +build !shaping package dialer diff --git a/internal/engine/netx/dialer/shaping_enabled.go b/internal/engine/netx/dialer/shaping_enabled.go index 7e0917c..a6368c5 100644 --- a/internal/engine/netx/dialer/shaping_enabled.go +++ b/internal/engine/netx/dialer/shaping_enabled.go @@ -1,3 +1,4 @@ +//go:build shaping // +build shaping package dialer diff --git a/internal/engine/netx/fake_test.go b/internal/engine/netx/fake_test.go index ba3f816..5553c61 100644 --- a/internal/engine/netx/fake_test.go +++ b/internal/engine/netx/fake_test.go @@ -6,7 +6,7 @@ import ( "net/http" "time" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) type FakeDialer struct { diff --git a/internal/engine/netx/httptransport/bytecounter_test.go b/internal/engine/netx/httptransport/bytecounter_test.go index 6251f17..c2905a4 100644 --- a/internal/engine/netx/httptransport/bytecounter_test.go +++ b/internal/engine/netx/httptransport/bytecounter_test.go @@ -10,7 +10,7 @@ import ( "github.com/ooni/probe-cli/v3/internal/bytecounter" "github.com/ooni/probe-cli/v3/internal/engine/netx/httptransport" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) func TestByteCounterFailure(t *testing.T) { diff --git a/internal/engine/netx/httptransport/fake_test.go b/internal/engine/netx/httptransport/fake_test.go index e5bbb0f..1877211 100644 --- a/internal/engine/netx/httptransport/fake_test.go +++ b/internal/engine/netx/httptransport/fake_test.go @@ -6,7 +6,7 @@ import ( "net/http" "time" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) type FakeDialer struct { diff --git a/internal/engine/netx/httptransport/saver.go b/internal/engine/netx/httptransport/saver.go index c94d4df..bf56e69 100644 --- a/internal/engine/netx/httptransport/saver.go +++ b/internal/engine/netx/httptransport/saver.go @@ -10,7 +10,7 @@ import ( "time" "github.com/ooni/probe-cli/v3/internal/engine/netx/trace" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) // SaverPerformanceHTTPTransport is a RoundTripper that saves diff --git a/internal/engine/netx/httptransport/saver_test.go b/internal/engine/netx/httptransport/saver_test.go index 9e52507..f8eec7e 100644 --- a/internal/engine/netx/httptransport/saver_test.go +++ b/internal/engine/netx/httptransport/saver_test.go @@ -11,7 +11,7 @@ import ( "github.com/ooni/probe-cli/v3/internal/engine/netx/httptransport" "github.com/ooni/probe-cli/v3/internal/engine/netx/trace" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) func TestSaverPerformanceNoMultipleEvents(t *testing.T) { diff --git a/internal/engine/netx/integration_test.go b/internal/engine/netx/integration_test.go index 37e2002..17ad622 100644 --- a/internal/engine/netx/integration_test.go +++ b/internal/engine/netx/integration_test.go @@ -11,7 +11,7 @@ import ( "github.com/ooni/probe-cli/v3/internal/engine/netx" "github.com/ooni/probe-cli/v3/internal/engine/netx/trace" "github.com/ooni/probe-cli/v3/internal/errorsx" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) func TestSuccess(t *testing.T) { diff --git a/internal/engine/netx/quicdialer/system.go b/internal/engine/netx/quicdialer/system.go index 63016a8..a8b6e7b 100644 --- a/internal/engine/netx/quicdialer/system.go +++ b/internal/engine/netx/quicdialer/system.go @@ -6,7 +6,7 @@ import ( "github.com/ooni/probe-cli/v3/internal/engine/netx/trace" "github.com/ooni/probe-cli/v3/internal/errorsx" - "github.com/ooni/probe-cli/v3/internal/quicx" + "github.com/ooni/probe-cli/v3/internal/netxlite/quicx" ) // QUICListener listens for QUIC connections. diff --git a/internal/engine/netx/quicdialer/system_test.go b/internal/engine/netx/quicdialer/system_test.go index 4e0f1a6..fe16fcd 100644 --- a/internal/engine/netx/quicdialer/system_test.go +++ b/internal/engine/netx/quicdialer/system_test.go @@ -12,14 +12,14 @@ import ( "github.com/ooni/probe-cli/v3/internal/engine/netx/trace" "github.com/ooni/probe-cli/v3/internal/errorsx" "github.com/ooni/probe-cli/v3/internal/netxlite" - "github.com/ooni/probe-cli/v3/internal/netxmocks" - "github.com/ooni/probe-cli/v3/internal/quicx" + "github.com/ooni/probe-cli/v3/internal/netxlite/mocks" + "github.com/ooni/probe-cli/v3/internal/netxlite/quicx" ) func TestQUICListenerSaverCannotListen(t *testing.T) { expected := errors.New("mocked error") qls := &quicdialer.QUICListenerSaver{ - QUICListener: &netxmocks.QUICListener{ + QUICListener: &mocks.QUICListener{ MockListen: func(addr *net.UDPAddr) (quicx.UDPLikeConn, error) { return nil, expected }, diff --git a/internal/engine/netx/resolver/dnsoverhttps.go b/internal/engine/netx/resolver/dnsoverhttps.go index e0686b1..4dc25a3 100644 --- a/internal/engine/netx/resolver/dnsoverhttps.go +++ b/internal/engine/netx/resolver/dnsoverhttps.go @@ -8,7 +8,7 @@ import ( "time" "github.com/ooni/probe-cli/v3/internal/engine/httpheader" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) // DNSOverHTTPS is a DNS over HTTPS RoundTripper. Requests are submitted over diff --git a/internal/engine/probeservices/collector_test.go b/internal/engine/probeservices/collector_test.go index 0096f20..4a1c0fa 100644 --- a/internal/engine/probeservices/collector_test.go +++ b/internal/engine/probeservices/collector_test.go @@ -15,7 +15,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/ooni/probe-cli/v3/internal/engine/model" "github.com/ooni/probe-cli/v3/internal/engine/probeservices" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) type fakeTestKeys struct { diff --git a/internal/engine/probeservices/probeservices_test.go b/internal/engine/probeservices/probeservices_test.go index ecd7d92..140afc9 100644 --- a/internal/engine/probeservices/probeservices_test.go +++ b/internal/engine/probeservices/probeservices_test.go @@ -16,7 +16,7 @@ import ( "github.com/ooni/probe-cli/v3/internal/engine/model" "github.com/ooni/probe-cli/v3/internal/engine/probeservices" "github.com/ooni/probe-cli/v3/internal/engine/probeservices/testorchestra" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) func newclient() *probeservices.Client { diff --git a/internal/engine/session_integration_test.go b/internal/engine/session_integration_test.go index db0a9fe..49ba4b4 100644 --- a/internal/engine/session_integration_test.go +++ b/internal/engine/session_integration_test.go @@ -16,7 +16,7 @@ import ( "github.com/ooni/probe-cli/v3/internal/engine/geolocate" "github.com/ooni/probe-cli/v3/internal/engine/model" "github.com/ooni/probe-cli/v3/internal/engine/probeservices" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" "github.com/ooni/probe-cli/v3/internal/version" ) diff --git a/internal/engine/session_nopsiphon.go b/internal/engine/session_nopsiphon.go index fe09e30..e543c9b 100644 --- a/internal/engine/session_nopsiphon.go +++ b/internal/engine/session_nopsiphon.go @@ -1,3 +1,4 @@ +//go:build !ooni_psiphon_config // +build !ooni_psiphon_config package engine diff --git a/internal/engine/session_nopsiphon_test.go b/internal/engine/session_nopsiphon_test.go index e5b3d0d..4564f5b 100644 --- a/internal/engine/session_nopsiphon_test.go +++ b/internal/engine/session_nopsiphon_test.go @@ -1,3 +1,4 @@ +//go:build !ooni_psiphon_config // +build !ooni_psiphon_config package engine diff --git a/internal/engine/session_psiphon.go b/internal/engine/session_psiphon.go index 050e264..4e374e6 100644 --- a/internal/engine/session_psiphon.go +++ b/internal/engine/session_psiphon.go @@ -1,3 +1,4 @@ +//go:build ooni_psiphon_config // +build ooni_psiphon_config package engine @@ -8,7 +9,7 @@ import ( _ "embed" "filippo.io/age" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) //go:embed psiphon-config.json.age diff --git a/internal/engine/session_psiphon_test.go b/internal/engine/session_psiphon_test.go index 92c1bc1..3ff4186 100644 --- a/internal/engine/session_psiphon_test.go +++ b/internal/engine/session_psiphon_test.go @@ -1,3 +1,4 @@ +//go:build ooni_psiphon_config // +build ooni_psiphon_config package engine diff --git a/internal/errorsx/dialer_test.go b/internal/errorsx/dialer_test.go index 4988e7b..ffd96e8 100644 --- a/internal/errorsx/dialer_test.go +++ b/internal/errorsx/dialer_test.go @@ -7,12 +7,12 @@ import ( "net" "testing" - "github.com/ooni/probe-cli/v3/internal/netxmocks" + "github.com/ooni/probe-cli/v3/internal/netxlite/mocks" ) func TestErrorWrapperDialerFailure(t *testing.T) { ctx := context.Background() - d := &ErrorWrapperDialer{Dialer: &netxmocks.Dialer{ + d := &ErrorWrapperDialer{Dialer: &mocks.Dialer{ MockDialContext: func(ctx context.Context, network string, address string) (net.Conn, error) { return nil, io.EOF }, @@ -39,7 +39,7 @@ func TestErrorWrapperDialerFailure(t *testing.T) { func TestErrorWrapperDialerSuccess(t *testing.T) { origConn := &net.TCPConn{} ctx := context.Background() - d := &ErrorWrapperDialer{Dialer: &netxmocks.Dialer{ + d := &ErrorWrapperDialer{Dialer: &mocks.Dialer{ MockDialContext: func(ctx context.Context, network string, address string) (net.Conn, error) { return origConn, nil }, @@ -59,7 +59,7 @@ func TestErrorWrapperDialerSuccess(t *testing.T) { func TestErrorWrapperConnReadFailure(t *testing.T) { c := &errorWrapperConn{ - Conn: &netxmocks.Conn{ + Conn: &mocks.Conn{ MockRead: func(b []byte) (int, error) { return 0, io.EOF }, @@ -87,7 +87,7 @@ func TestErrorWrapperConnReadFailure(t *testing.T) { func TestErrorWrapperConnReadSuccess(t *testing.T) { c := &errorWrapperConn{ - Conn: &netxmocks.Conn{ + Conn: &mocks.Conn{ MockRead: func(b []byte) (int, error) { return len(b), nil }, @@ -105,7 +105,7 @@ func TestErrorWrapperConnReadSuccess(t *testing.T) { func TestErrorWrapperConnWriteFailure(t *testing.T) { c := &errorWrapperConn{ - Conn: &netxmocks.Conn{ + Conn: &mocks.Conn{ MockWrite: func(b []byte) (int, error) { return 0, io.EOF }, @@ -133,7 +133,7 @@ func TestErrorWrapperConnWriteFailure(t *testing.T) { func TestErrorWrapperConnWriteSuccess(t *testing.T) { c := &errorWrapperConn{ - Conn: &netxmocks.Conn{ + Conn: &mocks.Conn{ MockWrite: func(b []byte) (int, error) { return len(b), nil }, @@ -151,7 +151,7 @@ func TestErrorWrapperConnWriteSuccess(t *testing.T) { func TestErrorWrapperConnCloseFailure(t *testing.T) { c := &errorWrapperConn{ - Conn: &netxmocks.Conn{ + Conn: &mocks.Conn{ MockClose: func() error { return io.EOF }, @@ -175,7 +175,7 @@ func TestErrorWrapperConnCloseFailure(t *testing.T) { func TestErrorWrapperConnCloseSuccess(t *testing.T) { c := &errorWrapperConn{ - Conn: &netxmocks.Conn{ + Conn: &mocks.Conn{ MockClose: func() error { return nil }, diff --git a/internal/errorsx/errno.go b/internal/errorsx/errno.go index 5c57ff1..4958768 100644 --- a/internal/errorsx/errno.go +++ b/internal/errorsx/errno.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// Generated: 2021-07-02 17:54:06.182341 +0200 CEST m=+0.120124584 +// Generated: 2021-09-05 13:54:14.649711 +0200 CEST m=+0.136980959 package errorsx diff --git a/internal/errorsx/errno_test.go b/internal/errorsx/errno_test.go index 409acc6..93bd00c 100644 --- a/internal/errorsx/errno_test.go +++ b/internal/errorsx/errno_test.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// Generated: 2021-07-02 17:54:06.226224 +0200 CEST m=+0.164008293 +// Generated: 2021-09-05 13:54:14.695896 +0200 CEST m=+0.183167084 package errorsx diff --git a/internal/errorsx/errno_unix.go b/internal/errorsx/errno_unix.go index 5776423..d4dbcd7 100644 --- a/internal/errorsx/errno_unix.go +++ b/internal/errorsx/errno_unix.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// Generated: 2021-07-02 17:54:06.062944 +0200 CEST m=+0.000724793 +// Generated: 2021-09-05 13:54:14.514032 +0200 CEST m=+0.001299626 package errorsx diff --git a/internal/errorsx/errno_windows.go b/internal/errorsx/errno_windows.go index 0b35ab9..c14c712 100644 --- a/internal/errorsx/errno_windows.go +++ b/internal/errorsx/errno_windows.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// Generated: 2021-07-02 17:54:06.155868 +0200 CEST m=+0.093650376 +// Generated: 2021-09-05 13:54:14.622035 +0200 CEST m=+0.109304917 package errorsx diff --git a/internal/errorsx/quic.go b/internal/errorsx/quic.go index 5ec2064..4fb6ab7 100644 --- a/internal/errorsx/quic.go +++ b/internal/errorsx/quic.go @@ -7,7 +7,7 @@ import ( "net" "github.com/lucas-clemente/quic-go" - "github.com/ooni/probe-cli/v3/internal/quicx" + "github.com/ooni/probe-cli/v3/internal/netxlite/quicx" ) // QUICContextDialer is a dialer for QUIC using Context. diff --git a/internal/errorsx/quic_test.go b/internal/errorsx/quic_test.go index 2da182c..ca3c21c 100644 --- a/internal/errorsx/quic_test.go +++ b/internal/errorsx/quic_test.go @@ -9,13 +9,13 @@ import ( "testing" "github.com/lucas-clemente/quic-go" - "github.com/ooni/probe-cli/v3/internal/netxmocks" - "github.com/ooni/probe-cli/v3/internal/quicx" + "github.com/ooni/probe-cli/v3/internal/netxlite/mocks" + "github.com/ooni/probe-cli/v3/internal/netxlite/quicx" ) func TestErrorWrapperQUICListenerSuccess(t *testing.T) { ql := &ErrorWrapperQUICListener{ - QUICListener: &netxmocks.QUICListener{ + QUICListener: &mocks.QUICListener{ MockListen: func(addr *net.UDPAddr) (quicx.UDPLikeConn, error) { return &net.UDPConn{}, nil }, @@ -30,7 +30,7 @@ func TestErrorWrapperQUICListenerSuccess(t *testing.T) { func TestErrorWrapperQUICListenerFailure(t *testing.T) { ql := &ErrorWrapperQUICListener{ - QUICListener: &netxmocks.QUICListener{ + QUICListener: &mocks.QUICListener{ MockListen: func(addr *net.UDPAddr) (quicx.UDPLikeConn, error) { return nil, io.EOF }, @@ -47,7 +47,7 @@ func TestErrorWrapperQUICListenerFailure(t *testing.T) { func TestErrorWrapperUDPConnWriteToSuccess(t *testing.T) { quc := &errorWrapperUDPConn{ - UDPLikeConn: &netxmocks.QUICUDPConn{ + UDPLikeConn: &mocks.QUICUDPConn{ MockWriteTo: func(p []byte, addr net.Addr) (int, error) { return 10, nil }, @@ -67,7 +67,7 @@ func TestErrorWrapperUDPConnWriteToSuccess(t *testing.T) { func TestErrorWrapperUDPConnWriteToFailure(t *testing.T) { expected := errors.New("mocked error") quc := &errorWrapperUDPConn{ - UDPLikeConn: &netxmocks.QUICUDPConn{ + UDPLikeConn: &mocks.QUICUDPConn{ MockWriteTo: func(p []byte, addr net.Addr) (int, error) { return 0, expected }, @@ -87,7 +87,7 @@ func TestErrorWrapperUDPConnWriteToFailure(t *testing.T) { func TestErrorWrapperUDPConnReadFromSuccess(t *testing.T) { expected := errors.New("mocked error") quc := &errorWrapperUDPConn{ - UDPLikeConn: &netxmocks.QUICUDPConn{ + UDPLikeConn: &mocks.QUICUDPConn{ MockReadFrom: func(b []byte) (int, net.Addr, error) { return 0, nil, expected }, @@ -108,7 +108,7 @@ func TestErrorWrapperUDPConnReadFromSuccess(t *testing.T) { func TestErrorWrapperUDPConnReadFromFailure(t *testing.T) { quc := &errorWrapperUDPConn{ - UDPLikeConn: &netxmocks.QUICUDPConn{ + UDPLikeConn: &mocks.QUICUDPConn{ MockReadFrom: func(b []byte) (int, net.Addr, error) { return 10, nil, nil }, @@ -129,7 +129,7 @@ func TestErrorWrapperUDPConnReadFromFailure(t *testing.T) { func TestErrorWrapperQUICDialerFailure(t *testing.T) { ctx := context.Background() - d := &ErrorWrapperQUICDialer{Dialer: &netxmocks.QUICContextDialer{ + d := &ErrorWrapperQUICDialer{Dialer: &mocks.QUICContextDialer{ MockDialContext: func(ctx context.Context, network, address string, tlsConfig *tls.Config, quicConfig *quic.Config) (quic.EarlySession, error) { return nil, io.EOF }, diff --git a/internal/errorsx/resolver_test.go b/internal/errorsx/resolver_test.go index b65caad..c4f9f78 100644 --- a/internal/errorsx/resolver_test.go +++ b/internal/errorsx/resolver_test.go @@ -6,13 +6,13 @@ import ( "net" "testing" - "github.com/ooni/probe-cli/v3/internal/netxmocks" + "github.com/ooni/probe-cli/v3/internal/netxlite/mocks" ) func TestErrorWrapperResolverSuccess(t *testing.T) { orig := []string{"8.8.8.8"} r := &ErrorWrapperResolver{ - Resolver: &netxmocks.Resolver{ + Resolver: &mocks.Resolver{ MockLookupHost: func(ctx context.Context, domain string) ([]string, error) { return orig, nil }, @@ -29,7 +29,7 @@ func TestErrorWrapperResolverSuccess(t *testing.T) { func TestErrorWrapperResolverFailure(t *testing.T) { r := &ErrorWrapperResolver{ - Resolver: &netxmocks.Resolver{ + Resolver: &mocks.Resolver{ MockLookupHost: func(ctx context.Context, domain string) ([]string, error) { return nil, errors.New("no such host") }, @@ -53,7 +53,7 @@ func TestErrorWrapperResolverFailure(t *testing.T) { } func TestErrorWrapperResolverChildNetworkAddress(t *testing.T) { - r := &ErrorWrapperResolver{Resolver: &netxmocks.Resolver{ + r := &ErrorWrapperResolver{Resolver: &mocks.Resolver{ MockNetwork: func() string { return "udp" }, diff --git a/internal/errorsx/tls_test.go b/internal/errorsx/tls_test.go index 60bd7b3..8773a70 100644 --- a/internal/errorsx/tls_test.go +++ b/internal/errorsx/tls_test.go @@ -8,17 +8,17 @@ import ( "net" "testing" - "github.com/ooni/probe-cli/v3/internal/netxmocks" + "github.com/ooni/probe-cli/v3/internal/netxlite/mocks" ) func TestErrorWrapperTLSHandshakerFailure(t *testing.T) { - th := ErrorWrapperTLSHandshaker{TLSHandshaker: &netxmocks.TLSHandshaker{ + th := ErrorWrapperTLSHandshaker{TLSHandshaker: &mocks.TLSHandshaker{ MockHandshake: func(ctx context.Context, conn net.Conn, config *tls.Config) (net.Conn, tls.ConnectionState, error) { return nil, tls.ConnectionState{}, io.EOF }, }} conn, _, err := th.Handshake( - context.Background(), &netxmocks.Conn{ + context.Background(), &mocks.Conn{ MockRead: func(b []byte) (int, error) { return 0, io.EOF }, diff --git a/internal/fsx/example_test.go b/internal/fsx/example_test.go index 853947c..2c86687 100644 --- a/internal/fsx/example_test.go +++ b/internal/fsx/example_test.go @@ -9,7 +9,7 @@ import ( "syscall" "github.com/ooni/probe-cli/v3/internal/fsx" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) func ExampleOpenFile_openingDir() { diff --git a/internal/mlablocate/mlablocate.go b/internal/mlablocate/mlablocate.go index 9f1192b..4d077f8 100644 --- a/internal/mlablocate/mlablocate.go +++ b/internal/mlablocate/mlablocate.go @@ -12,7 +12,7 @@ import ( "net/http" "net/url" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) // Logger is the logger expected by this package. diff --git a/internal/mlablocatev2/fake_test.go b/internal/mlablocatev2/fake_test.go index c0228d8..9605b2d 100644 --- a/internal/mlablocatev2/fake_test.go +++ b/internal/mlablocatev2/fake_test.go @@ -4,7 +4,7 @@ import ( "net/http" "time" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) type FakeTransport struct { diff --git a/internal/mlablocatev2/mlablocatev2.go b/internal/mlablocatev2/mlablocatev2.go index 690af85..8947b95 100644 --- a/internal/mlablocatev2/mlablocatev2.go +++ b/internal/mlablocatev2/mlablocatev2.go @@ -12,7 +12,7 @@ import ( "net/url" "regexp" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) const ( diff --git a/internal/netxlite/certifi.go b/internal/netxlite/certifi.go index 89cda50..28bd639 100644 --- a/internal/netxlite/certifi.go +++ b/internal/netxlite/certifi.go @@ -1,16 +1,16 @@ // Code generated by go generate; DO NOT EDIT. -// 2021-07-02 14:26:19.300018 +0200 CEST m=+0.978891751 +// 2021-09-05 14:01:12.627844 +0200 CEST m=+0.441951210 // https://curl.haxx.se/ca/cacert.pem package netxlite -//go:generate go run ./generator/ "https://curl.haxx.se/ca/cacert.pem" +//go:generate go run ./internal/generator/ "https://curl.haxx.se/ca/cacert.pem" const pemcerts string = ` ## ## Bundle of CA Root Certificates ## -## Certificate data from Mozilla as of: Tue May 25 03:12:05 2021 GMT +## Certificate data from Mozilla as of: Mon Jul 5 21:35:54 2021 GMT ## ## This is a bundle of X.509 certificates of public Certificate Authorities ## (CA). These were automatically extracted from Mozilla's root certificates @@ -23,7 +23,7 @@ const pemcerts string = ` ## Just configure this file as the SSLCACertificateFile. ## ## Conversion done with mk-ca-bundle.pl version 1.28. -## SHA256: e292bd4e2d500c86df45b830d89417be5c42ee670408f1d2c454c63d8a782865 +## SHA256: c8f6733d1ff4e6a4769c182971a1234f95ae079247a9c439a13423fe8ba5c24f ## @@ -165,38 +165,6 @@ Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z 12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== -----END CERTIFICATE----- -QuoVadis Root CA -================ ------BEGIN CERTIFICATE----- -MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE -ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 -eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz -MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp -cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD -EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk -J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL -F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL -YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen -AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w -PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y -ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7 -MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj -YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs -ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh -Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW -Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu -BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw -FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6 -tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo -fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul -LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x -gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi -5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi -5nrQNiOKSnQ2+Q== ------END CERTIFICATE----- - QuoVadis Root CA 2 ================== -----BEGIN CERTIFICATE----- @@ -284,26 +252,6 @@ s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ FL39vmwLAw== -----END CERTIFICATE----- -Sonera Class 2 Root CA -====================== ------BEGIN CERTIFICATE----- -MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG -U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw -NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh -IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3 -/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT -dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG -f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P -tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH -nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT -XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt -0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI -cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph -Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx -EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH -llpwrN9M ------END CERTIFICATE----- - XRamp Global CA Root ==================== -----BEGIN CERTIFICATE----- @@ -1203,27 +1151,6 @@ OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9 vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== -----END CERTIFICATE----- -Trustis FPS Root CA -=================== ------BEGIN CERTIFICATE----- -MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG -EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290 -IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV -BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ -KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ -RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk -H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa -cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt -o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA -AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd -BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c -GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC -yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P -8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV -l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl -iB6XzCGcKQENZetX2fNXlrtIzYE= ------END CERTIFICATE----- - Buypass Class 2 Root CA ======================= -----BEGIN CERTIFICATE----- @@ -3146,4 +3073,113 @@ vLtoURMMA/cVi4RguYv/Uo7njLwcAjA8+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+ CAezNIm8BZ/3Hobui3A= -----END CERTIFICATE----- +GLOBALTRUST 2020 +================ +-----BEGIN CERTIFICATE----- +MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkGA1UEBhMCQVQx +IzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVT +VCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYxMDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAh +BgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAy +MDIwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWi +D59bRatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9ZYybNpyrO +VPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3QWPKzv9pj2gOlTblzLmM +CcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPwyJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCm +fecqQjuCgGOlYx8ZzHyyZqjC0203b+J+BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKA +A1GqtH6qRNdDYfOiaxaJSaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9OR +JitHHmkHr96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj04KlG +DfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9MedKZssCz3AwyIDMvU +clOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIwq7ejMZdnrY8XD2zHc+0klGvIg5rQ +mjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1Ud +IwQYMBaAFNwuH9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA +VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJCXtzoRlgHNQIw +4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd6IwPS3BD0IL/qMy/pJTAvoe9 +iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf+I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS +8cE54+X1+NZK3TTN+2/BT+MAi1bikvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2 +HcqtbepBEX4tdJP7wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxS +vTOBTI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6CMUO+1918 +oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn4rnvyOL2NSl6dPrFf4IF +YqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+IaFvowdlxfv1k7/9nR4hYJS8+hge9+6jl +gqispdNpQ80xiEmEU5LAsTkbOYMBMMTyqfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg== +-----END CERTIFICATE----- + +ANF Secure Server Root CA +========================= +-----BEGIN CERTIFICATE----- +MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNVBAUTCUc2MzI4 +NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lv +bjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNVBAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3Qg +Q0EwHhcNMTkwOTA0MTAwMDM4WhcNMzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEw +MQswCQYDVQQGEwJFUzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQw +EgYDVQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9vdCBDQTCC +AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCjcqQZAZ2cC4Ffc0m6p6zz +BE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9qyGFOtibBTI3/TO80sh9l2Ll49a2pcbnv +T1gdpd50IJeh7WhM3pIXS7yr/2WanvtH2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcv +B2VSAKduyK9o7PQUlrZXH1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXse +zx76W0OLzc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyRp1RM +VwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQzW7i1o0TJrH93PB0j +7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/SiOL9V8BY9KHcyi1Swr1+KuCLH5z +JTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJnLNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe +8TZBAQIvfXOn3kLMTOmJDVb3n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVO +Hj1tyRRM4y5Bu8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj +o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAOBgNVHQ8BAf8E +BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEATh65isagmD9uw2nAalxJ +UqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzx +j6ptBZNscsdW699QIyjlRRA96Gejrw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDt +dD+4E5UGUcjohybKpFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM +5gf0vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjqOknkJjCb +5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ/zo1PqVUSlJZS2Db7v54 +EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ92zg/LFis6ELhDtjTO0wugumDLmsx2d1H +hk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI+PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGy +g77FGr8H6lnco4g175x2MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3 +r5+qPeoott7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw= +-----END CERTIFICATE----- + +Certum EC-384 CA +================ +-----BEGIN CERTIFICATE----- +MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQswCQYDVQQGEwJQ +TDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2 +MDcyNDU0WhcNNDMwMzI2MDcyNDU0WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERh +dGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx +GTAXBgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATEKI6rGFtq +vm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7TmFy8as10CW4kjPMIRBSqn +iBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68KjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFI0GZnQkdjrzife81r1HfS+8EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNo +ADBlAjADVS2m5hjEfO/JUG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0 +QoSZ/6vnnvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= +-----END CERTIFICATE----- + +Certum Trusted Root CA +====================== +-----BEGIN CERTIFICATE----- +MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6MQswCQYDVQQG +EwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0g +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0Ew +HhcNMTgwMzE2MTIxMDEzWhcNNDMwMzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMY +QXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZn0EGze2jusDbCSzBfN8p +fktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/qp1x4EaTByIVcJdPTsuclzxFUl6s1wB52 +HO8AU5853BSlLCIls3Jy/I2z5T4IHhQqNwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2 +fJmItdUDmj0VDT06qKhF8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGt +g/BKEiJ3HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGamqi4 +NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi7VdNIuJGmj8PkTQk +fVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSFytKAQd8FqKPVhJBPC/PgP5sZ0jeJ +P/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0PqafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSY +njYJdmZm/Bo/6khUHL4wvYBQv3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHK +HRzQ+8S1h9E6Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1 +vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQADggIBAEii1QAL +LtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4WxmB82M+w85bj/UvXgF2Ez8s +ALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvozMrnadyHncI013nR03e4qllY/p0m+jiGPp2K +h2RX5Rc64vmNueMzeMGQ2Ljdt4NR5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8 +CYyqOhNf6DR5UMEQGfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA +4kZf5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq0Uc9Nneo +WWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7DP78v3DSk+yshzWePS/Tj +6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTMqJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmT +OPQD8rv7gmsHINFSH5pkAnuYZttcTVoP0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZck +bxJF0WddCajJFdr60qZfE2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb +-----END CERTIFICATE----- + ` diff --git a/internal/netxlite/dialer.go b/internal/netxlite/dialer.go index 3f53c56..224b983 100644 --- a/internal/netxlite/dialer.go +++ b/internal/netxlite/dialer.go @@ -12,17 +12,17 @@ type Dialer interface { DialContext(ctx context.Context, network, address string) (net.Conn, error) } -// DefaultDialer is the Dialer we use by default. -var DefaultDialer = &net.Dialer{ +// defaultDialer is the Dialer we use by default. +var defaultDialer = &net.Dialer{ Timeout: 15 * time.Second, KeepAlive: 15 * time.Second, } -var _ Dialer = DefaultDialer +var _ Dialer = defaultDialer -// DialerResolver is a dialer that uses the configured Resolver to resolver a +// dialerResolver is a dialer that uses the configured Resolver to resolver a // domain name to IP addresses, and the configured Dialer to connect. -type DialerResolver struct { +type dialerResolver struct { // Dialer is the underlying Dialer. Dialer Dialer @@ -30,10 +30,10 @@ type DialerResolver struct { Resolver Resolver } -var _ Dialer = &DialerResolver{} +var _ Dialer = &dialerResolver{} // DialContext implements Dialer.DialContext. -func (d *DialerResolver) DialContext(ctx context.Context, network, address string) (net.Conn, error) { +func (d *dialerResolver) DialContext(ctx context.Context, network, address string) (net.Conn, error) { onlyhost, onlyport, err := net.SplitHostPort(address) if err != nil { return nil, err @@ -59,15 +59,15 @@ func (d *DialerResolver) DialContext(ctx context.Context, network, address strin } // lookupHost performs a domain name resolution. -func (d *DialerResolver) lookupHost(ctx context.Context, hostname string) ([]string, error) { +func (d *dialerResolver) lookupHost(ctx context.Context, hostname string) ([]string, error) { if net.ParseIP(hostname) != nil { return []string{hostname}, nil } return d.Resolver.LookupHost(ctx, hostname) } -// DialerLogger is a Dialer with logging. -type DialerLogger struct { +// dialerLogger is a Dialer with logging. +type dialerLogger struct { // Dialer is the underlying dialer. Dialer Dialer @@ -75,10 +75,10 @@ type DialerLogger struct { Logger Logger } -var _ Dialer = &DialerLogger{} +var _ Dialer = &dialerLogger{} // DialContext implements Dialer.DialContext -func (d *DialerLogger) DialContext(ctx context.Context, network, address string) (net.Conn, error) { +func (d *dialerLogger) DialContext(ctx context.Context, network, address string) (net.Conn, error) { d.Logger.Debugf("dial %s/%s...", address, network) start := time.Now() conn, err := d.Dialer.DialContext(ctx, network, address) diff --git a/internal/netxlite/dialer_test.go b/internal/netxlite/dialer_test.go index cb1b8c6..dd6b042 100644 --- a/internal/netxlite/dialer_test.go +++ b/internal/netxlite/dialer_test.go @@ -10,11 +10,11 @@ import ( "time" "github.com/apex/log" - "github.com/ooni/probe-cli/v3/internal/netxmocks" + "github.com/ooni/probe-cli/v3/internal/netxlite/mocks" ) func TestDialerResolverNoPort(t *testing.T) { - dialer := &DialerResolver{Dialer: &net.Dialer{}, Resolver: DefaultResolver} + dialer := &dialerResolver{Dialer: &net.Dialer{}, Resolver: DefaultResolver} conn, err := dialer.DialContext(context.Background(), "tcp", "ooni.nu") if err == nil || !strings.HasSuffix(err.Error(), "missing port in address") { t.Fatal("not the error we expected", err) @@ -25,7 +25,7 @@ func TestDialerResolverNoPort(t *testing.T) { } func TestDialerResolverLookupHostAddress(t *testing.T) { - dialer := &DialerResolver{Dialer: new(net.Dialer), Resolver: &netxmocks.Resolver{ + dialer := &dialerResolver{Dialer: new(net.Dialer), Resolver: &mocks.Resolver{ MockLookupHost: func(ctx context.Context, domain string) ([]string, error) { return nil, errors.New("we should not call this function") }, @@ -41,7 +41,7 @@ func TestDialerResolverLookupHostAddress(t *testing.T) { func TestDialerResolverLookupHostFailure(t *testing.T) { expected := errors.New("mocked error") - dialer := &DialerResolver{Dialer: new(net.Dialer), Resolver: &netxmocks.Resolver{ + dialer := &dialerResolver{Dialer: new(net.Dialer), Resolver: &mocks.Resolver{ MockLookupHost: func(ctx context.Context, domain string) ([]string, error) { return nil, expected }, @@ -57,7 +57,7 @@ func TestDialerResolverLookupHostFailure(t *testing.T) { } func TestDialerResolverDialForSingleIPFails(t *testing.T) { - dialer := &DialerResolver{Dialer: &netxmocks.Dialer{ + dialer := &dialerResolver{Dialer: &mocks.Dialer{ MockDialContext: func(ctx context.Context, network string, address string) (net.Conn, error) { return nil, io.EOF }, @@ -72,12 +72,12 @@ func TestDialerResolverDialForSingleIPFails(t *testing.T) { } func TestDialerResolverDialForManyIPFails(t *testing.T) { - dialer := &DialerResolver{ - Dialer: &netxmocks.Dialer{ + dialer := &dialerResolver{ + Dialer: &mocks.Dialer{ MockDialContext: func(ctx context.Context, network string, address string) (net.Conn, error) { return nil, io.EOF }, - }, Resolver: &netxmocks.Resolver{ + }, Resolver: &mocks.Resolver{ MockLookupHost: func(ctx context.Context, domain string) ([]string, error) { return []string{"1.1.1.1", "8.8.8.8"}, nil }, @@ -92,15 +92,15 @@ func TestDialerResolverDialForManyIPFails(t *testing.T) { } func TestDialerResolverDialForManyIPSuccess(t *testing.T) { - dialer := &DialerResolver{Dialer: &netxmocks.Dialer{ + dialer := &dialerResolver{Dialer: &mocks.Dialer{ MockDialContext: func(ctx context.Context, network string, address string) (net.Conn, error) { - return &netxmocks.Conn{ + return &mocks.Conn{ MockClose: func() error { return nil }, }, nil }, - }, Resolver: &netxmocks.Resolver{ + }, Resolver: &mocks.Resolver{ MockLookupHost: func(ctx context.Context, domain string) ([]string, error) { return []string{"1.1.1.1", "8.8.8.8"}, nil }, @@ -116,10 +116,10 @@ func TestDialerResolverDialForManyIPSuccess(t *testing.T) { } func TestDialerLoggerSuccess(t *testing.T) { - d := &DialerLogger{ - Dialer: &netxmocks.Dialer{ + d := &dialerLogger{ + Dialer: &mocks.Dialer{ MockDialContext: func(ctx context.Context, network string, address string) (net.Conn, error) { - return &netxmocks.Conn{ + return &mocks.Conn{ MockClose: func() error { return nil }, @@ -139,8 +139,8 @@ func TestDialerLoggerSuccess(t *testing.T) { } func TestDialerLoggerFailure(t *testing.T) { - d := &DialerLogger{ - Dialer: &netxmocks.Dialer{ + d := &dialerLogger{ + Dialer: &mocks.Dialer{ MockDialContext: func(ctx context.Context, network string, address string) (net.Conn, error) { return nil, io.EOF }, @@ -158,7 +158,7 @@ func TestDialerLoggerFailure(t *testing.T) { func TestDefaultDialerHasTimeout(t *testing.T) { expected := 15 * time.Second - if DefaultDialer.Timeout != expected { + if defaultDialer.Timeout != expected { t.Fatal("unexpected timeout value") } } diff --git a/internal/netxlite/http.go b/internal/netxlite/http.go index 243d0ae..ef7eeb7 100644 --- a/internal/netxlite/http.go +++ b/internal/netxlite/http.go @@ -17,8 +17,8 @@ type HTTPTransport interface { CloseIdleConnections() } -// HTTPTransportLogger is an HTTPTransport with logging. -type HTTPTransportLogger struct { +// httpTransportLogger is an HTTPTransport with logging. +type httpTransportLogger struct { // HTTPTransport is the underlying HTTP transport. HTTPTransport HTTPTransport @@ -26,10 +26,10 @@ type HTTPTransportLogger struct { Logger Logger } -var _ HTTPTransport = &HTTPTransportLogger{} +var _ HTTPTransport = &httpTransportLogger{} // RoundTrip implements HTTPTransport.RoundTrip. -func (txp *HTTPTransportLogger) RoundTrip(req *http.Request) (*http.Response, error) { +func (txp *httpTransportLogger) RoundTrip(req *http.Request) (*http.Response, error) { host := req.Host if host == "" { host = req.URL.Host @@ -39,7 +39,7 @@ func (txp *HTTPTransportLogger) RoundTrip(req *http.Request) (*http.Response, er } // logTrip is an HTTP round trip with logging. -func (txp *HTTPTransportLogger) logTrip(req *http.Request) (*http.Response, error) { +func (txp *httpTransportLogger) logTrip(req *http.Request) (*http.Response, error) { txp.Logger.Debugf("> %s %s", req.Method, req.URL.String()) for key, values := range req.Header { for _, value := range values { @@ -63,7 +63,7 @@ func (txp *HTTPTransportLogger) logTrip(req *http.Request) (*http.Response, erro } // CloseIdleConnections implement HTTPTransport.CloseIdleConnections. -func (txp *HTTPTransportLogger) CloseIdleConnections() { +func (txp *httpTransportLogger) CloseIdleConnections() { txp.HTTPTransport.CloseIdleConnections() } diff --git a/internal/netxlite/http3_test.go b/internal/netxlite/http3_test.go index e6a0d57..2234bdf 100644 --- a/internal/netxlite/http3_test.go +++ b/internal/netxlite/http3_test.go @@ -8,9 +8,9 @@ import ( ) func TestHTTP3TransportWorks(t *testing.T) { - d := &QUICDialerResolver{ - Dialer: &QUICDialerQUICGo{ - QUICListener: &QUICListenerStdlib{}, + d := &quicDialerResolver{ + Dialer: &quicDialerQUICGo{ + QUICListener: &quicListenerStdlib{}, }, Resolver: &net.Resolver{}, } diff --git a/internal/netxlite/http_test.go b/internal/netxlite/http_test.go index 8bed6b6..a094ff8 100644 --- a/internal/netxlite/http_test.go +++ b/internal/netxlite/http_test.go @@ -13,14 +13,14 @@ import ( "github.com/apex/log" "github.com/ooni/probe-cli/v3/internal/atomicx" - "github.com/ooni/probe-cli/v3/internal/iox" - "github.com/ooni/probe-cli/v3/internal/netxmocks" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/mocks" ) func TestHTTPTransportLoggerFailure(t *testing.T) { - txp := &HTTPTransportLogger{ + txp := &httpTransportLogger{ Logger: log.Log, - HTTPTransport: &netxmocks.HTTPTransport{ + HTTPTransport: &mocks.HTTPTransport{ MockRoundTrip: func(req *http.Request) (*http.Response, error) { return nil, io.EOF }, @@ -38,9 +38,9 @@ func TestHTTPTransportLoggerFailure(t *testing.T) { func TestHTTPTransportLoggerFailureWithNoHostHeader(t *testing.T) { foundHost := &atomicx.Int64{} - txp := &HTTPTransportLogger{ + txp := &httpTransportLogger{ Logger: log.Log, - HTTPTransport: &netxmocks.HTTPTransport{ + HTTPTransport: &mocks.HTTPTransport{ MockRoundTrip: func(req *http.Request) (*http.Response, error) { if req.Header.Get("Host") == "www.google.com" { foundHost.Add(1) @@ -70,9 +70,9 @@ func TestHTTPTransportLoggerFailureWithNoHostHeader(t *testing.T) { } func TestHTTPTransportLoggerSuccess(t *testing.T) { - txp := &HTTPTransportLogger{ + txp := &httpTransportLogger{ Logger: log.Log, - HTTPTransport: &netxmocks.HTTPTransport{ + HTTPTransport: &mocks.HTTPTransport{ MockRoundTrip: func(req *http.Request) (*http.Response, error) { return &http.Response{ Body: io.NopCloser(strings.NewReader("")), @@ -95,8 +95,8 @@ func TestHTTPTransportLoggerSuccess(t *testing.T) { func TestHTTPTransportLoggerCloseIdleConnections(t *testing.T) { calls := &atomicx.Int64{} - txp := &HTTPTransportLogger{ - HTTPTransport: &netxmocks.HTTPTransport{ + txp := &httpTransportLogger{ + HTTPTransport: &mocks.HTTPTransport{ MockCloseIdleConnections: func() { calls.Add(1) }, @@ -110,11 +110,11 @@ func TestHTTPTransportLoggerCloseIdleConnections(t *testing.T) { } func TestHTTPTransportWorks(t *testing.T) { - d := &DialerResolver{ - Dialer: DefaultDialer, + d := &dialerResolver{ + Dialer: defaultDialer, Resolver: &net.Resolver{}, } - th := &TLSHandshakerConfigurable{} + th := &tlsHandshakerConfigurable{} txp := NewHTTPTransport(d, &tls.Config{}, th) client := &http.Client{Transport: txp} resp, err := client.Get("https://www.google.com/robots.txt") @@ -127,8 +127,8 @@ func TestHTTPTransportWorks(t *testing.T) { func TestHTTPTransportWithFailingDialer(t *testing.T) { expected := errors.New("mocked error") - d := &DialerResolver{ - Dialer: &netxmocks.Dialer{ + d := &dialerResolver{ + Dialer: &mocks.Dialer{ MockDialContext: func(ctx context.Context, network, address string) (net.Conn, error) { return nil, expected @@ -136,7 +136,7 @@ func TestHTTPTransportWithFailingDialer(t *testing.T) { }, Resolver: &net.Resolver{}, } - th := &TLSHandshakerConfigurable{} + th := &tlsHandshakerConfigurable{} txp := NewHTTPTransport(d, &tls.Config{}, th) client := &http.Client{Transport: txp} resp, err := client.Get("https://www.google.com/robots.txt") diff --git a/internal/netxlite/generator/main.go b/internal/netxlite/internal/generator/main.go similarity index 93% rename from internal/netxlite/generator/main.go rename to internal/netxlite/internal/generator/main.go index e2db888..8b994ab 100644 --- a/internal/netxlite/generator/main.go +++ b/internal/netxlite/internal/generator/main.go @@ -19,7 +19,7 @@ import ( "text/template" "time" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) var tmpl = template.Must(template.New("").Parse(`// Code generated by go generate; DO NOT EDIT. @@ -28,7 +28,7 @@ var tmpl = template.Must(template.New("").Parse(`// Code generated by go generat package netxlite -//{{ .GoGenerate }} go run ./generator/ "{{ .URL }}" +//{{ .GoGenerate }} go run ./internal/generator/ "{{ .URL }}" const pemcerts string = ` + "`" + ` {{ .Bundle }} diff --git a/internal/iox/example_test.go b/internal/netxlite/iox/example_test.go similarity index 84% rename from internal/iox/example_test.go rename to internal/netxlite/iox/example_test.go index 3c3abc4..90f60c1 100644 --- a/internal/iox/example_test.go +++ b/internal/netxlite/iox/example_test.go @@ -6,7 +6,7 @@ import ( "log" "strings" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) func ExampleReadAllContext() { diff --git a/internal/iox/iox.go b/internal/netxlite/iox/iox.go similarity index 82% rename from internal/iox/iox.go rename to internal/netxlite/iox/iox.go index bf16cd5..9101187 100644 --- a/internal/iox/iox.go +++ b/internal/netxlite/iox/iox.go @@ -33,19 +33,6 @@ func ReadAllContext(ctx context.Context, r io.Reader) ([]byte, error) { } } -// MockableReader allows to mock any io.Reader. -type MockableReader struct { - MockRead func(b []byte) (int, error) -} - -// MockableReader implements an io.Reader. -var _ io.Reader = &MockableReader{} - -// Read implements io.Reader.Read. -func (r *MockableReader) Read(b []byte) (int, error) { - return r.MockRead(b) -} - // CopyContext is like io.Copy but may terminate earlier // when the context expires. This function has the same // caveats of ReadAllContext regarding the temporary leaking diff --git a/internal/iox/iox_test.go b/internal/netxlite/iox/iox_test.go similarity index 95% rename from internal/iox/iox_test.go rename to internal/netxlite/iox/iox_test.go index 0bb31df..5418fc9 100644 --- a/internal/iox/iox_test.go +++ b/internal/netxlite/iox/iox_test.go @@ -7,6 +7,8 @@ import ( "strings" "testing" "time" + + "github.com/ooni/probe-cli/v3/internal/netxlite/mocks" ) func TestReadAllContextCommonCase(t *testing.T) { @@ -23,7 +25,7 @@ func TestReadAllContextCommonCase(t *testing.T) { func TestReadAllContextWithError(t *testing.T) { expected := errors.New("mocked error") - r := &MockableReader{ + r := &mocks.Reader{ MockRead: func(b []byte) (int, error) { return 0, expected }, @@ -53,7 +55,7 @@ func TestReadAllContextWithCancelledContext(t *testing.T) { func TestReadAllContextWithErrorAndCancelledContext(t *testing.T) { expected := errors.New("mocked error") - r := &MockableReader{ + r := &mocks.Reader{ MockRead: func(b []byte) (int, error) { time.Sleep(time.Millisecond) return 0, expected @@ -84,7 +86,7 @@ func TestCopyContextCommonCase(t *testing.T) { func TestCopyContextWithError(t *testing.T) { expected := errors.New("mocked error") - r := &MockableReader{ + r := &mocks.Reader{ MockRead: func(b []byte) (int, error) { return 0, expected }, @@ -114,7 +116,7 @@ func TestCopyContextWithCancelledContext(t *testing.T) { func TestCopyContextWithErrorAndCancelledContext(t *testing.T) { expected := errors.New("mocked error") - r := &MockableReader{ + r := &mocks.Reader{ MockRead: func(b []byte) (int, error) { time.Sleep(time.Millisecond) return 0, expected diff --git a/internal/netxlite/legacy.go b/internal/netxlite/legacy.go index 72eaeee..d5bbb89 100644 --- a/internal/netxlite/legacy.go +++ b/internal/netxlite/legacy.go @@ -37,3 +37,25 @@ func reduceErrors(errorslist []error) error { // TODO(bassosimone): handle this case in a better way return errorslist[0] } + +// These vars export internal names to legacy ooni/probe-cli code. +var ( + DefaultDialer = defaultDialer + DefaultTLSHandshaker = defaultTLSHandshaker +) + +// These types export internal names to legacy ooni/probe-cli code. +type ( + DialerResolver = dialerResolver + DialerLogger = dialerLogger + HTTPTransportLogger = httpTransportLogger + QUICListenerStdlib = quicListenerStdlib + QUICDialerQUICGo = quicDialerQUICGo + QUICDialerResolver = quicDialerResolver + QUICDialerLogger = quicDialerLogger + ResolverSystem = resolverSystem + ResolverLogger = resolverLogger + ResolverIDNA = resolverIDNA + TLSHandshakerConfigurable = tlsHandshakerConfigurable + TLSHandshakerLogger = tlsHandshakerLogger +) diff --git a/internal/netxmocks/conn.go b/internal/netxlite/mocks/conn.go similarity index 98% rename from internal/netxmocks/conn.go rename to internal/netxlite/mocks/conn.go index ff938f8..c8520fe 100644 --- a/internal/netxmocks/conn.go +++ b/internal/netxlite/mocks/conn.go @@ -1,4 +1,4 @@ -package netxmocks +package mocks import ( "net" diff --git a/internal/netxmocks/conn_test.go b/internal/netxlite/mocks/conn_test.go similarity index 99% rename from internal/netxmocks/conn_test.go rename to internal/netxlite/mocks/conn_test.go index bab1599..91f5650 100644 --- a/internal/netxmocks/conn_test.go +++ b/internal/netxlite/mocks/conn_test.go @@ -1,4 +1,4 @@ -package netxmocks +package mocks import ( "errors" diff --git a/internal/netxmocks/dialer.go b/internal/netxlite/mocks/dialer.go similarity index 95% rename from internal/netxmocks/dialer.go rename to internal/netxlite/mocks/dialer.go index e6e0280..f37affc 100644 --- a/internal/netxmocks/dialer.go +++ b/internal/netxlite/mocks/dialer.go @@ -1,4 +1,4 @@ -package netxmocks +package mocks import ( "context" diff --git a/internal/netxmocks/dialer_test.go b/internal/netxlite/mocks/dialer_test.go similarity index 96% rename from internal/netxmocks/dialer_test.go rename to internal/netxlite/mocks/dialer_test.go index 4ea7545..a114d14 100644 --- a/internal/netxmocks/dialer_test.go +++ b/internal/netxlite/mocks/dialer_test.go @@ -1,4 +1,4 @@ -package netxmocks +package mocks import ( "context" diff --git a/internal/netxlite/mocks/doc.go b/internal/netxlite/mocks/doc.go new file mode 100644 index 0000000..7024ef3 --- /dev/null +++ b/internal/netxlite/mocks/doc.go @@ -0,0 +1,2 @@ +// Package mocks contains mocks for netx types. +package mocks diff --git a/internal/netxmocks/http.go b/internal/netxlite/mocks/http.go similarity index 96% rename from internal/netxmocks/http.go rename to internal/netxlite/mocks/http.go index ac37938..0d658e3 100644 --- a/internal/netxmocks/http.go +++ b/internal/netxlite/mocks/http.go @@ -1,4 +1,4 @@ -package netxmocks +package mocks import "net/http" diff --git a/internal/netxmocks/http_test.go b/internal/netxlite/mocks/http_test.go similarity index 97% rename from internal/netxmocks/http_test.go rename to internal/netxlite/mocks/http_test.go index 535a21d..d3457d0 100644 --- a/internal/netxmocks/http_test.go +++ b/internal/netxlite/mocks/http_test.go @@ -1,4 +1,4 @@ -package netxmocks +package mocks import ( "errors" diff --git a/internal/netxmocks/quic.go b/internal/netxlite/mocks/quic.go similarity index 98% rename from internal/netxmocks/quic.go rename to internal/netxlite/mocks/quic.go index 57e7040..2cf78e3 100644 --- a/internal/netxmocks/quic.go +++ b/internal/netxlite/mocks/quic.go @@ -1,4 +1,4 @@ -package netxmocks +package mocks import ( "context" @@ -8,7 +8,7 @@ import ( "time" "github.com/lucas-clemente/quic-go" - "github.com/ooni/probe-cli/v3/internal/quicx" + "github.com/ooni/probe-cli/v3/internal/netxlite/quicx" ) // QUICListener is a mockable netxlite.QUICListener. diff --git a/internal/netxmocks/quic_test.go b/internal/netxlite/mocks/quic_test.go similarity index 99% rename from internal/netxmocks/quic_test.go rename to internal/netxlite/mocks/quic_test.go index 5fe456c..7da1cdf 100644 --- a/internal/netxmocks/quic_test.go +++ b/internal/netxlite/mocks/quic_test.go @@ -1,4 +1,4 @@ -package netxmocks +package mocks import ( "context" @@ -12,7 +12,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/lucas-clemente/quic-go" - "github.com/ooni/probe-cli/v3/internal/quicx" + "github.com/ooni/probe-cli/v3/internal/netxlite/quicx" ) func TestQUICListenerListen(t *testing.T) { diff --git a/internal/netxlite/mocks/reader.go b/internal/netxlite/mocks/reader.go new file mode 100644 index 0000000..e9d5909 --- /dev/null +++ b/internal/netxlite/mocks/reader.go @@ -0,0 +1,16 @@ +package mocks + +import "io" + +// Reader allows to mock any io.Reader. +type Reader struct { + MockRead func(b []byte) (int, error) +} + +// MockableReader implements an io.Reader. +var _ io.Reader = &Reader{} + +// Read implements io.Reader.Read. +func (r *Reader) Read(b []byte) (int, error) { + return r.MockRead(b) +} diff --git a/internal/netxlite/mocks/reader_test.go b/internal/netxlite/mocks/reader_test.go new file mode 100644 index 0000000..6b37ac4 --- /dev/null +++ b/internal/netxlite/mocks/reader_test.go @@ -0,0 +1,23 @@ +package mocks + +import ( + "errors" + "testing" +) + +func TestReaderRead(t *testing.T) { + expected := errors.New("mocked error") + r := &Reader{ + MockRead: func(b []byte) (int, error) { + return 0, expected + }, + } + b := make([]byte, 128) + count, err := r.Read(b) + if !errors.Is(err, expected) { + t.Fatal("unexpected error", err) + } + if count != 0 { + t.Fatal("unexpected count", count) + } +} diff --git a/internal/netxmocks/resolver.go b/internal/netxlite/mocks/resolver.go similarity index 96% rename from internal/netxmocks/resolver.go rename to internal/netxlite/mocks/resolver.go index c488911..6ab5a40 100644 --- a/internal/netxmocks/resolver.go +++ b/internal/netxlite/mocks/resolver.go @@ -1,4 +1,4 @@ -package netxmocks +package mocks import "context" diff --git a/internal/netxmocks/resolver_test.go b/internal/netxlite/mocks/resolver_test.go similarity index 97% rename from internal/netxmocks/resolver_test.go rename to internal/netxlite/mocks/resolver_test.go index a9c42ff..79686c6 100644 --- a/internal/netxmocks/resolver_test.go +++ b/internal/netxlite/mocks/resolver_test.go @@ -1,4 +1,4 @@ -package netxmocks +package mocks import ( "context" diff --git a/internal/netxmocks/tlsconn.go b/internal/netxlite/mocks/tlsconn.go similarity index 96% rename from internal/netxmocks/tlsconn.go rename to internal/netxlite/mocks/tlsconn.go index 3a99af7..2b5f221 100644 --- a/internal/netxmocks/tlsconn.go +++ b/internal/netxlite/mocks/tlsconn.go @@ -1,4 +1,4 @@ -package netxmocks +package mocks import "crypto/tls" diff --git a/internal/netxmocks/tlsconn_test.go b/internal/netxlite/mocks/tlsconn_test.go similarity index 97% rename from internal/netxmocks/tlsconn_test.go rename to internal/netxlite/mocks/tlsconn_test.go index 255e441..3031fce 100644 --- a/internal/netxmocks/tlsconn_test.go +++ b/internal/netxlite/mocks/tlsconn_test.go @@ -1,4 +1,4 @@ -package netxmocks +package mocks import ( "crypto/tls" diff --git a/internal/netxmocks/tlshandshaker.go b/internal/netxlite/mocks/tlshandshaker.go similarity index 96% rename from internal/netxmocks/tlshandshaker.go rename to internal/netxlite/mocks/tlshandshaker.go index 8981c74..ddca993 100644 --- a/internal/netxmocks/tlshandshaker.go +++ b/internal/netxlite/mocks/tlshandshaker.go @@ -1,4 +1,4 @@ -package netxmocks +package mocks import ( "context" diff --git a/internal/netxmocks/tlshandshaker_test.go b/internal/netxlite/mocks/tlshandshaker_test.go similarity index 97% rename from internal/netxmocks/tlshandshaker_test.go rename to internal/netxlite/mocks/tlshandshaker_test.go index 7a0d427..8bca25a 100644 --- a/internal/netxmocks/tlshandshaker_test.go +++ b/internal/netxlite/mocks/tlshandshaker_test.go @@ -1,4 +1,4 @@ -package netxmocks +package mocks import ( "context" diff --git a/internal/netxlite/quic.go b/internal/netxlite/quic.go index b9c6940..cc5042e 100644 --- a/internal/netxlite/quic.go +++ b/internal/netxlite/quic.go @@ -8,7 +8,7 @@ import ( "strconv" "github.com/lucas-clemente/quic-go" - "github.com/ooni/probe-cli/v3/internal/quicx" + "github.com/ooni/probe-cli/v3/internal/netxlite/quicx" ) // QUICContextDialer is a dialer for QUIC using Context. @@ -26,18 +26,18 @@ type QUICListener interface { Listen(addr *net.UDPAddr) (quicx.UDPLikeConn, error) } -// QUICListenerStdlib is a QUICListener using the standard library. -type QUICListenerStdlib struct{} +// quicListenerStdlib is a QUICListener using the standard library. +type quicListenerStdlib struct{} -var _ QUICListener = &QUICListenerStdlib{} +var _ QUICListener = &quicListenerStdlib{} // Listen implements QUICListener.Listen. -func (qls *QUICListenerStdlib) Listen(addr *net.UDPAddr) (quicx.UDPLikeConn, error) { +func (qls *quicListenerStdlib) Listen(addr *net.UDPAddr) (quicx.UDPLikeConn, error) { return net.ListenUDP("udp", addr) } -// QUICDialerQUICGo dials using the lucas-clemente/quic-go library. -type QUICDialerQUICGo struct { +// quicDialerQUICGo dials using the lucas-clemente/quic-go library. +type quicDialerQUICGo struct { // QUICListener is the underlying QUICListener to use. QUICListener QUICListener @@ -47,7 +47,7 @@ type QUICDialerQUICGo struct { quicConfig *quic.Config) (quic.EarlySession, error) } -var _ QUICContextDialer = &QUICDialerQUICGo{} +var _ QUICContextDialer = &quicDialerQUICGo{} // errInvalidIP indicates that a string is not a valid IP. var errInvalidIP = errors.New("netxlite: invalid IP") @@ -60,7 +60,7 @@ var errInvalidIP = errors.New("netxlite: invalid IP") // // 2. if tlsConfig.NextProtos is empty _and_ the port is 443 or 8853, // then we configure, respectively, "h3" and "dq". -func (d *QUICDialerQUICGo) DialContext(ctx context.Context, network string, +func (d *quicDialerQUICGo) DialContext(ctx context.Context, network string, address string, tlsConfig *tls.Config, quicConfig *quic.Config) ( quic.EarlySession, error) { onlyhost, onlyport, err := net.SplitHostPort(address) @@ -89,7 +89,7 @@ func (d *QUICDialerQUICGo) DialContext(ctx context.Context, network string, return &quicSessionOwnsConn{EarlySession: sess, conn: pconn}, nil } -func (d *QUICDialerQUICGo) dialEarlyContext(ctx context.Context, +func (d *quicDialerQUICGo) dialEarlyContext(ctx context.Context, pconn net.PacketConn, remoteAddr net.Addr, address string, tlsConfig *tls.Config, quicConfig *quic.Config) (quic.EarlySession, error) { if d.mockDialEarlyContext != nil { @@ -102,7 +102,7 @@ func (d *QUICDialerQUICGo) dialEarlyContext(ctx context.Context, // maybeApplyTLSDefaults ensures that we're using our certificate pool, if // needed, and that we use a suitable ALPN, if needed, for h3 and dq. -func (d *QUICDialerQUICGo) maybeApplyTLSDefaults(config *tls.Config, port int) *tls.Config { +func (d *quicDialerQUICGo) maybeApplyTLSDefaults(config *tls.Config, port int) *tls.Config { config = config.Clone() if config.RootCAs == nil { config.RootCAs = defaultCertPool @@ -136,9 +136,9 @@ func (sess *quicSessionOwnsConn) CloseWithError( return err } -// QUICDialerResolver is a dialer that uses the configured Resolver +// quicDialerResolver is a dialer that uses the configured Resolver // to resolve a domain name to IP addrs. -type QUICDialerResolver struct { +type quicDialerResolver struct { // Dialer is the underlying QUIC dialer. Dialer QUICContextDialer @@ -146,14 +146,14 @@ type QUICDialerResolver struct { Resolver Resolver } -var _ QUICContextDialer = &QUICDialerResolver{} +var _ QUICContextDialer = &quicDialerResolver{} // DialContext implements QUICContextDialer.DialContext. This function // will apply the following TLS defaults: // // 1. if tlsConfig.ServerName is empty, we will use the hostname // contained inside of the `address` endpoint. -func (d *QUICDialerResolver) DialContext( +func (d *quicDialerResolver) DialContext( ctx context.Context, network, address string, tlsConfig *tls.Config, quicConfig *quic.Config) (quic.EarlySession, error) { onlyhost, onlyport, err := net.SplitHostPort(address) @@ -183,7 +183,7 @@ func (d *QUICDialerResolver) DialContext( } // maybeApplyTLSDefaults sets the SNI if it's not already configured. -func (d *QUICDialerResolver) maybeApplyTLSDefaults(config *tls.Config, host string) *tls.Config { +func (d *quicDialerResolver) maybeApplyTLSDefaults(config *tls.Config, host string) *tls.Config { config = config.Clone() if config.ServerName == "" { config.ServerName = host @@ -192,15 +192,15 @@ func (d *QUICDialerResolver) maybeApplyTLSDefaults(config *tls.Config, host stri } // lookupHost performs a domain name resolution. -func (d *QUICDialerResolver) lookupHost(ctx context.Context, hostname string) ([]string, error) { +func (d *quicDialerResolver) lookupHost(ctx context.Context, hostname string) ([]string, error) { if net.ParseIP(hostname) != nil { return []string{hostname}, nil } return d.Resolver.LookupHost(ctx, hostname) } -// QUICDialerLogger is a dialer with logging. -type QUICDialerLogger struct { +// quicDialerLogger is a dialer with logging. +type quicDialerLogger struct { // Dialer is the underlying QUIC dialer. Dialer QUICContextDialer @@ -208,10 +208,10 @@ type QUICDialerLogger struct { Logger Logger } -var _ QUICContextDialer = &QUICDialerLogger{} +var _ QUICContextDialer = &quicDialerLogger{} // DialContext implements QUICContextDialer.DialContext. -func (d *QUICDialerLogger) DialContext( +func (d *quicDialerLogger) DialContext( ctx context.Context, network, address string, tlsConfig *tls.Config, quicConfig *quic.Config) (quic.EarlySession, error) { d.Logger.Debugf("quic %s/%s...", address, network) diff --git a/internal/netxlite/quic_test.go b/internal/netxlite/quic_test.go index f06a0e0..d3c2b88 100644 --- a/internal/netxlite/quic_test.go +++ b/internal/netxlite/quic_test.go @@ -11,16 +11,16 @@ import ( "github.com/apex/log" "github.com/google/go-cmp/cmp" "github.com/lucas-clemente/quic-go" - "github.com/ooni/probe-cli/v3/internal/netxmocks" - "github.com/ooni/probe-cli/v3/internal/quicx" + "github.com/ooni/probe-cli/v3/internal/netxlite/mocks" + "github.com/ooni/probe-cli/v3/internal/netxlite/quicx" ) func TestQUICDialerQUICGoCannotSplitHostPort(t *testing.T) { tlsConfig := &tls.Config{ ServerName: "www.google.com", } - systemdialer := QUICDialerQUICGo{ - QUICListener: &QUICListenerStdlib{}, + systemdialer := quicDialerQUICGo{ + QUICListener: &quicListenerStdlib{}, } ctx := context.Background() sess, err := systemdialer.DialContext( @@ -37,8 +37,8 @@ func TestQUICDialerQUICGoInvalidPort(t *testing.T) { tlsConfig := &tls.Config{ ServerName: "www.google.com", } - systemdialer := QUICDialerQUICGo{ - QUICListener: &QUICListenerStdlib{}, + systemdialer := quicDialerQUICGo{ + QUICListener: &quicListenerStdlib{}, } ctx := context.Background() sess, err := systemdialer.DialContext( @@ -55,8 +55,8 @@ func TestQUICDialerQUICGoInvalidIP(t *testing.T) { tlsConfig := &tls.Config{ ServerName: "www.google.com", } - systemdialer := QUICDialerQUICGo{ - QUICListener: &QUICListenerStdlib{}, + systemdialer := quicDialerQUICGo{ + QUICListener: &quicListenerStdlib{}, } ctx := context.Background() sess, err := systemdialer.DialContext( @@ -74,8 +74,8 @@ func TestQUICDialerQUICGoCannotListen(t *testing.T) { tlsConfig := &tls.Config{ ServerName: "www.google.com", } - systemdialer := QUICDialerQUICGo{ - QUICListener: &netxmocks.QUICListener{ + systemdialer := quicDialerQUICGo{ + QUICListener: &mocks.QUICListener{ MockListen: func(addr *net.UDPAddr) (quicx.UDPLikeConn, error) { return nil, expected }, @@ -96,8 +96,8 @@ func TestQUICDialerQUICGoCannotPerformHandshake(t *testing.T) { tlsConfig := &tls.Config{ ServerName: "dns.google", } - systemdialer := QUICDialerQUICGo{ - QUICListener: &QUICListenerStdlib{}, + systemdialer := quicDialerQUICGo{ + QUICListener: &quicListenerStdlib{}, } ctx, cancel := context.WithCancel(context.Background()) cancel() // fail immediately @@ -115,8 +115,8 @@ func TestQUICDialerQUICGoWorksAsIntended(t *testing.T) { tlsConfig := &tls.Config{ ServerName: "dns.google", } - systemdialer := QUICDialerQUICGo{ - QUICListener: &QUICListenerStdlib{}, + systemdialer := quicDialerQUICGo{ + QUICListener: &quicListenerStdlib{}, } ctx := context.Background() sess, err := systemdialer.DialContext( @@ -136,8 +136,8 @@ func TestQUICDialerQUICGoTLSDefaultsForWeb(t *testing.T) { tlsConfig := &tls.Config{ ServerName: "dns.google", } - systemdialer := QUICDialerQUICGo{ - QUICListener: &QUICListenerStdlib{}, + systemdialer := quicDialerQUICGo{ + QUICListener: &quicListenerStdlib{}, mockDialEarlyContext: func(ctx context.Context, pconn net.PacketConn, remoteAddr net.Addr, host string, tlsConfig *tls.Config, quicConfig *quic.Config) (quic.EarlySession, error) { @@ -177,8 +177,8 @@ func TestQUICDialerQUICGoTLSDefaultsForDoQ(t *testing.T) { tlsConfig := &tls.Config{ ServerName: "dns.google", } - systemdialer := QUICDialerQUICGo{ - QUICListener: &QUICListenerStdlib{}, + systemdialer := quicDialerQUICGo{ + QUICListener: &quicListenerStdlib{}, mockDialEarlyContext: func(ctx context.Context, pconn net.PacketConn, remoteAddr net.Addr, host string, tlsConfig *tls.Config, quicConfig *quic.Config) (quic.EarlySession, error) { @@ -214,9 +214,9 @@ func TestQUICDialerQUICGoTLSDefaultsForDoQ(t *testing.T) { func TestQUICDialerResolverSuccess(t *testing.T) { tlsConfig := &tls.Config{} - dialer := &QUICDialerResolver{ - Resolver: &net.Resolver{}, Dialer: &QUICDialerQUICGo{ - QUICListener: &QUICListenerStdlib{}, + dialer := &quicDialerResolver{ + Resolver: &net.Resolver{}, Dialer: &quicDialerQUICGo{ + QUICListener: &quicListenerStdlib{}, }} sess, err := dialer.DialContext( context.Background(), "udp", "www.google.com:443", @@ -232,8 +232,8 @@ func TestQUICDialerResolverSuccess(t *testing.T) { func TestQUICDialerResolverNoPort(t *testing.T) { tlsConfig := &tls.Config{} - dialer := &QUICDialerResolver{ - Resolver: new(net.Resolver), Dialer: &QUICDialerQUICGo{}} + dialer := &quicDialerResolver{ + Resolver: new(net.Resolver), Dialer: &quicDialerQUICGo{}} sess, err := dialer.DialContext( context.Background(), "udp", "www.google.com", tlsConfig, &quic.Config{}) @@ -246,7 +246,7 @@ func TestQUICDialerResolverNoPort(t *testing.T) { } func TestQUICDialerResolverLookupHostAddress(t *testing.T) { - dialer := &QUICDialerResolver{Resolver: &netxmocks.Resolver{ + dialer := &quicDialerResolver{Resolver: &mocks.Resolver{ MockLookupHost: func(ctx context.Context, domain string) ([]string, error) { // We should not arrive here and call this function but if we do then // there is going to be an error that fails this test. @@ -265,7 +265,7 @@ func TestQUICDialerResolverLookupHostAddress(t *testing.T) { func TestQUICDialerResolverLookupHostFailure(t *testing.T) { tlsConfig := &tls.Config{} expected := errors.New("mocked error") - dialer := &QUICDialerResolver{Resolver: &netxmocks.Resolver{ + dialer := &quicDialerResolver{Resolver: &mocks.Resolver{ MockLookupHost: func(ctx context.Context, domain string) ([]string, error) { return nil, expected }, @@ -285,9 +285,9 @@ func TestQUICDialerResolverInvalidPort(t *testing.T) { // This test allows us to check for the case where every attempt // to establish a connection leads to a failure tlsConf := &tls.Config{} - dialer := &QUICDialerResolver{ - Resolver: new(net.Resolver), Dialer: &QUICDialerQUICGo{ - QUICListener: &QUICListenerStdlib{}, + dialer := &quicDialerResolver{ + Resolver: new(net.Resolver), Dialer: &quicDialerQUICGo{ + QUICListener: &quicListenerStdlib{}, }} sess, err := dialer.DialContext( context.Background(), "udp", "www.google.com:0", @@ -308,8 +308,8 @@ func TestQUICDialerResolverApplyTLSDefaults(t *testing.T) { expected := errors.New("mocked error") var gotTLSConfig *tls.Config tlsConfig := &tls.Config{} - dialer := &QUICDialerResolver{ - Resolver: new(net.Resolver), Dialer: &netxmocks.QUICContextDialer{ + dialer := &quicDialerResolver{ + Resolver: new(net.Resolver), Dialer: &mocks.QUICContextDialer{ MockDialContext: func(ctx context.Context, network, address string, tlsConfig *tls.Config, quicConfig *quic.Config) (quic.EarlySession, error) { gotTLSConfig = tlsConfig @@ -334,12 +334,12 @@ func TestQUICDialerResolverApplyTLSDefaults(t *testing.T) { } func TestQUICDialerLoggerSuccess(t *testing.T) { - d := &QUICDialerLogger{ - Dialer: &netxmocks.QUICContextDialer{ + d := &quicDialerLogger{ + Dialer: &mocks.QUICContextDialer{ MockDialContext: func(ctx context.Context, network string, address string, tlsConfig *tls.Config, quicConfig *quic.Config) (quic.EarlySession, error) { - return &netxmocks.QUICEarlySession{ + return &mocks.QUICEarlySession{ MockCloseWithError: func( code quic.ApplicationErrorCode, reason string) error { return nil @@ -363,8 +363,8 @@ func TestQUICDialerLoggerSuccess(t *testing.T) { func TestQUICDialerLoggerFailure(t *testing.T) { expected := errors.New("mocked error") - d := &QUICDialerLogger{ - Dialer: &netxmocks.QUICContextDialer{ + d := &quicDialerLogger{ + Dialer: &mocks.QUICContextDialer{ MockDialContext: func(ctx context.Context, network string, address string, tlsConfig *tls.Config, quicConfig *quic.Config) (quic.EarlySession, error) { diff --git a/internal/quicx/quicx.go b/internal/netxlite/quicx/quicx.go similarity index 95% rename from internal/quicx/quicx.go rename to internal/netxlite/quicx/quicx.go index e8c9be6..c186164 100644 --- a/internal/quicx/quicx.go +++ b/internal/netxlite/quicx/quicx.go @@ -3,7 +3,7 @@ // This code introduces the UDPLikeConn, whose documentation explain // why we need to introduce this new type. We could not put this // code inside an existing package because it's used (as of 20 Aug 2021) -// by the netxlite package as well as by the netxmocks package. +// by the netxlite package as well as by the mocks package. package quicx import ( diff --git a/internal/netxlite/resolver.go b/internal/netxlite/resolver.go index ce70b8c..5fa7374 100644 --- a/internal/netxlite/resolver.go +++ b/internal/netxlite/resolver.go @@ -14,39 +14,39 @@ type Resolver interface { LookupHost(ctx context.Context, hostname string) (addrs []string, err error) } -// ResolverSystem is the system resolver. -type ResolverSystem struct{} +// resolverSystem is the system resolver. +type resolverSystem struct{} -var _ Resolver = &ResolverSystem{} +var _ Resolver = &resolverSystem{} // LookupHost implements Resolver.LookupHost. -func (r *ResolverSystem) LookupHost(ctx context.Context, hostname string) ([]string, error) { +func (r *resolverSystem) LookupHost(ctx context.Context, hostname string) ([]string, error) { return net.DefaultResolver.LookupHost(ctx, hostname) } // Network implements Resolver.Network. -func (r *ResolverSystem) Network() string { +func (r *resolverSystem) Network() string { return "system" } // Address implements Resolver.Address. -func (r *ResolverSystem) Address() string { +func (r *resolverSystem) Address() string { return "" } // DefaultResolver is the resolver we use by default. -var DefaultResolver = &ResolverSystem{} +var DefaultResolver = &resolverSystem{} -// ResolverLogger is a resolver that emits events -type ResolverLogger struct { +// resolverLogger is a resolver that emits events +type resolverLogger struct { Resolver Logger Logger } -var _ Resolver = &ResolverLogger{} +var _ Resolver = &resolverLogger{} // LookupHost returns the IP addresses of a host -func (r *ResolverLogger) LookupHost(ctx context.Context, hostname string) ([]string, error) { +func (r *resolverLogger) LookupHost(ctx context.Context, hostname string) ([]string, error) { r.Logger.Debugf("resolve %s...", hostname) start := time.Now() addrs, err := r.Resolver.LookupHost(ctx, hostname) @@ -64,7 +64,7 @@ type resolverNetworker interface { } // Network implements Resolver.Network. -func (r *ResolverLogger) Network() string { +func (r *resolverLogger) Network() string { if rn, ok := r.Resolver.(resolverNetworker); ok { return rn.Network() } @@ -76,22 +76,22 @@ type resolverAddresser interface { } // Address implements Resolver.Address. -func (r *ResolverLogger) Address() string { +func (r *resolverLogger) Address() string { if ra, ok := r.Resolver.(resolverAddresser); ok { return ra.Address() } return "" } -// ResolverIDNA supports resolving Internationalized Domain Names. +// resolverIDNA supports resolving Internationalized Domain Names. // // See RFC3492 for more information. -type ResolverIDNA struct { +type resolverIDNA struct { Resolver } // LookupHost implements Resolver.LookupHost. -func (r *ResolverIDNA) LookupHost(ctx context.Context, hostname string) ([]string, error) { +func (r *resolverIDNA) LookupHost(ctx context.Context, hostname string) ([]string, error) { host, err := idna.ToASCII(hostname) if err != nil { return nil, err @@ -100,7 +100,7 @@ func (r *ResolverIDNA) LookupHost(ctx context.Context, hostname string) ([]strin } // Network implements Resolver.Network. -func (r *ResolverIDNA) Network() string { +func (r *resolverIDNA) Network() string { if rn, ok := r.Resolver.(resolverNetworker); ok { return rn.Network() } @@ -108,7 +108,7 @@ func (r *ResolverIDNA) Network() string { } // Address implements Resolver.Address. -func (r *ResolverIDNA) Address() string { +func (r *resolverIDNA) Address() string { if ra, ok := r.Resolver.(resolverAddresser); ok { return ra.Address() } diff --git a/internal/netxlite/resolver_test.go b/internal/netxlite/resolver_test.go index 3596ec5..80314f1 100644 --- a/internal/netxlite/resolver_test.go +++ b/internal/netxlite/resolver_test.go @@ -9,11 +9,11 @@ import ( "github.com/apex/log" "github.com/google/go-cmp/cmp" - "github.com/ooni/probe-cli/v3/internal/netxmocks" + "github.com/ooni/probe-cli/v3/internal/netxlite/mocks" ) func TestResolverSystemNetworkAddress(t *testing.T) { - r := ResolverSystem{} + r := resolverSystem{} if r.Network() != "system" { t.Fatal("invalid Network") } @@ -23,7 +23,7 @@ func TestResolverSystemNetworkAddress(t *testing.T) { } func TestResolverSystemWorksAsIntended(t *testing.T) { - r := ResolverSystem{} + r := resolverSystem{} addrs, err := r.LookupHost(context.Background(), "dns.google.com") if err != nil { t.Fatal(err) @@ -35,9 +35,9 @@ func TestResolverSystemWorksAsIntended(t *testing.T) { func TestResolverLoggerWithSuccess(t *testing.T) { expected := []string{"1.1.1.1"} - r := ResolverLogger{ + r := resolverLogger{ Logger: log.Log, - Resolver: &netxmocks.Resolver{ + Resolver: &mocks.Resolver{ MockLookupHost: func(ctx context.Context, domain string) ([]string, error) { return expected, nil }, @@ -54,9 +54,9 @@ func TestResolverLoggerWithSuccess(t *testing.T) { func TestResolverLoggerWithFailure(t *testing.T) { expected := errors.New("mocked error") - r := ResolverLogger{ + r := resolverLogger{ Logger: log.Log, - Resolver: &netxmocks.Resolver{ + Resolver: &mocks.Resolver{ MockLookupHost: func(ctx context.Context, domain string) ([]string, error) { return nil, expected }, @@ -72,7 +72,7 @@ func TestResolverLoggerWithFailure(t *testing.T) { } func TestResolverLoggerChildNetworkAddress(t *testing.T) { - r := &ResolverLogger{Logger: log.Log, Resolver: DefaultResolver} + r := &resolverLogger{Logger: log.Log, Resolver: DefaultResolver} if r.Network() != "system" { t.Fatal("invalid Network") } @@ -82,7 +82,7 @@ func TestResolverLoggerChildNetworkAddress(t *testing.T) { } func TestResolverLoggerNoChildNetworkAddress(t *testing.T) { - r := &ResolverLogger{Logger: log.Log, Resolver: &net.Resolver{}} + r := &resolverLogger{Logger: log.Log, Resolver: &net.Resolver{}} if r.Network() != "logger" { t.Fatal("invalid Network") } @@ -93,8 +93,8 @@ func TestResolverLoggerNoChildNetworkAddress(t *testing.T) { func TestResolverIDNAWorksAsIntended(t *testing.T) { expectedIPs := []string{"77.88.55.66"} - r := &ResolverIDNA{ - Resolver: &netxmocks.Resolver{ + r := &resolverIDNA{ + Resolver: &mocks.Resolver{ MockLookupHost: func(ctx context.Context, domain string) ([]string, error) { if domain != "xn--d1acpjx3f.xn--p1ai" { return nil, errors.New("passed invalid domain") @@ -113,8 +113,8 @@ func TestResolverIDNAWorksAsIntended(t *testing.T) { } } -func TestIDNAResolverWithInvalidPunycode(t *testing.T) { - r := &ResolverIDNA{Resolver: &netxmocks.Resolver{ +func TestResolverIDNAWithInvalidPunycode(t *testing.T) { + r := &resolverIDNA{Resolver: &mocks.Resolver{ MockLookupHost: func(ctx context.Context, domain string) ([]string, error) { return nil, errors.New("should not happen") }, @@ -131,7 +131,7 @@ func TestIDNAResolverWithInvalidPunycode(t *testing.T) { } func TestResolverIDNAChildNetworkAddress(t *testing.T) { - r := &ResolverIDNA{ + r := &resolverIDNA{ Resolver: DefaultResolver, } if v := r.Network(); v != "system" { @@ -143,7 +143,7 @@ func TestResolverIDNAChildNetworkAddress(t *testing.T) { } func TestResolverIDNANoChildNetworkAddress(t *testing.T) { - r := &ResolverIDNA{} + r := &resolverIDNA{} if v := r.Network(); v != "idna" { t.Fatal("invalid network", v) } diff --git a/internal/netxlite/tls.go b/internal/netxlite/tls.go new file mode 100644 index 0000000..b1af11c --- /dev/null +++ b/internal/netxlite/tls.go @@ -0,0 +1,273 @@ +package netxlite + +import ( + "context" + "crypto/tls" + "crypto/x509" + "errors" + "fmt" + "net" + "time" +) + +var ( + tlsVersionString = map[uint16]string{ + tls.VersionTLS10: "TLSv1", + tls.VersionTLS11: "TLSv1.1", + tls.VersionTLS12: "TLSv1.2", + tls.VersionTLS13: "TLSv1.3", + 0: "", // guarantee correct behaviour + } + + tlsCipherSuiteString = map[uint16]string{ + tls.TLS_RSA_WITH_RC4_128_SHA: "TLS_RSA_WITH_RC4_128_SHA", + tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA: "TLS_RSA_WITH_3DES_EDE_CBC_SHA", + tls.TLS_RSA_WITH_AES_128_CBC_SHA: "TLS_RSA_WITH_AES_128_CBC_SHA", + tls.TLS_RSA_WITH_AES_256_CBC_SHA: "TLS_RSA_WITH_AES_256_CBC_SHA", + tls.TLS_RSA_WITH_AES_128_CBC_SHA256: "TLS_RSA_WITH_AES_128_CBC_SHA256", + tls.TLS_RSA_WITH_AES_128_GCM_SHA256: "TLS_RSA_WITH_AES_128_GCM_SHA256", + tls.TLS_RSA_WITH_AES_256_GCM_SHA384: "TLS_RSA_WITH_AES_256_GCM_SHA384", + tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", + tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA: "TLS_ECDHE_RSA_WITH_RC4_128_SHA", + tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", + tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", + tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", + tls.TLS_AES_128_GCM_SHA256: "TLS_AES_128_GCM_SHA256", + tls.TLS_AES_256_GCM_SHA384: "TLS_AES_256_GCM_SHA384", + tls.TLS_CHACHA20_POLY1305_SHA256: "TLS_CHACHA20_POLY1305_SHA256", + 0: "", // guarantee correct behaviour + } +) + +// TLSVersionString returns a TLS version string. +func TLSVersionString(value uint16) string { + if str, found := tlsVersionString[value]; found { + return str + } + return fmt.Sprintf("TLS_VERSION_UNKNOWN_%d", value) +} + +// TLSCipherSuiteString returns the TLS cipher suite as a string. +func TLSCipherSuiteString(value uint16) string { + if str, found := tlsCipherSuiteString[value]; found { + return str + } + return fmt.Sprintf("TLS_CIPHER_SUITE_UNKNOWN_%d", value) +} + +// NewDefaultCertPool returns a copy of the default x509 +// certificate pool that we bundle from Mozilla. +func NewDefaultCertPool() *x509.CertPool { + pool := x509.NewCertPool() + // Assumption: AppendCertsFromPEM cannot fail because we + // run this function already in the generate.go file + pool.AppendCertsFromPEM([]byte(pemcerts)) + return pool +} + +// ErrInvalidTLSVersion indicates that you passed us a string +// that does not represent a valid TLS version. +var ErrInvalidTLSVersion = errors.New("invalid TLS version") + +// ConfigureTLSVersion configures the correct TLS version into +// the specified *tls.Config or returns an error. +func ConfigureTLSVersion(config *tls.Config, version string) error { + switch version { + case "TLSv1.3": + config.MinVersion = tls.VersionTLS13 + config.MaxVersion = tls.VersionTLS13 + case "TLSv1.2": + config.MinVersion = tls.VersionTLS12 + config.MaxVersion = tls.VersionTLS12 + case "TLSv1.1": + config.MinVersion = tls.VersionTLS11 + config.MaxVersion = tls.VersionTLS11 + case "TLSv1.0", "TLSv1": + config.MinVersion = tls.VersionTLS10 + config.MaxVersion = tls.VersionTLS10 + case "": + // nothing + default: + return ErrInvalidTLSVersion + } + return nil +} + +// TLSConn is any tls.Conn-like structure. +type TLSConn interface { + // net.Conn is the embedded conn. + net.Conn + + // ConnectionState returns the TLS connection state. + ConnectionState() tls.ConnectionState + + // Handshake performs the handshake. + Handshake() error +} + +// TLSHandshaker is the generic TLS handshaker. +type TLSHandshaker interface { + // Handshake creates a new TLS connection from the given connection and + // the given config. This function DOES NOT take ownership of the connection + // and it's your responsibility to close it on failure. + Handshake(ctx context.Context, conn net.Conn, config *tls.Config) ( + net.Conn, tls.ConnectionState, error) +} + +// tlsHandshakerConfigurable is a configurable TLS handshaker that +// uses by default the standard library's TLS implementation. +type tlsHandshakerConfigurable struct { + // NewConn is the OPTIONAL factory for creating a new connection. If + // this factory is not set, we'll use the stdlib. + NewConn func(conn net.Conn, config *tls.Config) TLSConn + + // Timeout is the OPTIONAL timeout imposed on the TLS handshake. If zero + // or negative, we will use default timeout of 10 seconds. + Timeout time.Duration +} + +var _ TLSHandshaker = &tlsHandshakerConfigurable{} + +// defaultCertPool is the cert pool we use by default. We store this +// value into a private variable to enable for unit testing. +var defaultCertPool = NewDefaultCertPool() + +// Handshake implements Handshaker.Handshake. This function will +// configure the code to use the built-in Mozilla CA if the config +// field contains a nil RootCAs field. +// +// Bug +// +// Until Go 1.17 is released, this function will not honour +// the context. We'll however always enforce an overall timeout. +func (h *tlsHandshakerConfigurable) Handshake( + ctx context.Context, conn net.Conn, config *tls.Config, +) (net.Conn, tls.ConnectionState, error) { + timeout := h.Timeout + if timeout <= 0 { + timeout = 10 * time.Second + } + defer conn.SetDeadline(time.Time{}) + conn.SetDeadline(time.Now().Add(timeout)) + if config.RootCAs == nil { + config = config.Clone() + config.RootCAs = defaultCertPool + } + tlsconn := h.newConn(conn, config) + if err := tlsconn.Handshake(); err != nil { + return nil, tls.ConnectionState{}, err + } + return tlsconn, tlsconn.ConnectionState(), nil +} + +// newConn creates a new TLSConn. +func (h *tlsHandshakerConfigurable) newConn(conn net.Conn, config *tls.Config) TLSConn { + if h.NewConn != nil { + return h.NewConn(conn, config) + } + return tls.Client(conn, config) +} + +// defaultTLSHandshaker is the default TLS handshaker. +var defaultTLSHandshaker = &tlsHandshakerConfigurable{} + +// tlsHandshakerLogger is a TLSHandshaker with logging. +type tlsHandshakerLogger struct { + // TLSHandshaker is the underlying handshaker. + TLSHandshaker TLSHandshaker + + // Logger is the underlying logger. + Logger Logger +} + +var _ TLSHandshaker = &tlsHandshakerLogger{} + +// Handshake implements Handshaker.Handshake +func (h *tlsHandshakerLogger) Handshake( + ctx context.Context, conn net.Conn, config *tls.Config, +) (net.Conn, tls.ConnectionState, error) { + h.Logger.Debugf( + "tls {sni=%s next=%+v}...", config.ServerName, config.NextProtos) + start := time.Now() + tlsconn, state, err := h.TLSHandshaker.Handshake(ctx, conn, config) + elapsed := time.Since(start) + if err != nil { + h.Logger.Debugf( + "tls {sni=%s next=%+v}... %s in %s", config.ServerName, + config.NextProtos, err, elapsed) + return nil, tls.ConnectionState{}, err + } + h.Logger.Debugf( + "tls {sni=%s next=%+v}... ok in %s {next=%s cipher=%s v=%s}", + config.ServerName, config.NextProtos, elapsed, state.NegotiatedProtocol, + TLSCipherSuiteString(state.CipherSuite), + TLSVersionString(state.Version)) + return tlsconn, state, nil +} + +// TLSDialer is the TLS dialer +type TLSDialer struct { + // Config is the OPTIONAL tls config. + Config *tls.Config + + // Dialer is the MANDATORY dialer. + Dialer Dialer + + // TLSHandshaker is the MANDATORY TLS handshaker. + TLSHandshaker TLSHandshaker +} + +// DialTLSContext dials a TLS connection. +func (d *TLSDialer) DialTLSContext(ctx context.Context, network, address string) (net.Conn, error) { + host, port, err := net.SplitHostPort(address) + if err != nil { + return nil, err + } + conn, err := d.Dialer.DialContext(ctx, network, address) + if err != nil { + return nil, err + } + config := d.config(host, port) + tlsconn, _, err := d.TLSHandshaker.Handshake(ctx, conn, config) + if err != nil { + conn.Close() + return nil, err + } + return tlsconn, nil +} + +// config creates a new config. If d.Config is nil, then we start +// from an empty config. Otherwise, we clone d.Config. +// +// We set the ServerName field if not already set. +// +// We set the ALPN if the port is 443 or 853, if not already set. +func (d *TLSDialer) config(host, port string) *tls.Config { + config := d.Config + if config == nil { + config = &tls.Config{} + } + config = config.Clone() // operate on a clone + if config.ServerName == "" { + config.ServerName = host + } + if len(config.NextProtos) <= 0 { + switch port { + case "443": + config.NextProtos = []string{"h2", "http/1.1"} + case "853": + config.NextProtos = []string{"dot"} + } + } + return config +} diff --git a/internal/netxlite/tls_test.go b/internal/netxlite/tls_test.go new file mode 100644 index 0000000..4866bac --- /dev/null +++ b/internal/netxlite/tls_test.go @@ -0,0 +1,409 @@ +package netxlite + +import ( + "context" + "crypto/tls" + "errors" + "io" + "net" + "net/http" + "net/http/httptest" + "net/url" + "reflect" + "strings" + "testing" + "time" + + "github.com/apex/log" + "github.com/google/go-cmp/cmp" + "github.com/ooni/probe-cli/v3/internal/netxlite/mocks" +) + +func TestVersionString(t *testing.T) { + if TLSVersionString(tls.VersionTLS13) != "TLSv1.3" { + t.Fatal("not working for existing version") + } + if TLSVersionString(1) != "TLS_VERSION_UNKNOWN_1" { + t.Fatal("not working for nonexisting version") + } + if TLSVersionString(0) != "" { + t.Fatal("not working for zero version") + } +} + +func TestCipherSuite(t *testing.T) { + if TLSCipherSuiteString(tls.TLS_AES_128_GCM_SHA256) != "TLS_AES_128_GCM_SHA256" { + t.Fatal("not working for existing cipher suite") + } + if TLSCipherSuiteString(1) != "TLS_CIPHER_SUITE_UNKNOWN_1" { + t.Fatal("not working for nonexisting cipher suite") + } + if TLSCipherSuiteString(0) != "" { + t.Fatal("not working for zero cipher suite") + } +} + +func TestNewDefaultCertPoolWorks(t *testing.T) { + pool := NewDefaultCertPool() + if pool == nil { + t.Fatal("expected non-nil value here") + } +} + +func TestConfigureTLSVersion(t *testing.T) { + tests := []struct { + name string + version string + wantErr error + versionMin int + versionMax int + }{{ + name: "with TLSv1.3", + version: "TLSv1.3", + wantErr: nil, + versionMin: tls.VersionTLS13, + versionMax: tls.VersionTLS13, + }, { + name: "with TLSv1.2", + version: "TLSv1.2", + wantErr: nil, + versionMin: tls.VersionTLS12, + versionMax: tls.VersionTLS12, + }, { + name: "with TLSv1.1", + version: "TLSv1.1", + wantErr: nil, + versionMin: tls.VersionTLS11, + versionMax: tls.VersionTLS11, + }, { + name: "with TLSv1.0", + version: "TLSv1.0", + wantErr: nil, + versionMin: tls.VersionTLS10, + versionMax: tls.VersionTLS10, + }, { + name: "with TLSv1", + version: "TLSv1", + wantErr: nil, + versionMin: tls.VersionTLS10, + versionMax: tls.VersionTLS10, + }, { + name: "with default", + version: "", + wantErr: nil, + versionMin: 0, + versionMax: 0, + }, { + name: "with invalid version", + version: "TLSv999", + wantErr: ErrInvalidTLSVersion, + versionMin: 0, + versionMax: 0, + }} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + conf := new(tls.Config) + err := ConfigureTLSVersion(conf, tt.version) + if !errors.Is(err, tt.wantErr) { + t.Fatalf("not the error we expected: %+v", err) + } + if conf.MinVersion != uint16(tt.versionMin) { + t.Fatalf("not the min version we expected: %+v", conf.MinVersion) + } + if conf.MaxVersion != uint16(tt.versionMax) { + t.Fatalf("not the max version we expected: %+v", conf.MaxVersion) + } + }) + } +} + +func TestTLSHandshakerConfigurableWithError(t *testing.T) { + var times []time.Time + h := &tlsHandshakerConfigurable{} + tcpConn := &mocks.Conn{ + MockWrite: func(b []byte) (int, error) { + return 0, io.EOF + }, + MockSetDeadline: func(t time.Time) error { + times = append(times, t) + return nil + }, + } + ctx := context.Background() + conn, _, err := h.Handshake(ctx, tcpConn, &tls.Config{ + ServerName: "x.org", + }) + if err != io.EOF { + t.Fatal("not the error that we expected") + } + if conn != nil { + t.Fatal("expected nil con here") + } + if len(times) != 2 { + t.Fatal("expected two time entries") + } + if !times[0].After(time.Now()) { + t.Fatal("timeout not in the future") + } + if !times[1].IsZero() { + t.Fatal("did not clear timeout on exit") + } +} + +func TestTLSHandshakerConfigurableSuccess(t *testing.T) { + handler := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + rw.WriteHeader(200) + }) + srvr := httptest.NewTLSServer(handler) + defer srvr.Close() + URL, err := url.Parse(srvr.URL) + if err != nil { + t.Fatal(err) + } + conn, err := net.Dial("tcp", URL.Host) + if err != nil { + t.Fatal(err) + } + defer conn.Close() + handshaker := &tlsHandshakerConfigurable{} + ctx := context.Background() + config := &tls.Config{ + InsecureSkipVerify: true, + MinVersion: tls.VersionTLS13, + MaxVersion: tls.VersionTLS13, + ServerName: URL.Hostname(), + } + tlsConn, connState, err := handshaker.Handshake(ctx, conn, config) + if err != nil { + t.Fatal(err) + } + defer tlsConn.Close() + if connState.Version != tls.VersionTLS13 { + t.Fatal("unexpected TLS version") + } +} + +func TestTLSHandshakerConfigurableSetsDefaultRootCAs(t *testing.T) { + expected := errors.New("mocked error") + var gotTLSConfig *tls.Config + handshaker := &tlsHandshakerConfigurable{ + NewConn: func(conn net.Conn, config *tls.Config) TLSConn { + gotTLSConfig = config + return &mocks.TLSConn{ + MockHandshake: func() error { + return expected + }, + } + }, + } + ctx := context.Background() + config := &tls.Config{} + conn := &mocks.Conn{ + MockSetDeadline: func(t time.Time) error { + return nil + }, + } + tlsConn, connState, err := handshaker.Handshake(ctx, conn, config) + if !errors.Is(err, expected) { + t.Fatal("not the error we expected", err) + } + if !reflect.ValueOf(connState).IsZero() { + t.Fatal("expected zero connState here") + } + if tlsConn != nil { + t.Fatal("expected nil tlsConn here") + } + if config.RootCAs != nil { + t.Fatal("config.RootCAs should still be nil") + } + if gotTLSConfig.RootCAs != defaultCertPool { + t.Fatal("gotTLSConfig.RootCAs has not been correctly set") + } +} + +func TestTLSHandshakerLoggerSuccess(t *testing.T) { + th := &tlsHandshakerLogger{ + TLSHandshaker: &mocks.TLSHandshaker{ + MockHandshake: func(ctx context.Context, conn net.Conn, config *tls.Config) (net.Conn, tls.ConnectionState, error) { + return tls.Client(conn, config), tls.ConnectionState{}, nil + }, + }, + Logger: log.Log, + } + conn := &mocks.Conn{ + MockClose: func() error { + return nil + }, + } + config := &tls.Config{} + ctx := context.Background() + tlsConn, connState, err := th.Handshake(ctx, conn, config) + if err != nil { + t.Fatal(err) + } + if err := tlsConn.Close(); err != nil { + t.Fatal(err) + } + if !reflect.ValueOf(connState).IsZero() { + t.Fatal("expected zero ConnectionState here") + } +} + +func TestTLSHandshakerLoggerFailure(t *testing.T) { + expected := errors.New("mocked error") + th := &tlsHandshakerLogger{ + TLSHandshaker: &mocks.TLSHandshaker{ + MockHandshake: func(ctx context.Context, conn net.Conn, config *tls.Config) (net.Conn, tls.ConnectionState, error) { + return nil, tls.ConnectionState{}, expected + }, + }, + Logger: log.Log, + } + conn := &mocks.Conn{ + MockClose: func() error { + return nil + }, + } + config := &tls.Config{} + ctx := context.Background() + tlsConn, connState, err := th.Handshake(ctx, conn, config) + if !errors.Is(err, expected) { + t.Fatal("not the error we expected", err) + } + if tlsConn != nil { + t.Fatal("expected nil conn here") + } + if !reflect.ValueOf(connState).IsZero() { + t.Fatal("expected zero ConnectionState here") + } +} + +func TestTLSDialerFailureSplitHostPort(t *testing.T) { + dialer := &TLSDialer{} + ctx := context.Background() + const address = "www.google.com" // missing port + conn, err := dialer.DialTLSContext(ctx, "tcp", address) + if err == nil || !strings.HasSuffix(err.Error(), "missing port in address") { + t.Fatal("not the error we expected", err) + } + if conn != nil { + t.Fatal("connection is not nil") + } +} + +func TestTLSDialerFailureDialing(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() // immediately fail + dialer := TLSDialer{Dialer: &net.Dialer{}} + conn, err := dialer.DialTLSContext(ctx, "tcp", "www.google.com:443") + if err == nil || !strings.HasSuffix(err.Error(), "operation was canceled") { + t.Fatal("not the error we expected", err) + } + if conn != nil { + t.Fatal("connection is not nil") + } +} + +func TestTLSDialerFailureHandshaking(t *testing.T) { + ctx := context.Background() + dialer := TLSDialer{ + Config: &tls.Config{}, + Dialer: &mocks.Dialer{MockDialContext: func(ctx context.Context, network, address string) (net.Conn, error) { + return &mocks.Conn{MockWrite: func(b []byte) (int, error) { + return 0, io.EOF + }, MockClose: func() error { + return nil + }, MockSetDeadline: func(t time.Time) error { + return nil + }}, nil + }}, + TLSHandshaker: &tlsHandshakerConfigurable{}, + } + conn, err := dialer.DialTLSContext(ctx, "tcp", "www.google.com:443") + if !errors.Is(err, io.EOF) { + t.Fatal("not the error we expected", err) + } + if conn != nil { + t.Fatal("connection is not nil") + } +} + +func TestTLSDialerSuccessHandshaking(t *testing.T) { + ctx := context.Background() + dialer := TLSDialer{ + Dialer: &mocks.Dialer{MockDialContext: func(ctx context.Context, network, address string) (net.Conn, error) { + return &mocks.Conn{MockWrite: func(b []byte) (int, error) { + return 0, io.EOF + }, MockClose: func() error { + return nil + }, MockSetDeadline: func(t time.Time) error { + return nil + }}, nil + }}, + TLSHandshaker: &mocks.TLSHandshaker{ + MockHandshake: func(ctx context.Context, conn net.Conn, config *tls.Config) (net.Conn, tls.ConnectionState, error) { + return tls.Client(conn, config), tls.ConnectionState{}, nil + }, + }, + } + conn, err := dialer.DialTLSContext(ctx, "tcp", "www.google.com:443") + if err != nil { + t.Fatal(err) + } + if conn == nil { + t.Fatal("connection is nil") + } + conn.Close() +} + +func TestTLSDialerConfigFromEmptyConfigForWeb(t *testing.T) { + d := &TLSDialer{} + config := d.config("www.google.com", "443") + if config.ServerName != "www.google.com" { + t.Fatal("invalid server name") + } + if diff := cmp.Diff(config.NextProtos, []string{"h2", "http/1.1"}); diff != "" { + t.Fatal(diff) + } +} + +func TestTLSDialerConfigFromEmptyConfigForDoT(t *testing.T) { + d := &TLSDialer{} + config := d.config("dns.google", "853") + if config.ServerName != "dns.google" { + t.Fatal("invalid server name") + } + if diff := cmp.Diff(config.NextProtos, []string{"dot"}); diff != "" { + t.Fatal(diff) + } +} + +func TestTLSDialerConfigWithServerName(t *testing.T) { + d := &TLSDialer{ + Config: &tls.Config{ + ServerName: "example.com", + }, + } + config := d.config("dns.google", "853") + if config.ServerName != "example.com" { + t.Fatal("invalid server name") + } + if diff := cmp.Diff(config.NextProtos, []string{"dot"}); diff != "" { + t.Fatal(diff) + } +} + +func TestTLSDialerConfigWithALPN(t *testing.T) { + d := &TLSDialer{ + Config: &tls.Config{ + NextProtos: []string{"h2"}, + }, + } + config := d.config("dns.google", "853") + if config.ServerName != "dns.google" { + t.Fatal("invalid server name") + } + if diff := cmp.Diff(config.NextProtos, []string{"h2"}); diff != "" { + t.Fatal(diff) + } +} diff --git a/internal/netxlite/tlsconn.go b/internal/netxlite/tlsconn.go deleted file mode 100644 index 0dbb5fc..0000000 --- a/internal/netxlite/tlsconn.go +++ /dev/null @@ -1,18 +0,0 @@ -package netxlite - -import ( - "crypto/tls" - "net" -) - -// TLSConn is any tls.Conn-like structure. -type TLSConn interface { - // net.Conn is the embedded conn. - net.Conn - - // ConnectionState returns the TLS connection state. - ConnectionState() tls.ConnectionState - - // Handshake performs the handshake. - Handshake() error -} diff --git a/internal/netxlite/tlsdialer.go b/internal/netxlite/tlsdialer.go deleted file mode 100644 index cc09e3a..0000000 --- a/internal/netxlite/tlsdialer.go +++ /dev/null @@ -1,64 +0,0 @@ -package netxlite - -import ( - "context" - "crypto/tls" - "net" -) - -// TLSDialer is the TLS dialer -type TLSDialer struct { - // Config is the OPTIONAL tls config. - Config *tls.Config - - // Dialer is the MANDATORY dialer. - Dialer Dialer - - // TLSHandshaker is the MANDATORY TLS handshaker. - TLSHandshaker TLSHandshaker -} - -// DialTLSContext dials a TLS connection. -func (d *TLSDialer) DialTLSContext(ctx context.Context, network, address string) (net.Conn, error) { - host, port, err := net.SplitHostPort(address) - if err != nil { - return nil, err - } - conn, err := d.Dialer.DialContext(ctx, network, address) - if err != nil { - return nil, err - } - config := d.config(host, port) - tlsconn, _, err := d.TLSHandshaker.Handshake(ctx, conn, config) - if err != nil { - conn.Close() - return nil, err - } - return tlsconn, nil -} - -// config creates a new config. If d.Config is nil, then we start -// from an empty config. Otherwise, we clone d.Config. -// -// We set the ServerName field if not already set. -// -// We set the ALPN if the port is 443 or 853, if not already set. -func (d *TLSDialer) config(host, port string) *tls.Config { - config := d.Config - if config == nil { - config = &tls.Config{} - } - config = config.Clone() // operate on a clone - if config.ServerName == "" { - config.ServerName = host - } - if len(config.NextProtos) <= 0 { - switch port { - case "443": - config.NextProtos = []string{"h2", "http/1.1"} - case "853": - config.NextProtos = []string{"dot"} - } - } - return config -} diff --git a/internal/netxlite/tlsdialer_test.go b/internal/netxlite/tlsdialer_test.go deleted file mode 100644 index 5195585..0000000 --- a/internal/netxlite/tlsdialer_test.go +++ /dev/null @@ -1,145 +0,0 @@ -package netxlite - -import ( - "context" - "crypto/tls" - "errors" - "io" - "net" - "strings" - "testing" - "time" - - "github.com/google/go-cmp/cmp" - "github.com/ooni/probe-cli/v3/internal/netxmocks" -) - -func TestTLSDialerFailureSplitHostPort(t *testing.T) { - dialer := &TLSDialer{} - ctx := context.Background() - const address = "www.google.com" // missing port - conn, err := dialer.DialTLSContext(ctx, "tcp", address) - if err == nil || !strings.HasSuffix(err.Error(), "missing port in address") { - t.Fatal("not the error we expected", err) - } - if conn != nil { - t.Fatal("connection is not nil") - } -} - -func TestTLSDialerFailureDialing(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - cancel() // immediately fail - dialer := TLSDialer{Dialer: &net.Dialer{}} - conn, err := dialer.DialTLSContext(ctx, "tcp", "www.google.com:443") - if err == nil || !strings.HasSuffix(err.Error(), "operation was canceled") { - t.Fatal("not the error we expected", err) - } - if conn != nil { - t.Fatal("connection is not nil") - } -} - -func TestTLSDialerFailureHandshaking(t *testing.T) { - ctx := context.Background() - dialer := TLSDialer{ - Config: &tls.Config{}, - Dialer: &netxmocks.Dialer{MockDialContext: func(ctx context.Context, network, address string) (net.Conn, error) { - return &netxmocks.Conn{MockWrite: func(b []byte) (int, error) { - return 0, io.EOF - }, MockClose: func() error { - return nil - }, MockSetDeadline: func(t time.Time) error { - return nil - }}, nil - }}, - TLSHandshaker: &TLSHandshakerConfigurable{}, - } - conn, err := dialer.DialTLSContext(ctx, "tcp", "www.google.com:443") - if !errors.Is(err, io.EOF) { - t.Fatal("not the error we expected", err) - } - if conn != nil { - t.Fatal("connection is not nil") - } -} - -func TestTLSDialerSuccessHandshaking(t *testing.T) { - ctx := context.Background() - dialer := TLSDialer{ - Dialer: &netxmocks.Dialer{MockDialContext: func(ctx context.Context, network, address string) (net.Conn, error) { - return &netxmocks.Conn{MockWrite: func(b []byte) (int, error) { - return 0, io.EOF - }, MockClose: func() error { - return nil - }, MockSetDeadline: func(t time.Time) error { - return nil - }}, nil - }}, - TLSHandshaker: &netxmocks.TLSHandshaker{ - MockHandshake: func(ctx context.Context, conn net.Conn, config *tls.Config) (net.Conn, tls.ConnectionState, error) { - return tls.Client(conn, config), tls.ConnectionState{}, nil - }, - }, - } - conn, err := dialer.DialTLSContext(ctx, "tcp", "www.google.com:443") - if err != nil { - t.Fatal(err) - } - if conn == nil { - t.Fatal("connection is nil") - } - conn.Close() -} - -func TestTLSDialerConfigFromEmptyConfigForWeb(t *testing.T) { - d := &TLSDialer{} - config := d.config("www.google.com", "443") - if config.ServerName != "www.google.com" { - t.Fatal("invalid server name") - } - if diff := cmp.Diff(config.NextProtos, []string{"h2", "http/1.1"}); diff != "" { - t.Fatal(diff) - } -} - -func TestTLSDialerConfigFromEmptyConfigForDoT(t *testing.T) { - d := &TLSDialer{} - config := d.config("dns.google", "853") - if config.ServerName != "dns.google" { - t.Fatal("invalid server name") - } - if diff := cmp.Diff(config.NextProtos, []string{"dot"}); diff != "" { - t.Fatal(diff) - } -} - -func TestTLSDialerConfigWithServerName(t *testing.T) { - d := &TLSDialer{ - Config: &tls.Config{ - ServerName: "example.com", - }, - } - config := d.config("dns.google", "853") - if config.ServerName != "example.com" { - t.Fatal("invalid server name") - } - if diff := cmp.Diff(config.NextProtos, []string{"dot"}); diff != "" { - t.Fatal(diff) - } -} - -func TestTLSDialerConfigWithALPN(t *testing.T) { - d := &TLSDialer{ - Config: &tls.Config{ - NextProtos: []string{"h2"}, - }, - } - config := d.config("dns.google", "853") - if config.ServerName != "dns.google" { - t.Fatal("invalid server name") - } - if diff := cmp.Diff(config.NextProtos, []string{"h2"}); diff != "" { - t.Fatal(diff) - } -} diff --git a/internal/netxlite/tlshandshaker.go b/internal/netxlite/tlshandshaker.go deleted file mode 100644 index 924eb95..0000000 --- a/internal/netxlite/tlshandshaker.go +++ /dev/null @@ -1,148 +0,0 @@ -package netxlite - -import ( - "context" - "crypto/tls" - "net" - "time" - - utls "gitlab.com/yawning/utls.git" -) - -// TLSHandshaker is the generic TLS handshaker. -type TLSHandshaker interface { - // Handshake creates a new TLS connection from the given connection and - // the given config. This function DOES NOT take ownership of the connection - // and it's your responsibility to close it on failure. - Handshake(ctx context.Context, conn net.Conn, config *tls.Config) ( - net.Conn, tls.ConnectionState, error) -} - -// TLSHandshakerConfigurable is a configurable TLS handshaker that -// uses by default the standard library's TLS implementation. -type TLSHandshakerConfigurable struct { - // NewConn is the OPTIONAL factory for creating a new connection. If - // this factory is not set, we'll use the stdlib. - NewConn func(conn net.Conn, config *tls.Config) TLSConn - - // Timeout is the OPTIONAL timeout imposed on the TLS handshake. If zero - // or negative, we will use default timeout of 10 seconds. - Timeout time.Duration -} - -var _ TLSHandshaker = &TLSHandshakerConfigurable{} - -// defaultCertPool is the cert pool we use by default. We store this -// value into a private variable to enable for unit testing. -var defaultCertPool = NewDefaultCertPool() - -// Handshake implements Handshaker.Handshake. This function will -// configure the code to use the built-in Mozilla CA if the config -// field contains a nil RootCAs field. -// -// Bug -// -// Until Go 1.17 is released, this function will not honour -// the context. We'll however always enforce an overall timeout. -func (h *TLSHandshakerConfigurable) Handshake( - ctx context.Context, conn net.Conn, config *tls.Config, -) (net.Conn, tls.ConnectionState, error) { - timeout := h.Timeout - if timeout <= 0 { - timeout = 10 * time.Second - } - defer conn.SetDeadline(time.Time{}) - conn.SetDeadline(time.Now().Add(timeout)) - if config.RootCAs == nil { - config = config.Clone() - config.RootCAs = defaultCertPool - } - tlsconn := h.newConn(conn, config) - if err := tlsconn.Handshake(); err != nil { - return nil, tls.ConnectionState{}, err - } - return tlsconn, tlsconn.ConnectionState(), nil -} - -// newConn creates a new TLSConn. -func (h *TLSHandshakerConfigurable) newConn(conn net.Conn, config *tls.Config) TLSConn { - if h.NewConn != nil { - return h.NewConn(conn, config) - } - return tls.Client(conn, config) -} - -// DefaultTLSHandshaker is the default TLS handshaker. -var DefaultTLSHandshaker = &TLSHandshakerConfigurable{} - -// TLSHandshakerLogger is a TLSHandshaker with logging. -type TLSHandshakerLogger struct { - // TLSHandshaker is the underlying handshaker. - TLSHandshaker TLSHandshaker - - // Logger is the underlying logger. - Logger Logger -} - -// Handshake implements Handshaker.Handshake -func (h *TLSHandshakerLogger) Handshake( - ctx context.Context, conn net.Conn, config *tls.Config, -) (net.Conn, tls.ConnectionState, error) { - h.Logger.Debugf( - "tls {sni=%s next=%+v}...", config.ServerName, config.NextProtos) - start := time.Now() - tlsconn, state, err := h.TLSHandshaker.Handshake(ctx, conn, config) - elapsed := time.Since(start) - if err != nil { - h.Logger.Debugf( - "tls {sni=%s next=%+v}... %s in %s", config.ServerName, - config.NextProtos, err, elapsed) - return nil, tls.ConnectionState{}, err - } - h.Logger.Debugf( - "tls {sni=%s next=%+v}... ok in %s {next=%s cipher=%s v=%s}", - config.ServerName, config.NextProtos, elapsed, state.NegotiatedProtocol, - TLSCipherSuiteString(state.CipherSuite), - TLSVersionString(state.Version)) - return tlsconn, state, nil -} - -// UTLSConn implements TLSConn and uses a utls UConn as its underlying connection -type UTLSConn struct { - *utls.UConn -} - -// NewConnUTLS creates a NewConn function creating a utls connection with a specified ClientHelloID -func NewConnUTLS(clientHello *utls.ClientHelloID) func(conn net.Conn, config *tls.Config) TLSConn { - return func(conn net.Conn, config *tls.Config) TLSConn { - uConfig := &utls.Config{ - RootCAs: config.RootCAs, - NextProtos: config.NextProtos, - ServerName: config.ServerName, - InsecureSkipVerify: config.InsecureSkipVerify, - DynamicRecordSizingDisabled: config.DynamicRecordSizingDisabled, - } - tlsConn := utls.UClient(conn, uConfig, *clientHello) - return &UTLSConn{tlsConn} - } -} - -func (c *UTLSConn) ConnectionState() tls.ConnectionState { - uState := c.Conn.ConnectionState() - return tls.ConnectionState{ - Version: uState.Version, - HandshakeComplete: uState.HandshakeComplete, - DidResume: uState.DidResume, - CipherSuite: uState.CipherSuite, - NegotiatedProtocol: uState.NegotiatedProtocol, - NegotiatedProtocolIsMutual: true, - ServerName: uState.ServerName, - PeerCertificates: uState.PeerCertificates, - VerifiedChains: uState.VerifiedChains, - SignedCertificateTimestamps: uState.SignedCertificateTimestamps, - OCSPResponse: uState.OCSPResponse, - TLSUnique: uState.TLSUnique, - } -} - -var _ TLSHandshaker = &TLSHandshakerLogger{} diff --git a/internal/netxlite/tlshandshaker_test.go b/internal/netxlite/tlshandshaker_test.go deleted file mode 100644 index 15451da..0000000 --- a/internal/netxlite/tlshandshaker_test.go +++ /dev/null @@ -1,198 +0,0 @@ -package netxlite - -import ( - "context" - "crypto/tls" - "errors" - "io" - "net" - "net/http" - "net/http/httptest" - "net/url" - "reflect" - "testing" - "time" - - "github.com/apex/log" - "github.com/ooni/probe-cli/v3/internal/netxmocks" - utls "gitlab.com/yawning/utls.git" -) - -func TestTLSHandshakerConfigurableWithError(t *testing.T) { - var times []time.Time - h := &TLSHandshakerConfigurable{} - tcpConn := &netxmocks.Conn{ - MockWrite: func(b []byte) (int, error) { - return 0, io.EOF - }, - MockSetDeadline: func(t time.Time) error { - times = append(times, t) - return nil - }, - } - ctx := context.Background() - conn, _, err := h.Handshake(ctx, tcpConn, &tls.Config{ - ServerName: "x.org", - }) - if err != io.EOF { - t.Fatal("not the error that we expected") - } - if conn != nil { - t.Fatal("expected nil con here") - } - if len(times) != 2 { - t.Fatal("expected two time entries") - } - if !times[0].After(time.Now()) { - t.Fatal("timeout not in the future") - } - if !times[1].IsZero() { - t.Fatal("did not clear timeout on exit") - } -} - -func TestTLSHandshakerConfigurableSuccess(t *testing.T) { - handler := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { - rw.WriteHeader(200) - }) - srvr := httptest.NewTLSServer(handler) - defer srvr.Close() - URL, err := url.Parse(srvr.URL) - if err != nil { - t.Fatal(err) - } - conn, err := net.Dial("tcp", URL.Host) - if err != nil { - t.Fatal(err) - } - defer conn.Close() - handshaker := &TLSHandshakerConfigurable{} - ctx := context.Background() - config := &tls.Config{ - InsecureSkipVerify: true, - MinVersion: tls.VersionTLS13, - MaxVersion: tls.VersionTLS13, - ServerName: URL.Hostname(), - } - tlsConn, connState, err := handshaker.Handshake(ctx, conn, config) - if err != nil { - t.Fatal(err) - } - defer tlsConn.Close() - if connState.Version != tls.VersionTLS13 { - t.Fatal("unexpected TLS version") - } -} - -func TestTLSHandshakerConfigurableSetsDefaultRootCAs(t *testing.T) { - expected := errors.New("mocked error") - var gotTLSConfig *tls.Config - handshaker := &TLSHandshakerConfigurable{ - NewConn: func(conn net.Conn, config *tls.Config) TLSConn { - gotTLSConfig = config - return &netxmocks.TLSConn{ - MockHandshake: func() error { - return expected - }, - } - }, - } - ctx := context.Background() - config := &tls.Config{} - conn := &netxmocks.Conn{ - MockSetDeadline: func(t time.Time) error { - return nil - }, - } - tlsConn, connState, err := handshaker.Handshake(ctx, conn, config) - if !errors.Is(err, expected) { - t.Fatal("not the error we expected", err) - } - if !reflect.ValueOf(connState).IsZero() { - t.Fatal("expected zero connState here") - } - if tlsConn != nil { - t.Fatal("expected nil tlsConn here") - } - if config.RootCAs != nil { - t.Fatal("config.RootCAs should still be nil") - } - if gotTLSConfig.RootCAs != defaultCertPool { - t.Fatal("gotTLSConfig.RootCAs has not been correctly set") - } -} - -func TestTLSHandshakerLoggerSuccess(t *testing.T) { - th := &TLSHandshakerLogger{ - TLSHandshaker: &netxmocks.TLSHandshaker{ - MockHandshake: func(ctx context.Context, conn net.Conn, config *tls.Config) (net.Conn, tls.ConnectionState, error) { - return tls.Client(conn, config), tls.ConnectionState{}, nil - }, - }, - Logger: log.Log, - } - conn := &netxmocks.Conn{ - MockClose: func() error { - return nil - }, - } - config := &tls.Config{} - ctx := context.Background() - tlsConn, connState, err := th.Handshake(ctx, conn, config) - if err != nil { - t.Fatal(err) - } - if err := tlsConn.Close(); err != nil { - t.Fatal(err) - } - if !reflect.ValueOf(connState).IsZero() { - t.Fatal("expected zero ConnectionState here") - } -} - -func TestTLSHandshakerLoggerFailure(t *testing.T) { - expected := errors.New("mocked error") - th := &TLSHandshakerLogger{ - TLSHandshaker: &netxmocks.TLSHandshaker{ - MockHandshake: func(ctx context.Context, conn net.Conn, config *tls.Config) (net.Conn, tls.ConnectionState, error) { - return nil, tls.ConnectionState{}, expected - }, - }, - Logger: log.Log, - } - conn := &netxmocks.Conn{ - MockClose: func() error { - return nil - }, - } - config := &tls.Config{} - ctx := context.Background() - tlsConn, connState, err := th.Handshake(ctx, conn, config) - if !errors.Is(err, expected) { - t.Fatal("not the error we expected", err) - } - if tlsConn != nil { - t.Fatal("expected nil conn here") - } - if !reflect.ValueOf(connState).IsZero() { - t.Fatal("expected zero ConnectionState here") - } -} - -func TestUTLSHandshakerChrome(t *testing.T) { - h := &TLSHandshakerConfigurable{ - NewConn: NewConnUTLS(&utls.HelloChrome_Auto), - } - cfg := &tls.Config{ServerName: "google.com"} - conn, err := net.Dial("tcp", "google.com:443") - if err != nil { - t.Fatal("unexpected error", err) - } - conn, _, err = h.Handshake(context.Background(), conn, cfg) - if err != nil { - t.Fatal("unexpected error", err) - } - if conn == nil { - t.Fatal("nil connection") - } -} diff --git a/internal/netxlite/tlsx.go b/internal/netxlite/tlsx.go deleted file mode 100644 index 750c2b4..0000000 --- a/internal/netxlite/tlsx.go +++ /dev/null @@ -1,101 +0,0 @@ -package netxlite - -import ( - "crypto/tls" - "crypto/x509" - "errors" - "fmt" -) - -var ( - tlsVersionString = map[uint16]string{ - tls.VersionTLS10: "TLSv1", - tls.VersionTLS11: "TLSv1.1", - tls.VersionTLS12: "TLSv1.2", - tls.VersionTLS13: "TLSv1.3", - 0: "", // guarantee correct behaviour - } - - tlsCipherSuiteString = map[uint16]string{ - tls.TLS_RSA_WITH_RC4_128_SHA: "TLS_RSA_WITH_RC4_128_SHA", - tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA: "TLS_RSA_WITH_3DES_EDE_CBC_SHA", - tls.TLS_RSA_WITH_AES_128_CBC_SHA: "TLS_RSA_WITH_AES_128_CBC_SHA", - tls.TLS_RSA_WITH_AES_256_CBC_SHA: "TLS_RSA_WITH_AES_256_CBC_SHA", - tls.TLS_RSA_WITH_AES_128_CBC_SHA256: "TLS_RSA_WITH_AES_128_CBC_SHA256", - tls.TLS_RSA_WITH_AES_128_GCM_SHA256: "TLS_RSA_WITH_AES_128_GCM_SHA256", - tls.TLS_RSA_WITH_AES_256_GCM_SHA384: "TLS_RSA_WITH_AES_256_GCM_SHA384", - tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", - tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", - tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", - tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA: "TLS_ECDHE_RSA_WITH_RC4_128_SHA", - tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", - tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", - tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", - tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", - tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", - tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", - tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", - tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", - tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", - tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305: "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305", - tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305: "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305", - tls.TLS_AES_128_GCM_SHA256: "TLS_AES_128_GCM_SHA256", - tls.TLS_AES_256_GCM_SHA384: "TLS_AES_256_GCM_SHA384", - tls.TLS_CHACHA20_POLY1305_SHA256: "TLS_CHACHA20_POLY1305_SHA256", - 0: "", // guarantee correct behaviour - } -) - -// TLSVersionString returns a TLS version string. -func TLSVersionString(value uint16) string { - if str, found := tlsVersionString[value]; found { - return str - } - return fmt.Sprintf("TLS_VERSION_UNKNOWN_%d", value) -} - -// TLSCipherSuiteString returns the TLS cipher suite as a string. -func TLSCipherSuiteString(value uint16) string { - if str, found := tlsCipherSuiteString[value]; found { - return str - } - return fmt.Sprintf("TLS_CIPHER_SUITE_UNKNOWN_%d", value) -} - -// NewDefaultCertPool returns a copy of the default x509 -// certificate pool that we bundle from Mozilla. -func NewDefaultCertPool() *x509.CertPool { - pool := x509.NewCertPool() - // Assumption: AppendCertsFromPEM cannot fail because we - // run this function already in the generate.go file - pool.AppendCertsFromPEM([]byte(pemcerts)) - return pool -} - -// ErrInvalidTLSVersion indicates that you passed us a string -// that does not represent a valid TLS version. -var ErrInvalidTLSVersion = errors.New("invalid TLS version") - -// ConfigureTLSVersion configures the correct TLS version into -// the specified *tls.Config or returns an error. -func ConfigureTLSVersion(config *tls.Config, version string) error { - switch version { - case "TLSv1.3": - config.MinVersion = tls.VersionTLS13 - config.MaxVersion = tls.VersionTLS13 - case "TLSv1.2": - config.MinVersion = tls.VersionTLS12 - config.MaxVersion = tls.VersionTLS12 - case "TLSv1.1": - config.MinVersion = tls.VersionTLS11 - config.MaxVersion = tls.VersionTLS11 - case "TLSv1.0", "TLSv1": - config.MinVersion = tls.VersionTLS10 - config.MaxVersion = tls.VersionTLS10 - case "": - // nothing - default: - return ErrInvalidTLSVersion - } - return nil -} diff --git a/internal/netxlite/tlsx_test.go b/internal/netxlite/tlsx_test.go deleted file mode 100644 index 35b9064..0000000 --- a/internal/netxlite/tlsx_test.go +++ /dev/null @@ -1,105 +0,0 @@ -package netxlite - -import ( - "crypto/tls" - "errors" - "testing" -) - -func TestVersionString(t *testing.T) { - if TLSVersionString(tls.VersionTLS13) != "TLSv1.3" { - t.Fatal("not working for existing version") - } - if TLSVersionString(1) != "TLS_VERSION_UNKNOWN_1" { - t.Fatal("not working for nonexisting version") - } - if TLSVersionString(0) != "" { - t.Fatal("not working for zero version") - } -} - -func TestCipherSuite(t *testing.T) { - if TLSCipherSuiteString(tls.TLS_AES_128_GCM_SHA256) != "TLS_AES_128_GCM_SHA256" { - t.Fatal("not working for existing cipher suite") - } - if TLSCipherSuiteString(1) != "TLS_CIPHER_SUITE_UNKNOWN_1" { - t.Fatal("not working for nonexisting cipher suite") - } - if TLSCipherSuiteString(0) != "" { - t.Fatal("not working for zero cipher suite") - } -} - -func TestNewDefaultCertPoolWorks(t *testing.T) { - pool := NewDefaultCertPool() - if pool == nil { - t.Fatal("expected non-nil value here") - } -} - -func TestConfigureTLSVersion(t *testing.T) { - tests := []struct { - name string - version string - wantErr error - versionMin int - versionMax int - }{{ - name: "with TLSv1.3", - version: "TLSv1.3", - wantErr: nil, - versionMin: tls.VersionTLS13, - versionMax: tls.VersionTLS13, - }, { - name: "with TLSv1.2", - version: "TLSv1.2", - wantErr: nil, - versionMin: tls.VersionTLS12, - versionMax: tls.VersionTLS12, - }, { - name: "with TLSv1.1", - version: "TLSv1.1", - wantErr: nil, - versionMin: tls.VersionTLS11, - versionMax: tls.VersionTLS11, - }, { - name: "with TLSv1.0", - version: "TLSv1.0", - wantErr: nil, - versionMin: tls.VersionTLS10, - versionMax: tls.VersionTLS10, - }, { - name: "with TLSv1", - version: "TLSv1", - wantErr: nil, - versionMin: tls.VersionTLS10, - versionMax: tls.VersionTLS10, - }, { - name: "with default", - version: "", - wantErr: nil, - versionMin: 0, - versionMax: 0, - }, { - name: "with invalid version", - version: "TLSv999", - wantErr: ErrInvalidTLSVersion, - versionMin: 0, - versionMax: 0, - }} - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - conf := new(tls.Config) - err := ConfigureTLSVersion(conf, tt.version) - if !errors.Is(err, tt.wantErr) { - t.Fatalf("not the error we expected: %+v", err) - } - if conf.MinVersion != uint16(tt.versionMin) { - t.Fatalf("not the min version we expected: %+v", conf.MinVersion) - } - if conf.MaxVersion != uint16(tt.versionMax) { - t.Fatalf("not the max version we expected: %+v", conf.MaxVersion) - } - }) - } -} diff --git a/internal/netxlite/utls.go b/internal/netxlite/utls.go new file mode 100644 index 0000000..6666c95 --- /dev/null +++ b/internal/netxlite/utls.go @@ -0,0 +1,46 @@ +package netxlite + +import ( + "crypto/tls" + "net" + + utls "gitlab.com/yawning/utls.git" +) + +// utlsConn implements TLSConn and uses a utls UConn as its underlying connection +type utlsConn struct { + *utls.UConn +} + +// NewConnUTLS creates a NewConn function creating a utls connection with a specified ClientHelloID +func NewConnUTLS(clientHello *utls.ClientHelloID) func(conn net.Conn, config *tls.Config) TLSConn { + return func(conn net.Conn, config *tls.Config) TLSConn { + uConfig := &utls.Config{ + RootCAs: config.RootCAs, + NextProtos: config.NextProtos, + ServerName: config.ServerName, + InsecureSkipVerify: config.InsecureSkipVerify, + DynamicRecordSizingDisabled: config.DynamicRecordSizingDisabled, + } + tlsConn := utls.UClient(conn, uConfig, *clientHello) + return &utlsConn{tlsConn} + } +} + +func (c *utlsConn) ConnectionState() tls.ConnectionState { + uState := c.Conn.ConnectionState() + return tls.ConnectionState{ + Version: uState.Version, + HandshakeComplete: uState.HandshakeComplete, + DidResume: uState.DidResume, + CipherSuite: uState.CipherSuite, + NegotiatedProtocol: uState.NegotiatedProtocol, + NegotiatedProtocolIsMutual: uState.NegotiatedProtocolIsMutual, + ServerName: uState.ServerName, + PeerCertificates: uState.PeerCertificates, + VerifiedChains: uState.VerifiedChains, + SignedCertificateTimestamps: uState.SignedCertificateTimestamps, + OCSPResponse: uState.OCSPResponse, + TLSUnique: uState.TLSUnique, + } +} diff --git a/internal/netxlite/utls_test.go b/internal/netxlite/utls_test.go new file mode 100644 index 0000000..8c8e230 --- /dev/null +++ b/internal/netxlite/utls_test.go @@ -0,0 +1,28 @@ +package netxlite + +import ( + "context" + "crypto/tls" + "net" + "testing" + + utls "gitlab.com/yawning/utls.git" +) + +func TestUTLSHandshakerChrome(t *testing.T) { + h := &tlsHandshakerConfigurable{ + NewConn: NewConnUTLS(&utls.HelloChrome_Auto), + } + cfg := &tls.Config{ServerName: "google.com"} + conn, err := net.Dial("tcp", "google.com:443") + if err != nil { + t.Fatal("unexpected error", err) + } + conn, _, err = h.Handshake(context.Background(), conn, cfg) + if err != nil { + t.Fatal("unexpected error", err) + } + if conn == nil { + t.Fatal("nil connection") + } +} diff --git a/internal/netxmocks/doc.go b/internal/netxmocks/doc.go deleted file mode 100644 index 5db7bff..0000000 --- a/internal/netxmocks/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package netxmocks contains mocks for netx types. -package netxmocks diff --git a/internal/ooapi/apis.go b/internal/ooapi/apis.go index bb76b32..6de5d76 100644 --- a/internal/ooapi/apis.go +++ b/internal/ooapi/apis.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// 2021-06-15 10:55:55.967236 +0200 CEST m=+0.000374501 +// 2021-09-05 13:54:18.962287 +0200 CEST m=+0.000333710 package ooapi diff --git a/internal/ooapi/apis_test.go b/internal/ooapi/apis_test.go index acc52bb..0eb4ba9 100644 --- a/internal/ooapi/apis_test.go +++ b/internal/ooapi/apis_test.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// 2021-06-15 10:55:56.308361 +0200 CEST m=+0.000215751 +// 2021-09-05 13:54:19.316964 +0200 CEST m=+0.000287376 package ooapi @@ -17,7 +17,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" "github.com/ooni/probe-cli/v3/internal/ooapi/apimodel" ) diff --git a/internal/ooapi/caching.go b/internal/ooapi/caching.go index cf05d5c..164bc4a 100644 --- a/internal/ooapi/caching.go +++ b/internal/ooapi/caching.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// 2021-06-15 10:55:56.587245 +0200 CEST m=+0.000218959 +// 2021-09-05 13:54:19.664951 +0200 CEST m=+0.000206417 package ooapi diff --git a/internal/ooapi/caching_test.go b/internal/ooapi/caching_test.go index e5085d6..3954001 100644 --- a/internal/ooapi/caching_test.go +++ b/internal/ooapi/caching_test.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// 2021-06-15 10:55:56.851681 +0200 CEST m=+0.000186126 +// 2021-09-05 13:54:19.945161 +0200 CEST m=+0.000190709 package ooapi diff --git a/internal/ooapi/callers.go b/internal/ooapi/callers.go index 7a4ae4c..c18b747 100644 --- a/internal/ooapi/callers.go +++ b/internal/ooapi/callers.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// 2021-06-15 10:55:57.174427 +0200 CEST m=+0.000217876 +// 2021-09-05 13:54:20.211832 +0200 CEST m=+0.000215876 package ooapi diff --git a/internal/ooapi/clientcall.go b/internal/ooapi/clientcall.go index 60dddd6..0962e8a 100644 --- a/internal/ooapi/clientcall.go +++ b/internal/ooapi/clientcall.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// 2021-06-15 10:55:57.445485 +0200 CEST m=+0.000219751 +// 2021-09-05 13:54:20.571825 +0200 CEST m=+0.000210710 package ooapi diff --git a/internal/ooapi/clientcall_test.go b/internal/ooapi/clientcall_test.go index fa0210f..e30e6d1 100644 --- a/internal/ooapi/clientcall_test.go +++ b/internal/ooapi/clientcall_test.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// 2021-06-15 10:55:57.708833 +0200 CEST m=+0.000193418 +// 2021-09-05 13:54:20.84233 +0200 CEST m=+0.000203459 package ooapi @@ -15,8 +15,8 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/ooni/probe-cli/v3/internal/iox" "github.com/ooni/probe-cli/v3/internal/kvstore" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" "github.com/ooni/probe-cli/v3/internal/ooapi/apimodel" ) diff --git a/internal/ooapi/cloners.go b/internal/ooapi/cloners.go index 2eced32..d13c17e 100644 --- a/internal/ooapi/cloners.go +++ b/internal/ooapi/cloners.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// 2021-06-15 10:55:57.987741 +0200 CEST m=+0.000211126 +// 2021-09-05 13:54:21.153077 +0200 CEST m=+0.000199334 package ooapi diff --git a/internal/ooapi/fake_test.go b/internal/ooapi/fake_test.go index 9738d6c..5e9f225 100644 --- a/internal/ooapi/fake_test.go +++ b/internal/ooapi/fake_test.go @@ -6,7 +6,7 @@ import ( "net/http" "time" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) type FakeCodec struct { diff --git a/internal/ooapi/fakeapi_test.go b/internal/ooapi/fakeapi_test.go index 7b040e6..13b23fd 100644 --- a/internal/ooapi/fakeapi_test.go +++ b/internal/ooapi/fakeapi_test.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// 2021-06-15 10:55:58.234786 +0200 CEST m=+0.000218167 +// 2021-09-05 13:54:21.412036 +0200 CEST m=+0.000169751 package ooapi diff --git a/internal/ooapi/internal/generator/apistest.go b/internal/ooapi/internal/generator/apistest.go index 02dba5b..66b8a9f 100644 --- a/internal/ooapi/internal/generator/apistest.go +++ b/internal/ooapi/internal/generator/apistest.go @@ -451,7 +451,7 @@ func GenAPIsTestGo(file string) { fmt.Fprint(&sb, "\t\"sync\"\n") fmt.Fprint(&sb, "\n") fmt.Fprint(&sb, "\t\"github.com/google/go-cmp/cmp\"\n") - fmt.Fprint(&sb, "\t\"github.com/ooni/probe-cli/v3/internal/iox\"\n") + fmt.Fprint(&sb, "\t\"github.com/ooni/probe-cli/v3/internal/netxlite/iox\"\n") fmt.Fprint(&sb, "\t\"github.com/ooni/probe-cli/v3/internal/ooapi/apimodel\"\n") fmt.Fprint(&sb, ")\n") for _, desc := range Descriptors { diff --git a/internal/ooapi/internal/generator/clientcalltest.go b/internal/ooapi/internal/generator/clientcalltest.go index 01fa47c..9e4f0a7 100644 --- a/internal/ooapi/internal/generator/clientcalltest.go +++ b/internal/ooapi/internal/generator/clientcalltest.go @@ -168,7 +168,7 @@ func GenClientCallTestGo(file string) { fmt.Fprint(&sb, "\t\"sync\"\n") fmt.Fprint(&sb, "\n") fmt.Fprint(&sb, "\t\"github.com/google/go-cmp/cmp\"\n") - fmt.Fprint(&sb, "\t\"github.com/ooni/probe-cli/v3/internal/iox\"\n") + fmt.Fprint(&sb, "\t\"github.com/ooni/probe-cli/v3/internal/netxlite/iox\"\n") fmt.Fprint(&sb, "\t\"github.com/ooni/probe-cli/v3/internal/kvstore\"\n") fmt.Fprint(&sb, "\t\"github.com/ooni/probe-cli/v3/internal/ooapi/apimodel\"\n") fmt.Fprint(&sb, ")\n") diff --git a/internal/ooapi/internal/generator/responses.go b/internal/ooapi/internal/generator/responses.go index 3a7ad30..3b0da9a 100644 --- a/internal/ooapi/internal/generator/responses.go +++ b/internal/ooapi/internal/generator/responses.go @@ -71,7 +71,7 @@ func GenResponsesGo(file string) { fmt.Fprint(&sb, "\t\"io\"\n") fmt.Fprint(&sb, "\t\"net/http\"\n") fmt.Fprint(&sb, "\n") - fmt.Fprint(&sb, "\t\"github.com/ooni/probe-cli/v3/internal/iox\"\n") + fmt.Fprint(&sb, "\t\"github.com/ooni/probe-cli/v3/internal/netxlite/iox\"\n") fmt.Fprint(&sb, "\t\"github.com/ooni/probe-cli/v3/internal/ooapi/apimodel\"\n") fmt.Fprint(&sb, ")\n\n") for _, desc := range Descriptors { diff --git a/internal/ooapi/login.go b/internal/ooapi/login.go index f629eec..5a9adfb 100644 --- a/internal/ooapi/login.go +++ b/internal/ooapi/login.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// 2021-06-15 10:55:58.487888 +0200 CEST m=+0.000221710 +// 2021-09-05 13:54:21.648163 +0200 CEST m=+0.000177959 package ooapi diff --git a/internal/ooapi/login_test.go b/internal/ooapi/login_test.go index 037a4e7..55dd369 100644 --- a/internal/ooapi/login_test.go +++ b/internal/ooapi/login_test.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// 2021-06-15 10:55:58.755431 +0200 CEST m=+0.000217917 +// 2021-09-05 13:54:21.967872 +0200 CEST m=+0.000174460 package ooapi diff --git a/internal/ooapi/loginhandler_test.go b/internal/ooapi/loginhandler_test.go index 51242a9..5d75968 100644 --- a/internal/ooapi/loginhandler_test.go +++ b/internal/ooapi/loginhandler_test.go @@ -9,7 +9,7 @@ import ( "time" "github.com/ooni/probe-cli/v3/internal/atomicx" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" "github.com/ooni/probe-cli/v3/internal/ooapi/apimodel" ) diff --git a/internal/ooapi/requests.go b/internal/ooapi/requests.go index 4e2ff33..400cea7 100644 --- a/internal/ooapi/requests.go +++ b/internal/ooapi/requests.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// 2021-06-15 10:55:59.020364 +0200 CEST m=+0.000217085 +// 2021-09-05 13:54:22.226116 +0200 CEST m=+0.000176793 package ooapi diff --git a/internal/ooapi/responses.go b/internal/ooapi/responses.go index 4401eb9..5bdd963 100644 --- a/internal/ooapi/responses.go +++ b/internal/ooapi/responses.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// 2021-06-15 10:55:59.329509 +0200 CEST m=+0.000220043 +// 2021-09-05 13:54:22.556115 +0200 CEST m=+0.000158543 package ooapi @@ -10,7 +10,7 @@ import ( "io" "net/http" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" "github.com/ooni/probe-cli/v3/internal/ooapi/apimodel" ) diff --git a/internal/ooapi/swagger_test.go b/internal/ooapi/swagger_test.go index 5539e5e..0d7980d 100644 --- a/internal/ooapi/swagger_test.go +++ b/internal/ooapi/swagger_test.go @@ -1,5 +1,5 @@ // Code generated by go generate; DO NOT EDIT. -// 2021-06-15 10:55:59.636856 +0200 CEST m=+0.000624459 +// 2021-09-05 13:54:22.884854 +0200 CEST m=+0.000556501 package ooapi @@ -9,7 +9,7 @@ const swagger = `{ "swagger": "2.0", "info": { "title": "OONI API specification", - "version": "0.20210615.6085559" + "version": "0.20210905.9115422" }, "host": "api.ooni.io", "basePath": "/", diff --git a/internal/ooapi/swaggerdiff_test.go b/internal/ooapi/swaggerdiff_test.go index 31ea27c..faaf6be 100644 --- a/internal/ooapi/swaggerdiff_test.go +++ b/internal/ooapi/swaggerdiff_test.go @@ -13,7 +13,7 @@ import ( "github.com/hexops/gotextdiff" "github.com/hexops/gotextdiff/myers" "github.com/hexops/gotextdiff/span" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" "github.com/ooni/probe-cli/v3/internal/ooapi/internal/openapi" ) diff --git a/internal/ptx/obfs4_test.go b/internal/ptx/obfs4_test.go index d0924c1..e00d3c0 100644 --- a/internal/ptx/obfs4_test.go +++ b/internal/ptx/obfs4_test.go @@ -9,7 +9,7 @@ import ( "testing" "github.com/ooni/probe-cli/v3/internal/atomicx" - "github.com/ooni/probe-cli/v3/internal/netxmocks" + "github.com/ooni/probe-cli/v3/internal/netxlite/mocks" ) func TestOBFS4DialerWorks(t *testing.T) { @@ -49,7 +49,7 @@ func TestOBFS4DialerFailsWithInvalidCert(t *testing.T) { func TestOBFS4DialerFailsWithConnectionErrorAndNoContextExpiration(t *testing.T) { expected := errors.New("mocked error") o4d := DefaultTestingOBFS4Bridge() - o4d.UnderlyingDialer = &netxmocks.Dialer{ + o4d.UnderlyingDialer = &mocks.Dialer{ MockDialContext: func(ctx context.Context, network string, address string) (net.Conn, error) { return nil, expected }, @@ -71,7 +71,7 @@ func TestOBFS4DialerFailsWithConnectionErrorAndContextExpiration(t *testing.T) { sigch := make(chan interface{}) wg := &sync.WaitGroup{} wg.Add(1) - o4d.UnderlyingDialer = &netxmocks.Dialer{ + o4d.UnderlyingDialer = &mocks.Dialer{ MockDialContext: func(ctx context.Context, network string, address string) (net.Conn, error) { cancel() <-sigch @@ -107,7 +107,7 @@ func TestOBFS4DialerWorksWithContextExpiration(t *testing.T) { defer cancel() called := &atomicx.Int64{} o4d := DefaultTestingOBFS4Bridge() - o4d.UnderlyingDialer = &netxmocks.Dialer{ + o4d.UnderlyingDialer = &mocks.Dialer{ MockDialContext: func(ctx context.Context, network string, address string) (net.Conn, error) { // We cancel the context before returning the error, which makes // the context cancellation happen before us returning. diff --git a/internal/ptx/ptx.go b/internal/ptx/ptx.go index 0094141..d39ae6a 100644 --- a/internal/ptx/ptx.go +++ b/internal/ptx/ptx.go @@ -45,7 +45,7 @@ import ( "sync" pt "git.torproject.org/pluggable-transports/goptlib.git" - "github.com/ooni/probe-cli/v3/internal/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" ) // PTDialer is a generic pluggable transports dialer. diff --git a/internal/ptx/ptx_test.go b/internal/ptx/ptx_test.go index 39fe6b9..32f90c5 100644 --- a/internal/ptx/ptx_test.go +++ b/internal/ptx/ptx_test.go @@ -13,8 +13,8 @@ import ( "github.com/apex/log" "github.com/ooni/probe-cli/v3/internal/atomicx" - "github.com/ooni/probe-cli/v3/internal/iox" - "github.com/ooni/probe-cli/v3/internal/netxmocks" + "github.com/ooni/probe-cli/v3/internal/netxlite/iox" + "github.com/ooni/probe-cli/v3/internal/netxlite/mocks" ) func TestListenerLoggerWorks(t *testing.T) { @@ -96,8 +96,8 @@ func TestListenerCastListenerWorksFineOnError(t *testing.T) { // mockableSocksConn is a mockable ptxSocksConn. type mockableSocksConn struct { - // netxmocks.Conn allows to mock all net.Conn functionality. - *netxmocks.Conn + // mocks.Conn allows to mock all net.Conn functionality. + *mocks.Conn // MockGrant allows to mock the Grant function. MockGrant func(addr *net.TCPAddr) error @@ -160,7 +160,7 @@ func TestListenerHandleSocksConnWithDialContextFailure(t *testing.T) { } lst := &Listener{PTDialer: d} c := &mockableSocksConn{ - Conn: &netxmocks.Conn{ + Conn: &mocks.Conn{ MockClose: func() error { return nil }, diff --git a/internal/ptx/snowflake_test.go b/internal/ptx/snowflake_test.go index 1b33005..8e73215 100644 --- a/internal/ptx/snowflake_test.go +++ b/internal/ptx/snowflake_test.go @@ -7,7 +7,7 @@ import ( "testing" "github.com/ooni/probe-cli/v3/internal/atomicx" - "github.com/ooni/probe-cli/v3/internal/netxmocks" + "github.com/ooni/probe-cli/v3/internal/netxlite/mocks" ) func TestSnowflakeDialerWorks(t *testing.T) { @@ -50,7 +50,7 @@ func TestSnowflakeDialerWorksWithMocks(t *testing.T) { newClientTransport: func(brokerURL, frontDomain string, iceAddresses []string, keepLocalAddresses bool, maxSnowflakes int) (snowflakeTransport, error) { return &mockableSnowflakeTransport{ MockDial: func() (net.Conn, error) { - return &netxmocks.Conn{ + return &mocks.Conn{ MockClose: func() error { return nil }, @@ -144,7 +144,7 @@ func TestSnowflakeDialerWorksWithWithCancelledContext(t *testing.T) { return &mockableSnowflakeTransport{ MockDial: func() (net.Conn, error) { cancel() // cause a cancel before we can really have a conn - return &netxmocks.Conn{ + return &mocks.Conn{ MockClose: func() error { called.Add(1) return nil