2022-07-01 12:22:22 +02:00
|
|
|
package measurexlite
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"context"
|
|
|
|
"crypto/tls"
|
|
|
|
"crypto/x509"
|
|
|
|
"errors"
|
|
|
|
"net"
|
|
|
|
"reflect"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
|
|
"github.com/ooni/probe-cli/v3/internal/model"
|
|
|
|
"github.com/ooni/probe-cli/v3/internal/model/mocks"
|
|
|
|
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
|
|
|
"github.com/ooni/probe-cli/v3/internal/netxlite/filtering"
|
|
|
|
"github.com/ooni/probe-cli/v3/internal/testingx"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestNewTLSHandshakerStdlib(t *testing.T) {
|
|
|
|
t.Run("NewTLSHandshakerStdlib creates a wrapped TLSHandshaker", func(t *testing.T) {
|
|
|
|
underlying := &mocks.TLSHandshaker{}
|
|
|
|
zeroTime := time.Now()
|
|
|
|
trace := NewTrace(0, zeroTime)
|
|
|
|
trace.NewTLSHandshakerStdlibFn = func(dl model.DebugLogger) model.TLSHandshaker {
|
|
|
|
return underlying
|
|
|
|
}
|
|
|
|
thx := trace.NewTLSHandshakerStdlib(model.DiscardLogger)
|
|
|
|
thxt := thx.(*tlsHandshakerTrace)
|
|
|
|
if thxt.thx != underlying {
|
|
|
|
t.Fatal("invalid TLS handshaker")
|
|
|
|
}
|
|
|
|
if thxt.tx != trace {
|
|
|
|
t.Fatal("invalid trace")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Handshake calls the underlying dialer with context-based tracing", func(t *testing.T) {
|
|
|
|
expectedErr := errors.New("mocked err")
|
|
|
|
zeroTime := time.Now()
|
|
|
|
trace := NewTrace(0, zeroTime)
|
|
|
|
var hasCorrectTrace bool
|
|
|
|
underlying := &mocks.TLSHandshaker{
|
|
|
|
MockHandshake: func(ctx context.Context, conn net.Conn, config *tls.Config) (net.Conn, tls.ConnectionState, error) {
|
|
|
|
gotTrace := netxlite.ContextTraceOrDefault(ctx)
|
|
|
|
hasCorrectTrace = (gotTrace == trace)
|
|
|
|
return nil, tls.ConnectionState{}, expectedErr
|
|
|
|
},
|
|
|
|
}
|
|
|
|
trace.NewTLSHandshakerStdlibFn = func(dl model.DebugLogger) model.TLSHandshaker {
|
|
|
|
return underlying
|
|
|
|
}
|
|
|
|
thx := trace.NewTLSHandshakerStdlib(model.DiscardLogger)
|
|
|
|
ctx := context.Background()
|
|
|
|
conn, state, err := thx.Handshake(ctx, &mocks.Conn{}, &tls.Config{})
|
|
|
|
if !errors.Is(err, expectedErr) {
|
|
|
|
t.Fatal("unexpected err", err)
|
|
|
|
}
|
|
|
|
if !reflect.ValueOf(state).IsZero() {
|
|
|
|
t.Fatal("expected zero-value state")
|
|
|
|
}
|
|
|
|
if conn != nil {
|
|
|
|
t.Fatal("expected nil conn")
|
|
|
|
}
|
|
|
|
if !hasCorrectTrace {
|
|
|
|
t.Fatal("does not have the correct trace")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Handshake saves into the trace", func(t *testing.T) {
|
|
|
|
mockedErr := errors.New("mocked")
|
|
|
|
zeroTime := time.Now()
|
|
|
|
td := testingx.NewTimeDeterministic(zeroTime)
|
|
|
|
trace := NewTrace(0, zeroTime)
|
|
|
|
trace.TimeNowFn = td.Now // deterministic timing
|
|
|
|
thx := trace.NewTLSHandshakerStdlib(model.DiscardLogger)
|
2022-07-08 12:29:08 +02:00
|
|
|
ctx := context.Background()
|
2022-07-01 12:22:22 +02:00
|
|
|
tcpConn := &mocks.Conn{
|
|
|
|
MockSetDeadline: func(t time.Time) error {
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
MockRemoteAddr: func() net.Addr {
|
|
|
|
return &mocks.Addr{
|
|
|
|
MockNetwork: func() string {
|
|
|
|
return "tcp"
|
|
|
|
},
|
|
|
|
MockString: func() string {
|
|
|
|
return "1.1.1.1:443"
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
|
|
|
MockWrite: func(b []byte) (int, error) {
|
|
|
|
return 0, mockedErr
|
|
|
|
},
|
|
|
|
MockClose: func() error {
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
tlsConfig := &tls.Config{
|
|
|
|
InsecureSkipVerify: true,
|
|
|
|
ServerName: "dns.cloudflare.com",
|
|
|
|
}
|
|
|
|
conn, state, err := thx.Handshake(ctx, tcpConn, tlsConfig)
|
2022-07-08 12:29:08 +02:00
|
|
|
if !errors.Is(err, mockedErr) {
|
2022-07-01 12:22:22 +02:00
|
|
|
t.Fatal("unexpected err", err)
|
|
|
|
}
|
|
|
|
if !reflect.ValueOf(state).IsZero() {
|
|
|
|
t.Fatal("expected zero-value state")
|
|
|
|
}
|
|
|
|
if conn != nil {
|
|
|
|
t.Fatal("expected nil conn")
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("TLSHandshake events", func(t *testing.T) {
|
|
|
|
events := trace.TLSHandshakes()
|
|
|
|
if len(events) != 1 {
|
|
|
|
t.Fatal("expected to see single TLSHandshake event")
|
|
|
|
}
|
2022-07-08 12:29:08 +02:00
|
|
|
expectedFailure := "unknown_failure: mocked"
|
2022-07-01 12:22:22 +02:00
|
|
|
expect := &model.ArchivalTLSOrQUICHandshakeResult{
|
fix(datafmt): sync measurexlite and v0.5 with previous code (#942)
* fix(model/archival.go): more optional keys
Basically, `t0` and `transaction_id` should be optional. Version 0.4.x
of web_connectivity should not include them, version 0.5.x should.
There is a technical reason why v0.4.x should not include them. The code
it is based on, tracex, does not record these two fields.
Whereas, v0.5.x, uses measurexlite, which records these two fields.
Part of https://github.com/ooni/probe/issues/2238
* fix(webconnectivity@v0.5): add more fields
This diff adds the following fields to webconnectivity@v0.5:
1. agent, always set to "redirect" (legacy field);
2. client_resolver, properly initialized w/ the resolver's IPv4 address;
3. retries, legacy field always set to null;
4. socksproxy, legacy field always set to null.
Part of https://github.com/ooni/probe/issues/2238
* fix(webconnectivity@v0.5): register extensions
The general idea behind this field is that we would be able
in the future to tweak the data model for some fields, by declaring
we're using a later version, so it seems useful to add it.
See https://github.com/ooni/probe/issues/2238
* fix(measurexlite): use tcp or quic for tls handshake network
This diff fixes a bug where measurexlite was using "tls" as the
protocol for the TLS handshake when using TCP.
While this choice _could_ make sense, the rest of the code we have
written so far uses "tcp" instead.
Using "tcp" makes more sense because it allows you to search for
the same endpoint across different events by checking for the same
network and for the same endpoint rather than special casing TLS
handshakes for using "tls" when the endpoint is "tcp".
See https://github.com/ooni/probe/issues/2238
* chore: run alltests.yml for "alltestsbuild" branches
Part of https://github.com/ooni/probe/issues/2238
2022-09-08 10:02:47 +02:00
|
|
|
Network: "tcp",
|
2022-07-01 12:22:22 +02:00
|
|
|
Address: "1.1.1.1:443",
|
|
|
|
CipherSuite: "",
|
|
|
|
Failure: &expectedFailure,
|
|
|
|
NegotiatedProtocol: "",
|
|
|
|
NoTLSVerify: true,
|
|
|
|
PeerCertificates: []model.ArchivalMaybeBinaryData{},
|
|
|
|
ServerName: "dns.cloudflare.com",
|
|
|
|
T: time.Second.Seconds(),
|
|
|
|
Tags: []string{},
|
|
|
|
TLSVersion: "",
|
|
|
|
}
|
|
|
|
got := events[0]
|
|
|
|
if diff := cmp.Diff(expect, got); diff != "" {
|
|
|
|
t.Fatal(diff)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Network events", func(t *testing.T) {
|
|
|
|
events := trace.NetworkEvents()
|
|
|
|
if len(events) != 2 {
|
|
|
|
t.Fatal("expected to see two Network events")
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("tls_handshake_start", func(t *testing.T) {
|
|
|
|
expect := &model.ArchivalNetworkEvent{
|
|
|
|
Address: "",
|
|
|
|
Failure: nil,
|
|
|
|
NumBytes: 0,
|
|
|
|
Operation: "tls_handshake_start",
|
|
|
|
Proto: "",
|
|
|
|
T: 0,
|
|
|
|
Tags: []string{},
|
|
|
|
}
|
|
|
|
got := events[0]
|
|
|
|
if diff := cmp.Diff(expect, got); diff != "" {
|
|
|
|
t.Fatal(diff)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("tls_handshake_done", func(t *testing.T) {
|
|
|
|
expect := &model.ArchivalNetworkEvent{
|
|
|
|
Address: "",
|
|
|
|
Failure: nil,
|
|
|
|
NumBytes: 0,
|
|
|
|
Operation: "tls_handshake_done",
|
|
|
|
Proto: "",
|
2022-08-25 13:41:26 +02:00
|
|
|
T0: time.Second.Seconds(),
|
2022-07-01 12:22:22 +02:00
|
|
|
T: time.Second.Seconds(),
|
|
|
|
Tags: []string{},
|
|
|
|
}
|
|
|
|
got := events[1]
|
|
|
|
if diff := cmp.Diff(expect, got); diff != "" {
|
|
|
|
t.Fatal(diff)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Handshake discards events when buffers are full", func(t *testing.T) {
|
|
|
|
mockedErr := errors.New("mocked")
|
|
|
|
zeroTime := time.Now()
|
|
|
|
trace := NewTrace(0, zeroTime)
|
2022-08-17 20:10:48 +02:00
|
|
|
trace.networkEvent = make(chan *model.ArchivalNetworkEvent) // no buffer
|
|
|
|
trace.tlsHandshake = make(chan *model.ArchivalTLSOrQUICHandshakeResult) // no buffer
|
2022-07-01 12:22:22 +02:00
|
|
|
thx := trace.NewTLSHandshakerStdlib(model.DiscardLogger)
|
2022-07-08 12:29:08 +02:00
|
|
|
ctx := context.Background()
|
2022-07-01 12:22:22 +02:00
|
|
|
tcpConn := &mocks.Conn{
|
|
|
|
MockSetDeadline: func(t time.Time) error {
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
MockRemoteAddr: func() net.Addr {
|
|
|
|
return &mocks.Addr{
|
|
|
|
MockNetwork: func() string {
|
|
|
|
return "tcp"
|
|
|
|
},
|
|
|
|
MockString: func() string {
|
|
|
|
return "1.1.1.1:443"
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
|
|
|
MockWrite: func(b []byte) (int, error) {
|
|
|
|
return 0, mockedErr
|
|
|
|
},
|
|
|
|
MockClose: func() error {
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
tlsConfig := &tls.Config{
|
|
|
|
InsecureSkipVerify: true,
|
|
|
|
ServerName: "dns.cloudflare.com",
|
|
|
|
}
|
|
|
|
conn, state, err := thx.Handshake(ctx, tcpConn, tlsConfig)
|
2022-07-08 12:29:08 +02:00
|
|
|
if !errors.Is(err, mockedErr) {
|
2022-07-01 12:22:22 +02:00
|
|
|
t.Fatal("unexpected err", err)
|
|
|
|
}
|
|
|
|
if !reflect.ValueOf(state).IsZero() {
|
|
|
|
t.Fatal("expected zero-value state")
|
|
|
|
}
|
|
|
|
if conn != nil {
|
|
|
|
t.Fatal("expected nil conn")
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("TLSHandshake events", func(t *testing.T) {
|
|
|
|
events := trace.TLSHandshakes()
|
|
|
|
if len(events) != 0 {
|
|
|
|
t.Fatal("expected to see no TLSHandshake events")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Network events", func(t *testing.T) {
|
|
|
|
events := trace.NetworkEvents()
|
|
|
|
if len(events) != 0 {
|
|
|
|
t.Fatal("expected to see no Network events")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("we collect the desired data with a local TLS server", func(t *testing.T) {
|
|
|
|
server := filtering.NewTLSServer(filtering.TLSActionBlockText)
|
|
|
|
dialer := netxlite.NewDialerWithoutResolver(model.DiscardLogger)
|
|
|
|
ctx := context.Background()
|
|
|
|
conn, err := dialer.DialContext(ctx, "tcp", server.Endpoint())
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer conn.Close()
|
|
|
|
zeroTime := time.Now()
|
|
|
|
dt := testingx.NewTimeDeterministic(zeroTime)
|
|
|
|
trace := NewTrace(0, zeroTime)
|
|
|
|
trace.TimeNowFn = dt.Now // deterministic timing
|
|
|
|
thx := trace.NewTLSHandshakerStdlib(model.DiscardLogger)
|
|
|
|
tlsConfig := &tls.Config{
|
|
|
|
RootCAs: server.CertPool(),
|
|
|
|
ServerName: "dns.google",
|
|
|
|
}
|
|
|
|
tlsConn, connState, err := thx.Handshake(ctx, conn, tlsConfig)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer tlsConn.Close()
|
|
|
|
data, err := netxlite.ReadAllContext(ctx, tlsConn)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if !bytes.Equal(data, filtering.HTTPBlockpage451) {
|
|
|
|
t.Fatal("bytes should match")
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("TLSHandshake events", func(t *testing.T) {
|
|
|
|
events := trace.TLSHandshakes()
|
|
|
|
if len(events) != 1 {
|
|
|
|
t.Fatal("expected to see a single TLSHandshake event")
|
|
|
|
}
|
|
|
|
expected := &model.ArchivalTLSOrQUICHandshakeResult{
|
fix(datafmt): sync measurexlite and v0.5 with previous code (#942)
* fix(model/archival.go): more optional keys
Basically, `t0` and `transaction_id` should be optional. Version 0.4.x
of web_connectivity should not include them, version 0.5.x should.
There is a technical reason why v0.4.x should not include them. The code
it is based on, tracex, does not record these two fields.
Whereas, v0.5.x, uses measurexlite, which records these two fields.
Part of https://github.com/ooni/probe/issues/2238
* fix(webconnectivity@v0.5): add more fields
This diff adds the following fields to webconnectivity@v0.5:
1. agent, always set to "redirect" (legacy field);
2. client_resolver, properly initialized w/ the resolver's IPv4 address;
3. retries, legacy field always set to null;
4. socksproxy, legacy field always set to null.
Part of https://github.com/ooni/probe/issues/2238
* fix(webconnectivity@v0.5): register extensions
The general idea behind this field is that we would be able
in the future to tweak the data model for some fields, by declaring
we're using a later version, so it seems useful to add it.
See https://github.com/ooni/probe/issues/2238
* fix(measurexlite): use tcp or quic for tls handshake network
This diff fixes a bug where measurexlite was using "tls" as the
protocol for the TLS handshake when using TCP.
While this choice _could_ make sense, the rest of the code we have
written so far uses "tcp" instead.
Using "tcp" makes more sense because it allows you to search for
the same endpoint across different events by checking for the same
network and for the same endpoint rather than special casing TLS
handshakes for using "tls" when the endpoint is "tcp".
See https://github.com/ooni/probe/issues/2238
* chore: run alltests.yml for "alltestsbuild" branches
Part of https://github.com/ooni/probe/issues/2238
2022-09-08 10:02:47 +02:00
|
|
|
Network: "tcp",
|
2022-07-01 12:22:22 +02:00
|
|
|
Address: conn.RemoteAddr().String(),
|
|
|
|
CipherSuite: netxlite.TLSCipherSuiteString(connState.CipherSuite),
|
|
|
|
Failure: nil,
|
|
|
|
NegotiatedProtocol: "",
|
|
|
|
NoTLSVerify: false,
|
|
|
|
PeerCertificates: []model.ArchivalMaybeBinaryData{},
|
|
|
|
ServerName: "dns.google",
|
|
|
|
T: time.Second.Seconds(),
|
|
|
|
Tags: []string{},
|
|
|
|
TLSVersion: netxlite.TLSVersionString(connState.Version),
|
|
|
|
}
|
|
|
|
got := events[0]
|
|
|
|
// TODO(bassosimone): it's still unclear to me how to test that
|
|
|
|
// I am getting exactly the expected certificate here. I think the
|
|
|
|
// certificate is generated on the fly by google/martian. So, I'm
|
|
|
|
// just going to reduce the precision of this check.
|
|
|
|
if len(got.PeerCertificates) != 2 {
|
|
|
|
t.Fatal("expected to see two certificates")
|
|
|
|
}
|
|
|
|
got.PeerCertificates = []model.ArchivalMaybeBinaryData{} // see above
|
|
|
|
if diff := cmp.Diff(expected, got); diff != "" {
|
|
|
|
t.Fatal(diff)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("Network events", func(t *testing.T) {
|
|
|
|
events := trace.NetworkEvents()
|
|
|
|
if len(events) != 2 {
|
|
|
|
t.Fatal("expected to see two Network events")
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("tls_handshake_start", func(t *testing.T) {
|
|
|
|
expect := &model.ArchivalNetworkEvent{
|
|
|
|
Address: "",
|
|
|
|
Failure: nil,
|
|
|
|
NumBytes: 0,
|
|
|
|
Operation: "tls_handshake_start",
|
|
|
|
Proto: "",
|
|
|
|
T: 0,
|
|
|
|
Tags: []string{},
|
|
|
|
}
|
|
|
|
got := events[0]
|
|
|
|
if diff := cmp.Diff(expect, got); diff != "" {
|
|
|
|
t.Fatal(diff)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("tls_handshake_done", func(t *testing.T) {
|
|
|
|
expect := &model.ArchivalNetworkEvent{
|
|
|
|
Address: "",
|
|
|
|
Failure: nil,
|
|
|
|
NumBytes: 0,
|
|
|
|
Operation: "tls_handshake_done",
|
|
|
|
Proto: "",
|
2022-08-25 13:41:26 +02:00
|
|
|
T0: time.Second.Seconds(),
|
2022-07-01 12:22:22 +02:00
|
|
|
T: time.Second.Seconds(),
|
|
|
|
Tags: []string{},
|
|
|
|
}
|
|
|
|
got := events[1]
|
|
|
|
if diff := cmp.Diff(expect, got); diff != "" {
|
|
|
|
t.Fatal(diff)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-08-17 20:10:48 +02:00
|
|
|
func TestFirstTLSHandshake(t *testing.T) {
|
|
|
|
t.Run("returns nil when buffer is empty", func(t *testing.T) {
|
|
|
|
zeroTime := time.Now()
|
|
|
|
trace := NewTrace(0, zeroTime)
|
|
|
|
got := trace.FirstTLSHandshakeOrNil()
|
|
|
|
if got != nil {
|
|
|
|
t.Fatal("expected nil event")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("return first non-nil TLSHandshake", func(t *testing.T) {
|
|
|
|
filler := func(tx *Trace, events []*model.ArchivalTLSOrQUICHandshakeResult) {
|
|
|
|
for _, ev := range events {
|
|
|
|
tx.tlsHandshake <- ev
|
|
|
|
}
|
|
|
|
}
|
|
|
|
zeroTime := time.Now()
|
|
|
|
trace := NewTrace(0, zeroTime)
|
|
|
|
expect := []*model.ArchivalTLSOrQUICHandshakeResult{{
|
fix(datafmt): sync measurexlite and v0.5 with previous code (#942)
* fix(model/archival.go): more optional keys
Basically, `t0` and `transaction_id` should be optional. Version 0.4.x
of web_connectivity should not include them, version 0.5.x should.
There is a technical reason why v0.4.x should not include them. The code
it is based on, tracex, does not record these two fields.
Whereas, v0.5.x, uses measurexlite, which records these two fields.
Part of https://github.com/ooni/probe/issues/2238
* fix(webconnectivity@v0.5): add more fields
This diff adds the following fields to webconnectivity@v0.5:
1. agent, always set to "redirect" (legacy field);
2. client_resolver, properly initialized w/ the resolver's IPv4 address;
3. retries, legacy field always set to null;
4. socksproxy, legacy field always set to null.
Part of https://github.com/ooni/probe/issues/2238
* fix(webconnectivity@v0.5): register extensions
The general idea behind this field is that we would be able
in the future to tweak the data model for some fields, by declaring
we're using a later version, so it seems useful to add it.
See https://github.com/ooni/probe/issues/2238
* fix(measurexlite): use tcp or quic for tls handshake network
This diff fixes a bug where measurexlite was using "tls" as the
protocol for the TLS handshake when using TCP.
While this choice _could_ make sense, the rest of the code we have
written so far uses "tcp" instead.
Using "tcp" makes more sense because it allows you to search for
the same endpoint across different events by checking for the same
network and for the same endpoint rather than special casing TLS
handshakes for using "tls" when the endpoint is "tcp".
See https://github.com/ooni/probe/issues/2238
* chore: run alltests.yml for "alltestsbuild" branches
Part of https://github.com/ooni/probe/issues/2238
2022-09-08 10:02:47 +02:00
|
|
|
Network: "tcp",
|
2022-08-17 20:10:48 +02:00
|
|
|
Address: "1.1.1.1:443",
|
|
|
|
CipherSuite: "",
|
|
|
|
Failure: nil,
|
|
|
|
NegotiatedProtocol: "",
|
|
|
|
NoTLSVerify: true,
|
|
|
|
PeerCertificates: []model.ArchivalMaybeBinaryData{},
|
|
|
|
ServerName: "dns.cloudflare.com",
|
|
|
|
T: time.Second.Seconds(),
|
|
|
|
Tags: []string{},
|
|
|
|
TLSVersion: "",
|
|
|
|
}, {
|
fix(datafmt): sync measurexlite and v0.5 with previous code (#942)
* fix(model/archival.go): more optional keys
Basically, `t0` and `transaction_id` should be optional. Version 0.4.x
of web_connectivity should not include them, version 0.5.x should.
There is a technical reason why v0.4.x should not include them. The code
it is based on, tracex, does not record these two fields.
Whereas, v0.5.x, uses measurexlite, which records these two fields.
Part of https://github.com/ooni/probe/issues/2238
* fix(webconnectivity@v0.5): add more fields
This diff adds the following fields to webconnectivity@v0.5:
1. agent, always set to "redirect" (legacy field);
2. client_resolver, properly initialized w/ the resolver's IPv4 address;
3. retries, legacy field always set to null;
4. socksproxy, legacy field always set to null.
Part of https://github.com/ooni/probe/issues/2238
* fix(webconnectivity@v0.5): register extensions
The general idea behind this field is that we would be able
in the future to tweak the data model for some fields, by declaring
we're using a later version, so it seems useful to add it.
See https://github.com/ooni/probe/issues/2238
* fix(measurexlite): use tcp or quic for tls handshake network
This diff fixes a bug where measurexlite was using "tls" as the
protocol for the TLS handshake when using TCP.
While this choice _could_ make sense, the rest of the code we have
written so far uses "tcp" instead.
Using "tcp" makes more sense because it allows you to search for
the same endpoint across different events by checking for the same
network and for the same endpoint rather than special casing TLS
handshakes for using "tls" when the endpoint is "tcp".
See https://github.com/ooni/probe/issues/2238
* chore: run alltests.yml for "alltestsbuild" branches
Part of https://github.com/ooni/probe/issues/2238
2022-09-08 10:02:47 +02:00
|
|
|
Network: "tcp",
|
2022-08-17 20:10:48 +02:00
|
|
|
Address: "8.8.8.8:443",
|
|
|
|
CipherSuite: "",
|
|
|
|
Failure: nil,
|
|
|
|
NegotiatedProtocol: "",
|
|
|
|
NoTLSVerify: true,
|
|
|
|
PeerCertificates: []model.ArchivalMaybeBinaryData{},
|
|
|
|
ServerName: "dns.google.com",
|
|
|
|
T: time.Second.Seconds(),
|
|
|
|
Tags: []string{},
|
|
|
|
TLSVersion: "",
|
|
|
|
}}
|
|
|
|
filler(trace, expect)
|
|
|
|
got := trace.FirstTLSHandshakeOrNil()
|
|
|
|
if diff := cmp.Diff(got, expect[0]); diff != "" {
|
|
|
|
t.Fatal(diff)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-07-01 12:22:22 +02:00
|
|
|
func TestTLSPeerCerts(t *testing.T) {
|
|
|
|
type args struct {
|
|
|
|
state tls.ConnectionState
|
|
|
|
err error
|
|
|
|
}
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
args args
|
|
|
|
wantOut []model.ArchivalMaybeBinaryData
|
|
|
|
}{{
|
|
|
|
name: "x509.HostnameError",
|
|
|
|
args: args{
|
|
|
|
state: tls.ConnectionState{},
|
|
|
|
err: x509.HostnameError{
|
|
|
|
Certificate: &x509.Certificate{
|
|
|
|
Raw: []byte("deadbeef"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
wantOut: []model.ArchivalMaybeBinaryData{{
|
|
|
|
Value: "deadbeef",
|
|
|
|
}},
|
|
|
|
}, {
|
|
|
|
name: "x509.UnknownAuthorityError",
|
|
|
|
args: args{
|
|
|
|
state: tls.ConnectionState{},
|
|
|
|
err: x509.UnknownAuthorityError{
|
|
|
|
Cert: &x509.Certificate{
|
|
|
|
Raw: []byte("deadbeef"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
wantOut: []model.ArchivalMaybeBinaryData{{
|
|
|
|
Value: "deadbeef",
|
|
|
|
}},
|
|
|
|
}, {
|
|
|
|
name: "x509.CertificateInvalidError",
|
|
|
|
args: args{
|
|
|
|
state: tls.ConnectionState{},
|
|
|
|
err: x509.CertificateInvalidError{
|
|
|
|
Cert: &x509.Certificate{
|
|
|
|
Raw: []byte("deadbeef"),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
wantOut: []model.ArchivalMaybeBinaryData{{
|
|
|
|
Value: "deadbeef",
|
|
|
|
}},
|
|
|
|
}, {
|
|
|
|
name: "successful case",
|
|
|
|
args: args{
|
|
|
|
state: tls.ConnectionState{
|
|
|
|
PeerCertificates: []*x509.Certificate{{
|
|
|
|
Raw: []byte("deadbeef"),
|
|
|
|
}, {
|
|
|
|
Raw: []byte("abad1dea"),
|
|
|
|
}},
|
|
|
|
},
|
|
|
|
err: nil,
|
|
|
|
},
|
|
|
|
wantOut: []model.ArchivalMaybeBinaryData{{
|
|
|
|
Value: "deadbeef",
|
|
|
|
}, {
|
|
|
|
Value: "abad1dea",
|
|
|
|
}},
|
|
|
|
}}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
gotOut := TLSPeerCerts(tt.args.state, tt.args.err)
|
|
|
|
if diff := cmp.Diff(tt.wantOut, gotOut); diff != "" {
|
|
|
|
t.Fatal(diff)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|