From c35e01f64067b98df30ca055c44fd4fbf6279830 Mon Sep 17 00:00:00 2001 From: ooninoob Date: Sun, 20 Nov 2022 18:22:42 +0100 Subject: [PATCH] more abstractions for errors --- internal/engine/experiment/smtp/smtp.go | 56 ++++++++++++++++++------- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/internal/engine/experiment/smtp/smtp.go b/internal/engine/experiment/smtp/smtp.go index 671dd16..a0d38ac 100644 --- a/internal/engine/experiment/smtp/smtp.go +++ b/internal/engine/experiment/smtp/smtp.go @@ -92,7 +92,7 @@ type TestKeys struct { Queries []*model.ArchivalDNSLookupResult `json:"queries"` TCPConnect []*model.ArchivalTCPConnectResult `json:"tcp_connect"` TLSHandshakes []*model.ArchivalTLSOrQUICHandshakeResult `json:"tls_handshakes"` - SMTPErrors []*string `json:"smtp"` + SMTPErrors map[string][]*string `json:"smtp"` NoOpCounter uint8 `json:"successful_noops"` // Used for global failure (DNS resolution) Failure string `json:"failure"` @@ -117,12 +117,28 @@ func (m Measurer) ExperimentVersion() string { return testVersion } +// Manages sequential SMTP sessions to the same hostname (over different IPs) +// don't use in parallel! type SMTPRunner struct { trace *measurexlite.Trace logger model.Logger ctx context.Context tk *TestKeys tlsconfig *tls.Config + host string + port string + // addr is changed everytime SMTPRunner.conn(addr) is called + addr string +} + +func (r SMTPRunner) smtp_error(err error) { + key := net.JoinHostPort(r.addr, r.port) + errors, exists := r.tk.SMTPErrors[key] + if exists { + r.tk.SMTPErrors[key] = append(errors, tracex.NewFailure(err)) + } else { + r.tk.SMTPErrors[key] = []*string{tracex.NewFailure(err)} + } } func (r SMTPRunner) resolve(host string) ([]string, bool) { @@ -139,44 +155,49 @@ func (r SMTPRunner) resolve(host string) ([]string, bool) { return addrs, true } -func (r SMTPRunner) conn(addr string, port string) (net.Conn, bool) { +func (r SMTPRunner) conn(addr string) (net.Conn, bool) { + r.addr = addr dialer := r.trace.NewDialerWithoutResolver(r.logger) - conn, err := dialer.DialContext(r.ctx, "tcp", net.JoinHostPort(addr, port)) + conn, err := dialer.DialContext(r.ctx, "tcp", net.JoinHostPort(r.addr, r.port)) r.tk.TCPConnect = append(r.tk.TCPConnect, r.trace.TCPConnects()...) if err != nil { + r.smtp_error(err) return nil, false } return conn, true } -func (r SMTPRunner) handshake(conn net.Conn, host string, port string) (net.Conn, bool) { - r.logger.Infof("Starting TLS handshake with %s:%s", host, port) +func (r SMTPRunner) handshake(conn net.Conn) (net.Conn, bool) { + r.logger.Infof("Starting TLS handshake with %s:%s (%s)", r.host, r.port, r.addr) thx := r.trace.NewTLSHandshakerStdlib(r.logger) tconn, _, err := thx.Handshake(r.ctx, conn, r.tlsconfig) r.tk.TLSHandshakes = append(r.tk.TLSHandshakes, r.trace.FirstTLSHandshakeOrNil()) if err != nil { + r.smtp_error(err) return nil, false } r.logger.Infof("Handshake succeeded") return tconn, true } -func (r SMTPRunner) starttls(conn net.Conn, host string, port string, message string) (net.Conn, bool) { - r.logger.Infof("Asking for StartTLS upgrade") - conn.Write([]byte(message)) - tconn, success := r.handshake(conn, host, port) +func (r SMTPRunner) starttls(conn net.Conn, message string) (net.Conn, bool) { + if message != "" { + r.logger.Infof("Asking for StartTLS upgrade") + conn.Write([]byte(message)) + } + tconn, success := r.handshake(conn) return tconn, success } func (r SMTPRunner) smtp(conn net.Conn, ehlo string, noop uint8) bool { client, err := smtp.NewClient(conn, ehlo) if err != nil { - r.tk.SMTPErrors = append(r.tk.SMTPErrors, []*string{tracex.NewFailure(err)}...) + r.smtp_error(err) return false } err = client.Hello(ehlo) if err != nil { - r.tk.SMTPErrors = append(r.tk.SMTPErrors, []*string{tracex.NewFailure(err)}...) + r.smtp_error(err) return false } @@ -189,7 +210,7 @@ func (r SMTPRunner) smtp(conn net.Conn, ehlo string, noop uint8) bool { r.logger.Infof("NoOp Iteration %d", r.tk.NoOpCounter) err = client.Noop() if err != nil { - r.tk.SMTPErrors = append(r.tk.SMTPErrors, []*string{tracex.NewFailure(err)}...) + r.smtp_error(err) break } } @@ -222,6 +243,8 @@ func (m Measurer) Run( } tk := new(TestKeys) + // TODO: make it so we don't forget it + tk.SMTPErrors = make(map[string][]*string) measurement.TestKeys = tk ctx, cancel := context.WithTimeout(ctx, 60*time.Second) @@ -238,6 +261,9 @@ func (m Measurer) Run( ctx: ctx, tk: tk, tlsconfig: &tlsconfig, + host: config.host, + port: config.port, + addr: "", } // First resolve DNS @@ -247,7 +273,7 @@ func (m Measurer) Run( } for _, addr := range addrs { - conn, success := runner.conn(addr, config.port) + conn, success := runner.conn(addr) if !success { return nil } @@ -255,7 +281,7 @@ func (m Measurer) Run( if config.forced_tls { // Direct TLS connection - tconn, success := runner.handshake(conn, config.host, config.port) + tconn, success := runner.handshake(conn) if !success { continue } @@ -272,7 +298,7 @@ func (m Measurer) Run( } // Upgrade via StartTLS and try EHLO + NoOps - tconn, success := runner.starttls(conn, config.host, config.port, "STARTTLS\n") + tconn, success := runner.starttls(conn, "STARTTLS\n") if !success { continue }