more abstractions for errors

This commit is contained in:
ooni noob 2022-11-20 18:22:42 +01:00
parent c80dca4a59
commit c35e01f640

View File

@ -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
}