Documentation ¶
Overview ¶
Package measurexlite contains measurement extensions.
See docs/design/dd-003-step-by-step.md in the ooni/probe-cli repository for the design document.
This implementation features a Trace that saves events in buffered channels as proposed by df-003-step-by-step.md. We have reasonable default buffers for channels. But, if you are not draining them, eventually we stop collecting events.
Index ¶
- Constants
- Variables
- func MaybeClose(conn net.Conn) (err error)
- func MaybeCloseUDPLikeConn(conn model.UDPLikeConn) (err error)
- func NewAnnotationArchivalNetworkEvent(index int64, time time.Duration, operation string) *model.ArchivalNetworkEvent
- func NewArchivalDNSLookupResultFromRoundTrip(index int64, started time.Duration, reso DNSNetworkAddresser, ...) *model.ArchivalDNSLookupResult
- func NewArchivalHTTPRequestResult(index int64, started time.Duration, network, address, alpn string, ...) *model.ArchivalHTTPRequestResult
- func NewArchivalNetworkEvent(index int64, started time.Duration, operation string, network string, ...) *model.ArchivalNetworkEvent
- func NewArchivalTCPConnectResult(index int64, started time.Duration, address string, err error, ...) *model.ArchivalTCPConnectResult
- func NewArchivalTLSOrQUICHandshakeResult(index int64, started time.Duration, network string, address string, ...) *model.ArchivalTLSOrQUICHandshakeResult
- func NewFailure(err error) *string
- func TLSPeerCerts(state tls.ConnectionState, err error) (out []model.ArchivalMaybeBinaryData)
- func WebGetTitle(measurementBody string) string
- type DNSNetworkAddresser
- type OperationLogger
- type Trace
- func (tx *Trace) DNSLookupsFromRoundTrip() (out []*model.ArchivalDNSLookupResult)
- func (tx *Trace) DelayedDNSResponseWithTimeout(ctx context.Context, timeout time.Duration) (out []*model.ArchivalDNSLookupResult)
- func (tx *Trace) FirstDNSLookup() *model.ArchivalDNSLookupResult
- func (tx *Trace) FirstNetworkEventOrNil() *model.ArchivalNetworkEvent
- func (tx *Trace) FirstQUICHandshakeOrNil() *model.ArchivalTLSOrQUICHandshakeResult
- func (tx *Trace) FirstTCPConnectOrNil() *model.ArchivalTCPConnectResult
- func (tx *Trace) FirstTLSHandshakeOrNil() *model.ArchivalTLSOrQUICHandshakeResult
- func (tx *Trace) MaybeWrapNetConn(conn net.Conn) net.Conn
- func (tx *Trace) MaybeWrapUDPLikeConn(conn model.UDPLikeConn) model.UDPLikeConn
- func (tx *Trace) NetworkEvents() (out []*model.ArchivalNetworkEvent)
- func (tx *Trace) NewDialerWithoutResolver(dl model.DebugLogger) model.Dialer
- func (tx *Trace) NewParallelDNSOverHTTPSResolver(logger model.Logger, URL string) model.Resolver
- func (tx *Trace) NewParallelUDPResolver(logger model.Logger, dialer model.Dialer, address string) model.Resolver
- func (tx *Trace) NewQUICDialerWithoutResolver(listener model.QUICListener, dl model.DebugLogger) model.QUICDialer
- func (tx *Trace) NewStdlibResolver(logger model.Logger) model.Resolver
- func (tx *Trace) NewTLSHandshakerStdlib(dl model.DebugLogger) model.TLSHandshaker
- func (tx *Trace) OnConnectDone(started time.Time, network, domain, remoteAddr string, err error, ...)
- func (tx *Trace) OnDNSRoundTripForLookupHost(started time.Time, reso model.Resolver, query model.DNSQuery, ...)
- func (tx *Trace) OnDelayedDNSResponse(started time.Time, txp model.DNSTransport, query model.DNSQuery, ...) error
- func (tx *Trace) OnQUICHandshakeDone(started time.Time, remoteAddr string, qconn quic.EarlyConnection, ...)
- func (tx *Trace) OnQUICHandshakeStart(now time.Time, remoteAddr string, config *quic.Config)
- func (tx *Trace) OnTLSHandshakeDone(started time.Time, remoteAddr string, config *tls.Config, ...)
- func (tx *Trace) OnTLSHandshakeStart(now time.Time, remoteAddr string, config *tls.Config)
- func (tx *Trace) QUICHandshakes() (out []*model.ArchivalTLSOrQUICHandshakeResult)
- func (tx *Trace) TCPConnects() (out []*model.ArchivalTCPConnectResult)
- func (tx *Trace) TLSHandshakes() (out []*model.ArchivalTLSOrQUICHandshakeResult)
- func (tx *Trace) TimeNow() time.Time
- func (tx *Trace) TimeSince(t0 time.Time) time.Duration
Constants ¶
const ( // NetworkEventBufferSize is the buffer size for constructing // the Trace's networkEvent buffered channel. NetworkEventBufferSize = 64 // DNSLookupBufferSize is the buffer size for constructing // the Trace's dnsLookup buffered channel. DNSLookupBufferSize = 8 // DNSResponseBufferSize is the buffer size for constructing // the Trace's dnsDelayedResponse buffered channel. DelayedDNSResponseBufferSize = 8 // TCPConnectBufferSize is the buffer size for constructing // the Trace's tcpConnect buffered channel. TCPConnectBufferSize = 8 // TLSHandshakeBufferSize is the buffer for construcing // the Trace's tlsHandshake buffered channel. TLSHandshakeBufferSize = 8 // QUICHandshakeBufferSize is the buffer for constructing // the Trace's quicHandshake buffered channel. QUICHandshakeBufferSize = 8 )
Variables ¶
var ErrDelayedDNSResponseBufferFull = errors.New("buffer full")
ErrDelayedDNSResponseBufferFull indicates that the delayedDNSResponse buffer is full.
Functions ¶
func MaybeClose ¶
MaybeClose is a convenience function for closing a conn only when such a conn isn't nil.
func MaybeCloseUDPLikeConn ¶
func MaybeCloseUDPLikeConn(conn model.UDPLikeConn) (err error)
MaybeUDPLikeClose is a convenience function for closing a conn only when such a conn isn't nil.
func NewAnnotationArchivalNetworkEvent ¶
func NewAnnotationArchivalNetworkEvent( index int64, time time.Duration, operation string) *model.ArchivalNetworkEvent
NewAnnotationArchivalNetworkEvent is a simplified NewArchivalNetworkEvent where we create a simple annotation without attached I/O info.
func NewArchivalDNSLookupResultFromRoundTrip ¶
func NewArchivalDNSLookupResultFromRoundTrip(index int64, started time.Duration, reso DNSNetworkAddresser, query model.DNSQuery, response model.DNSResponse, addrs []string, err error, finished time.Duration) *model.ArchivalDNSLookupResult
NewArchivalDNSLookupResultFromRoundTrip generates a model.ArchivalDNSLookupResultFromRoundTrip from the available information right after the DNS RoundTrip
func NewArchivalHTTPRequestResult ¶
func NewArchivalHTTPRequestResult(index int64, started time.Duration, network, address, alpn string, transport string, req *http.Request, resp *http.Response, maxRespBodySize int64, body []byte, err error, finished time.Duration) *model.ArchivalHTTPRequestResult
NewArchivalHTTPRequestResult creates a new model.ArchivalHTTPRequestResult.
Arguments:
- index is the index of the trace;
- started is when we started sending the request;
- network is the underlying network in use ("tcp" or "udp");
- address is the remote endpoint's address;
- alpn is the negotiated ALPN or an empty string when not applicable;
- transport is the HTTP transport's protocol we're using ("udp" or "tcp"): this field was introduced a long time ago to support QUIC measurements and we keep it for backwards compatibility but network, address, and alpn are much more informative;
- req is the certainly-non-nil HTTP request;
- resp is the possibly-nil HTTP response;
- maxRespBodySize is the maximum body snapshot size;
- body is the possibly-nil HTTP response body;
- err is the possibly-nil error that occurred during the transaction;
- finished is when we finished reading the response's body.
func NewArchivalNetworkEvent ¶
func NewArchivalNetworkEvent(index int64, started time.Duration, operation string, network string, address string, count int, err error, finished time.Duration) *model.ArchivalNetworkEvent
NewArchivalNetworkEvent creates a new model.ArchivalNetworkEvent.
func NewArchivalTCPConnectResult ¶
func NewArchivalTCPConnectResult(index int64, started time.Duration, address string, err error, finished time.Duration) *model.ArchivalTCPConnectResult
NewArchivalTCPConnectResult generates a model.ArchivalTCPConnectResult from the available information right after connect returns.
func NewArchivalTLSOrQUICHandshakeResult ¶
func NewArchivalTLSOrQUICHandshakeResult( index int64, started time.Duration, network string, address string, config *tls.Config, state tls.ConnectionState, err error, finished time.Duration) *model.ArchivalTLSOrQUICHandshakeResult
NewArchivalTLSOrQUICHandshakeResult generates a model.ArchivalTLSOrQUICHandshakeResult from the available information right after the TLS handshake returns.
func NewFailure ¶
NewFailure creates an OONI failure from an error. If the error is nil, we return nil. If the error is not already an ErrWrapper, it's converted to an ErrWrapper. If the ErrWrapper's Failure is not empty, we return its string representation. Otherwise we return a string indicating that an ErrWrapper has an empty failure (should not happen).
See https://github.com/ooni/spec/blob/master/data-formats/df-007-errors.md for more information about OONI failures.
func TLSPeerCerts ¶
func TLSPeerCerts( state tls.ConnectionState, err error) (out []model.ArchivalMaybeBinaryData)
TLSPeerCerts extracts the certificates either from the list of certificates in the connection state or from the error that occurred.
func WebGetTitle ¶
WebGetTitle returns the title or an empty string.
Types ¶
type DNSNetworkAddresser ¶
type DNSNetworkAddresser interface { // Address is like model.DNSTransport.Address Address() string // Network is like model.DNSTransport.Network Network() string }
DNSNetworkAddresser is the type of something we just used to perform a DNS round trip (e.g., model.DNSTransport, model.Resolver) that allows us to get the network and the address of the underlying resolver/transport.
type OperationLogger ¶
type OperationLogger struct {
// contains filtered or unexported fields
}
OperationLogger keeps state required to log about an in-progress operation as documented by NewOperationLogger.
func NewOperationLogger ¶
func NewOperationLogger(logger model.Logger, format string, v ...any) *OperationLogger
NewOperationLogger creates a new logger that logs about an in-progress operation. If it takes too much time to emit the result of the operation, the code will emit an interim log message mentioning that the operation is currently in progress.
func (*OperationLogger) Stop ¶
func (ol *OperationLogger) Stop(err error)
Stop must be called when the operation is done. The [err] argument is the result of the operation, which may be nil. This method ensures that we log the final result of the now-completed operation.
type Trace ¶
type Trace struct { // Index is the MANDATORY unique index of this trace within the // current measurement. If you don't care about uniquely identifying // traces, you can use zero to indicate the "default" trace. Index int64 // NewStdlibResolverFn is OPTIONAL and can be used to overide // calls to the netxlite.NewStdlibResolver factory. NewStdlibResolverFn func(logger model.Logger) model.Resolver // NewParallelUDPResolverFn is OPTIONAL and can be used to overide // calls to the netxlite.NewParallelUDPResolver factory. NewParallelUDPResolverFn func(logger model.Logger, dialer model.Dialer, address string) model.Resolver // NewParallelDNSOverHTTPSResolverFn is OPTIONAL and can be used to overide // calls to the netxlite.NewParallelDNSOverHTTPSUDPResolver factory. NewParallelDNSOverHTTPSResolverFn func(logger model.Logger, URL string) model.Resolver // NewDialerWithoutResolverFn is OPTIONAL and can be used to override // calls to the netxlite.NewDialerWithoutResolver factory. NewDialerWithoutResolverFn func(dl model.DebugLogger) model.Dialer // NewTLSHandshakerStdlibFn is OPTIONAL and can be used to overide // calls to the netxlite.NewTLSHandshakerStdlib factory. NewTLSHandshakerStdlibFn func(dl model.DebugLogger) model.TLSHandshaker // NewDialerWithoutResolverFn is OPTIONAL and can be used to override // calls to the netxlite.NewQUICDialerWithoutResolver factory. NewQUICDialerWithoutResolverFn func(listener model.QUICListener, dl model.DebugLogger) model.QUICDialer // TimeNowFn is OPTIONAL and can be used to override calls to time.Now // to produce deterministic timing when testing. TimeNowFn func() time.Time // ZeroTime is the MANDATORY time when we started the current measurement. ZeroTime time.Time // contains filtered or unexported fields }
Trace implements model.Trace.
The zero-value of this struct is invalid. To construct you should either fill all the fields marked as MANDATORY or use NewTrace.
Buffered channels ¶
NewTrace uses reasonable buffer sizes for the channels used for collecting events. You should drain the channels used by this implementation after each operation you perform (i.e., we expect you to peform step-by-step measurements). If you want larger (or smaller) buffers, then you should construct this data type manually with the desired buffer sizes.
We have convenience methods for extracting events from the buffered channels. Otherwise, you could read the channels directly. (In which case, remember to issue nonblocking channel reads because channels are never closed and they're just written when new events occur.)
func NewTrace ¶
NewTrace creates a new instance of Trace using default settings.
We create buffered channels using as buffer sizes the constants that are also defined by this package.
Arguments:
- index is the unique index of this trace within the current measurement (use zero if you don't care about giving this trace a unique ID);
- zeroTime is the time when we started the current measurement.
func (*Trace) DNSLookupsFromRoundTrip ¶
func (tx *Trace) DNSLookupsFromRoundTrip() (out []*model.ArchivalDNSLookupResult)
DNSLookupsFromRoundTrip drains the network events buffered inside the DNSLookup channel
func (*Trace) DelayedDNSResponseWithTimeout ¶
func (tx *Trace) DelayedDNSResponseWithTimeout(ctx context.Context, timeout time.Duration) (out []*model.ArchivalDNSLookupResult)
DelayedDNSResponseWithTimeout drains the network events buffered inside the delayedDNSResponse channel. We construct a child context based on [ctx] and the given [timeout] and we stop reading when original [ctx] has been cancelled or the given [timeout] expires, whatever happens first. Once the timeout expired, we drain the chan as much as possible before returning.
func (*Trace) FirstDNSLookup ¶
func (tx *Trace) FirstDNSLookup() *model.ArchivalDNSLookupResult
FirstDNSLookupOrNil drains the network events buffered inside the DNSLookup channel and returns the first DNSLookup, if any. Otherwise, it returns nil.
func (*Trace) FirstNetworkEventOrNil ¶
func (tx *Trace) FirstNetworkEventOrNil() *model.ArchivalNetworkEvent
FirstNetworkEventOrNil drains the network events buffered inside the NetworkEvents channel and returns the first NetworkEvent, if any. Otherwise, it returns nil.
func (*Trace) FirstQUICHandshakeOrNil ¶
func (tx *Trace) FirstQUICHandshakeOrNil() *model.ArchivalTLSOrQUICHandshakeResult
FirstQUICHandshakeOrNil drains the network events buffered inside the QUICHandshake channel and returns the first QUICHandshake, if any. Otherwise, it returns nil.
func (*Trace) FirstTCPConnectOrNil ¶
func (tx *Trace) FirstTCPConnectOrNil() *model.ArchivalTCPConnectResult
FirstTCPConnectOrNil drains the network events buffered inside the TCPConnect channel and returns the first TCPConnect, if any. Otherwise, it returns nil.
func (*Trace) FirstTLSHandshakeOrNil ¶
func (tx *Trace) FirstTLSHandshakeOrNil() *model.ArchivalTLSOrQUICHandshakeResult
FirstTLSHandshakeOrNil drains the network events buffered inside the TLSHandshake channel and returns the first TLSHandshake, if any. Otherwise, it returns nil.
func (*Trace) MaybeWrapNetConn ¶
MaybeWrapNetConn implements model.Trace.MaybeWrapNetConn.
func (*Trace) MaybeWrapUDPLikeConn ¶
func (tx *Trace) MaybeWrapUDPLikeConn(conn model.UDPLikeConn) model.UDPLikeConn
MaybeWrapUDPLikeConn implements model.Trace.MaybeWrapUDPLikeConn.
func (*Trace) NetworkEvents ¶
func (tx *Trace) NetworkEvents() (out []*model.ArchivalNetworkEvent)
NetworkEvents drains the network events buffered inside the NetworkEvent channel.
func (*Trace) NewDialerWithoutResolver ¶
func (tx *Trace) NewDialerWithoutResolver(dl model.DebugLogger) model.Dialer
NewDialerWithoutResolver is equivalent to netxlite.NewDialerWithoutResolver except that it returns a model.Dialer that uses this trace.
Note: unlike code in netx or measurex, this factory DOES NOT return you a dialer that also performs wrapping of a net.Conn in case of success. If you want to wrap the conn, you need to wrap it explicitly using WrapNetConn.
func (*Trace) NewParallelDNSOverHTTPSResolver ¶
NewParallelDNSOverHTTPSResolver returns a trace-aware parallel DoH resolver
func (*Trace) NewParallelUDPResolver ¶
func (tx *Trace) NewParallelUDPResolver(logger model.Logger, dialer model.Dialer, address string) model.Resolver
NewParallelUDPResolver returns a trace-ware parallel UDP resolver
func (*Trace) NewQUICDialerWithoutResolver ¶
func (tx *Trace) NewQUICDialerWithoutResolver(listener model.QUICListener, dl model.DebugLogger) model.QUICDialer
NewQUICDialerWithoutResolver is equivalent to netxlite.NewQUICDialerWithoutResolver except that it returns a model.QUICDialer that uses this trace.
func (*Trace) NewStdlibResolver ¶
NewStdlibResolver returns a trace-ware system resolver
func (*Trace) NewTLSHandshakerStdlib ¶
func (tx *Trace) NewTLSHandshakerStdlib(dl model.DebugLogger) model.TLSHandshaker
NewTLSHandshakerStdlib is equivalent to netxlite.NewTLSHandshakerStdlib except that it returns a model.TLSHandshaker that uses this trace.
func (*Trace) OnConnectDone ¶
func (tx *Trace) OnConnectDone( started time.Time, network, domain, remoteAddr string, err error, finished time.Time)
OnTCPConnectDone implements model.Trace.OnTCPConnectDone.
func (*Trace) OnDNSRoundTripForLookupHost ¶
func (tx *Trace) OnDNSRoundTripForLookupHost(started time.Time, reso model.Resolver, query model.DNSQuery, response model.DNSResponse, addrs []string, err error, finished time.Time)
OnDNSRoundTripForLookupHost implements model.Trace.OnDNSRoundTripForLookupHost
func (*Trace) OnDelayedDNSResponse ¶
func (tx *Trace) OnDelayedDNSResponse(started time.Time, txp model.DNSTransport, query model.DNSQuery, response model.DNSResponse, addrs []string, err error, finished time.Time) error
OnDelayedDNSResponse implements model.Trace.OnDelayedDNSResponse
func (*Trace) OnQUICHandshakeDone ¶
func (tx *Trace) OnQUICHandshakeDone(started time.Time, remoteAddr string, qconn quic.EarlyConnection, config *tls.Config, err error, finished time.Time)
OnQUICHandshakeDone implements model.Trace.OnQUICHandshakeDone
func (*Trace) OnQUICHandshakeStart ¶
OnQUICHandshakeStart implements model.Trace.OnQUICHandshakeStart
func (*Trace) OnTLSHandshakeDone ¶
func (tx *Trace) OnTLSHandshakeDone(started time.Time, remoteAddr string, config *tls.Config, state tls.ConnectionState, err error, finished time.Time)
OnTLSHandshakeDone implements model.Trace.OnTLSHandshakeDone.
func (*Trace) OnTLSHandshakeStart ¶
OnTLSHandshakeStart implements model.Trace.OnTLSHandshakeStart.
func (*Trace) QUICHandshakes ¶
func (tx *Trace) QUICHandshakes() (out []*model.ArchivalTLSOrQUICHandshakeResult)
QUICHandshakes drains the network events buffered inside the QUICHandshake channel.
func (*Trace) TCPConnects ¶
func (tx *Trace) TCPConnects() (out []*model.ArchivalTCPConnectResult)
TCPConnects drains the network events buffered inside the TCPConnect channel.
func (*Trace) TLSHandshakes ¶
func (tx *Trace) TLSHandshakes() (out []*model.ArchivalTLSOrQUICHandshakeResult)
TLSHandshakes drains the network events buffered inside the TLSHandshake channel.