Skip to content
This repository has been archived by the owner on Mar 6, 2020. It is now read-only.

Commit

Permalink
Extend scoreboard to also track TLS handshake RST (#82)
Browse files Browse the repository at this point in the history
The scoreboard package will probably benefit from some more
precise unit testing with respect to returned keys.

Work related to ooni/probe-engine#87
  • Loading branch information
bassosimone authored Oct 29, 2019
1 parent 48cfb0e commit 5972a62
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 12 deletions.
6 changes: 5 additions & 1 deletion internal/httptransport/tracetripper/tracetripper.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,17 @@ func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
Error: err,
TransactionID: tid,
}.MaybeBuild()
durationSinceBeginning := time.Now().Sub(root.Beginning)
root.X.Scoreboard.MaybeTLSHandshakeReset(
durationSinceBeginning, req.URL, err,
)
// Event emitted by net/http when DialTLS is not
// configured in the http.Transport
root.Handler.OnMeasurement(model.Measurement{
TLSHandshakeDone: &model.TLSHandshakeDoneEvent{
ConnectionState: model.NewTLSConnectionState(state),
Error: err,
DurationSinceBeginning: time.Now().Sub(root.Beginning),
DurationSinceBeginning: durationSinceBeginning,
TransactionID: tid,
},
})
Expand Down
4 changes: 2 additions & 2 deletions x/nervousresolver/nervousresolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ func (c *Resolver) LookupHost(ctx context.Context, hostname string) ([]string, e
root.X.Scoreboard.AddDNSBogonInfo(scoreboard.DNSBogonInfo{
Addresses: addrs,
DurationSinceBeginning: durationSinceBeginning,
FollowupAction: "retry using DoH resolver",
Hostname: hostname,
Domain: hostname,
FallbackPlan: "ignore_and_retry_with_doh",
})
value := bogonLookup{
Addresses: addrs,
Expand Down
51 changes: 47 additions & 4 deletions x/scoreboard/scoreboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@ package scoreboard

import (
"encoding/json"
"errors"
"net"
"net/url"
"sync"
"time"
)

// Board contains what we learned during measurements.
type Board struct {
DNSBogonInfo []DNSBogonInfo
mu sync.Mutex
DNSBogonInfo []DNSBogonInfo
TLSHandshakeReset []TLSHandshakeReset
mu sync.Mutex
}

// DNSBogonInfo contains info on bogon replies received when
Expand All @@ -22,8 +26,17 @@ type Board struct {
type DNSBogonInfo struct {
Addresses []string
DurationSinceBeginning time.Duration
FollowupAction string
Hostname string
Domain string
FallbackPlan string
}

// TLSHandshakeReset contains info on a RST received when
// performing a TLS handshake with a server.
type TLSHandshakeReset struct {
Address string
Domain string
DurationSinceBeginning time.Duration
RecommendedFollowups []string
}

// AddDNSBogonInfo adds info on a DNS bogon reply
Expand All @@ -33,6 +46,36 @@ func (b *Board) AddDNSBogonInfo(info DNSBogonInfo) {
b.DNSBogonInfo = append(b.DNSBogonInfo, info)
}

// MaybeTLSHandshakeReset inspects the provided error and
// updates the scoreboard with TLS handshake RST info, when
// this kind of interference has been detected.
func (b *Board) MaybeTLSHandshakeReset(
durationSinceBeginning time.Duration, URL *url.URL, err error,
) {
// TODO(bassosimone): add also EOF here?
if err == nil || err.Error() != "connection_reset" {
return
}
var (
opError *net.OpError
remoteAddr string
)
if errors.As(err, &opError) && opError.Addr != nil {
remoteAddr = opError.Addr.String()
}
b.mu.Lock()
defer b.mu.Unlock()
b.TLSHandshakeReset = append(b.TLSHandshakeReset, TLSHandshakeReset{
Address: remoteAddr,
Domain: URL.Hostname(),
DurationSinceBeginning: durationSinceBeginning,
RecommendedFollowups: []string{
"sni_blocking",
"ip_valid_for_domain",
},
})
}

// Marshal marshals the board in JSON format.
func (b *Board) Marshal() string {
data, _ := json.Marshal(b)
Expand Down
53 changes: 48 additions & 5 deletions x/scoreboard/scoreboard_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,52 @@
package scoreboard
// must be another package to avoid import cycle
package scoreboard_test

import "testing"
import (
"errors"
"net"
"net/url"
"testing"

func TestIntegration(t *testing.T) {
board := &Board{}
board.AddDNSBogonInfo(DNSBogonInfo{})
"github.com/ooni/netx/model"
"github.com/ooni/netx/x/scoreboard"
)

func TestIntegrationDNSBogon(t *testing.T) {
board := &scoreboard.Board{}
board.AddDNSBogonInfo(scoreboard.DNSBogonInfo{})
t.Log(board.Marshal())
}

func TestIntegrationTLSHandshakeResetNil(t *testing.T) {
board := &scoreboard.Board{}
board.MaybeTLSHandshakeReset(0, nil, nil)
t.Log(board.Marshal())
}

func TestIntegrationTLSHandshakeResetNotReset(t *testing.T) {
board := &scoreboard.Board{}
board.MaybeTLSHandshakeReset(0, nil, errors.New("antani"))
t.Log(board.Marshal())
}

func TestIntegrationTLSHandshakeResetIsReset(t *testing.T) {
board := &scoreboard.Board{}
board.MaybeTLSHandshakeReset(0, &url.URL{}, errors.New("connection_reset"))
t.Log(board.Marshal())
}

func TestIntegrationTLSHandshakeResetIsResetWithAddr(t *testing.T) {
board := &scoreboard.Board{}
board.MaybeTLSHandshakeReset(
0, &url.URL{}, &model.ErrWrapper{
Failure: "connection_reset",
WrappedErr: &net.OpError{
Addr: &net.TCPAddr{
IP: net.IPv4(8, 8, 8, 8),
Port: 53,
},
},
},
)
t.Log(board.Marshal())
}

0 comments on commit 5972a62

Please sign in to comment.