From 4442a6ba02d17c424c4a8a587ad6ca52377daa1a Mon Sep 17 00:00:00 2001 From: Simone Basso Date: Wed, 1 Jun 2022 14:04:53 +0200 Subject: [PATCH] refactor(tracex): do not depend on strings for event names Rather than matching a string, match a type. This is more robust considering future refactorings. We're confident the names did not change in _this_ refactoring because we're still testing the same strings in the tests. Part of https://github.com/ooni/probe/issues/2121 --- internal/engine/experiment/dash/dash.go | 4 +- internal/engine/experiment/dash/dash_test.go | 5 +- internal/engine/netx/tracex/archival.go | 82 +++--- internal/engine/netx/tracex/archival_test.go | 112 +++----- internal/engine/netx/tracex/dialer.go | 16 +- internal/engine/netx/tracex/dialer_test.go | 18 +- internal/engine/netx/tracex/event.go | 261 ++++++++++++++++++- internal/engine/netx/tracex/http.go | 30 +-- internal/engine/netx/tracex/http_test.go | 80 +++--- internal/engine/netx/tracex/quic.go | 25 +- internal/engine/netx/tracex/quic_test.go | 44 ++-- internal/engine/netx/tracex/resolver.go | 20 +- internal/engine/netx/tracex/resolver_test.go | 72 ++--- internal/engine/netx/tracex/saver_test.go | 2 +- internal/engine/netx/tracex/tls.go | 10 +- internal/engine/netx/tracex/tls_test.go | 92 +++---- 16 files changed, 533 insertions(+), 340 deletions(-) diff --git a/internal/engine/experiment/dash/dash.go b/internal/engine/experiment/dash/dash.go index e0a09d84e2..ee36b8fcc9 100644 --- a/internal/engine/experiment/dash/dash.go +++ b/internal/engine/experiment/dash/dash.go @@ -171,8 +171,8 @@ func (r runner) measure( // of the latest connect time. We should have one sample in most // cases, because the connection should be persistent. for _, ev := range r.saver.Read() { - if ev.Name == netxlite.ConnectOperation { - connectTime = ev.Duration.Seconds() + if _, ok := ev.(*tracex.EventConnectOperation); ok { + connectTime = ev.Value().Duration.Seconds() } } current.ConnectTime = connectTime diff --git a/internal/engine/experiment/dash/dash_test.go b/internal/engine/experiment/dash/dash_test.go index 050f281fba..0a8e0f3363 100644 --- a/internal/engine/experiment/dash/dash_test.go +++ b/internal/engine/experiment/dash/dash_test.go @@ -14,7 +14,6 @@ import ( "github.com/ooni/probe-cli/v3/internal/engine/mockable" "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" ) func TestRunnerLoopLocateFailure(t *testing.T) { @@ -108,7 +107,7 @@ func TestRunnerLoopMeasureFailure(t *testing.T) { func TestRunnerLoopCollectFailure(t *testing.T) { expected := errors.New("mocked error") saver := new(tracex.Saver) - saver.Write(tracex.Event{Name: netxlite.ConnectOperation, Duration: 150 * time.Millisecond}) + saver.Write(&tracex.EventConnectOperation{V: &tracex.EventValue{Duration: 150 * time.Millisecond}}) r := runner{ callbacks: model.NewPrinterCallbacks(log.Log), httpClient: &http.Client{ @@ -152,7 +151,7 @@ func TestRunnerLoopCollectFailure(t *testing.T) { func TestRunnerLoopSuccess(t *testing.T) { saver := new(tracex.Saver) - saver.Write(tracex.Event{Name: netxlite.ConnectOperation, Duration: 150 * time.Millisecond}) + saver.Write(&tracex.EventConnectOperation{V: &tracex.EventValue{Duration: 150 * time.Millisecond}}) r := runner{ callbacks: model.NewPrinterCallbacks(log.Log), httpClient: &http.Client{ diff --git a/internal/engine/netx/tracex/archival.go b/internal/engine/netx/tracex/archival.go index fe8714c9e8..6e81abdf6c 100644 --- a/internal/engine/netx/tracex/archival.go +++ b/internal/engine/netx/tracex/archival.go @@ -45,10 +45,11 @@ var ( // NewTCPConnectList creates a new TCPConnectList func NewTCPConnectList(begin time.Time, events []Event) []TCPConnectEntry { var out []TCPConnectEntry - for _, event := range events { - if event.Name != netxlite.ConnectOperation { + for _, wrapper := range events { + if _, ok := wrapper.(*EventConnectOperation); !ok { continue } + event := wrapper.Value() if event.Proto != "tcp" { continue } @@ -140,31 +141,32 @@ func newRequestList(begin time.Time, events []Event) []RequestEntry { out []RequestEntry entry RequestEntry ) - for _, ev := range events { - switch ev.Name { - case "http_transaction_start": + for _, wrapper := range events { + ev := wrapper.Value() + switch wrapper.(type) { + case *EventHTTPTransactionStart: entry = RequestEntry{} entry.T = ev.Time.Sub(begin).Seconds() - case "http_request_body_snapshot": + case *EventHTTPRequestBodySnapshot: entry.Request.Body.Value = string(ev.Data) entry.Request.BodyIsTruncated = ev.DataIsTruncated - case "http_request_metadata": + case *EventHTTPRequestMetadata: entry.Request.Headers = make(map[string]MaybeBinaryValue) httpAddHeaders( ev.HTTPHeaders, &entry.Request.HeadersList, &entry.Request.Headers) entry.Request.Method = ev.HTTPMethod entry.Request.URL = ev.HTTPURL entry.Request.Transport = ev.Transport - case "http_response_metadata": + case *EventHTTPResponseMetadata: entry.Response.Headers = make(map[string]MaybeBinaryValue) httpAddHeaders( ev.HTTPHeaders, &entry.Response.HeadersList, &entry.Response.Headers) entry.Response.Code = int64(ev.HTTPStatusCode) entry.Response.Locations = ev.HTTPHeaders.Values("Location") - case "http_response_body_snapshot": + case *EventHTTPResponseBodySnapshot: entry.Response.Body.Value = string(ev.Data) entry.Response.BodyIsTruncated = ev.DataIsTruncated - case "http_transaction_done": + case *EventHTTPTransactionDone: entry.Failure = NewFailure(ev.Err) out = append(out, entry) } @@ -178,10 +180,11 @@ type dnsQueryType string func NewDNSQueriesList(begin time.Time, events []Event) []DNSQueryEntry { // TODO(bassosimone): add support for CNAME lookups. var out []DNSQueryEntry - for _, ev := range events { - if ev.Name != "resolve_done" { + for _, wrapper := range events { + if _, ok := wrapper.(*EventResolveDone); !ok { continue } + ev := wrapper.Value() for _, qtype := range []dnsQueryType{"A", "AAAA"} { entry := qtype.makeQueryEntry(begin, ev) for _, addr := range ev.Addresses { @@ -230,7 +233,7 @@ func (qtype dnsQueryType) makeAnswerEntry(addr string) DNSAnswerEntry { return answer } -func (qtype dnsQueryType) makeQueryEntry(begin time.Time, ev Event) DNSQueryEntry { +func (qtype dnsQueryType) makeQueryEntry(begin time.Time, ev *EventValue) DNSQueryEntry { return DNSQueryEntry{ Engine: ev.Proto, Failure: NewFailure(ev.Err), @@ -244,60 +247,54 @@ func (qtype dnsQueryType) makeQueryEntry(begin time.Time, ev Event) DNSQueryEntr // NewNetworkEventsList returns a list of DNS queries. func NewNetworkEventsList(begin time.Time, events []Event) []NetworkEvent { var out []NetworkEvent - for _, ev := range events { - if ev.Name == netxlite.ConnectOperation { + for _, wrapper := range events { + ev := wrapper.Value() + switch wrapper.(type) { + case *EventConnectOperation: out = append(out, NetworkEvent{ Address: ev.Address, Failure: NewFailure(ev.Err), - Operation: ev.Name, + Operation: wrapper.Name(), Proto: ev.Proto, T: ev.Time.Sub(begin).Seconds(), }) - continue - } - if ev.Name == netxlite.ReadOperation { + case *EventReadOperation: out = append(out, NetworkEvent{ Failure: NewFailure(ev.Err), - Operation: ev.Name, + Operation: wrapper.Name(), NumBytes: int64(ev.NumBytes), T: ev.Time.Sub(begin).Seconds(), }) - continue - } - if ev.Name == netxlite.WriteOperation { + case *EventWriteOperation: out = append(out, NetworkEvent{ Failure: NewFailure(ev.Err), - Operation: ev.Name, + Operation: wrapper.Name(), NumBytes: int64(ev.NumBytes), T: ev.Time.Sub(begin).Seconds(), }) - continue - } - if ev.Name == netxlite.ReadFromOperation { + case *EventReadFromOperation: out = append(out, NetworkEvent{ Address: ev.Address, Failure: NewFailure(ev.Err), - Operation: ev.Name, + Operation: wrapper.Name(), NumBytes: int64(ev.NumBytes), T: ev.Time.Sub(begin).Seconds(), }) - continue - } - if ev.Name == netxlite.WriteToOperation { + case *EventWriteToOperation: out = append(out, NetworkEvent{ Address: ev.Address, Failure: NewFailure(ev.Err), - Operation: ev.Name, + Operation: wrapper.Name(), NumBytes: int64(ev.NumBytes), T: ev.Time.Sub(begin).Seconds(), }) - continue + default: + out = append(out, NetworkEvent{ + Failure: NewFailure(ev.Err), + Operation: wrapper.Name(), + T: ev.Time.Sub(begin).Seconds(), + }) } - out = append(out, NetworkEvent{ - Failure: NewFailure(ev.Err), - Operation: ev.Name, - T: ev.Time.Sub(begin).Seconds(), - }) } return out } @@ -305,10 +302,13 @@ func NewNetworkEventsList(begin time.Time, events []Event) []NetworkEvent { // NewTLSHandshakesList creates a new TLSHandshakesList func NewTLSHandshakesList(begin time.Time, events []Event) []TLSHandshake { var out []TLSHandshake - for _, ev := range events { - if !strings.Contains(ev.Name, "_handshake_done") { - continue + for _, wrapper := range events { + switch wrapper.(type) { + case *EventQUICHandshakeDone, *EventTLSHandshakeDone: // ok + default: + continue // not interested } + ev := wrapper.Value() out = append(out, TLSHandshake{ Address: ev.Address, CipherSuite: ev.TLSCipherSuite, diff --git a/internal/engine/netx/tracex/archival_test.go b/internal/engine/netx/tracex/archival_test.go index a437d9692a..38f69065c6 100644 --- a/internal/engine/netx/tracex/archival_test.go +++ b/internal/engine/netx/tracex/archival_test.go @@ -74,31 +74,27 @@ func TestNewTCPConnectList(t *testing.T) { name: "realistic run", args: args{ begin: begin, - events: []Event{{ + events: []Event{&EventResolveDone{&EventValue{ Addresses: []string{"8.8.8.8", "8.8.4.4"}, Hostname: "dns.google.com", - Name: "resolve_done", Time: begin.Add(100 * time.Millisecond), - }, { + }}, &EventConnectOperation{&EventValue{ Address: "8.8.8.8:853", Duration: 30 * time.Millisecond, - Name: netxlite.ConnectOperation, Proto: "tcp", Time: begin.Add(130 * time.Millisecond), - }, { + }}, &EventConnectOperation{&EventValue{ Address: "8.8.8.8:853", Duration: 55 * time.Millisecond, - Name: netxlite.ConnectOperation, Proto: "udp", Time: begin.Add(130 * time.Millisecond), - }, { + }}, &EventConnectOperation{&EventValue{ Address: "8.8.4.4:53", Duration: 50 * time.Millisecond, Err: io.EOF, - Name: netxlite.ConnectOperation, Proto: "tcp", Time: begin.Add(180 * time.Millisecond), - }}, + }}}, }, want: []TCPConnectEntry{{ IP: "8.8.8.8", @@ -147,46 +143,36 @@ func TestNewRequestList(t *testing.T) { name: "realistic run", args: args{ begin: begin, - events: []Event{{ - Name: "http_transaction_start", + events: []Event{&EventHTTPTransactionStart{&EventValue{ Time: begin.Add(10 * time.Millisecond), - }, { - Name: "http_request_body_snapshot", + }}, &EventHTTPRequestBodySnapshot{&EventValue{ Data: []byte("deadbeef"), DataIsTruncated: false, - }, { - Name: "http_request_metadata", + }}, &EventHTTPRequestMetadata{&EventValue{ HTTPHeaders: http.Header{ "User-Agent": []string{"miniooni/0.1.0-dev"}, }, HTTPMethod: "POST", HTTPURL: "https://www.example.com/submit", - }, { - Name: "http_response_metadata", + }}, &EventHTTPResponseMetadata{&EventValue{ HTTPHeaders: http.Header{ "Server": []string{"miniooni/0.1.0-dev"}, }, HTTPStatusCode: 200, - }, { - Name: "http_response_body_snapshot", + }}, &EventHTTPResponseBodySnapshot{&EventValue{ Data: []byte("{}"), DataIsTruncated: false, - }, { - Name: "http_transaction_done", - }, { - Name: "http_transaction_start", + }}, &EventHTTPTransactionDone{&EventValue{}}, &EventHTTPTransactionStart{&EventValue{ Time: begin.Add(20 * time.Millisecond), - }, { - Name: "http_request_metadata", + }}, &EventHTTPRequestMetadata{&EventValue{ HTTPHeaders: http.Header{ "User-Agent": []string{"miniooni/0.1.0-dev"}, }, HTTPMethod: "GET", HTTPURL: "https://www.example.com/result", - }, { - Name: "http_transaction_done", - Err: io.EOF, - }}, + }}, &EventHTTPTransactionDone{&EventValue{ + Err: io.EOF, + }}}, }, want: []RequestEntry{{ Failure: NewFailure(io.EOF), @@ -245,26 +231,21 @@ func TestNewRequestList(t *testing.T) { name: "run with redirect and headers to sort", args: args{ begin: begin, - events: []Event{{ - Name: "http_transaction_start", + events: []Event{&EventHTTPTransactionStart{&EventValue{ Time: begin.Add(10 * time.Millisecond), - }, { - Name: "http_request_metadata", + }}, &EventHTTPRequestMetadata{&EventValue{ HTTPHeaders: http.Header{ "User-Agent": []string{"miniooni/0.1.0-dev"}, }, HTTPMethod: "GET", HTTPURL: "https://www.example.com/", - }, { - Name: "http_response_metadata", + }}, &EventHTTPResponseMetadata{&EventValue{ HTTPHeaders: http.Header{ "Server": []string{"miniooni/0.1.0-dev"}, "Location": []string{"https://x.example.com", "https://y.example.com"}, }, HTTPStatusCode: 302, - }, { - Name: "http_transaction_done", - }}, + }}, &EventHTTPTransactionDone{&EventValue{}}}, }, want: []RequestEntry{{ Request: HTTPRequest{ @@ -339,27 +320,24 @@ func TestNewDNSQueriesList(t *testing.T) { name: "realistic run", args: args{ begin: begin, - events: []Event{{ + events: []Event{&EventResolveDone{&EventValue{ Address: "1.1.1.1:853", Addresses: []string{"8.8.8.8", "8.8.4.4"}, Hostname: "dns.google.com", - Name: "resolve_done", Proto: "dot", Time: begin.Add(100 * time.Millisecond), - }, { + }}, &EventConnectOperation{&EventValue{ Address: "8.8.8.8:853", Duration: 30 * time.Millisecond, - Name: netxlite.ConnectOperation, Proto: "tcp", Time: begin.Add(130 * time.Millisecond), - }, { + }}, &EventConnectOperation{&EventValue{ Address: "8.8.4.4:53", Duration: 50 * time.Millisecond, Err: io.EOF, - Name: netxlite.ConnectOperation, Proto: "tcp", Time: begin.Add(180 * time.Millisecond), - }}, + }}}, }, want: []DNSQueryEntry{{ Answers: []DNSAnswerEntry{{ @@ -383,12 +361,11 @@ func TestNewDNSQueriesList(t *testing.T) { name: "run with IPv6 results", args: args{ begin: begin, - events: []Event{{ + events: []Event{&EventResolveDone{&EventValue{ Addresses: []string{"2001:4860:4860::8888"}, Hostname: "dns.google.com", - Name: "resolve_done", Time: begin.Add(200 * time.Millisecond), - }}, + }}}, }, want: []DNSQueryEntry{{ Answers: []DNSAnswerEntry{{ @@ -405,12 +382,11 @@ func TestNewDNSQueriesList(t *testing.T) { name: "run with errors", args: args{ begin: begin, - events: []Event{{ + events: []Event{&EventResolveDone{&EventValue{ Err: &netxlite.ErrWrapper{Failure: netxlite.FailureDNSNXDOMAINError}, Hostname: "dns.google.com", - Name: "resolve_done", Time: begin.Add(200 * time.Millisecond), - }}, + }}}, }, want: []DNSQueryEntry{{ Answers: nil, @@ -459,39 +435,30 @@ func TestNewNetworkEventsList(t *testing.T) { name: "realistic run", args: args{ begin: begin, - events: []Event{{ - Name: netxlite.ConnectOperation, + events: []Event{&EventConnectOperation{&EventValue{ Address: "8.8.8.8:853", Err: io.EOF, Proto: "tcp", Time: begin.Add(7 * time.Millisecond), - }, { - Name: netxlite.ReadOperation, + }}, &EventReadOperation{&EventValue{ Err: context.Canceled, NumBytes: 7117, Time: begin.Add(11 * time.Millisecond), - }, { + }}, &EventReadFromOperation{&EventValue{ Address: "8.8.8.8:853", - Name: netxlite.ReadFromOperation, Err: context.Canceled, NumBytes: 7117, Time: begin.Add(11 * time.Millisecond), - }, { - Name: netxlite.WriteOperation, + }}, &EventWriteOperation{&EventValue{ Err: websocket.ErrBadHandshake, NumBytes: 4114, Time: begin.Add(14 * time.Millisecond), - }, { + }}, &EventWriteToOperation{&EventValue{ Address: "8.8.8.8:853", - Name: netxlite.WriteToOperation, Err: websocket.ErrBadHandshake, NumBytes: 4114, Time: begin.Add(14 * time.Millisecond), - }, { - Name: netxlite.CloseOperation, - Err: websocket.ErrReadLimit, - Time: begin.Add(17 * time.Millisecond), - }}, + }}}, }, want: []NetworkEvent{{ Address: "8.8.8.8:853", @@ -521,10 +488,6 @@ func TestNewNetworkEventsList(t *testing.T) { NumBytes: 4114, Operation: netxlite.WriteToOperation, T: 0.014, - }, { - Failure: NewFailure(websocket.ErrReadLimit), - Operation: netxlite.CloseOperation, - T: 0.017, }}, }} for _, tt := range tests { @@ -557,13 +520,8 @@ func TestNewTLSHandshakesList(t *testing.T) { name: "realistic run", args: args{ begin: begin, - events: []Event{{ - Name: netxlite.CloseOperation, - Err: websocket.ErrReadLimit, - Time: begin.Add(17 * time.Millisecond), - }, { + events: []Event{&EventTLSHandshakeDone{&EventValue{ Address: "131.252.210.176:443", - Name: "tls_handshake_done", Err: io.EOF, NoTLSVerify: false, TLSCipherSuite: "SUITE", @@ -576,7 +534,7 @@ func TestNewTLSHandshakesList(t *testing.T) { TLSServerName: "x.org", TLSVersion: "TLSv1.3", Time: begin.Add(55 * time.Millisecond), - }}, + }}}, }, want: []TLSHandshake{{ Address: "131.252.210.176:443", diff --git a/internal/engine/netx/tracex/dialer.go b/internal/engine/netx/tracex/dialer.go index 528b93041b..5096b64289 100644 --- a/internal/engine/netx/tracex/dialer.go +++ b/internal/engine/netx/tracex/dialer.go @@ -10,7 +10,6 @@ import ( "time" "github.com/ooni/probe-cli/v3/internal/model" - "github.com/ooni/probe-cli/v3/internal/netxlite" ) // SaverDialer saves events occurring during the dial @@ -52,14 +51,13 @@ func (d *SaverDialer) DialContext(ctx context.Context, network, address string) start := time.Now() conn, err := d.Dialer.DialContext(ctx, network, address) stop := time.Now() - d.Saver.Write(Event{ + d.Saver.Write(&EventConnectOperation{&EventValue{ Address: address, Duration: stop.Sub(start), Err: err, - Name: netxlite.ConnectOperation, Proto: network, Time: stop, - }) + }}) return conn, err } @@ -124,14 +122,13 @@ func (c *saverConn) Read(p []byte) (int, error) { start := time.Now() count, err := c.Conn.Read(p) stop := time.Now() - c.saver.Write(Event{ + c.saver.Write(&EventReadOperation{&EventValue{ Data: p[:count], Duration: stop.Sub(start), Err: err, NumBytes: count, - Name: netxlite.ReadOperation, Time: stop, - }) + }}) return count, err } @@ -139,14 +136,13 @@ func (c *saverConn) Write(p []byte) (int, error) { start := time.Now() count, err := c.Conn.Write(p) stop := time.Now() - c.saver.Write(Event{ + c.saver.Write(&EventWriteOperation{&EventValue{ Data: p[:count], Duration: stop.Sub(start), Err: err, NumBytes: count, - Name: netxlite.WriteOperation, Time: stop, - }) + }}) return count, err } diff --git a/internal/engine/netx/tracex/dialer_test.go b/internal/engine/netx/tracex/dialer_test.go index 18299a6dcb..8608faa5c2 100644 --- a/internal/engine/netx/tracex/dialer_test.go +++ b/internal/engine/netx/tracex/dialer_test.go @@ -34,22 +34,22 @@ func TestSaverDialerFailure(t *testing.T) { if len(ev) != 1 { t.Fatal("expected a single event here") } - if ev[0].Address != "www.google.com:443" { + if ev[0].Value().Address != "www.google.com:443" { t.Fatal("unexpected Address") } - if ev[0].Duration <= 0 { + if ev[0].Value().Duration <= 0 { t.Fatal("unexpected Duration") } - if !errors.Is(ev[0].Err, expected) { + if !errors.Is(ev[0].Value().Err, expected) { t.Fatal("unexpected Err") } - if ev[0].Name != netxlite.ConnectOperation { + if ev[0].Name() != netxlite.ConnectOperation { t.Fatal("unexpected Name") } - if ev[0].Proto != "tcp" { + if ev[0].Value().Proto != "tcp" { t.Fatal("unexpected Proto") } - if !ev[0].Time.Before(time.Now()) { + if !ev[0].Value().Time.Before(time.Now()) { t.Fatal("unexpected Time") } } @@ -111,15 +111,15 @@ func TestSaverConnDialerSuccess(t *testing.T) { if len(events) != 3 { t.Fatal("unexpected number of events saved", len(events)) } - if events[0].Name != "connect" { + if events[0].Name() != "connect" { t.Fatal("expected a connect event") } saverCheckConnectEvent(t, &events[0]) - if events[1].Name != "read" { + if events[1].Name() != "read" { t.Fatal("expected a read event") } saverCheckReadEvent(t, &events[1]) - if events[2].Name != "write" { + if events[2].Name() != "write" { t.Fatal("expected a write event") } saverCheckWriteEvent(t, &events[2]) diff --git a/internal/engine/netx/tracex/event.go b/internal/engine/netx/tracex/event.go index 3509d6cd27..1be3c810dc 100644 --- a/internal/engine/netx/tracex/event.go +++ b/internal/engine/netx/tracex/event.go @@ -4,10 +4,268 @@ import ( "crypto/x509" "net/http" "time" + + "github.com/ooni/probe-cli/v3/internal/netxlite" ) +// Event is one of the events within a trace. +type Event interface { + // Value returns the event value + Value() *EventValue + + // Name returns the event name + Name() string +} + +// EventTLSHandshakeStart is the beginning of the TLS handshake. +type EventTLSHandshakeStart struct { + V *EventValue +} + +func (ev *EventTLSHandshakeStart) Value() *EventValue { + return ev.V +} + +func (ev *EventTLSHandshakeStart) Name() string { + return "tls_handshake_start" +} + +// EventTLSHandshakeDone is the end of the TLS handshake. +type EventTLSHandshakeDone struct { + V *EventValue +} + +func (ev *EventTLSHandshakeDone) Value() *EventValue { + return ev.V +} + +func (ev *EventTLSHandshakeDone) Name() string { + return "tls_handshake_done" +} + +// EventResolveStart is the beginning of a DNS lookup operation. +type EventResolveStart struct { + V *EventValue +} + +func (ev *EventResolveStart) Value() *EventValue { + return ev.V +} + +func (ev *EventResolveStart) Name() string { + return "resolve_start" +} + +// EventResolveDone is the end of a DNS lookup operation. +type EventResolveDone struct { + V *EventValue +} + +func (ev *EventResolveDone) Value() *EventValue { + return ev.V +} + +func (ev *EventResolveDone) Name() string { + return "resolve_done" +} + +// EventDNSRoundTripStart is the start of a DNS round trip. +type EventDNSRoundTripStart struct { + V *EventValue +} + +func (ev *EventDNSRoundTripStart) Value() *EventValue { + return ev.V +} + +func (ev *EventDNSRoundTripStart) Name() string { + return "dns_round_trip_start" +} + +// EventDNSRoundTripDone is the end of a DNS round trip. +type EventDNSRoundTripDone struct { + V *EventValue +} + +func (ev *EventDNSRoundTripDone) Value() *EventValue { + return ev.V +} + +func (ev *EventDNSRoundTripDone) Name() string { + return "dns_round_trip_done" +} + +// EventQUICHandshakeStart is the start of a QUIC handshake. +type EventQUICHandshakeStart struct { + V *EventValue +} + +func (ev *EventQUICHandshakeStart) Value() *EventValue { + return ev.V +} + +func (ev *EventQUICHandshakeStart) Name() string { + return "quic_handshake_start" +} + +// EventQUICHandshakeDone is the end of a QUIC handshake. +type EventQUICHandshakeDone struct { + V *EventValue +} + +func (ev *EventQUICHandshakeDone) Value() *EventValue { + return ev.V +} + +func (ev *EventQUICHandshakeDone) Name() string { + return "quic_handshake_done" +} + +// EventWriteToOperation summarizes the WriteTo operation. +type EventWriteToOperation struct { + V *EventValue +} + +func (ev *EventWriteToOperation) Value() *EventValue { + return ev.V +} + +func (ev *EventWriteToOperation) Name() string { + return netxlite.WriteToOperation +} + +// EventReadFromOperation summarizes the ReadFrom operation. +type EventReadFromOperation struct { + V *EventValue +} + +func (ev *EventReadFromOperation) Value() *EventValue { + return ev.V +} + +func (ev *EventReadFromOperation) Name() string { + return netxlite.ReadFromOperation +} + +// EventHTTPRequestMetadata contains HTTP request metadata. +type EventHTTPRequestMetadata struct { + V *EventValue +} + +func (ev *EventHTTPRequestMetadata) Value() *EventValue { + return ev.V +} + +func (ev *EventHTTPRequestMetadata) Name() string { + return "http_request_metadata" +} + +// EventHTTPResponseMetadata contains HTTP response metadata. +type EventHTTPResponseMetadata struct { + V *EventValue +} + +func (ev *EventHTTPResponseMetadata) Value() *EventValue { + return ev.V +} + +func (ev *EventHTTPResponseMetadata) Name() string { + return "http_response_metadata" +} + +// EventHTTPTransactionStart is the beginning of an HTTP transaction. +type EventHTTPTransactionStart struct { + V *EventValue +} + +func (ev *EventHTTPTransactionStart) Value() *EventValue { + return ev.V +} + +func (ev *EventHTTPTransactionStart) Name() string { + return "http_transaction_start" +} + +// EventHTTPTransactionDone is the end of an HTTP transaction. +type EventHTTPTransactionDone struct { + V *EventValue +} + +func (ev *EventHTTPTransactionDone) Value() *EventValue { + return ev.V +} + +func (ev *EventHTTPTransactionDone) Name() string { + return "http_transaction_done" +} + +// EventHTTPRequestBodySnapshot contains a snapshot of the request body. +type EventHTTPRequestBodySnapshot struct { + V *EventValue +} + +func (ev *EventHTTPRequestBodySnapshot) Value() *EventValue { + return ev.V +} + +func (ev *EventHTTPRequestBodySnapshot) Name() string { + return "http_request_body_snapshot" +} + +// EventHTTPResponseBodySnapshot contains a snapshot of the response body. +type EventHTTPResponseBodySnapshot struct { + V *EventValue +} + +func (ev *EventHTTPResponseBodySnapshot) Value() *EventValue { + return ev.V +} + +func (ev *EventHTTPResponseBodySnapshot) Name() string { + return "http_response_body_snapshot" +} + +// EventConnectOperation contains information about the connect operation. +type EventConnectOperation struct { + V *EventValue +} + +func (ev *EventConnectOperation) Value() *EventValue { + return ev.V +} + +func (ev *EventConnectOperation) Name() string { + return netxlite.ConnectOperation +} + +// EventReadOperation contains information about a read operation. +type EventReadOperation struct { + V *EventValue +} + +func (ev *EventReadOperation) Value() *EventValue { + return ev.V +} + +func (ev *EventReadOperation) Name() string { + return netxlite.ReadOperation +} + +// EventWriteOperation contains information about a write operation. +type EventWriteOperation struct { + V *EventValue +} + +func (ev *EventWriteOperation) Value() *EventValue { + return ev.V +} + +func (ev *EventWriteOperation) Name() string { + return netxlite.WriteOperation +} + // Event is one of the events within a trace -type Event struct { +type EventValue struct { Addresses []string `json:",omitempty"` Address string `json:",omitempty"` DNSQuery []byte `json:",omitempty"` @@ -21,7 +279,6 @@ type Event struct { HTTPStatusCode int `json:",omitempty"` HTTPURL string `json:",omitempty"` Hostname string `json:",omitempty"` - Name string `json:",omitempty"` NoTLSVerify bool `json:",omitempty"` NumBytes int `json:",omitempty"` Proto string `json:",omitempty"` diff --git a/internal/engine/netx/tracex/http.go b/internal/engine/netx/tracex/http.go index 03d15f9677..4e68ea0158 100644 --- a/internal/engine/netx/tracex/http.go +++ b/internal/engine/netx/tracex/http.go @@ -24,24 +24,22 @@ type SaverMetadataHTTPTransport struct { // RoundTrip implements RoundTripper.RoundTrip func (txp SaverMetadataHTTPTransport) RoundTrip(req *http.Request) (*http.Response, error) { - txp.Saver.Write(Event{ + txp.Saver.Write(&EventHTTPRequestMetadata{&EventValue{ HTTPHeaders: httpCloneHeaders(req), HTTPMethod: req.Method, HTTPURL: req.URL.String(), Transport: txp.HTTPTransport.Network(), - Name: "http_request_metadata", Time: time.Now(), - }) + }}) resp, err := txp.HTTPTransport.RoundTrip(req) if err != nil { return nil, err } - txp.Saver.Write(Event{ + txp.Saver.Write(&EventHTTPResponseMetadata{&EventValue{ HTTPHeaders: resp.Header, HTTPStatusCode: resp.StatusCode, - Name: "http_response_metadata", Time: time.Now(), - }) + }}) return resp, err } @@ -67,16 +65,14 @@ type SaverTransactionHTTPTransport struct { // RoundTrip implements RoundTripper.RoundTrip func (txp SaverTransactionHTTPTransport) RoundTrip(req *http.Request) (*http.Response, error) { - txp.Saver.Write(Event{ - Name: "http_transaction_start", + txp.Saver.Write(&EventHTTPTransactionStart{&EventValue{ Time: time.Now(), - }) + }}) resp, err := txp.HTTPTransport.RoundTrip(req) - txp.Saver.Write(Event{ + txp.Saver.Write(&EventHTTPTransactionDone{&EventValue{ Err: err, - Name: "http_transaction_done", Time: time.Now(), - }) + }}) return resp, err } @@ -101,12 +97,11 @@ func (txp SaverBodyHTTPTransport) RoundTrip(req *http.Request) (*http.Response, return nil, err } req.Body = httpSaverCompose(data, req.Body) - txp.Saver.Write(Event{ + txp.Saver.Write(&EventHTTPRequestBodySnapshot{&EventValue{ DataIsTruncated: len(data) >= snapsize, Data: data, - Name: "http_request_body_snapshot", Time: time.Now(), - }) + }}) } resp, err := txp.HTTPTransport.RoundTrip(req) if err != nil { @@ -118,12 +113,11 @@ func (txp SaverBodyHTTPTransport) RoundTrip(req *http.Request) (*http.Response, return nil, err } resp.Body = httpSaverCompose(data, resp.Body) - txp.Saver.Write(Event{ + txp.Saver.Write(&EventHTTPResponseBodySnapshot{&EventValue{ DataIsTruncated: len(data) >= snapsize, Data: data, - Name: "http_response_body_snapshot", Time: time.Now(), - }) + }}) return resp, nil } diff --git a/internal/engine/netx/tracex/http_test.go b/internal/engine/netx/tracex/http_test.go index c0285a01bd..36f1b0ea1e 100644 --- a/internal/engine/netx/tracex/http_test.go +++ b/internal/engine/netx/tracex/http_test.go @@ -41,32 +41,32 @@ func TestSaverMetadataSuccess(t *testing.T) { t.Fatal("expected two events") } // - if ev[0].HTTPMethod != "GET" { + if ev[0].Value().HTTPMethod != "GET" { t.Fatal("unexpected Method") } - if len(ev[0].HTTPHeaders) <= 0 { + if len(ev[0].Value().HTTPHeaders) <= 0 { t.Fatal("unexpected Headers") } - if ev[0].HTTPURL != "https://www.google.com" { + if ev[0].Value().HTTPURL != "https://www.google.com" { t.Fatal("unexpected URL") } - if ev[0].Name != "http_request_metadata" { + if ev[0].Name() != "http_request_metadata" { t.Fatal("unexpected Name") } - if !ev[0].Time.Before(time.Now()) { + if !ev[0].Value().Time.Before(time.Now()) { t.Fatal("unexpected Time") } // - if ev[1].HTTPStatusCode != 200 { + if ev[1].Value().HTTPStatusCode != 200 { t.Fatal("unexpected StatusCode") } - if len(ev[1].HTTPHeaders) <= 0 { + if len(ev[1].Value().HTTPHeaders) <= 0 { t.Fatal("unexpected Headers") } - if ev[1].Name != "http_response_metadata" { + if ev[1].Name() != "http_response_metadata" { t.Fatal("unexpected Name") } - if !ev[1].Time.After(ev[0].Time) { + if !ev[1].Value().Time.After(ev[0].Value().Time) { t.Fatal("unexpected Time") } } @@ -96,19 +96,19 @@ func TestSaverMetadataFailure(t *testing.T) { if len(ev) != 1 { t.Fatal("expected one event") } - if ev[0].HTTPMethod != "GET" { + if ev[0].Value().HTTPMethod != "GET" { t.Fatal("unexpected Method") } - if len(ev[0].HTTPHeaders) <= 0 { + if len(ev[0].Value().HTTPHeaders) <= 0 { t.Fatal("unexpected Headers") } - if ev[0].HTTPURL != "http://www.google.com" { + if ev[0].Value().HTTPURL != "http://www.google.com" { t.Fatal("unexpected URL") } - if ev[0].Name != "http_request_metadata" { + if ev[0].Name() != "http_request_metadata" { t.Fatal("unexpected Name") } - if !ev[0].Time.Before(time.Now()) { + if !ev[0].Value().Time.Before(time.Now()) { t.Fatal("unexpected Time") } } @@ -138,20 +138,20 @@ func TestSaverTransactionSuccess(t *testing.T) { t.Fatal("expected two events") } // - if ev[0].Name != "http_transaction_start" { + if ev[0].Name() != "http_transaction_start" { t.Fatal("unexpected Name") } - if !ev[0].Time.Before(time.Now()) { + if !ev[0].Value().Time.Before(time.Now()) { t.Fatal("unexpected Time") } // - if ev[1].Err != nil { + if ev[1].Value().Err != nil { t.Fatal("unexpected Err") } - if ev[1].Name != "http_transaction_done" { + if ev[1].Name() != "http_transaction_done" { t.Fatal("unexpected Name") } - if !ev[1].Time.After(ev[0].Time) { + if !ev[1].Value().Time.After(ev[0].Value().Time) { t.Fatal("unexpected Time") } } @@ -180,19 +180,19 @@ func TestSaverTransactionFailure(t *testing.T) { if len(ev) != 2 { t.Fatal("expected two events") } - if ev[0].Name != "http_transaction_start" { + if ev[0].Name() != "http_transaction_start" { t.Fatal("unexpected Name") } - if !ev[0].Time.Before(time.Now()) { + if !ev[0].Value().Time.Before(time.Now()) { t.Fatal("unexpected Time") } - if ev[1].Name != "http_transaction_done" { + if ev[1].Name() != "http_transaction_done" { t.Fatal("unexpected Name") } - if !errors.Is(ev[1].Err, expected) { + if !errors.Is(ev[1].Value().Err, expected) { t.Fatal("unexpected Err") } - if !ev[1].Time.After(ev[0].Time) { + if !ev[1].Value().Time.After(ev[0].Value().Time) { t.Fatal("unexpected Time") } } @@ -242,28 +242,28 @@ func TestSaverBodySuccess(t *testing.T) { if len(ev) != 2 { t.Fatal("unexpected number of events") } - if string(ev[0].Data) != "dead" { + if string(ev[0].Value().Data) != "dead" { t.Fatal("invalid Data") } - if ev[0].DataIsTruncated != true { + if ev[0].Value().DataIsTruncated != true { t.Fatal("invalid DataIsTruncated") } - if ev[0].Name != "http_request_body_snapshot" { + if ev[0].Name() != "http_request_body_snapshot" { t.Fatal("invalid Name") } - if ev[0].Time.After(time.Now()) { + if ev[0].Value().Time.After(time.Now()) { t.Fatal("invalid Time") } - if string(ev[1].Data) != "abad" { + if string(ev[1].Value().Data) != "abad" { t.Fatal("invalid Data") } - if ev[1].DataIsTruncated != true { + if ev[1].Value().DataIsTruncated != true { t.Fatal("invalid DataIsTruncated") } - if ev[1].Name != "http_response_body_snapshot" { + if ev[1].Name() != "http_response_body_snapshot" { t.Fatal("invalid Name") } - if ev[1].Time.Before(ev[0].Time) { + if ev[1].Value().Time.Before(ev[0].Value().Time) { t.Fatal("invalid Time") } } @@ -324,16 +324,16 @@ func TestSaverBodyRoundTripError(t *testing.T) { if len(ev) != 1 { t.Fatal("unexpected number of events") } - if string(ev[0].Data) != "dead" { + if string(ev[0].Value().Data) != "dead" { t.Fatal("invalid Data") } - if ev[0].DataIsTruncated != true { + if ev[0].Value().DataIsTruncated != true { t.Fatal("invalid DataIsTruncated") } - if ev[0].Name != "http_request_body_snapshot" { + if ev[0].Name() != "http_request_body_snapshot" { t.Fatal("invalid Name") } - if ev[0].Time.After(time.Now()) { + if ev[0].Value().Time.After(time.Now()) { t.Fatal("invalid Time") } } @@ -371,16 +371,16 @@ func TestSaverBodyResponseReadError(t *testing.T) { if len(ev) != 1 { t.Fatal("unexpected number of events") } - if string(ev[0].Data) != "dead" { + if string(ev[0].Value().Data) != "dead" { t.Fatal("invalid Data") } - if ev[0].DataIsTruncated != true { + if ev[0].Value().DataIsTruncated != true { t.Fatal("invalid DataIsTruncated") } - if ev[0].Name != "http_request_body_snapshot" { + if ev[0].Name() != "http_request_body_snapshot" { t.Fatal("invalid Name") } - if ev[0].Time.After(time.Now()) { + if ev[0].Value().Time.After(time.Now()) { t.Fatal("invalid Time") } } diff --git a/internal/engine/netx/tracex/quic.go b/internal/engine/netx/tracex/quic.go index 6a11de9d83..fb4f2c7d81 100644 --- a/internal/engine/netx/tracex/quic.go +++ b/internal/engine/netx/tracex/quic.go @@ -45,34 +45,31 @@ func (h *QUICHandshakeSaver) DialContext(ctx context.Context, network string, 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{ + h.Saver.Write(&EventQUICHandshakeStart{&EventValue{ 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 { // TODO(bassosimone): here we should save the peer certs - h.Saver.Write(Event{ + h.Saver.Write(&EventQUICHandshakeDone{&EventValue{ 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{ + h.Saver.Write(&EventQUICHandshakeDone{&EventValue{ Duration: stop.Sub(start), - Name: "quic_handshake_done", NoTLSVerify: tlsCfg.InsecureSkipVerify, TLSCipherSuite: netxlite.TLSCipherSuiteString(state.CipherSuite), TLSNegotiatedProto: state.NegotiatedProtocol, @@ -81,7 +78,7 @@ func (h *QUICHandshakeSaver) DialContext(ctx context.Context, network string, TLSServerName: tlsCfg.ServerName, TLSVersion: netxlite.TLSVersionString(state.Version), Time: stop, - }) + }}) return sess, nil } @@ -144,15 +141,14 @@ func (c *udpLikeConnSaver) 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{ + c.saver.Write(&EventWriteToOperation{&EventValue{ Address: addr.String(), Data: p[:count], Duration: stop.Sub(start), Err: err, NumBytes: count, - Name: netxlite.WriteToOperation, Time: stop, - }) + }}) return count, err } @@ -164,15 +160,14 @@ func (c *udpLikeConnSaver) ReadFrom(b []byte) (int, net.Addr, error) { if n > 0 { data = b[:n] } - c.saver.Write(Event{ + c.saver.Write(&EventReadFromOperation{&EventValue{ Address: c.safeAddrString(addr), Data: data, Duration: stop.Sub(start), Err: err, NumBytes: n, - Name: netxlite.ReadFromOperation, Time: stop, - }) + }}) return n, addr, err } diff --git a/internal/engine/netx/tracex/quic_test.go b/internal/engine/netx/tracex/quic_test.go index 143de7faca..804cbb6c30 100644 --- a/internal/engine/netx/tracex/quic_test.go +++ b/internal/engine/netx/tracex/quic_test.go @@ -54,34 +54,34 @@ func TestHandshakeSaverSuccess(t *testing.T) { if len(ev) != 2 { t.Fatal("unexpected number of events") } - if ev[0].Name != "quic_handshake_start" { + if ev[0].Name() != "quic_handshake_start" { t.Fatal("unexpected Name") } - if ev[0].TLSServerName != quictesting.Domain { + if ev[0].Value().TLSServerName != quictesting.Domain { t.Fatal("unexpected TLSServerName") } - if !reflect.DeepEqual(ev[0].TLSNextProtos, nextprotos) { + if !reflect.DeepEqual(ev[0].Value().TLSNextProtos, nextprotos) { t.Fatal("unexpected TLSNextProtos") } - if ev[0].Time.After(time.Now()) { + if ev[0].Value().Time.After(time.Now()) { t.Fatal("unexpected Time") } - if ev[1].Duration <= 0 { + if ev[1].Value().Duration <= 0 { t.Fatal("unexpected Duration") } - if ev[1].Err != nil { - t.Fatal("unexpected Err", ev[1].Err) + if ev[1].Value().Err != nil { + t.Fatal("unexpected Err", ev[1].Value().Err) } - if ev[1].Name != "quic_handshake_done" { + if ev[1].Name() != "quic_handshake_done" { t.Fatal("unexpected Name") } - if !reflect.DeepEqual(ev[1].TLSNextProtos, nextprotos) { + if !reflect.DeepEqual(ev[1].Value().TLSNextProtos, nextprotos) { t.Fatal("unexpected TLSNextProtos") } - if ev[1].TLSServerName != quictesting.Domain { + if ev[1].Value().TLSServerName != quictesting.Domain { t.Fatal("unexpected TLSServerName") } - if ev[1].Time.Before(ev[0].Time) { + if ev[1].Value().Time.Before(ev[0].Value().Time) { t.Fatal("unexpected Time") } } @@ -106,14 +106,14 @@ func TestHandshakeSaverHostNameError(t *testing.T) { t.Fatal("expected nil sess here") } for _, ev := range saver.Read() { - if ev.Name != "quic_handshake_done" { + if ev.Name() != "quic_handshake_done" { continue } - if ev.NoTLSVerify == true { + if ev.Value().NoTLSVerify == true { t.Fatal("expected NoTLSVerify to be false") } - if !strings.HasSuffix(ev.Err.Error(), "tls: handshake failure") { - t.Fatal("unexpected error", ev.Err) + if !strings.HasSuffix(ev.Value().Err.Error(), "tls: handshake failure") { + t.Fatal("unexpected error", ev.Value().Err) } } } @@ -160,25 +160,25 @@ func TestSystemDialerSuccessWithReadWrite(t *testing.T) { } last := len(ev) - 1 for idx := 1; idx < last; idx++ { - if ev[idx].Data == nil { + if ev[idx].Value().Data == nil { t.Fatal("unexpected Data") } - if ev[idx].Duration <= 0 { + if ev[idx].Value().Duration <= 0 { t.Fatal("unexpected Duration") } - if ev[idx].Err != nil { + if ev[idx].Value().Err != nil { t.Fatal("unexpected Err") } - if ev[idx].NumBytes <= 0 { + if ev[idx].Value().NumBytes <= 0 { t.Fatal("unexpected NumBytes") } - switch ev[idx].Name { + 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) + if ev[idx].Value().Time.Before(ev[idx-1].Value().Time) { + t.Fatal("unexpected Time", ev[idx].Value().Time, ev[idx-1].Value().Time) } } } diff --git a/internal/engine/netx/tracex/resolver.go b/internal/engine/netx/tracex/resolver.go index 8e5c7c8657..aa45a45375 100644 --- a/internal/engine/netx/tracex/resolver.go +++ b/internal/engine/netx/tracex/resolver.go @@ -39,25 +39,23 @@ func (s *Saver) WrapResolver(r model.Resolver) model.Resolver { // LookupHost implements Resolver.LookupHost func (r *SaverResolver) LookupHost(ctx context.Context, hostname string) ([]string, error) { start := time.Now() - r.Saver.Write(Event{ + r.Saver.Write(&EventResolveStart{&EventValue{ Address: r.Resolver.Address(), Hostname: hostname, - Name: "resolve_start", Proto: r.Resolver.Network(), Time: start, - }) + }}) addrs, err := r.Resolver.LookupHost(ctx, hostname) stop := time.Now() - r.Saver.Write(Event{ + r.Saver.Write(&EventResolveDone{&EventValue{ Addresses: addrs, Address: r.Resolver.Address(), Duration: stop.Sub(start), Err: err, Hostname: hostname, - Name: "resolve_done", Proto: r.Resolver.Network(), Time: stop, - }) + }}) return addrs, err } @@ -111,25 +109,23 @@ func (s *Saver) WrapDNSTransport(txp model.DNSTransport) model.DNSTransport { func (txp *SaverDNSTransport) RoundTrip( ctx context.Context, query model.DNSQuery) (model.DNSResponse, error) { start := time.Now() - txp.Saver.Write(Event{ + txp.Saver.Write(&EventDNSRoundTripStart{&EventValue{ Address: txp.DNSTransport.Address(), DNSQuery: dnsMaybeQueryBytes(query), - Name: "dns_round_trip_start", Proto: txp.DNSTransport.Network(), Time: start, - }) + }}) response, err := txp.DNSTransport.RoundTrip(ctx, query) stop := time.Now() - txp.Saver.Write(Event{ + txp.Saver.Write(&EventDNSRoundTripDone{&EventValue{ Address: txp.DNSTransport.Address(), DNSQuery: dnsMaybeQueryBytes(query), DNSReply: dnsMaybeResponseBytes(response), Duration: stop.Sub(start), Err: err, - Name: "dns_round_trip_done", Proto: txp.DNSTransport.Network(), Time: stop, - }) + }}) return response, err } diff --git a/internal/engine/netx/tracex/resolver_test.go b/internal/engine/netx/tracex/resolver_test.go index 643a0a2878..4dc7066271 100644 --- a/internal/engine/netx/tracex/resolver_test.go +++ b/internal/engine/netx/tracex/resolver_test.go @@ -29,31 +29,31 @@ func TestSaverResolverFailure(t *testing.T) { if len(ev) != 2 { t.Fatal("expected number of events") } - if ev[0].Hostname != "www.google.com" { + if ev[0].Value().Hostname != "www.google.com" { t.Fatal("unexpected Hostname") } - if ev[0].Name != "resolve_start" { + if ev[0].Name() != "resolve_start" { t.Fatal("unexpected name") } - if !ev[0].Time.Before(time.Now()) { + if !ev[0].Value().Time.Before(time.Now()) { t.Fatal("the saved time is wrong") } - if ev[1].Addresses != nil { + if ev[1].Value().Addresses != nil { t.Fatal("unexpected Addresses") } - if ev[1].Duration <= 0 { + if ev[1].Value().Duration <= 0 { t.Fatal("unexpected Duration") } - if !errors.Is(ev[1].Err, expected) { + if !errors.Is(ev[1].Value().Err, expected) { t.Fatal("unexpected Err") } - if ev[1].Hostname != "www.google.com" { + if ev[1].Value().Hostname != "www.google.com" { t.Fatal("unexpected Hostname") } - if ev[1].Name != "resolve_done" { + if ev[1].Name() != "resolve_done" { t.Fatal("unexpected name") } - if !ev[1].Time.After(ev[0].Time) { + if !ev[1].Value().Time.After(ev[0].Value().Time) { t.Fatal("the saved time is wrong") } } @@ -73,31 +73,31 @@ func TestSaverResolverSuccess(t *testing.T) { if len(ev) != 2 { t.Fatal("expected number of events") } - if ev[0].Hostname != "www.google.com" { + if ev[0].Value().Hostname != "www.google.com" { t.Fatal("unexpected Hostname") } - if ev[0].Name != "resolve_start" { + if ev[0].Name() != "resolve_start" { t.Fatal("unexpected name") } - if !ev[0].Time.Before(time.Now()) { + if !ev[0].Value().Time.Before(time.Now()) { t.Fatal("the saved time is wrong") } - if !reflect.DeepEqual(ev[1].Addresses, expected) { + if !reflect.DeepEqual(ev[1].Value().Addresses, expected) { t.Fatal("unexpected Addresses") } - if ev[1].Duration <= 0 { + if ev[1].Value().Duration <= 0 { t.Fatal("unexpected Duration") } - if ev[1].Err != nil { + if ev[1].Value().Err != nil { t.Fatal("unexpected Err") } - if ev[1].Hostname != "www.google.com" { + if ev[1].Value().Hostname != "www.google.com" { t.Fatal("unexpected Hostname") } - if ev[1].Name != "resolve_done" { + if ev[1].Name() != "resolve_done" { t.Fatal("unexpected name") } - if !ev[1].Time.After(ev[0].Time) { + if !ev[1].Value().Time.After(ev[0].Value().Time) { t.Fatal("the saved time is wrong") } } @@ -133,31 +133,31 @@ func TestSaverDNSTransportFailure(t *testing.T) { if len(ev) != 2 { t.Fatal("expected number of events") } - if !bytes.Equal(ev[0].DNSQuery, rawQuery) { + if !bytes.Equal(ev[0].Value().DNSQuery, rawQuery) { t.Fatal("unexpected DNSQuery") } - if ev[0].Name != "dns_round_trip_start" { + if ev[0].Name() != "dns_round_trip_start" { t.Fatal("unexpected name") } - if !ev[0].Time.Before(time.Now()) { + if !ev[0].Value().Time.Before(time.Now()) { t.Fatal("the saved time is wrong") } - if !bytes.Equal(ev[1].DNSQuery, rawQuery) { + if !bytes.Equal(ev[1].Value().DNSQuery, rawQuery) { t.Fatal("unexpected DNSQuery") } - if ev[1].DNSReply != nil { + if ev[1].Value().DNSReply != nil { t.Fatal("unexpected DNSReply") } - if ev[1].Duration <= 0 { + if ev[1].Value().Duration <= 0 { t.Fatal("unexpected Duration") } - if !errors.Is(ev[1].Err, expected) { + if !errors.Is(ev[1].Value().Err, expected) { t.Fatal("unexpected Err") } - if ev[1].Name != "dns_round_trip_done" { + if ev[1].Name() != "dns_round_trip_done" { t.Fatal("unexpected name") } - if !ev[1].Time.After(ev[0].Time) { + if !ev[1].Value().Time.After(ev[0].Value().Time) { t.Fatal("the saved time is wrong") } } @@ -198,31 +198,31 @@ func TestSaverDNSTransportSuccess(t *testing.T) { if len(ev) != 2 { t.Fatal("expected number of events") } - if !bytes.Equal(ev[0].DNSQuery, rawQuery) { + if !bytes.Equal(ev[0].Value().DNSQuery, rawQuery) { t.Fatal("unexpected DNSQuery") } - if ev[0].Name != "dns_round_trip_start" { + if ev[0].Name() != "dns_round_trip_start" { t.Fatal("unexpected name") } - if !ev[0].Time.Before(time.Now()) { + if !ev[0].Value().Time.Before(time.Now()) { t.Fatal("the saved time is wrong") } - if !bytes.Equal(ev[1].DNSQuery, rawQuery) { + if !bytes.Equal(ev[1].Value().DNSQuery, rawQuery) { t.Fatal("unexpected DNSQuery") } - if !bytes.Equal(ev[1].DNSReply, expected) { + if !bytes.Equal(ev[1].Value().DNSReply, expected) { t.Fatal("unexpected DNSReply") } - if ev[1].Duration <= 0 { + if ev[1].Value().Duration <= 0 { t.Fatal("unexpected Duration") } - if ev[1].Err != nil { + if ev[1].Value().Err != nil { t.Fatal("unexpected Err") } - if ev[1].Name != "dns_round_trip_done" { + if ev[1].Name() != "dns_round_trip_done" { t.Fatal("unexpected name") } - if !ev[1].Time.After(ev[0].Time) { + if !ev[1].Value().Time.After(ev[0].Value().Time) { t.Fatal("the saved time is wrong") } } diff --git a/internal/engine/netx/tracex/saver_test.go b/internal/engine/netx/tracex/saver_test.go index f4122539ff..784e168b1c 100644 --- a/internal/engine/netx/tracex/saver_test.go +++ b/internal/engine/netx/tracex/saver_test.go @@ -12,7 +12,7 @@ func TestSaver(t *testing.T) { wg.Add(parallel) for idx := 0; idx < parallel; idx++ { go func() { - saver.Write(Event{}) + saver.Write(&EventReadFromOperation{&EventValue{}}) wg.Done() }() } diff --git a/internal/engine/netx/tracex/tls.go b/internal/engine/netx/tracex/tls.go index 9ce4098ad3..32eb51cb46 100644 --- a/internal/engine/netx/tracex/tls.go +++ b/internal/engine/netx/tracex/tls.go @@ -44,21 +44,19 @@ func (s *Saver) WrapTLSHandshaker(thx model.TLSHandshaker) model.TLSHandshaker { func (h *SaverTLSHandshaker) Handshake( ctx context.Context, conn net.Conn, config *tls.Config) (net.Conn, tls.ConnectionState, error) { start := time.Now() - h.Saver.Write(Event{ - Name: "tls_handshake_start", + h.Saver.Write(&EventTLSHandshakeStart{&EventValue{ NoTLSVerify: config.InsecureSkipVerify, TLSNextProtos: config.NextProtos, TLSServerName: config.ServerName, Time: start, - }) + }}) remoteAddr := conn.RemoteAddr().String() tlsconn, state, err := h.TLSHandshaker.Handshake(ctx, conn, config) stop := time.Now() - h.Saver.Write(Event{ + h.Saver.Write(&EventTLSHandshakeDone{&EventValue{ Address: remoteAddr, Duration: stop.Sub(start), Err: err, - Name: "tls_handshake_done", NoTLSVerify: config.InsecureSkipVerify, TLSCipherSuite: netxlite.TLSCipherSuiteString(state.CipherSuite), TLSNegotiatedProto: state.NegotiatedProtocol, @@ -67,7 +65,7 @@ func (h *SaverTLSHandshaker) Handshake( TLSServerName: config.ServerName, TLSVersion: netxlite.TLSVersionString(state.Version), Time: stop, - }) + }}) return tlsconn, state, err } diff --git a/internal/engine/netx/tracex/tls_test.go b/internal/engine/netx/tracex/tls_test.go index 5a322a0c9b..96da0c6541 100644 --- a/internal/engine/netx/tracex/tls_test.go +++ b/internal/engine/netx/tracex/tls_test.go @@ -39,69 +39,69 @@ func TestSaverTLSHandshakerSuccessWithReadWrite(t *testing.T) { // events because network conditions may influence that t.Fatal("unexpected number of events") } - if ev[0].Name != "tls_handshake_start" { + if ev[0].Name() != "tls_handshake_start" { t.Fatal("unexpected Name") } - if ev[0].TLSServerName != "www.google.com" { + if ev[0].Value().TLSServerName != "www.google.com" { t.Fatal("unexpected TLSServerName") } - if !reflect.DeepEqual(ev[0].TLSNextProtos, nextprotos) { + if !reflect.DeepEqual(ev[0].Value().TLSNextProtos, nextprotos) { t.Fatal("unexpected TLSNextProtos") } - if ev[0].Time.After(time.Now()) { + if ev[0].Value().Time.After(time.Now()) { t.Fatal("unexpected Time") } last := len(ev) - 1 for idx := 1; idx < last; idx++ { - if ev[idx].Data == nil { + if ev[idx].Value().Data == nil { t.Fatal("unexpected Data") } - if ev[idx].Duration <= 0 { + if ev[idx].Value().Duration <= 0 { t.Fatal("unexpected Duration") } - if ev[idx].Err != nil { + if ev[idx].Value().Err != nil { t.Fatal("unexpected Err") } - if ev[idx].NumBytes <= 0 { + if ev[idx].Value().NumBytes <= 0 { t.Fatal("unexpected NumBytes") } - switch ev[idx].Name { + switch ev[idx].Name() { case netxlite.ReadOperation, netxlite.WriteOperation: default: t.Fatal("unexpected Name") } - if ev[idx].Time.Before(ev[idx-1].Time) { + if ev[idx].Value().Time.Before(ev[idx-1].Value().Time) { t.Fatal("unexpected Time") } } - if ev[last].Duration <= 0 { + if ev[last].Value().Duration <= 0 { t.Fatal("unexpected Duration") } - if ev[last].Err != nil { + if ev[last].Value().Err != nil { t.Fatal("unexpected Err") } - if ev[last].Name != "tls_handshake_done" { + if ev[last].Name() != "tls_handshake_done" { t.Fatal("unexpected Name") } - if ev[last].TLSCipherSuite == "" { + if ev[last].Value().TLSCipherSuite == "" { t.Fatal("unexpected TLSCipherSuite") } - if ev[last].TLSNegotiatedProto != "h2" { + if ev[last].Value().TLSNegotiatedProto != "h2" { t.Fatal("unexpected TLSNegotiatedProto") } - if !reflect.DeepEqual(ev[last].TLSNextProtos, nextprotos) { + if !reflect.DeepEqual(ev[last].Value().TLSNextProtos, nextprotos) { t.Fatal("unexpected TLSNextProtos") } - if ev[last].TLSPeerCerts == nil { + if ev[last].Value().TLSPeerCerts == nil { t.Fatal("unexpected TLSPeerCerts") } - if ev[last].TLSServerName != "www.google.com" { + if ev[last].Value().TLSServerName != "www.google.com" { t.Fatal("unexpected TLSServerName") } - if ev[last].TLSVersion == "" { + if ev[last].Value().TLSVersion == "" { t.Fatal("unexpected TLSVersion") } - if ev[last].Time.Before(ev[last-1].Time) { + if ev[last].Value().Time.Before(ev[last-1].Value().Time) { t.Fatal("unexpected Time") } } @@ -126,46 +126,46 @@ func TestSaverTLSHandshakerSuccess(t *testing.T) { if len(ev) != 2 { t.Fatal("unexpected number of events") } - if ev[0].Name != "tls_handshake_start" { + if ev[0].Name() != "tls_handshake_start" { t.Fatal("unexpected Name") } - if ev[0].TLSServerName != "www.google.com" { + if ev[0].Value().TLSServerName != "www.google.com" { t.Fatal("unexpected TLSServerName") } - if !reflect.DeepEqual(ev[0].TLSNextProtos, nextprotos) { + if !reflect.DeepEqual(ev[0].Value().TLSNextProtos, nextprotos) { t.Fatal("unexpected TLSNextProtos") } - if ev[0].Time.After(time.Now()) { + if ev[0].Value().Time.After(time.Now()) { t.Fatal("unexpected Time") } - if ev[1].Duration <= 0 { + if ev[1].Value().Duration <= 0 { t.Fatal("unexpected Duration") } - if ev[1].Err != nil { + if ev[1].Value().Err != nil { t.Fatal("unexpected Err") } - if ev[1].Name != "tls_handshake_done" { + if ev[1].Name() != "tls_handshake_done" { t.Fatal("unexpected Name") } - if ev[1].TLSCipherSuite == "" { + if ev[1].Value().TLSCipherSuite == "" { t.Fatal("unexpected TLSCipherSuite") } - if ev[1].TLSNegotiatedProto != "h2" { + if ev[1].Value().TLSNegotiatedProto != "h2" { t.Fatal("unexpected TLSNegotiatedProto") } - if !reflect.DeepEqual(ev[1].TLSNextProtos, nextprotos) { + if !reflect.DeepEqual(ev[1].Value().TLSNextProtos, nextprotos) { t.Fatal("unexpected TLSNextProtos") } - if ev[1].TLSPeerCerts == nil { + if ev[1].Value().TLSPeerCerts == nil { t.Fatal("unexpected TLSPeerCerts") } - if ev[1].TLSServerName != "www.google.com" { + if ev[1].Value().TLSServerName != "www.google.com" { t.Fatal("unexpected TLSServerName") } - if ev[1].TLSVersion == "" { + if ev[1].Value().TLSVersion == "" { t.Fatal("unexpected TLSVersion") } - if ev[1].Time.Before(ev[0].Time) { + if ev[1].Value().Time.Before(ev[0].Value().Time) { t.Fatal("unexpected Time") } } @@ -188,13 +188,13 @@ func TestSaverTLSHandshakerHostnameError(t *testing.T) { t.Fatal("expected nil conn here") } for _, ev := range saver.Read() { - if ev.Name != "tls_handshake_done" { + if ev.Name() != "tls_handshake_done" { continue } - if ev.NoTLSVerify == true { + if ev.Value().NoTLSVerify == true { t.Fatal("expected NoTLSVerify to be false") } - if len(ev.TLSPeerCerts) < 1 { + if len(ev.Value().TLSPeerCerts) < 1 { t.Fatal("expected at least a certificate here") } } @@ -218,13 +218,13 @@ func TestSaverTLSHandshakerInvalidCertError(t *testing.T) { t.Fatal("expected nil conn here") } for _, ev := range saver.Read() { - if ev.Name != "tls_handshake_done" { + if ev.Name() != "tls_handshake_done" { continue } - if ev.NoTLSVerify == true { + if ev.Value().NoTLSVerify == true { t.Fatal("expected NoTLSVerify to be false") } - if len(ev.TLSPeerCerts) < 1 { + if len(ev.Value().TLSPeerCerts) < 1 { t.Fatal("expected at least a certificate here") } } @@ -248,13 +248,13 @@ func TestSaverTLSHandshakerAuthorityError(t *testing.T) { t.Fatal("expected nil conn here") } for _, ev := range saver.Read() { - if ev.Name != "tls_handshake_done" { + if ev.Name() != "tls_handshake_done" { continue } - if ev.NoTLSVerify == true { + if ev.Value().NoTLSVerify == true { t.Fatal("expected NoTLSVerify to be false") } - if len(ev.TLSPeerCerts) < 1 { + if len(ev.Value().TLSPeerCerts) < 1 { t.Fatal("expected at least a certificate here") } } @@ -280,13 +280,13 @@ func TestSaverTLSHandshakerNoTLSVerify(t *testing.T) { } conn.Close() for _, ev := range saver.Read() { - if ev.Name != "tls_handshake_done" { + if ev.Name() != "tls_handshake_done" { continue } - if ev.NoTLSVerify != true { + if ev.Value().NoTLSVerify != true { t.Fatal("expected NoTLSVerify to be true") } - if len(ev.TLSPeerCerts) < 1 { + if len(ev.Value().TLSPeerCerts) < 1 { t.Fatal("expected at least a certificate here") } }