Documentation
¶
Index ¶
Constants ¶
const ( DoppelGangerMaxDurations = 4096 DoppelGangerScoutRaidEach = 6 * time.Hour DoppelGangerScoutRepeats = 10 MinCertSizesToCalculate = 3 )
const ( // Please see Stats description // https://blog.cloudflare.com/optimizing-tls-over-tcp-to-reduce-latency/ // https://github.com/cloudflare/sslconfig/blob/master/patches/nginx__dynamic_tls_records.patch TLSRecordSizeStart = 1450 TLSRecordSizeAccel = 4096 TLSRecordSizeMax = 16384 - tls.SizeHeader TLSCounterAccelAfter = 40 TLSCounterMaxAfter = TLSCounterAccelAfter + 20 TLSRecordSizeResetAfter = time.Second )
const ( StatsBisectTimes = 70 StatsLowK = 0.01 StatsHighK = 10.0 // do not calculate statistics if we have < than this number of durations MinDurationsToCalculate = 100 // these values are taken from ok.ru. measured from moscow site. StatsDefaultK = 0.37846373895785335 StatsDefaultLambda = 1.73177086015485 // how many bytes should we drift DRSNoise = 100 )
const (
ScoutConnCollectedPreallocSize = 100
)
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Conn ¶
type Conn struct {
essentials.Conn
// contains filtered or unexported fields
}
type Ganger ¶
type Ganger struct {
// contains filtered or unexported fields
}
func (*Ganger) NoiseParams ¶ added in v2.2.5
func (g *Ganger) NoiseParams() NoiseParams
NoiseParams returns the current cert-size-based noise parameters. Returns zero-value NoiseParams if not yet measured (caller should use fallback).
type Network ¶
type Network interface {
// Dial establishes context-free TCP connections.
Dial(network, address string) (essentials.Conn, error)
// DialContext dials using a context. This is a preferable way of
// establishing TCP connections.
DialContext(ctx context.Context, network, address string) (essentials.Conn, error)
// MakeHTTPClient build an HTTP client with given dial function. If nothing is
// provided, then DialContext of this interface is going to be used.
MakeHTTPClient(func(ctx context.Context, network, address string) (essentials.Conn, error)) *http.Client
// NativeDialer returns a configured instance of native dialer that
// skips proxy connections or any other irrelevant settings.
NativeDialer() *net.Dialer
}
copypasted from mtglib
type NoiseParams ¶ added in v2.2.5
NoiseParams holds the measured cert chain size for FakeTLS noise calibration. If Mean is 0, the caller should use a legacy fallback.
type ScoutConn ¶
func NewScoutConn ¶
func NewScoutConn(conn essentials.Conn, results *ScoutConnCollected) *ScoutConn
type ScoutConnCollected ¶
type ScoutConnCollected struct {
// contains filtered or unexported fields
}
func NewScoutConnCollected ¶
func NewScoutConnCollected() *ScoutConnCollected
func (*ScoutConnCollected) Add ¶
func (s *ScoutConnCollected) Add(record byte, payloadLen int)
func (*ScoutConnCollected) MarkWrite ¶ added in v2.2.5
func (s *ScoutConnCollected) MarkWrite()
MarkWrite records the current data length as the handshake boundary.
func (*ScoutConnCollected) Snapshot ¶ added in v2.2.7
func (s *ScoutConnCollected) Snapshot() ([]ScoutConnResult, int)
Snapshot returns a copy of the collected data and the write index.
type ScoutConnResult ¶
type ScoutConnResult struct {
// contains filtered or unexported fields
}
type ScoutResult ¶ added in v2.2.5
type ScoutResult struct {
Durations []time.Duration
CertSize int // total ApplicationData bytes during TLS handshake; 0 if unknown
}
ScoutResult holds measurements from a single scout HTTP request.
type Stats ¶
type Stats struct {
// contains filtered or unexported fields
}
Stats is responsible for generating values that are distributed according to some statistical distribution.
It follows several ideas:
- Based on nginx and Cloudflare behaviour, even if server is eager to send a lot, they all start with small TLS packets that are approximately MTU-sized. After
- After ~40 TLS records, server considers TCP session as somewhat solid and reliable and ramps up to 4096.
- After ~20 TLS records more it jumps to the max 16384 bytes and keep this size as long as it can
- If there is no any byte within a connection for a longer time period, this counter resets.
This is called Dynamic TLS Record Sizing
- https://blog.cloudflare.com/optimizing-tls-over-tcp-to-reduce-latency/
- https://community.f5.com/kb/technicalarticles/boosting-tls-performance-with-dynamic-record-sizing-on-big-ip/280798
- https://www.igvita.com/2013/10/24/optimizing-tls-record-size-and-buffering-latency/
And this optimized for the very first byte, so web browsers could start to render as early as possible, showing user some preliminary results, optimizing for perceived latency.
Since this is very typical for the website, we also aim for that.
Another important idea is how delays between TLS packets are distributed. In case of sending huge heavy content with max sized record, delays have lognormal distribution. But a nature of a typical website shows that it eagers to deliver as fast as it can in a few very first records and could possibly slow down later.
This is perfectly described by Weibull distribution:
- https://en.wikipedia.org/wiki/Weibull_distribution
- https://ieeexplore.ieee.org/document/6662948
- https://www.researchgate.net/publication/224621285_Traffic_modelling_and_cost_optimization_for_transmitting_traffic_messages_over_a_hybrid_broadcast_and_cellular_network
- https://ir.uitm.edu.my/id/eprint/105386/1/105386.pdf
In other word, a combination of Dynamic TLS Record Sizing hints us for Weibull distribution.
But we also have to keep in mind that DRS is not well spread yet. In most cases users still rely on OpenSSL or webserver defaults. OpenSSL chunks with biggest packet sizes, nginx relies on static setting that is 16k by default. Thus, dynamic sizing has to be present but we cannot oblige users to use that.