Documentation
¶
Overview ¶
Package skyquic pkg/skyquic/flowcontrol.go c1-net-transport
Shared QUIC flow-control windows for every skywire QUIC-based carrier: the skynet QUIC transport (squicr, pkg/transport/network), dmsg-over-QUIC (pkg/dmsg/dmsg) and the WebTransport carriers that ride the same sockets. They live here, next to the shared TLS identity, because both packages build their own quic.Config and pkg/dmsg cannot import pkg/transport/network back.
Why they have to be set explicitly: quic-go's defaults are a 512 KB initial stream window and a 768 KB initial CONNECTION window, and the receiver's window is the whole in-flight budget of a BDP-bound path. On a 150 ms-RTT link that caps one connection at
768 KiB / 0.150 s ≈ 5.1 MB/s
which is exactly the throughput a squicr transport measured at before these were set. quic-go does auto-tune the window upward, but only while the receiver drains at least half a window inside ~4 RTT; a receive chain that hands frames to an application through a buffered channel does not reliably meet that, so the connection sits at the initial value indefinitely. One skywire transport is one QUIC connection carrying one stream, so the connection window is that transport's entire budget.
The values below start at ~8 MiB/stream and 12 MiB/connection (≈ 80 MB/s at 150 ms RTT, so the window is no longer the limit on any path we serve) and let auto-tuning grow to 64/96 MiB for longer or fatter paths. They are receive-side buffer CEILINGS, not allocations: quic-go grows the actual buffer on demand, so an idle or slow connection does not pay for them.
Package skyquic pkg/skyquic/identity.go c1-net-transport option A), shared by the skynet QUIC transport (pkg/transport/network) and dmsg-over-QUIC (pkg/dmsg). It lives in its own package — depending only on crypto/* and pkg/cipher — because pkg/transport/network imports pkg/dmsg/dmsg (the dmsg transport), so dmsg cannot import the helpers back from there without an import cycle.
QUIC mandates TLS 1.3, but skywire authenticates with secp256k1 keys, not a CA. Following the libp2p-tls pattern, each side presents a self-signed certificate with an ephemeral ed25519 key, and a custom X.509 extension carries the skywire public key plus a signature, by the matching skywire secret key, over the TLS key. The peer's VerifyPeerCertificate extracts the extension, checks the signature (proving the TLS key — hence the QUIC session — is controlled by the holder of the skywire SK), and pins it to the expected remote PK. A connection from the wrong PK is rejected at the TLS layer.
Package skyquic pkg/skyquic/webtransport.go c1-net-transport
Index ¶
- Constants
- func MatchesPinned(der []byte, pins [][]byte) bool
- func NewCertificate(lPK cipher.PubKey, lSK cipher.SecKey) (tls.Certificate, error)
- func NewWebTransportCertificate() (tls.Certificate, [32]byte, error)
- func PinnedHashes(hexHashes ...string) ([][]byte, error)
- func TLSConfig(cert tls.Certificate, expectedRemotePK *cipher.PubKey, ...) *tls.Config
- func TLSConfigALPN(cert tls.Certificate, expectedRemotePK *cipher.PubKey, ...) *tls.Config
- func VerifyCert(rawCerts [][]byte) (cipher.PubKey, error)
- func WebTransportTLSConfig(cert tls.Certificate) *tls.Config
- type RotatingWebTransportCert
- func (r *RotatingWebTransportCert) Close()
- func (r *RotatingWebTransportCert) Hash() [32]byte
- func (r *RotatingWebTransportCert) NextHash() [32]byte
- func (r *RotatingWebTransportCert) OnRotate(fn func(current, next [32]byte))
- func (r *RotatingWebTransportCert) Rotate() error
- func (r *RotatingWebTransportCert) TLSConfig() *tls.Config
Constants ¶
const ( // InitialStreamReceiveWindow is the per-stream receive window a QUIC // connection starts with (quic-go default: 512 KB). InitialStreamReceiveWindow = 8 << 20 // 8 MiB // MaxStreamReceiveWindow bounds per-stream auto-tuning (default: 6 MB). MaxStreamReceiveWindow = 64 << 20 // 64 MiB // InitialConnectionReceiveWindow is the whole-connection receive window a // QUIC connection starts with (quic-go default: 768 KB — the cap this // fixes). InitialConnectionReceiveWindow = 12 << 20 // 12 MiB // MaxConnectionReceiveWindow bounds whole-connection auto-tuning // (default: 15 MB). MaxConnectionReceiveWindow = 96 << 20 // 96 MiB )
const DmsgNextProto = "skywire-dmsg-1"
DmsgNextProto is the ALPN protocol id for dmsg-over-QUIC. It is distinct from NextProto on purpose: a dmsg server and the squicr transport can sit on the same UDP port (the transport port), demuxed by ALPN, and when both offered "skywire-quic-1" a dmsg session was handed to the transport acceptor, which waited 30 s for a stream a dmsg session never opens and then closed it — every dmsg client on QUIC redialed every server every 30 s. A dmsg client offers ONLY this id, so a socket with no dmsg server behind it refuses the handshake at once and the client falls back to TCP; a dmsg server accepts both ids so clients built before this keep their sessions.
const NextProto = "skywire-quic-1"
NextProto is the ALPN protocol id for the skywire QUIC TRANSPORT (squicr).
const WebTransportNextProto = "h3"
WebTransportNextProto is the ALPN for WebTransport over HTTP/3.
Variables ¶
This section is empty.
Functions ¶
func MatchesPinned ¶ added in v1.3.99
MatchesPinned reports whether the DER certificate's SHA-256 is one of pins.
func NewCertificate ¶
NewCertificate creates a self-signed TLS certificate whose ephemeral ed25519 key is bound to the skywire static identity (lPK/lSK).
func NewWebTransportCertificate ¶
func NewWebTransportCertificate() (tls.Certificate, [32]byte, error)
NewWebTransportCertificate returns a fresh self-signed ECDSA P-256 certificate suitable for the browser WebTransport serverCertificateHashes path, plus its SHA-256 fingerprint (the value to publish in discovery and pin in the browser constructor). Unlike the QUIC identity cert (skyquic.NewCertificate), this cert carries NO skywire-PK binding extension: WebTransport's trust comes from the browser pinning this exact cert hash, and the binding "server PK X has WT cert hash H" lives in X's signed discovery entry. The client→server skywire-PK authentication happens in the dmsg Noise handshake over the WT stream (a browser cannot present a client certificate, so it can't be done in TLS).
The cert must be ECDSA P-256 with <=14-day validity for the browser to accept it via serverCertificateHashes.
func PinnedHashes ¶ added in v1.3.99
PinnedHashes decodes the advertised hex hashes a client pins, skipping empty ones (an older server advertises no next hash). A server is accepted if its certificate matches any of them.
func TLSConfig ¶
func TLSConfig(cert tls.Certificate, expectedRemotePK *cipher.PubKey, onPeerPK func(cipher.PubKey)) *tls.Config
TLSConfig builds a *tls.Config that presents the local skywire-bound certificate and verifies the peer's certificate binds to a skywire PK.
- expectedRemotePK != nil (dialer): the peer MUST present that exact PK.
- onPeerPK != nil (listener): called with the verified remote PK.
func TLSConfigALPN ¶
func TLSConfigALPN(cert tls.Certificate, expectedRemotePK *cipher.PubKey, onPeerPK func(cipher.PubKey), protos ...string) *tls.Config
TLSConfigALPN is TLSConfig with an explicit ALPN list: the ids this side offers (dialer) or accepts (listener), most preferred first.
func VerifyCert ¶
VerifyCert parses the leaf certificate, extracts the skywire identity extension, verifies the binding signature, and returns the authenticated skywire public key.
func WebTransportTLSConfig ¶
func WebTransportTLSConfig(cert tls.Certificate) *tls.Config
WebTransportTLSConfig builds a server *tls.Config for the WebTransport (HTTP/3) listener presenting the given cert. No client certificate is requested — the browser cannot present one; client PK auth is done in the dmsg Noise handshake.
Types ¶
type RotatingWebTransportCert ¶ added in v1.3.99
type RotatingWebTransportCert struct {
// contains filtered or unexported fields
}
RotatingWebTransportCert is a WebTransport server certificate that replaces itself before it expires, and always has its successor ready.
Both hashes are advertised. A browser pins every hash it is given and accepts the server if its certificate matches any of them, so a client that learned [current, next] keeps connecting straight through a rotation, with no fresh lookup — it only has to learn the new pair within one rotation period.
TLSConfig presents whichever certificate is current at each handshake, so a rotation reaches new connections at once and leaves established ones alone.
func NewRotatingWebTransportCert ¶ added in v1.3.99
func NewRotatingWebTransportCert() (*RotatingWebTransportCert, error)
NewRotatingWebTransportCert makes the first certificate and its successor, and starts rotating. Close stops the rotation.
func (*RotatingWebTransportCert) Close ¶ added in v1.3.99
func (r *RotatingWebTransportCert) Close()
Close stops the rotation. The current certificate keeps being served.
func (*RotatingWebTransportCert) Hash ¶ added in v1.3.99
func (r *RotatingWebTransportCert) Hash() [32]byte
Hash is the SHA-256 of the current certificate.
func (*RotatingWebTransportCert) NextHash ¶ added in v1.3.99
func (r *RotatingWebTransportCert) NextHash() [32]byte
NextHash is the SHA-256 of the certificate the next rotation will serve.
func (*RotatingWebTransportCert) OnRotate ¶ added in v1.3.99
func (r *RotatingWebTransportCert) OnRotate(fn func(current, next [32]byte))
OnRotate calls fn with the current and next hashes after every rotation.
func (*RotatingWebTransportCert) Rotate ¶ added in v1.3.99
func (r *RotatingWebTransportCert) Rotate() error
Rotate serves the next certificate from now on, makes a new next one, and tells every OnRotate subscriber both hashes.
func (*RotatingWebTransportCert) TLSConfig ¶ added in v1.3.99
func (r *RotatingWebTransportCert) TLSConfig() *tls.Config
TLSConfig is a server *tls.Config, as WebTransportTLSConfig builds, that presents the current certificate at each handshake.