Compare commits
3 Commits
c80dca4a59
...
fad69bdef1
Author | SHA1 | Date | |
---|---|---|---|
fad69bdef1 | |||
25ebafa427 | |||
c35e01f640 |
|
@ -89,13 +89,22 @@ func config(input model.MeasurementTarget) (*Config, error) {
|
|||
|
||||
// TestKeys contains the experiment results
|
||||
type TestKeys struct {
|
||||
Queries []*model.ArchivalDNSLookupResult `json:"queries"`
|
||||
TCPConnect []*model.ArchivalTCPConnectResult `json:"tcp_connect"`
|
||||
TLSHandshakes []*model.ArchivalTLSOrQUICHandshakeResult `json:"tls_handshakes"`
|
||||
SMTPErrors []*string `json:"smtp"`
|
||||
NoOpCounter uint8 `json:"successful_noops"`
|
||||
Queries []*model.ArchivalDNSLookupResult `json:"queries"`
|
||||
Runs map[string]IndividualTestKeys `json:"runs"`
|
||||
// Used for global failure (DNS resolution)
|
||||
Failure string `json:"failure"`
|
||||
// Used to indicate global failure state
|
||||
Failed bool `json:"failed"`
|
||||
}
|
||||
|
||||
// IndividualTestKeys contains results for TCP/IP level stuff for each address found
|
||||
// in the DNS lookup
|
||||
type IndividualTestKeys struct {
|
||||
NoOpCounter uint8
|
||||
TCPConnect []*model.ArchivalTCPConnectResult `json:"tcp_connect"`
|
||||
TLSHandshakes []*model.ArchivalTLSOrQUICHandshakeResult `json:"tls_handshakes"`
|
||||
// Individual failure aborting the test run for this address/port combo
|
||||
Failure *string `json:"failure"`
|
||||
}
|
||||
|
||||
type Measurer struct {
|
||||
|
@ -117,21 +126,45 @@ func (m Measurer) ExperimentVersion() string {
|
|||
return testVersion
|
||||
}
|
||||
|
||||
// Manages sequential SMTP sessions to the same hostname (over different IPs)
|
||||
// don't use in parallel because addr changed dynamically
|
||||
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) resolve(host string) ([]string, bool) {
|
||||
func (r *SMTPRunner) run_key() string {
|
||||
return net.JoinHostPort(r.addr, r.port)
|
||||
}
|
||||
|
||||
func (r *SMTPRunner) run_error(err error) {
|
||||
r.tk.Failed = true
|
||||
key := r.run_key()
|
||||
// Key is initialized in conn() no need to check here
|
||||
entry, _ := r.tk.Runs[key]
|
||||
entry.Failure = tracex.NewFailure(err)
|
||||
r.tk.Runs[key] = entry
|
||||
}
|
||||
|
||||
func (r *SMTPRunner) global_error(err error) {
|
||||
r.tk.Failed = true
|
||||
r.tk.Failure = *tracex.NewFailure(err)
|
||||
}
|
||||
|
||||
func (r *SMTPRunner) resolve(host string) ([]string, bool) {
|
||||
r.logger.Infof("Resolving DNS for %s", host)
|
||||
resolver := r.trace.NewStdlibResolver(r.logger)
|
||||
addrs, err := resolver.LookupHost(r.ctx, host)
|
||||
r.tk.Queries = append(r.tk.Queries, r.trace.DNSLookupsFromRoundTrip()...)
|
||||
if err != nil {
|
||||
r.tk.Failure = *tracex.NewFailure(err)
|
||||
r.global_error(err)
|
||||
return []string{}, false
|
||||
}
|
||||
r.logger.Infof("Finished DNS for %s: %v", host, addrs)
|
||||
|
@ -139,66 +172,99 @@ 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) get_run() IndividualTestKeys {
|
||||
if r.tk.Runs == nil {
|
||||
r.tk.Runs = make(map[string]IndividualTestKeys)
|
||||
}
|
||||
key := r.run_key()
|
||||
val, exists := r.tk.Runs[key]
|
||||
if exists {
|
||||
return val
|
||||
} else {
|
||||
return IndividualTestKeys{}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *SMTPRunner) save_run(itk IndividualTestKeys) {
|
||||
key := r.run_key()
|
||||
r.tk.Runs[key] = itk
|
||||
}
|
||||
|
||||
func (r *SMTPRunner) conn(addr string) (net.Conn, bool) {
|
||||
// Initialize addr field and corresponding errors in TestKeys
|
||||
r.logger.Infof("Establishing TCP to %s", addr)
|
||||
r.addr = addr
|
||||
run := r.get_run()
|
||||
|
||||
dialer := r.trace.NewDialerWithoutResolver(r.logger)
|
||||
conn, err := dialer.DialContext(r.ctx, "tcp", net.JoinHostPort(addr, port))
|
||||
r.tk.TCPConnect = append(r.tk.TCPConnect, r.trace.TCPConnects()...)
|
||||
conn, err := dialer.DialContext(r.ctx, "tcp", net.JoinHostPort(addr, r.port))
|
||||
run.TCPConnect = append(run.TCPConnect, r.trace.TCPConnects()...)
|
||||
if err != nil {
|
||||
r.run_error(err)
|
||||
return nil, false
|
||||
}
|
||||
r.save_run(run)
|
||||
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)
|
||||
run := r.get_run()
|
||||
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())
|
||||
run.TLSHandshakes = append(run.TLSHandshakes, r.trace.FirstTLSHandshakeOrNil())
|
||||
if err != nil {
|
||||
r.run_error(err)
|
||||
return nil, false
|
||||
}
|
||||
r.save_run(run)
|
||||
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 {
|
||||
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.run_error(err)
|
||||
return false
|
||||
}
|
||||
err = client.Hello(ehlo)
|
||||
if err != nil {
|
||||
r.tk.SMTPErrors = append(r.tk.SMTPErrors, []*string{tracex.NewFailure(err)}...)
|
||||
r.run_error(err)
|
||||
return false
|
||||
}
|
||||
|
||||
if noop > 0 {
|
||||
run := r.get_run()
|
||||
r.logger.Infof("Trying to generate more no-op traffic")
|
||||
// TODO: noop counter per IP address
|
||||
r.tk.NoOpCounter = 0
|
||||
for r.tk.NoOpCounter < noop {
|
||||
r.tk.NoOpCounter += 1
|
||||
r.logger.Infof("NoOp Iteration %d", r.tk.NoOpCounter)
|
||||
run.NoOpCounter = 0
|
||||
for run.NoOpCounter < noop {
|
||||
run.NoOpCounter += 1
|
||||
r.logger.Infof("NoOp Iteration %d", run.NoOpCounter)
|
||||
err = client.Noop()
|
||||
if err != nil {
|
||||
r.tk.SMTPErrors = append(r.tk.SMTPErrors, []*string{tracex.NewFailure(err)}...)
|
||||
r.run_error(err)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if r.tk.NoOpCounter == noop {
|
||||
r.save_run(run)
|
||||
|
||||
if run.NoOpCounter == noop {
|
||||
r.logger.Infof("Successfully generated no-op traffic")
|
||||
return true
|
||||
} else {
|
||||
r.logger.Infof("Failed no-op traffic at iteration %d", r.tk.NoOpCounter)
|
||||
r.logger.Infof("Failed no-op traffic at iteration %d", run.NoOpCounter)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -232,12 +298,15 @@ func (m Measurer) Run(
|
|||
ServerName: config.host,
|
||||
}
|
||||
|
||||
runner := SMTPRunner{
|
||||
runner := &SMTPRunner{
|
||||
trace: trace,
|
||||
logger: log,
|
||||
ctx: ctx,
|
||||
tk: tk,
|
||||
tlsconfig: &tlsconfig,
|
||||
host: config.host,
|
||||
port: config.port,
|
||||
addr: "",
|
||||
}
|
||||
|
||||
// First resolve DNS
|
||||
|
@ -247,7 +316,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 +324,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 +341,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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user