refactor(netx): merge archival, trace, and the savers (#772)

This diff creates a new package under netx called tracex that
contains everything we need to perform measurements using events
tracing and postprocessing (which is the technique with which
we implement most network experiments).

The general idea here is to (1) create a unique package out of
all of these packages; (2) clean up the code a bit (improve tests,
docs, apply more recent code patterns); (3) move the resulting
code as a toplevel package inside of internal.

Once this is done, netx can be further refactored to avoid
subpackages and we can search for more code to salvage/refactor.

See https://github.com/ooni/probe/issues/2121
This commit is contained in:
Simone Basso
2022-05-31 21:53:01 +02:00
committed by GitHub
parent dd5655eaee
commit bbcd2e2280
53 changed files with 869 additions and 865 deletions
@@ -1,41 +0,0 @@
package archival
import "testing"
func TestDNSQueryIPOfType(t *testing.T) {
type expectation struct {
qtype dnsQueryType
ip string
output bool
}
var expectations = []expectation{{
qtype: "A",
ip: "8.8.8.8",
output: true,
}, {
qtype: "A",
ip: "2a00:1450:4002:801::2004",
output: false,
}, {
qtype: "AAAA",
ip: "8.8.8.8",
output: false,
}, {
qtype: "AAAA",
ip: "2a00:1450:4002:801::2004",
output: true,
}, {
qtype: "ANTANI",
ip: "2a00:1450:4002:801::2004",
output: false,
}, {
qtype: "ANTANI",
ip: "8.8.8.8",
output: false,
}}
for _, exp := range expectations {
if exp.qtype.ipoftype(exp.ip) != exp.output {
t.Fatalf("failure for %+v", exp)
}
}
}
+5 -5
View File
@@ -7,7 +7,7 @@ import (
"net/url"
"github.com/ooni/probe-cli/v3/internal/bytecounter"
"github.com/ooni/probe-cli/v3/internal/engine/netx/trace"
"github.com/ooni/probe-cli/v3/internal/engine/netx/tracex"
"github.com/ooni/probe-cli/v3/internal/model"
"github.com/ooni/probe-cli/v3/internal/netxlite"
)
@@ -35,7 +35,7 @@ type Config struct {
// DialSaver is the optional saver for dialing events. If not
// set, we will not save any dialing event.
DialSaver *trace.Saver
DialSaver *tracex.Saver
// Logger is the optional logger. If not set, there
// will be no logging from the new dialer.
@@ -45,7 +45,7 @@ type Config struct {
ProxyURL *url.URL
// ReadWriteSaver is like DialSaver but for I/O events.
ReadWriteSaver *trace.Saver
ReadWriteSaver *tracex.Saver
}
// New creates a new Dialer from the specified config and resolver.
@@ -57,13 +57,13 @@ func New(config *Config, resolver model.Resolver) model.Dialer {
modifiers := []netxlite.DialerWrapper{
func(dialer model.Dialer) model.Dialer {
if config.DialSaver != nil {
dialer = &saverDialer{Dialer: dialer, Saver: config.DialSaver}
dialer = &tracex.SaverDialer{Dialer: dialer, Saver: config.DialSaver}
}
return dialer
},
func(dialer model.Dialer) model.Dialer {
if config.ReadWriteSaver != nil {
dialer = &saverConnDialer{Dialer: dialer, Saver: config.ReadWriteSaver}
dialer = &tracex.SaverConnDialer{Dialer: dialer, Saver: config.ReadWriteSaver}
}
return dialer
},
+2 -2
View File
@@ -7,12 +7,12 @@ import (
"github.com/apex/log"
"github.com/ooni/probe-cli/v3/internal/bytecounter"
"github.com/ooni/probe-cli/v3/internal/engine/netx/trace"
"github.com/ooni/probe-cli/v3/internal/engine/netx/tracex"
"github.com/ooni/probe-cli/v3/internal/netxlite"
)
func TestNewCreatesTheExpectedChain(t *testing.T) {
saver := &trace.Saver{}
saver := &tracex.Saver{}
dlr := New(&Config{
ContextByteCounting: true,
DialSaver: saver,
+7 -7
View File
@@ -9,7 +9,7 @@ import (
"github.com/apex/log"
"github.com/ooni/probe-cli/v3/internal/bytecounter"
"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/engine/netx/tracex"
"github.com/ooni/probe-cli/v3/internal/netxlite"
)
@@ -24,12 +24,12 @@ func TestSuccess(t *testing.T) {
ByteCounter: counter,
CacheResolutions: true,
ContextByteCounting: true,
DialSaver: &trace.Saver{},
HTTPSaver: &trace.Saver{},
DialSaver: &tracex.Saver{},
HTTPSaver: &tracex.Saver{},
Logger: log.Log,
ReadWriteSaver: &trace.Saver{},
ResolveSaver: &trace.Saver{},
TLSSaver: &trace.Saver{},
ReadWriteSaver: &tracex.Saver{},
ResolveSaver: &tracex.Saver{},
TLSSaver: &tracex.Saver{},
}
txp := netx.NewHTTPTransport(config)
client := &http.Client{Transport: txp}
@@ -67,7 +67,7 @@ func TestSuccess(t *testing.T) {
}
func TestBogonResolutionNotBroken(t *testing.T) {
saver := new(trace.Saver)
saver := new(tracex.Saver)
r := netx.NewResolver(netx.Config{
BogonIsError: true,
DNSCache: map[string][]string{
+17 -19
View File
@@ -33,10 +33,8 @@ import (
"github.com/ooni/probe-cli/v3/internal/bytecounter"
"github.com/ooni/probe-cli/v3/internal/engine/netx/dialer"
"github.com/ooni/probe-cli/v3/internal/engine/netx/httptransport"
"github.com/ooni/probe-cli/v3/internal/engine/netx/quicdialer"
"github.com/ooni/probe-cli/v3/internal/engine/netx/resolver"
"github.com/ooni/probe-cli/v3/internal/engine/netx/tlsdialer"
"github.com/ooni/probe-cli/v3/internal/engine/netx/trace"
"github.com/ooni/probe-cli/v3/internal/engine/netx/tracex"
"github.com/ooni/probe-cli/v3/internal/model"
"github.com/ooni/probe-cli/v3/internal/netxlite"
)
@@ -54,20 +52,20 @@ type Config struct {
CertPool *x509.CertPool // default: use vendored gocertifi
ContextByteCounting bool // default: no implicit byte counting
DNSCache map[string][]string // default: cache is empty
DialSaver *trace.Saver // default: not saving dials
DialSaver *tracex.Saver // default: not saving dials
Dialer model.Dialer // default: dialer.DNSDialer
FullResolver model.Resolver // default: base resolver + goodies
QUICDialer model.QUICDialer // default: quicdialer.DNSDialer
HTTP3Enabled bool // default: disabled
HTTPSaver *trace.Saver // default: not saving HTTP
HTTPSaver *tracex.Saver // default: not saving HTTP
Logger model.DebugLogger // default: no logging
NoTLSVerify bool // default: perform TLS verify
ProxyURL *url.URL // default: no proxy
ReadWriteSaver *trace.Saver // default: not saving read/write
ResolveSaver *trace.Saver // default: not saving resolves
ReadWriteSaver *tracex.Saver // default: not saving read/write
ResolveSaver *tracex.Saver // default: not saving resolves
TLSConfig *tls.Config // default: attempt using h2
TLSDialer model.TLSDialer // default: dialer.TLSDialer
TLSSaver *trace.Saver // default: not saving TLS
TLSSaver *tracex.Saver // default: not saving TLS
}
type tlsHandshaker interface {
@@ -107,7 +105,7 @@ func NewResolver(config Config) model.Resolver {
}
}
if config.ResolveSaver != nil {
r = resolver.SaverResolver{Resolver: r, Saver: config.ResolveSaver}
r = tracex.SaverResolver{Resolver: r, Saver: config.ResolveSaver}
}
return &netxlite.ResolverIDNA{Resolver: r}
}
@@ -133,7 +131,7 @@ func NewQUICDialer(config Config) model.QUICDialer {
}
ql := netxlite.NewQUICListener()
if config.ReadWriteSaver != nil {
ql = &quicdialer.QUICListenerSaver{
ql = &tracex.QUICListenerSaver{
QUICListener: ql,
Saver: config.ReadWriteSaver,
}
@@ -145,7 +143,7 @@ func NewQUICDialer(config Config) model.QUICDialer {
extensions := []netxlite.QUICDialerWrapper{
func(dialer model.QUICDialer) model.QUICDialer {
if config.TLSSaver != nil {
dialer = quicdialer.HandshakeSaver{Saver: config.TLSSaver, QUICDialer: dialer}
dialer = tracex.QUICHandshakeSaver{Saver: config.TLSSaver, QUICDialer: dialer}
}
return dialer
},
@@ -164,7 +162,7 @@ func NewTLSDialer(config Config) model.TLSDialer {
h = &netxlite.TLSHandshakerLogger{DebugLogger: config.Logger, TLSHandshaker: h}
}
if config.TLSSaver != nil {
h = tlsdialer.SaverTLSHandshaker{TLSHandshaker: h, Saver: config.TLSSaver}
h = tracex.SaverTLSHandshaker{TLSHandshaker: h, Saver: config.TLSSaver}
}
if config.TLSConfig == nil {
config.TLSConfig = &tls.Config{NextProtos: []string{"h2", "http/1.1"}}
@@ -207,11 +205,11 @@ func NewHTTPTransport(config Config) model.HTTPTransport {
txp = &netxlite.HTTPTransportLogger{Logger: config.Logger, HTTPTransport: txp}
}
if config.HTTPSaver != nil {
txp = httptransport.SaverMetadataHTTPTransport{
txp = tracex.SaverMetadataHTTPTransport{
HTTPTransport: txp, Saver: config.HTTPSaver}
txp = httptransport.SaverBodyHTTPTransport{
txp = tracex.SaverBodyHTTPTransport{
HTTPTransport: txp, Saver: config.HTTPSaver}
txp = httptransport.SaverTransactionHTTPTransport{
txp = tracex.SaverTransactionHTTPTransport{
HTTPTransport: txp, Saver: config.HTTPSaver}
}
return txp
@@ -287,7 +285,7 @@ func NewDNSClientWithOverrides(config Config, URL, hostOverride, SNIOverride,
var txp model.DNSTransport = netxlite.NewDNSOverHTTPSTransportWithHostOverride(
httpClient, URL, hostOverride)
if config.ResolveSaver != nil {
txp = resolver.SaverDNSTransport{
txp = tracex.SaverDNSTransport{
DNSTransport: txp,
Saver: config.ResolveSaver,
}
@@ -302,7 +300,7 @@ func NewDNSClientWithOverrides(config Config, URL, hostOverride, SNIOverride,
var txp model.DNSTransport = netxlite.NewDNSOverUDPTransport(
dialer, endpoint)
if config.ResolveSaver != nil {
txp = resolver.SaverDNSTransport{
txp = tracex.SaverDNSTransport{
DNSTransport: txp,
Saver: config.ResolveSaver,
}
@@ -318,7 +316,7 @@ func NewDNSClientWithOverrides(config Config, URL, hostOverride, SNIOverride,
var txp model.DNSTransport = netxlite.NewDNSOverTLSTransport(
tlsDialer.DialTLSContext, endpoint)
if config.ResolveSaver != nil {
txp = resolver.SaverDNSTransport{
txp = tracex.SaverDNSTransport{
DNSTransport: txp,
Saver: config.ResolveSaver,
}
@@ -333,7 +331,7 @@ func NewDNSClientWithOverrides(config Config, URL, hostOverride, SNIOverride,
var txp model.DNSTransport = netxlite.NewDNSOverTCPTransport(
dialer.DialContext, endpoint)
if config.ResolveSaver != nil {
txp = resolver.SaverDNSTransport{
txp = tracex.SaverDNSTransport{
DNSTransport: txp,
Saver: config.ResolveSaver,
}
+17 -19
View File
@@ -12,10 +12,8 @@ import (
"github.com/apex/log"
"github.com/ooni/probe-cli/v3/internal/bytecounter"
"github.com/ooni/probe-cli/v3/internal/engine/netx"
"github.com/ooni/probe-cli/v3/internal/engine/netx/httptransport"
"github.com/ooni/probe-cli/v3/internal/engine/netx/resolver"
"github.com/ooni/probe-cli/v3/internal/engine/netx/tlsdialer"
"github.com/ooni/probe-cli/v3/internal/engine/netx/trace"
"github.com/ooni/probe-cli/v3/internal/engine/netx/tracex"
"github.com/ooni/probe-cli/v3/internal/model/mocks"
"github.com/ooni/probe-cli/v3/internal/netxlite"
)
@@ -120,7 +118,7 @@ func TestNewResolverWithLogging(t *testing.T) {
}
func TestNewResolverWithSaver(t *testing.T) {
saver := new(trace.Saver)
saver := new(tracex.Saver)
r := netx.NewResolver(netx.Config{
ResolveSaver: saver,
})
@@ -128,7 +126,7 @@ func TestNewResolverWithSaver(t *testing.T) {
if !ok {
t.Fatal("not the resolver we expected")
}
sr, ok := ir.Resolver.(resolver.SaverResolver)
sr, ok := ir.Resolver.(tracex.SaverResolver)
if !ok {
t.Fatal("not the resolver we expected")
}
@@ -311,7 +309,7 @@ func TestNewTLSDialerWithLogging(t *testing.T) {
}
func TestNewTLSDialerWithSaver(t *testing.T) {
saver := new(trace.Saver)
saver := new(tracex.Saver)
td := netx.NewTLSDialer(netx.Config{
TLSSaver: saver,
})
@@ -334,7 +332,7 @@ func TestNewTLSDialerWithSaver(t *testing.T) {
if rtd.TLSHandshaker == nil {
t.Fatal("invalid TLSHandshaker")
}
sth, ok := rtd.TLSHandshaker.(tlsdialer.SaverTLSHandshaker)
sth, ok := rtd.TLSHandshaker.(tracex.SaverTLSHandshaker)
if !ok {
t.Fatal("not the TLSHandshaker we expected")
}
@@ -502,25 +500,25 @@ func TestNewWithLogger(t *testing.T) {
}
func TestNewWithSaver(t *testing.T) {
saver := new(trace.Saver)
saver := new(tracex.Saver)
txp := netx.NewHTTPTransport(netx.Config{
HTTPSaver: saver,
})
stxptxp, ok := txp.(httptransport.SaverTransactionHTTPTransport)
stxptxp, ok := txp.(tracex.SaverTransactionHTTPTransport)
if !ok {
t.Fatal("not the transport we expected")
}
if stxptxp.Saver != saver {
t.Fatal("not the logger we expected")
}
sbtxp, ok := stxptxp.HTTPTransport.(httptransport.SaverBodyHTTPTransport)
sbtxp, ok := stxptxp.HTTPTransport.(tracex.SaverBodyHTTPTransport)
if !ok {
t.Fatal("not the transport we expected")
}
if sbtxp.Saver != saver {
t.Fatal("not the logger we expected")
}
smtxp, ok := sbtxp.HTTPTransport.(httptransport.SaverMetadataHTTPTransport)
smtxp, ok := sbtxp.HTTPTransport.(tracex.SaverMetadataHTTPTransport)
if !ok {
t.Fatal("not the transport we expected")
}
@@ -625,7 +623,7 @@ func TestNewDNSClientCloudflareDoH(t *testing.T) {
}
func TestNewDNSClientCloudflareDoHSaver(t *testing.T) {
saver := new(trace.Saver)
saver := new(tracex.Saver)
dnsclient, err := netx.NewDNSClient(
netx.Config{ResolveSaver: saver}, "doh://cloudflare")
if err != nil {
@@ -635,7 +633,7 @@ func TestNewDNSClientCloudflareDoHSaver(t *testing.T) {
if !ok {
t.Fatal("not the resolver we expected")
}
txp, ok := r.Transport().(resolver.SaverDNSTransport)
txp, ok := r.Transport().(tracex.SaverDNSTransport)
if !ok {
t.Fatal("not the transport we expected")
}
@@ -662,7 +660,7 @@ func TestNewDNSClientUDP(t *testing.T) {
}
func TestNewDNSClientUDPDNSSaver(t *testing.T) {
saver := new(trace.Saver)
saver := new(tracex.Saver)
dnsclient, err := netx.NewDNSClient(
netx.Config{ResolveSaver: saver}, "udp://8.8.8.8:53")
if err != nil {
@@ -672,7 +670,7 @@ func TestNewDNSClientUDPDNSSaver(t *testing.T) {
if !ok {
t.Fatal("not the resolver we expected")
}
txp, ok := r.Transport().(resolver.SaverDNSTransport)
txp, ok := r.Transport().(tracex.SaverDNSTransport)
if !ok {
t.Fatal("not the transport we expected")
}
@@ -703,7 +701,7 @@ func TestNewDNSClientTCP(t *testing.T) {
}
func TestNewDNSClientTCPDNSSaver(t *testing.T) {
saver := new(trace.Saver)
saver := new(tracex.Saver)
dnsclient, err := netx.NewDNSClient(
netx.Config{ResolveSaver: saver}, "tcp://8.8.8.8:53")
if err != nil {
@@ -713,7 +711,7 @@ func TestNewDNSClientTCPDNSSaver(t *testing.T) {
if !ok {
t.Fatal("not the resolver we expected")
}
txp, ok := r.Transport().(resolver.SaverDNSTransport)
txp, ok := r.Transport().(tracex.SaverDNSTransport)
if !ok {
t.Fatal("not the transport we expected")
}
@@ -748,7 +746,7 @@ func TestNewDNSClientDoT(t *testing.T) {
}
func TestNewDNSClientDoTDNSSaver(t *testing.T) {
saver := new(trace.Saver)
saver := new(tracex.Saver)
dnsclient, err := netx.NewDNSClient(
netx.Config{ResolveSaver: saver}, "dot://8.8.8.8:53")
if err != nil {
@@ -758,7 +756,7 @@ func TestNewDNSClientDoTDNSSaver(t *testing.T) {
if !ok {
t.Fatal("not the resolver we expected")
}
txp, ok := r.Transport().(resolver.SaverDNSTransport)
txp, ok := r.Transport().(tracex.SaverDNSTransport)
if !ok {
t.Fatal("not the transport we expected")
}
-68
View File
@@ -1,68 +0,0 @@
package quicdialer
import (
"context"
"crypto/tls"
"time"
"github.com/lucas-clemente/quic-go"
"github.com/ooni/probe-cli/v3/internal/engine/netx/trace"
"github.com/ooni/probe-cli/v3/internal/model"
"github.com/ooni/probe-cli/v3/internal/netxlite"
)
// HandshakeSaver saves events occurring during the handshake
type HandshakeSaver struct {
Saver *trace.Saver
model.QUICDialer
}
// DialContext implements ContextDialer.DialContext
func (h HandshakeSaver) DialContext(ctx context.Context, network string,
host string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) {
start := time.Now()
// TODO(bassosimone): in the future we probably want to also save
// information about what versions we're willing to accept.
h.Saver.Write(trace.Event{
Address: host,
Name: "quic_handshake_start",
NoTLSVerify: tlsCfg.InsecureSkipVerify,
Proto: network,
TLSNextProtos: tlsCfg.NextProtos,
TLSServerName: tlsCfg.ServerName,
Time: start,
})
sess, err := h.QUICDialer.DialContext(ctx, network, host, tlsCfg, cfg)
stop := time.Now()
if err != nil {
h.Saver.Write(trace.Event{
Duration: stop.Sub(start),
Err: err,
Name: "quic_handshake_done",
NoTLSVerify: tlsCfg.InsecureSkipVerify,
TLSNextProtos: tlsCfg.NextProtos,
TLSServerName: tlsCfg.ServerName,
Time: stop,
})
return nil, err
}
state := connectionState(sess)
h.Saver.Write(trace.Event{
Duration: stop.Sub(start),
Name: "quic_handshake_done",
NoTLSVerify: tlsCfg.InsecureSkipVerify,
TLSCipherSuite: netxlite.TLSCipherSuiteString(state.CipherSuite),
TLSNegotiatedProto: state.NegotiatedProtocol,
TLSNextProtos: tlsCfg.NextProtos,
TLSPeerCerts: trace.PeerCerts(state, err),
TLSServerName: tlsCfg.ServerName,
TLSVersion: netxlite.TLSVersionString(state.Version),
Time: stop,
})
return sess, nil
}
// connectionState returns the ConnectionState of a QUIC Session.
func connectionState(sess quic.EarlyConnection) tls.ConnectionState {
return sess.ConnectionState().TLS.ConnectionState
}
-81
View File
@@ -1,81 +0,0 @@
package quicdialer
import (
"net"
"time"
"github.com/ooni/probe-cli/v3/internal/engine/netx/trace"
"github.com/ooni/probe-cli/v3/internal/model"
"github.com/ooni/probe-cli/v3/internal/netxlite"
)
// QUICListenerSaver is a QUICListener that also implements saving events.
type QUICListenerSaver struct {
// QUICListener is the underlying QUICListener.
model.QUICListener
// Saver is the underlying Saver.
Saver *trace.Saver
}
// Listen implements QUICListener.Listen.
func (qls *QUICListenerSaver) Listen(addr *net.UDPAddr) (model.UDPLikeConn, error) {
pconn, err := qls.QUICListener.Listen(addr)
if err != nil {
return nil, err
}
return &saverUDPConn{
UDPLikeConn: pconn,
saver: qls.Saver,
}, nil
}
type saverUDPConn struct {
model.UDPLikeConn
saver *trace.Saver
}
var _ model.UDPLikeConn = &saverUDPConn{}
func (c *saverUDPConn) WriteTo(p []byte, addr net.Addr) (int, error) {
start := time.Now()
count, err := c.UDPLikeConn.WriteTo(p, addr)
stop := time.Now()
c.saver.Write(trace.Event{
Address: addr.String(),
Data: p[:count],
Duration: stop.Sub(start),
Err: err,
NumBytes: count,
Name: netxlite.WriteToOperation,
Time: stop,
})
return count, err
}
func (c *saverUDPConn) ReadFrom(b []byte) (int, net.Addr, error) {
start := time.Now()
n, addr, err := c.UDPLikeConn.ReadFrom(b)
stop := time.Now()
var data []byte
if n > 0 {
data = b[:n]
}
c.saver.Write(trace.Event{
Address: c.safeAddrString(addr),
Data: data,
Duration: stop.Sub(start),
Err: err,
NumBytes: n,
Name: netxlite.ReadFromOperation,
Time: stop,
})
return n, addr, err
}
func (c *saverUDPConn) safeAddrString(addr net.Addr) (out string) {
if addr != nil {
out = addr.String()
}
return
}
@@ -1,87 +0,0 @@
package quicdialer_test
import (
"context"
"crypto/tls"
"errors"
"net"
"testing"
"github.com/lucas-clemente/quic-go"
"github.com/ooni/probe-cli/v3/internal/engine/netx/quicdialer"
"github.com/ooni/probe-cli/v3/internal/engine/netx/trace"
"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/quictesting"
)
func TestQUICListenerSaverCannotListen(t *testing.T) {
expected := errors.New("mocked error")
qls := &quicdialer.QUICListenerSaver{
QUICListener: &mocks.QUICListener{
MockListen: func(addr *net.UDPAddr) (model.UDPLikeConn, error) {
return nil, expected
},
},
Saver: &trace.Saver{},
}
pconn, err := qls.Listen(&net.UDPAddr{
IP: []byte{},
Port: 8080,
Zone: "",
})
if !errors.Is(err, expected) {
t.Fatal("unexpected error", err)
}
if pconn != nil {
t.Fatal("expected nil pconn here")
}
}
func TestSystemDialerSuccessWithReadWrite(t *testing.T) {
// This is the most common use case for collecting reads, writes
tlsConf := &tls.Config{
NextProtos: []string{"h3"},
ServerName: quictesting.Domain,
}
saver := &trace.Saver{}
systemdialer := &netxlite.QUICDialerQUICGo{
QUICListener: &quicdialer.QUICListenerSaver{
QUICListener: &netxlite.QUICListenerStdlib{},
Saver: saver,
},
}
_, err := systemdialer.DialContext(context.Background(), "udp",
quictesting.Endpoint("443"), tlsConf, &quic.Config{})
if err != nil {
t.Fatal(err)
}
ev := saver.Read()
if len(ev) < 2 {
t.Fatal("unexpected number of events")
}
last := len(ev) - 1
for idx := 1; idx < last; idx++ {
if ev[idx].Data == nil {
t.Fatal("unexpected Data")
}
if ev[idx].Duration <= 0 {
t.Fatal("unexpected Duration")
}
if ev[idx].Err != nil {
t.Fatal("unexpected Err")
}
if ev[idx].NumBytes <= 0 {
t.Fatal("unexpected NumBytes")
}
switch ev[idx].Name {
case netxlite.ReadFromOperation, netxlite.WriteToOperation:
default:
t.Fatal("unexpected Name")
}
if ev[idx].Time.Before(ev[idx-1].Time) {
t.Fatal("unexpected Time", ev[idx].Time, ev[idx-1].Time)
}
}
}
@@ -1,7 +1,4 @@
// Package archival contains data formats used for archival.
//
// See https://github.com/ooni/spec.
package archival
package tracex
import (
"crypto/x509"
@@ -14,7 +11,6 @@ import (
"time"
"github.com/ooni/probe-cli/v3/internal/engine/geolocate"
"github.com/ooni/probe-cli/v3/internal/engine/netx/trace"
"github.com/ooni/probe-cli/v3/internal/model"
"github.com/ooni/probe-cli/v3/internal/netxlite"
)
@@ -47,7 +43,7 @@ var (
)
// NewTCPConnectList creates a new TCPConnectList
func NewTCPConnectList(begin time.Time, events []trace.Event) []TCPConnectEntry {
func NewTCPConnectList(begin time.Time, events []Event) []TCPConnectEntry {
var out []TCPConnectEntry
for _, event := range events {
if event.Name != netxlite.ConnectOperation {
@@ -129,7 +125,7 @@ func addheaders(
}
// NewRequestList returns the list for "requests"
func NewRequestList(begin time.Time, events []trace.Event) []RequestEntry {
func NewRequestList(begin time.Time, events []Event) []RequestEntry {
// OONI wants the last request to appear first
var out []RequestEntry
tmp := newRequestList(begin, events)
@@ -139,7 +135,7 @@ func NewRequestList(begin time.Time, events []trace.Event) []RequestEntry {
return out
}
func newRequestList(begin time.Time, events []trace.Event) []RequestEntry {
func newRequestList(begin time.Time, events []Event) []RequestEntry {
var (
out []RequestEntry
entry RequestEntry
@@ -179,7 +175,7 @@ func newRequestList(begin time.Time, events []trace.Event) []RequestEntry {
type dnsQueryType string
// NewDNSQueriesList returns a list of DNS queries.
func NewDNSQueriesList(begin time.Time, events []trace.Event) []DNSQueryEntry {
func NewDNSQueriesList(begin time.Time, events []Event) []DNSQueryEntry {
// TODO(bassosimone): add support for CNAME lookups.
var out []DNSQueryEntry
for _, ev := range events {
@@ -234,7 +230,7 @@ func (qtype dnsQueryType) makeanswerentry(addr string) DNSAnswerEntry {
return answer
}
func (qtype dnsQueryType) makequeryentry(begin time.Time, ev trace.Event) DNSQueryEntry {
func (qtype dnsQueryType) makequeryentry(begin time.Time, ev Event) DNSQueryEntry {
return DNSQueryEntry{
Engine: ev.Proto,
Failure: NewFailure(ev.Err),
@@ -246,7 +242,7 @@ func (qtype dnsQueryType) makequeryentry(begin time.Time, ev trace.Event) DNSQue
}
// NewNetworkEventsList returns a list of DNS queries.
func NewNetworkEventsList(begin time.Time, events []trace.Event) []NetworkEvent {
func NewNetworkEventsList(begin time.Time, events []Event) []NetworkEvent {
var out []NetworkEvent
for _, ev := range events {
if ev.Name == netxlite.ConnectOperation {
@@ -307,7 +303,7 @@ func NewNetworkEventsList(begin time.Time, events []trace.Event) []NetworkEvent
}
// NewTLSHandshakesList creates a new TLSHandshakesList
func NewTLSHandshakesList(begin time.Time, events []trace.Event) []TLSHandshake {
func NewTLSHandshakesList(begin time.Time, events []Event) []TLSHandshake {
var out []TLSHandshake
for _, ev := range events {
if !strings.Contains(ev.Name, "_handshake_done") {
@@ -1,4 +1,4 @@
package archival_test
package tracex
import (
"context"
@@ -12,21 +12,57 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/gorilla/websocket"
"github.com/ooni/probe-cli/v3/internal/engine/netx/archival"
"github.com/ooni/probe-cli/v3/internal/engine/netx/trace"
"github.com/ooni/probe-cli/v3/internal/netxlite"
)
func TestDNSQueryIPOfType(t *testing.T) {
type expectation struct {
qtype dnsQueryType
ip string
output bool
}
var expectations = []expectation{{
qtype: "A",
ip: "8.8.8.8",
output: true,
}, {
qtype: "A",
ip: "2a00:1450:4002:801::2004",
output: false,
}, {
qtype: "AAAA",
ip: "8.8.8.8",
output: false,
}, {
qtype: "AAAA",
ip: "2a00:1450:4002:801::2004",
output: true,
}, {
qtype: "ANTANI",
ip: "2a00:1450:4002:801::2004",
output: false,
}, {
qtype: "ANTANI",
ip: "8.8.8.8",
output: false,
}}
for _, exp := range expectations {
if exp.qtype.ipoftype(exp.ip) != exp.output {
t.Fatalf("failure for %+v", exp)
}
}
}
func TestNewTCPConnectList(t *testing.T) {
begin := time.Now()
type args struct {
begin time.Time
events []trace.Event
events []Event
}
tests := []struct {
name string
args args
want []archival.TCPConnectEntry
want []TCPConnectEntry
}{{
name: "empty run",
args: args{
@@ -38,7 +74,7 @@ func TestNewTCPConnectList(t *testing.T) {
name: "realistic run",
args: args{
begin: begin,
events: []trace.Event{{
events: []Event{{
Addresses: []string{"8.8.8.8", "8.8.4.4"},
Hostname: "dns.google.com",
Name: "resolve_done",
@@ -64,18 +100,18 @@ func TestNewTCPConnectList(t *testing.T) {
Time: begin.Add(180 * time.Millisecond),
}},
},
want: []archival.TCPConnectEntry{{
want: []TCPConnectEntry{{
IP: "8.8.8.8",
Port: 853,
Status: archival.TCPConnectStatus{
Status: TCPConnectStatus{
Success: true,
},
T: 0.13,
}, {
IP: "8.8.4.4",
Port: 53,
Status: archival.TCPConnectStatus{
Failure: archival.NewFailure(io.EOF),
Status: TCPConnectStatus{
Failure: NewFailure(io.EOF),
Success: false,
},
T: 0.18,
@@ -83,7 +119,7 @@ func TestNewTCPConnectList(t *testing.T) {
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := archival.NewTCPConnectList(tt.args.begin, tt.args.events); !reflect.DeepEqual(got, tt.want) {
if got := NewTCPConnectList(tt.args.begin, tt.args.events); !reflect.DeepEqual(got, tt.want) {
t.Error(cmp.Diff(got, tt.want))
}
})
@@ -94,12 +130,12 @@ func TestNewRequestList(t *testing.T) {
begin := time.Now()
type args struct {
begin time.Time
events []trace.Event
events []Event
}
tests := []struct {
name string
args args
want []archival.RequestEntry
want []RequestEntry
}{{
name: "empty run",
args: args{
@@ -111,7 +147,7 @@ func TestNewRequestList(t *testing.T) {
name: "realistic run",
args: args{
begin: begin,
events: []trace.Event{{
events: []Event{{
Name: "http_transaction_start",
Time: begin.Add(10 * time.Millisecond),
}, {
@@ -152,16 +188,16 @@ func TestNewRequestList(t *testing.T) {
Err: io.EOF,
}},
},
want: []archival.RequestEntry{{
Failure: archival.NewFailure(io.EOF),
Request: archival.HTTPRequest{
HeadersList: []archival.HTTPHeader{{
want: []RequestEntry{{
Failure: NewFailure(io.EOF),
Request: HTTPRequest{
HeadersList: []HTTPHeader{{
Key: "User-Agent",
Value: archival.MaybeBinaryValue{
Value: MaybeBinaryValue{
Value: "miniooni/0.1.0-dev",
},
}},
Headers: map[string]archival.MaybeBinaryValue{
Headers: map[string]MaybeBinaryValue{
"User-Agent": {Value: "miniooni/0.1.0-dev"},
},
Method: "GET",
@@ -169,34 +205,34 @@ func TestNewRequestList(t *testing.T) {
},
T: 0.02,
}, {
Request: archival.HTTPRequest{
Body: archival.MaybeBinaryValue{
Request: HTTPRequest{
Body: MaybeBinaryValue{
Value: "deadbeef",
},
HeadersList: []archival.HTTPHeader{{
HeadersList: []HTTPHeader{{
Key: "User-Agent",
Value: archival.MaybeBinaryValue{
Value: MaybeBinaryValue{
Value: "miniooni/0.1.0-dev",
},
}},
Headers: map[string]archival.MaybeBinaryValue{
Headers: map[string]MaybeBinaryValue{
"User-Agent": {Value: "miniooni/0.1.0-dev"},
},
Method: "POST",
URL: "https://www.example.com/submit",
},
Response: archival.HTTPResponse{
Body: archival.MaybeBinaryValue{
Response: HTTPResponse{
Body: MaybeBinaryValue{
Value: "{}",
},
Code: 200,
HeadersList: []archival.HTTPHeader{{
HeadersList: []HTTPHeader{{
Key: "Server",
Value: archival.MaybeBinaryValue{
Value: MaybeBinaryValue{
Value: "miniooni/0.1.0-dev",
},
}},
Headers: map[string]archival.MaybeBinaryValue{
Headers: map[string]MaybeBinaryValue{
"Server": {Value: "miniooni/0.1.0-dev"},
},
Locations: nil,
@@ -209,7 +245,7 @@ func TestNewRequestList(t *testing.T) {
name: "run with redirect and headers to sort",
args: args{
begin: begin,
events: []trace.Event{{
events: []Event{{
Name: "http_transaction_start",
Time: begin.Add(10 * time.Millisecond),
}, {
@@ -230,39 +266,39 @@ func TestNewRequestList(t *testing.T) {
Name: "http_transaction_done",
}},
},
want: []archival.RequestEntry{{
Request: archival.HTTPRequest{
HeadersList: []archival.HTTPHeader{{
want: []RequestEntry{{
Request: HTTPRequest{
HeadersList: []HTTPHeader{{
Key: "User-Agent",
Value: archival.MaybeBinaryValue{
Value: MaybeBinaryValue{
Value: "miniooni/0.1.0-dev",
},
}},
Headers: map[string]archival.MaybeBinaryValue{
Headers: map[string]MaybeBinaryValue{
"User-Agent": {Value: "miniooni/0.1.0-dev"},
},
Method: "GET",
URL: "https://www.example.com/",
},
Response: archival.HTTPResponse{
Response: HTTPResponse{
Code: 302,
HeadersList: []archival.HTTPHeader{{
HeadersList: []HTTPHeader{{
Key: "Location",
Value: archival.MaybeBinaryValue{
Value: MaybeBinaryValue{
Value: "https://x.example.com",
},
}, {
Key: "Location",
Value: archival.MaybeBinaryValue{
Value: MaybeBinaryValue{
Value: "https://y.example.com",
},
}, {
Key: "Server",
Value: archival.MaybeBinaryValue{
Value: MaybeBinaryValue{
Value: "miniooni/0.1.0-dev",
},
}},
Headers: map[string]archival.MaybeBinaryValue{
Headers: map[string]MaybeBinaryValue{
"Server": {Value: "miniooni/0.1.0-dev"},
"Location": {Value: "https://x.example.com"},
},
@@ -275,7 +311,7 @@ func TestNewRequestList(t *testing.T) {
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := archival.NewRequestList(tt.args.begin, tt.args.events); !reflect.DeepEqual(got, tt.want) {
if got := NewRequestList(tt.args.begin, tt.args.events); !reflect.DeepEqual(got, tt.want) {
t.Error(cmp.Diff(got, tt.want))
}
})
@@ -286,12 +322,12 @@ func TestNewDNSQueriesList(t *testing.T) {
begin := time.Now()
type args struct {
begin time.Time
events []trace.Event
events []Event
}
tests := []struct {
name string
args args
want []archival.DNSQueryEntry
want []DNSQueryEntry
}{{
name: "empty run",
args: args{
@@ -303,7 +339,7 @@ func TestNewDNSQueriesList(t *testing.T) {
name: "realistic run",
args: args{
begin: begin,
events: []trace.Event{{
events: []Event{{
Address: "1.1.1.1:853",
Addresses: []string{"8.8.8.8", "8.8.4.4"},
Hostname: "dns.google.com",
@@ -325,8 +361,8 @@ func TestNewDNSQueriesList(t *testing.T) {
Time: begin.Add(180 * time.Millisecond),
}},
},
want: []archival.DNSQueryEntry{{
Answers: []archival.DNSAnswerEntry{{
want: []DNSQueryEntry{{
Answers: []DNSAnswerEntry{{
ASN: 15169,
ASOrgName: "Google LLC",
AnswerType: "A",
@@ -347,15 +383,15 @@ func TestNewDNSQueriesList(t *testing.T) {
name: "run with IPv6 results",
args: args{
begin: begin,
events: []trace.Event{{
events: []Event{{
Addresses: []string{"2001:4860:4860::8888"},
Hostname: "dns.google.com",
Name: "resolve_done",
Time: begin.Add(200 * time.Millisecond),
}},
},
want: []archival.DNSQueryEntry{{
Answers: []archival.DNSAnswerEntry{{
want: []DNSQueryEntry{{
Answers: []DNSAnswerEntry{{
ASN: 15169,
ASOrgName: "Google LLC",
AnswerType: "AAAA",
@@ -369,23 +405,23 @@ func TestNewDNSQueriesList(t *testing.T) {
name: "run with errors",
args: args{
begin: begin,
events: []trace.Event{{
events: []Event{{
Err: &netxlite.ErrWrapper{Failure: netxlite.FailureDNSNXDOMAINError},
Hostname: "dns.google.com",
Name: "resolve_done",
Time: begin.Add(200 * time.Millisecond),
}},
},
want: []archival.DNSQueryEntry{{
want: []DNSQueryEntry{{
Answers: nil,
Failure: archival.NewFailure(
Failure: NewFailure(
&netxlite.ErrWrapper{Failure: netxlite.FailureDNSNXDOMAINError}),
Hostname: "dns.google.com",
QueryType: "A",
T: 0.2,
}, {
Answers: nil,
Failure: archival.NewFailure(
Failure: NewFailure(
&netxlite.ErrWrapper{Failure: netxlite.FailureDNSNXDOMAINError}),
Hostname: "dns.google.com",
QueryType: "AAAA",
@@ -394,7 +430,7 @@ func TestNewDNSQueriesList(t *testing.T) {
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := archival.NewDNSQueriesList(tt.args.begin, tt.args.events)
got := NewDNSQueriesList(tt.args.begin, tt.args.events)
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Fatal(diff)
}
@@ -406,12 +442,12 @@ func TestNewNetworkEventsList(t *testing.T) {
begin := time.Now()
type args struct {
begin time.Time
events []trace.Event
events []Event
}
tests := []struct {
name string
args args
want []archival.NetworkEvent
want []NetworkEvent
}{{
name: "empty run",
args: args{
@@ -423,7 +459,7 @@ func TestNewNetworkEventsList(t *testing.T) {
name: "realistic run",
args: args{
begin: begin,
events: []trace.Event{{
events: []Event{{
Name: netxlite.ConnectOperation,
Address: "8.8.8.8:853",
Err: io.EOF,
@@ -457,43 +493,43 @@ func TestNewNetworkEventsList(t *testing.T) {
Time: begin.Add(17 * time.Millisecond),
}},
},
want: []archival.NetworkEvent{{
want: []NetworkEvent{{
Address: "8.8.8.8:853",
Failure: archival.NewFailure(io.EOF),
Failure: NewFailure(io.EOF),
Operation: netxlite.ConnectOperation,
Proto: "tcp",
T: 0.007,
}, {
Failure: archival.NewFailure(context.Canceled),
Failure: NewFailure(context.Canceled),
NumBytes: 7117,
Operation: netxlite.ReadOperation,
T: 0.011,
}, {
Address: "8.8.8.8:853",
Failure: archival.NewFailure(context.Canceled),
Failure: NewFailure(context.Canceled),
NumBytes: 7117,
Operation: netxlite.ReadFromOperation,
T: 0.011,
}, {
Failure: archival.NewFailure(websocket.ErrBadHandshake),
Failure: NewFailure(websocket.ErrBadHandshake),
NumBytes: 4114,
Operation: netxlite.WriteOperation,
T: 0.014,
}, {
Address: "8.8.8.8:853",
Failure: archival.NewFailure(websocket.ErrBadHandshake),
Failure: NewFailure(websocket.ErrBadHandshake),
NumBytes: 4114,
Operation: netxlite.WriteToOperation,
T: 0.014,
}, {
Failure: archival.NewFailure(websocket.ErrReadLimit),
Failure: NewFailure(websocket.ErrReadLimit),
Operation: netxlite.CloseOperation,
T: 0.017,
}},
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := archival.NewNetworkEventsList(tt.args.begin, tt.args.events); !reflect.DeepEqual(got, tt.want) {
if got := NewNetworkEventsList(tt.args.begin, tt.args.events); !reflect.DeepEqual(got, tt.want) {
t.Error(cmp.Diff(got, tt.want))
}
})
@@ -504,12 +540,12 @@ func TestNewTLSHandshakesList(t *testing.T) {
begin := time.Now()
type args struct {
begin time.Time
events []trace.Event
events []Event
}
tests := []struct {
name string
args args
want []archival.TLSHandshake
want []TLSHandshake
}{{
name: "empty run",
args: args{
@@ -521,7 +557,7 @@ func TestNewTLSHandshakesList(t *testing.T) {
name: "realistic run",
args: args{
begin: begin,
events: []trace.Event{{
events: []Event{{
Name: netxlite.CloseOperation,
Err: websocket.ErrReadLimit,
Time: begin.Add(17 * time.Millisecond),
@@ -542,13 +578,13 @@ func TestNewTLSHandshakesList(t *testing.T) {
Time: begin.Add(55 * time.Millisecond),
}},
},
want: []archival.TLSHandshake{{
want: []TLSHandshake{{
Address: "131.252.210.176:443",
CipherSuite: "SUITE",
Failure: archival.NewFailure(io.EOF),
Failure: NewFailure(io.EOF),
NegotiatedProtocol: "h2",
NoTLSVerify: false,
PeerCertificates: []archival.MaybeBinaryValue{{
PeerCertificates: []MaybeBinaryValue{{
Value: "deadbeef",
}, {
Value: "abad1dea",
@@ -560,7 +596,7 @@ func TestNewTLSHandshakesList(t *testing.T) {
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := archival.NewTLSHandshakesList(tt.args.begin, tt.args.events); !reflect.DeepEqual(got, tt.want) {
if got := NewTLSHandshakesList(tt.args.begin, tt.args.events); !reflect.DeepEqual(got, tt.want) {
t.Error(cmp.Diff(got, tt.want))
}
})
@@ -620,7 +656,7 @@ func TestNewFailure(t *testing.T) {
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := archival.NewFailure(tt.args.err)
got := NewFailure(tt.args.err)
if tt.want == nil && got == nil {
return
}
@@ -689,7 +725,7 @@ func TestNewFailedOperation(t *testing.T) {
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := archival.NewFailedOperation(tt.args.err)
got := NewFailedOperation(tt.args.err)
if got == nil && tt.want == nil {
return
}
@@ -1,27 +1,26 @@
package dialer
package tracex
import (
"context"
"net"
"time"
"github.com/ooni/probe-cli/v3/internal/engine/netx/trace"
"github.com/ooni/probe-cli/v3/internal/model"
"github.com/ooni/probe-cli/v3/internal/netxlite"
)
// saverDialer saves events occurring during the dial
type saverDialer struct {
// SaverDialer saves events occurring during the dial
type SaverDialer struct {
model.Dialer
Saver *trace.Saver
Saver *Saver
}
// DialContext implements Dialer.DialContext
func (d *saverDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
func (d *SaverDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
start := time.Now()
conn, err := d.Dialer.DialContext(ctx, network, address)
stop := time.Now()
d.Saver.Write(trace.Event{
d.Saver.Write(Event{
Address: address,
Duration: stop.Sub(start),
Err: err,
@@ -32,15 +31,15 @@ func (d *saverDialer) DialContext(ctx context.Context, network, address string)
return conn, err
}
// saverConnDialer wraps the returned connection such that we
// SaverConnDialer wraps the returned connection such that we
// collect all the read/write events that occur.
type saverConnDialer struct {
type SaverConnDialer struct {
model.Dialer
Saver *trace.Saver
Saver *Saver
}
// DialContext implements Dialer.DialContext
func (d *saverConnDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
func (d *SaverConnDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
conn, err := d.Dialer.DialContext(ctx, network, address)
if err != nil {
return nil, err
@@ -50,14 +49,14 @@ func (d *saverConnDialer) DialContext(ctx context.Context, network, address stri
type saverConn struct {
net.Conn
saver *trace.Saver
saver *Saver
}
func (c *saverConn) Read(p []byte) (int, error) {
start := time.Now()
count, err := c.Conn.Read(p)
stop := time.Now()
c.saver.Write(trace.Event{
c.saver.Write(Event{
Data: p[:count],
Duration: stop.Sub(start),
Err: err,
@@ -72,7 +71,7 @@ func (c *saverConn) Write(p []byte) (int, error) {
start := time.Now()
count, err := c.Conn.Write(p)
stop := time.Now()
c.saver.Write(trace.Event{
c.saver.Write(Event{
Data: p[:count],
Duration: stop.Sub(start),
Err: err,
@@ -83,6 +82,6 @@ func (c *saverConn) Write(p []byte) (int, error) {
return count, err
}
var _ model.Dialer = &saverDialer{}
var _ model.Dialer = &saverConnDialer{}
var _ model.Dialer = &SaverDialer{}
var _ model.Dialer = &SaverConnDialer{}
var _ net.Conn = &saverConn{}
@@ -1,4 +1,4 @@
package dialer
package tracex
import (
"context"
@@ -8,15 +8,14 @@ import (
"testing"
"time"
"github.com/ooni/probe-cli/v3/internal/engine/netx/trace"
"github.com/ooni/probe-cli/v3/internal/model/mocks"
"github.com/ooni/probe-cli/v3/internal/netxlite"
)
func TestSaverDialerFailure(t *testing.T) {
expected := errors.New("mocked error")
saver := &trace.Saver{}
dlr := &saverDialer{
saver := &Saver{}
dlr := &SaverDialer{
Dialer: &mocks.Dialer{
MockDialContext: func(ctx context.Context, network string, address string) (net.Conn, error) {
return nil, expected
@@ -57,8 +56,8 @@ func TestSaverDialerFailure(t *testing.T) {
func TestSaverConnDialerFailure(t *testing.T) {
expected := errors.New("mocked error")
saver := &trace.Saver{}
dlr := &saverConnDialer{
saver := &Saver{}
dlr := &SaverConnDialer{
Dialer: &mocks.Dialer{
MockDialContext: func(ctx context.Context, network string, address string) (net.Conn, error) {
return nil, expected
@@ -76,9 +75,9 @@ func TestSaverConnDialerFailure(t *testing.T) {
}
func TestSaverConnDialerSuccess(t *testing.T) {
saver := &trace.Saver{}
dlr := &saverConnDialer{
Dialer: &saverDialer{
saver := &Saver{}
dlr := &SaverConnDialer{
Dialer: &SaverDialer{
Dialer: &mocks.Dialer{
MockDialContext: func(ctx context.Context, network string, address string) (net.Conn, error) {
return &mocks.Conn{
@@ -126,14 +125,14 @@ func TestSaverConnDialerSuccess(t *testing.T) {
saverCheckWriteEvent(t, &events[2])
}
func saverCheckConnectEvent(t *testing.T, ev *trace.Event) {
func saverCheckConnectEvent(t *testing.T, ev *Event) {
// TODO(bassosimone): implement
}
func saverCheckReadEvent(t *testing.T, ev *trace.Event) {
func saverCheckReadEvent(t *testing.T, ev *Event) {
// TODO(bassosimone): implement
}
func saverCheckWriteEvent(t *testing.T, ev *trace.Event) {
func saverCheckWriteEvent(t *testing.T, ev *Event) {
// TODO(bassosimone): implement
}
+2
View File
@@ -0,0 +1,2 @@
// Package tracex contains code to perform measurements using tracing.
package tracex
@@ -1,4 +1,4 @@
package trace
package tracex
import (
"crypto/tls"
@@ -1,4 +1,4 @@
package httptransport
package tracex
import (
"bytes"
@@ -7,7 +7,6 @@ import (
"net/http"
"time"
"github.com/ooni/probe-cli/v3/internal/engine/netx/trace"
"github.com/ooni/probe-cli/v3/internal/model"
"github.com/ooni/probe-cli/v3/internal/netxlite"
)
@@ -16,12 +15,12 @@ import (
// events related to HTTP request and response metadata
type SaverMetadataHTTPTransport struct {
model.HTTPTransport
Saver *trace.Saver
Saver *Saver
}
// RoundTrip implements RoundTripper.RoundTrip
func (txp SaverMetadataHTTPTransport) RoundTrip(req *http.Request) (*http.Response, error) {
txp.Saver.Write(trace.Event{
txp.Saver.Write(Event{
HTTPHeaders: txp.CloneHeaders(req),
HTTPMethod: req.Method,
HTTPURL: req.URL.String(),
@@ -33,7 +32,7 @@ func (txp SaverMetadataHTTPTransport) RoundTrip(req *http.Request) (*http.Respon
if err != nil {
return nil, err
}
txp.Saver.Write(trace.Event{
txp.Saver.Write(Event{
HTTPHeaders: resp.Header,
HTTPStatusCode: resp.StatusCode,
Name: "http_response_metadata",
@@ -59,17 +58,17 @@ func (txp SaverMetadataHTTPTransport) CloneHeaders(req *http.Request) http.Heade
// events related to the HTTP transaction
type SaverTransactionHTTPTransport struct {
model.HTTPTransport
Saver *trace.Saver
Saver *Saver
}
// RoundTrip implements RoundTripper.RoundTrip
func (txp SaverTransactionHTTPTransport) RoundTrip(req *http.Request) (*http.Response, error) {
txp.Saver.Write(trace.Event{
txp.Saver.Write(Event{
Name: "http_transaction_start",
Time: time.Now(),
})
resp, err := txp.HTTPTransport.RoundTrip(req)
txp.Saver.Write(trace.Event{
txp.Saver.Write(Event{
Err: err,
Name: "http_transaction_done",
Time: time.Now(),
@@ -81,7 +80,7 @@ func (txp SaverTransactionHTTPTransport) RoundTrip(req *http.Request) (*http.Res
// body events occurring during the round trip
type SaverBodyHTTPTransport struct {
model.HTTPTransport
Saver *trace.Saver
Saver *Saver
SnapshotSize int
}
@@ -98,7 +97,7 @@ func (txp SaverBodyHTTPTransport) RoundTrip(req *http.Request) (*http.Response,
return nil, err
}
req.Body = saverCompose(data, req.Body)
txp.Saver.Write(trace.Event{
txp.Saver.Write(Event{
DataIsTruncated: len(data) >= snapsize,
Data: data,
Name: "http_request_body_snapshot",
@@ -115,7 +114,7 @@ func (txp SaverBodyHTTPTransport) RoundTrip(req *http.Request) (*http.Response,
return nil, err
}
resp.Body = saverCompose(data, resp.Body)
txp.Saver.Write(trace.Event{
txp.Saver.Write(Event{
DataIsTruncated: len(data) >= snapsize,
Data: data,
Name: "http_response_body_snapshot",
@@ -1,4 +1,4 @@
package httptransport_test
package tracex
import (
"context"
@@ -11,8 +11,6 @@ import (
"testing"
"time"
"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/model"
"github.com/ooni/probe-cli/v3/internal/netxlite"
)
@@ -21,8 +19,8 @@ func TestSaverMetadataSuccess(t *testing.T) {
if testing.Short() {
t.Skip("skip test in short mode")
}
saver := &trace.Saver{}
txp := httptransport.SaverMetadataHTTPTransport{
saver := &Saver{}
txp := SaverMetadataHTTPTransport{
HTTPTransport: netxlite.NewHTTPTransportStdlib(model.DiscardLogger),
Saver: saver,
}
@@ -75,8 +73,8 @@ func TestSaverMetadataSuccess(t *testing.T) {
func TestSaverMetadataFailure(t *testing.T) {
expected := errors.New("mocked error")
saver := &trace.Saver{}
txp := httptransport.SaverMetadataHTTPTransport{
saver := &Saver{}
txp := SaverMetadataHTTPTransport{
HTTPTransport: FakeTransport{
Err: expected,
},
@@ -119,8 +117,8 @@ func TestSaverTransactionSuccess(t *testing.T) {
if testing.Short() {
t.Skip("skip test in short mode")
}
saver := &trace.Saver{}
txp := httptransport.SaverTransactionHTTPTransport{
saver := &Saver{}
txp := SaverTransactionHTTPTransport{
HTTPTransport: netxlite.NewHTTPTransportStdlib(model.DiscardLogger),
Saver: saver,
}
@@ -160,8 +158,8 @@ func TestSaverTransactionSuccess(t *testing.T) {
func TestSaverTransactionFailure(t *testing.T) {
expected := errors.New("mocked error")
saver := &trace.Saver{}
txp := httptransport.SaverTransactionHTTPTransport{
saver := &Saver{}
txp := SaverTransactionHTTPTransport{
HTTPTransport: FakeTransport{
Err: expected,
},
@@ -200,8 +198,8 @@ func TestSaverTransactionFailure(t *testing.T) {
}
func TestSaverBodySuccess(t *testing.T) {
saver := new(trace.Saver)
txp := httptransport.SaverBodyHTTPTransport{
saver := new(Saver)
txp := SaverBodyHTTPTransport{
HTTPTransport: FakeTransport{
Func: func(req *http.Request) (*http.Response, error) {
data, err := netxlite.ReadAllContext(context.Background(), req.Body)
@@ -271,8 +269,8 @@ func TestSaverBodySuccess(t *testing.T) {
}
func TestSaverBodyRequestReadError(t *testing.T) {
saver := new(trace.Saver)
txp := httptransport.SaverBodyHTTPTransport{
saver := new(Saver)
txp := SaverBodyHTTPTransport{
HTTPTransport: FakeTransport{
Func: func(req *http.Request) (*http.Response, error) {
panic("should not be called")
@@ -301,9 +299,9 @@ func TestSaverBodyRequestReadError(t *testing.T) {
}
func TestSaverBodyRoundTripError(t *testing.T) {
saver := new(trace.Saver)
saver := new(Saver)
expected := errors.New("mocked error")
txp := httptransport.SaverBodyHTTPTransport{
txp := SaverBodyHTTPTransport{
HTTPTransport: FakeTransport{
Err: expected,
},
@@ -341,9 +339,9 @@ func TestSaverBodyRoundTripError(t *testing.T) {
}
func TestSaverBodyResponseReadError(t *testing.T) {
saver := new(trace.Saver)
saver := new(Saver)
expected := errors.New("mocked error")
txp := httptransport.SaverBodyHTTPTransport{
txp := SaverBodyHTTPTransport{
HTTPTransport: FakeTransport{
Func: func(req *http.Request) (*http.Response, error) {
return &http.Response{
@@ -396,7 +394,7 @@ func TestCloneHeaders(t *testing.T) {
},
Header: http.Header{},
}
txp := httptransport.SaverMetadataHTTPTransport{}
txp := SaverMetadataHTTPTransport{}
header := txp.CloneHeaders(req)
if header.Get("Host") != "www.example.com" {
t.Fatal("did not set Host header correctly")
@@ -411,7 +409,7 @@ func TestCloneHeaders(t *testing.T) {
},
Header: http.Header{},
}
txp := httptransport.SaverMetadataHTTPTransport{}
txp := SaverMetadataHTTPTransport{}
header := txp.CloneHeaders(req)
if header.Get("Host") != "www.kernel.org" {
t.Fatal("did not set Host header correctly")
+139
View File
@@ -0,0 +1,139 @@
package tracex
import (
"context"
"crypto/tls"
"net"
"time"
"github.com/lucas-clemente/quic-go"
"github.com/ooni/probe-cli/v3/internal/model"
"github.com/ooni/probe-cli/v3/internal/netxlite"
)
// QUICHandshakeSaver saves events occurring during the handshake
type QUICHandshakeSaver struct {
Saver *Saver
model.QUICDialer
}
// DialContext implements ContextDialer.DialContext
func (h QUICHandshakeSaver) DialContext(ctx context.Context, network string,
host string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) {
start := time.Now()
// TODO(bassosimone): in the future we probably want to also save
// information about what versions we're willing to accept.
h.Saver.Write(Event{
Address: host,
Name: "quic_handshake_start",
NoTLSVerify: tlsCfg.InsecureSkipVerify,
Proto: network,
TLSNextProtos: tlsCfg.NextProtos,
TLSServerName: tlsCfg.ServerName,
Time: start,
})
sess, err := h.QUICDialer.DialContext(ctx, network, host, tlsCfg, cfg)
stop := time.Now()
if err != nil {
h.Saver.Write(Event{
Duration: stop.Sub(start),
Err: err,
Name: "quic_handshake_done",
NoTLSVerify: tlsCfg.InsecureSkipVerify,
TLSNextProtos: tlsCfg.NextProtos,
TLSServerName: tlsCfg.ServerName,
Time: stop,
})
return nil, err
}
state := quicConnectionState(sess)
h.Saver.Write(Event{
Duration: stop.Sub(start),
Name: "quic_handshake_done",
NoTLSVerify: tlsCfg.InsecureSkipVerify,
TLSCipherSuite: netxlite.TLSCipherSuiteString(state.CipherSuite),
TLSNegotiatedProto: state.NegotiatedProtocol,
TLSNextProtos: tlsCfg.NextProtos,
TLSPeerCerts: PeerCerts(state, err),
TLSServerName: tlsCfg.ServerName,
TLSVersion: netxlite.TLSVersionString(state.Version),
Time: stop,
})
return sess, nil
}
// quicConnectionState returns the ConnectionState of a QUIC Session.
func quicConnectionState(sess quic.EarlyConnection) tls.ConnectionState {
return sess.ConnectionState().TLS.ConnectionState
}
// QUICListenerSaver is a QUICListener that also implements saving events.
type QUICListenerSaver struct {
// QUICListener is the underlying QUICListener.
model.QUICListener
// Saver is the underlying Saver.
Saver *Saver
}
// Listen implements QUICListener.Listen.
func (qls *QUICListenerSaver) Listen(addr *net.UDPAddr) (model.UDPLikeConn, error) {
pconn, err := qls.QUICListener.Listen(addr)
if err != nil {
return nil, err
}
return &saverUDPConn{
UDPLikeConn: pconn,
saver: qls.Saver,
}, nil
}
type saverUDPConn struct {
model.UDPLikeConn
saver *Saver
}
var _ model.UDPLikeConn = &saverUDPConn{}
func (c *saverUDPConn) WriteTo(p []byte, addr net.Addr) (int, error) {
start := time.Now()
count, err := c.UDPLikeConn.WriteTo(p, addr)
stop := time.Now()
c.saver.Write(Event{
Address: addr.String(),
Data: p[:count],
Duration: stop.Sub(start),
Err: err,
NumBytes: count,
Name: netxlite.WriteToOperation,
Time: stop,
})
return count, err
}
func (c *saverUDPConn) ReadFrom(b []byte) (int, net.Addr, error) {
start := time.Now()
n, addr, err := c.UDPLikeConn.ReadFrom(b)
stop := time.Now()
var data []byte
if n > 0 {
data = b[:n]
}
c.saver.Write(Event{
Address: c.safeAddrString(addr),
Data: data,
Duration: stop.Sub(start),
Err: err,
NumBytes: n,
Name: netxlite.ReadFromOperation,
Time: stop,
})
return n, addr, err
}
func (c *saverUDPConn) safeAddrString(addr net.Addr) (out string) {
if addr != nil {
out = addr.String()
}
return
}
@@ -1,17 +1,18 @@
package quicdialer_test
package tracex
import (
"context"
"crypto/tls"
"errors"
"net"
"reflect"
"strings"
"testing"
"time"
"github.com/lucas-clemente/quic-go"
"github.com/ooni/probe-cli/v3/internal/engine/netx/quicdialer"
"github.com/ooni/probe-cli/v3/internal/engine/netx/trace"
"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/quictesting"
)
@@ -37,8 +38,8 @@ func TestHandshakeSaverSuccess(t *testing.T) {
NextProtos: nextprotos,
ServerName: servername,
}
saver := &trace.Saver{}
dlr := quicdialer.HandshakeSaver{
saver := &Saver{}
dlr := QUICHandshakeSaver{
QUICDialer: &netxlite.QUICDialerQUICGo{
QUICListener: &netxlite.QUICListenerStdlib{},
},
@@ -95,8 +96,8 @@ func TestHandshakeSaverHostNameError(t *testing.T) {
NextProtos: nextprotos,
ServerName: servername,
}
saver := &trace.Saver{}
dlr := quicdialer.HandshakeSaver{
saver := &Saver{}
dlr := QUICHandshakeSaver{
QUICDialer: &netxlite.QUICDialerQUICGo{
QUICListener: &netxlite.QUICListenerStdlib{},
},
@@ -122,3 +123,73 @@ func TestHandshakeSaverHostNameError(t *testing.T) {
}
}
}
func TestQUICListenerSaverCannotListen(t *testing.T) {
expected := errors.New("mocked error")
qls := &QUICListenerSaver{
QUICListener: &mocks.QUICListener{
MockListen: func(addr *net.UDPAddr) (model.UDPLikeConn, error) {
return nil, expected
},
},
Saver: &Saver{},
}
pconn, err := qls.Listen(&net.UDPAddr{
IP: []byte{},
Port: 8080,
Zone: "",
})
if !errors.Is(err, expected) {
t.Fatal("unexpected error", err)
}
if pconn != nil {
t.Fatal("expected nil pconn here")
}
}
func TestSystemDialerSuccessWithReadWrite(t *testing.T) {
// This is the most common use case for collecting reads, writes
tlsConf := &tls.Config{
NextProtos: []string{"h3"},
ServerName: quictesting.Domain,
}
saver := &Saver{}
systemdialer := &netxlite.QUICDialerQUICGo{
QUICListener: &QUICListenerSaver{
QUICListener: &netxlite.QUICListenerStdlib{},
Saver: saver,
},
}
_, err := systemdialer.DialContext(context.Background(), "udp",
quictesting.Endpoint("443"), tlsConf, &quic.Config{})
if err != nil {
t.Fatal(err)
}
ev := saver.Read()
if len(ev) < 2 {
t.Fatal("unexpected number of events")
}
last := len(ev) - 1
for idx := 1; idx < last; idx++ {
if ev[idx].Data == nil {
t.Fatal("unexpected Data")
}
if ev[idx].Duration <= 0 {
t.Fatal("unexpected Duration")
}
if ev[idx].Err != nil {
t.Fatal("unexpected Err")
}
if ev[idx].NumBytes <= 0 {
t.Fatal("unexpected NumBytes")
}
switch ev[idx].Name {
case netxlite.ReadFromOperation, netxlite.WriteToOperation:
default:
t.Fatal("unexpected Name")
}
if ev[idx].Time.Before(ev[idx-1].Time) {
t.Fatal("unexpected Time", ev[idx].Time, ev[idx-1].Time)
}
}
}
@@ -1,23 +1,22 @@
package resolver
package tracex
import (
"context"
"time"
"github.com/ooni/probe-cli/v3/internal/engine/netx/trace"
"github.com/ooni/probe-cli/v3/internal/model"
)
// SaverResolver is a resolver that saves events
type SaverResolver struct {
model.Resolver
Saver *trace.Saver
Saver *Saver
}
// LookupHost implements Resolver.LookupHost
func (r SaverResolver) LookupHost(ctx context.Context, hostname string) ([]string, error) {
start := time.Now()
r.Saver.Write(trace.Event{
r.Saver.Write(Event{
Address: r.Resolver.Address(),
Hostname: hostname,
Name: "resolve_start",
@@ -26,7 +25,7 @@ func (r SaverResolver) LookupHost(ctx context.Context, hostname string) ([]strin
})
addrs, err := r.Resolver.LookupHost(ctx, hostname)
stop := time.Now()
r.Saver.Write(trace.Event{
r.Saver.Write(Event{
Addresses: addrs,
Address: r.Resolver.Address(),
Duration: stop.Sub(start),
@@ -42,14 +41,14 @@ func (r SaverResolver) LookupHost(ctx context.Context, hostname string) ([]strin
// SaverDNSTransport is a DNS transport that saves events
type SaverDNSTransport struct {
model.DNSTransport
Saver *trace.Saver
Saver *Saver
}
// RoundTrip implements RoundTripper.RoundTrip
func (txp SaverDNSTransport) RoundTrip(
ctx context.Context, query model.DNSQuery) (model.DNSResponse, error) {
start := time.Now()
txp.Saver.Write(trace.Event{
txp.Saver.Write(Event{
Address: txp.Address(),
DNSQuery: txp.maybeQueryBytes(query),
Name: "dns_round_trip_start",
@@ -58,7 +57,7 @@ func (txp SaverDNSTransport) RoundTrip(
})
response, err := txp.DNSTransport.RoundTrip(ctx, query)
stop := time.Now()
txp.Saver.Write(trace.Event{
txp.Saver.Write(Event{
Address: txp.Address(),
DNSQuery: txp.maybeQueryBytes(query),
DNSReply: txp.maybeResponseBytes(response),
@@ -1,24 +1,24 @@
package resolver_test
package tracex
import (
"bytes"
"context"
"errors"
"net"
"reflect"
"testing"
"time"
"github.com/ooni/probe-cli/v3/internal/engine/netx/resolver"
"github.com/ooni/probe-cli/v3/internal/engine/netx/trace"
"github.com/ooni/probe-cli/v3/internal/model"
"github.com/ooni/probe-cli/v3/internal/model/mocks"
"github.com/ooni/probe-cli/v3/internal/runtimex"
)
func TestSaverResolverFailure(t *testing.T) {
expected := errors.New("no such host")
saver := &trace.Saver{}
reso := resolver.SaverResolver{
Resolver: resolver.NewFakeResolverWithExplicitError(expected),
saver := &Saver{}
reso := SaverResolver{
Resolver: NewFakeResolverWithExplicitError(expected),
Saver: saver,
}
addrs, err := reso.LookupHost(context.Background(), "www.google.com")
@@ -63,9 +63,9 @@ func TestSaverResolverFailure(t *testing.T) {
func TestSaverResolverSuccess(t *testing.T) {
expected := []string{"8.8.8.8", "8.8.4.4"}
saver := &trace.Saver{}
reso := resolver.SaverResolver{
Resolver: resolver.NewFakeResolverWithResult(expected),
saver := &Saver{}
reso := SaverResolver{
Resolver: NewFakeResolverWithResult(expected),
Saver: saver,
}
addrs, err := reso.LookupHost(context.Background(), "www.google.com")
@@ -110,8 +110,8 @@ func TestSaverResolverSuccess(t *testing.T) {
func TestSaverDNSTransportFailure(t *testing.T) {
expected := errors.New("no such host")
saver := &trace.Saver{}
txp := resolver.SaverDNSTransport{
saver := &Saver{}
txp := SaverDNSTransport{
DNSTransport: &mocks.DNSTransport{
MockRoundTrip: func(ctx context.Context, query model.DNSQuery) (model.DNSResponse, error) {
return nil, expected
@@ -173,13 +173,13 @@ func TestSaverDNSTransportFailure(t *testing.T) {
func TestSaverDNSTransportSuccess(t *testing.T) {
expected := []byte{0xef, 0xbe, 0xad, 0xde}
saver := &trace.Saver{}
saver := &Saver{}
response := &mocks.DNSResponse{
MockBytes: func() []byte {
return expected
},
}
txp := resolver.SaverDNSTransport{
txp := SaverDNSTransport{
DNSTransport: &mocks.DNSTransport{
MockRoundTrip: func(ctx context.Context, query model.DNSQuery) (model.DNSResponse, error) {
return response, nil
@@ -238,3 +238,50 @@ func TestSaverDNSTransportSuccess(t *testing.T) {
t.Fatal("the saved time is wrong")
}
}
func NewFakeResolverWithExplicitError(err error) model.Resolver {
runtimex.PanicIfNil(err, "passed nil error")
return &mocks.Resolver{
MockLookupHost: func(ctx context.Context, domain string) ([]string, error) {
return nil, err
},
MockNetwork: func() string {
return "fake"
},
MockAddress: func() string {
return ""
},
MockCloseIdleConnections: func() {
// nothing
},
MockLookupHTTPS: func(ctx context.Context, domain string) (*model.HTTPSSvc, error) {
return nil, errors.New("not implemented")
},
MockLookupNS: func(ctx context.Context, domain string) ([]*net.NS, error) {
return nil, errors.New("not implemented")
},
}
}
func NewFakeResolverWithResult(r []string) model.Resolver {
return &mocks.Resolver{
MockLookupHost: func(ctx context.Context, domain string) ([]string, error) {
return r, nil
},
MockNetwork: func() string {
return "fake"
},
MockAddress: func() string {
return ""
},
MockCloseIdleConnections: func() {
// nothing
},
MockLookupHTTPS: func(ctx context.Context, domain string) (*model.HTTPSSvc, error) {
return nil, errors.New("not implemented")
},
MockLookupNS: func(ctx context.Context, domain string) ([]*net.NS, error) {
return nil, errors.New("not implemented")
},
}
}
@@ -1,4 +1,4 @@
package trace
package tracex
import "sync"
@@ -1,20 +1,18 @@
package trace_test
package tracex
import (
"sync"
"testing"
"github.com/ooni/probe-cli/v3/internal/engine/netx/trace"
)
func TestGood(t *testing.T) {
saver := trace.Saver{}
saver := Saver{}
var wg sync.WaitGroup
const parallel = 10
wg.Add(parallel)
for idx := 0; idx < parallel; idx++ {
go func() {
saver.Write(trace.Event{})
saver.Write(Event{})
wg.Done()
}()
}
@@ -1,4 +1,4 @@
package tlsdialer
package tracex
import (
"context"
@@ -6,7 +6,6 @@ import (
"net"
"time"
"github.com/ooni/probe-cli/v3/internal/engine/netx/trace"
"github.com/ooni/probe-cli/v3/internal/model"
"github.com/ooni/probe-cli/v3/internal/netxlite"
)
@@ -14,7 +13,7 @@ import (
// SaverTLSHandshaker saves events occurring during the handshake
type SaverTLSHandshaker struct {
model.TLSHandshaker
Saver *trace.Saver
Saver *Saver
}
// Handshake implements TLSHandshaker.Handshake
@@ -22,7 +21,7 @@ func (h SaverTLSHandshaker) Handshake(
ctx context.Context, conn net.Conn, config *tls.Config,
) (net.Conn, tls.ConnectionState, error) {
start := time.Now()
h.Saver.Write(trace.Event{
h.Saver.Write(Event{
Name: "tls_handshake_start",
NoTLSVerify: config.InsecureSkipVerify,
TLSNextProtos: config.NextProtos,
@@ -32,7 +31,7 @@ func (h SaverTLSHandshaker) Handshake(
remoteAddr := conn.RemoteAddr().String()
tlsconn, state, err := h.TLSHandshaker.Handshake(ctx, conn, config)
stop := time.Now()
h.Saver.Write(trace.Event{
h.Saver.Write(Event{
Address: remoteAddr,
Duration: stop.Sub(start),
Err: err,
@@ -41,7 +40,7 @@ func (h SaverTLSHandshaker) Handshake(
TLSCipherSuite: netxlite.TLSCipherSuiteString(state.CipherSuite),
TLSNegotiatedProto: state.NegotiatedProtocol,
TLSNextProtos: config.NextProtos,
TLSPeerCerts: trace.PeerCerts(state, err),
TLSPeerCerts: PeerCerts(state, err),
TLSServerName: config.ServerName,
TLSVersion: netxlite.TLSVersionString(state.Version),
Time: stop,
@@ -1,4 +1,4 @@
package tlsdialer_test
package tracex
import (
"context"
@@ -7,9 +7,7 @@ import (
"testing"
"time"
"github.com/ooni/probe-cli/v3/internal/engine/netx/dialer"
"github.com/ooni/probe-cli/v3/internal/engine/netx/tlsdialer"
"github.com/ooni/probe-cli/v3/internal/engine/netx/trace"
"github.com/ooni/probe-cli/v3/internal/model"
"github.com/ooni/probe-cli/v3/internal/netxlite"
)
@@ -19,11 +17,20 @@ func TestSaverTLSHandshakerSuccessWithReadWrite(t *testing.T) {
t.Skip("skip test in short mode")
}
nextprotos := []string{"h2"}
saver := &trace.Saver{}
saver := &Saver{}
tlsdlr := &netxlite.TLSDialerLegacy{
Config: &tls.Config{NextProtos: nextprotos},
Dialer: dialer.New(&dialer.Config{ReadWriteSaver: saver}, netxlite.DefaultResolver),
TLSHandshaker: tlsdialer.SaverTLSHandshaker{
Dialer: netxlite.NewDialerWithResolver(
model.DiscardLogger,
netxlite.NewResolverStdlib(model.DiscardLogger),
func(dialer model.Dialer) model.Dialer {
return &SaverConnDialer{
Dialer: dialer,
Saver: saver,
}
},
),
TLSHandshaker: SaverTLSHandshaker{
TLSHandshaker: &netxlite.TLSHandshakerConfigurable{},
Saver: saver,
},
@@ -112,11 +119,11 @@ func TestSaverTLSHandshakerSuccess(t *testing.T) {
t.Skip("skip test in short mode")
}
nextprotos := []string{"h2"}
saver := &trace.Saver{}
saver := &Saver{}
tlsdlr := &netxlite.TLSDialerLegacy{
Config: &tls.Config{NextProtos: nextprotos},
Dialer: netxlite.DefaultDialer,
TLSHandshaker: tlsdialer.SaverTLSHandshaker{
TLSHandshaker: SaverTLSHandshaker{
TLSHandshaker: &netxlite.TLSHandshakerConfigurable{},
Saver: saver,
},
@@ -178,10 +185,10 @@ func TestSaverTLSHandshakerHostnameError(t *testing.T) {
if testing.Short() {
t.Skip("skip test in short mode")
}
saver := &trace.Saver{}
saver := &Saver{}
tlsdlr := &netxlite.TLSDialerLegacy{
Dialer: netxlite.DefaultDialer,
TLSHandshaker: tlsdialer.SaverTLSHandshaker{
TLSHandshaker: SaverTLSHandshaker{
TLSHandshaker: &netxlite.TLSHandshakerConfigurable{},
Saver: saver,
},
@@ -211,10 +218,10 @@ func TestSaverTLSHandshakerInvalidCertError(t *testing.T) {
if testing.Short() {
t.Skip("skip test in short mode")
}
saver := &trace.Saver{}
saver := &Saver{}
tlsdlr := &netxlite.TLSDialerLegacy{
Dialer: netxlite.DefaultDialer,
TLSHandshaker: tlsdialer.SaverTLSHandshaker{
TLSHandshaker: SaverTLSHandshaker{
TLSHandshaker: &netxlite.TLSHandshakerConfigurable{},
Saver: saver,
},
@@ -244,10 +251,10 @@ func TestSaverTLSHandshakerAuthorityError(t *testing.T) {
if testing.Short() {
t.Skip("skip test in short mode")
}
saver := &trace.Saver{}
saver := &Saver{}
tlsdlr := &netxlite.TLSDialerLegacy{
Dialer: netxlite.DefaultDialer,
TLSHandshaker: tlsdialer.SaverTLSHandshaker{
TLSHandshaker: SaverTLSHandshaker{
TLSHandshaker: &netxlite.TLSHandshakerConfigurable{},
Saver: saver,
},
@@ -277,11 +284,11 @@ func TestSaverTLSHandshakerNoTLSVerify(t *testing.T) {
if testing.Short() {
t.Skip("skip test in short mode")
}
saver := &trace.Saver{}
saver := &Saver{}
tlsdlr := &netxlite.TLSDialerLegacy{
Config: &tls.Config{InsecureSkipVerify: true},
Dialer: netxlite.DefaultDialer,
TLSHandshaker: tlsdialer.SaverTLSHandshaker{
TLSHandshaker: SaverTLSHandshaker{
TLSHandshaker: &netxlite.TLSHandshakerConfigurable{},
Saver: saver,
},