mirror of
https://github.com/DNSCrypt/dnscrypt-proxy.git
synced 2024-09-11 21:17:40 +03:00
Update quic-go
This commit is contained in:
parent
0c26d1637a
commit
f9f68cf0a3
@ -279,7 +279,7 @@ func (xTransport *XTransport) rebuildTransport() {
|
||||
ipOnly = "[" + cachedIP.String() + "]"
|
||||
}
|
||||
} else {
|
||||
dlog.Debugf("[%s] IP address was not cached in H3 DialContext", host)
|
||||
dlog.Debugf("[%s] IP address was not cached in H3 context", host)
|
||||
}
|
||||
addrStr = ipOnly + ":" + strconv.Itoa(port)
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", addrStr)
|
||||
@ -292,7 +292,8 @@ func (xTransport *XTransport) rebuildTransport() {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return quic.DialEarlyContext(ctx, xTransport.h3UDPConn, udpAddr, host, tlsCfg, cfg)
|
||||
tlsCfg.ServerName = host
|
||||
return quic.DialEarly(ctx, xTransport.h3UDPConn, udpAddr, tlsCfg, cfg)
|
||||
}}
|
||||
xTransport.h3Transport = h3Transport
|
||||
}
|
||||
|
10
go.mod
10
go.mod
@ -10,17 +10,17 @@ require (
|
||||
github.com/hashicorp/go-immutable-radix v1.3.1
|
||||
github.com/hashicorp/golang-lru v0.5.0
|
||||
github.com/hectane/go-acl v0.0.0-20230122075934-ca0b05cb1adb
|
||||
github.com/jedisct1/dlog v0.0.0-20230211133026-0338add8743f
|
||||
github.com/jedisct1/dlog v0.0.0-20230513092435-93bc2a55ad59
|
||||
github.com/jedisct1/go-clocksmith v0.0.0-20230211133011-392c1afea73e
|
||||
github.com/jedisct1/go-dnsstamps v0.0.0-20230211133001-124a632de565
|
||||
github.com/jedisct1/go-hpke-compact v0.0.0-20230211184420-51d4440017ce
|
||||
github.com/jedisct1/go-minisign v0.0.0-20230410063418-3d885d71f62c
|
||||
github.com/jedisct1/xsecretbox v0.0.0-20230211185120-2025cdbb9f0f
|
||||
github.com/jedisct1/go-hpke-compact v0.0.0-20230513092519-91c912752223
|
||||
github.com/jedisct1/go-minisign v0.0.0-20230513092556-d96eb068239a
|
||||
github.com/jedisct1/xsecretbox v0.0.0-20230513092623-8c0b2dff5e24
|
||||
github.com/k-sone/critbitgo v1.4.0
|
||||
github.com/kardianos/service v1.2.2
|
||||
github.com/miekg/dns v1.1.54
|
||||
github.com/powerman/check v1.7.0
|
||||
github.com/quic-go/quic-go v0.34.0
|
||||
github.com/quic-go/quic-go v0.35.0
|
||||
golang.org/x/crypto v0.9.0
|
||||
golang.org/x/net v0.10.0
|
||||
golang.org/x/sys v0.8.0
|
||||
|
23
go.sum
23
go.sum
@ -36,18 +36,18 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
|
||||
github.com/hectane/go-acl v0.0.0-20230122075934-ca0b05cb1adb h1:PGufWXXDq9yaev6xX1YQauaO1MV90e6Mpoq1I7Lz/VM=
|
||||
github.com/hectane/go-acl v0.0.0-20230122075934-ca0b05cb1adb/go.mod h1:QiyDdbZLaJ/mZP4Zwc9g2QsfaEA4o7XvvgZegSci5/E=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/jedisct1/dlog v0.0.0-20230211133026-0338add8743f h1:FBZqNKGn+mB/9PZG/1bNGKQ1azw2o7dZV0ZGmTPoboA=
|
||||
github.com/jedisct1/dlog v0.0.0-20230211133026-0338add8743f/go.mod h1:35aII3PkLMvmc8daWy0vcZXDU+a40lJczHHTFRJmnvw=
|
||||
github.com/jedisct1/dlog v0.0.0-20230513092435-93bc2a55ad59 h1:Bw7a+o84VjOun21ieO9Y6d9GuE2MAjlR9aFcvA0K7RU=
|
||||
github.com/jedisct1/dlog v0.0.0-20230513092435-93bc2a55ad59/go.mod h1:Lfl1ng5dZ6ywtV5i6DoJ1ZXkpB6GbIaVitwG/vWrzgc=
|
||||
github.com/jedisct1/go-clocksmith v0.0.0-20230211133011-392c1afea73e h1:tzG4EjKgHIqKVkLIAC4pXTIapuM2BR05uXokEEysAXA=
|
||||
github.com/jedisct1/go-clocksmith v0.0.0-20230211133011-392c1afea73e/go.mod h1:SAINchklztk2jcLWJ4bpNF4KnwDUSUTX+cJbspWC2Rw=
|
||||
github.com/jedisct1/go-dnsstamps v0.0.0-20230211133001-124a632de565 h1:BPBMaUCgtmiHvqgugbSuegXjADJfERsPbmRqgdq8Pjo=
|
||||
github.com/jedisct1/go-dnsstamps v0.0.0-20230211133001-124a632de565/go.mod h1:mEGEFZsGe4sG5Mb3Xi89pmsy+TZ0946ArbYMGKAM5uA=
|
||||
github.com/jedisct1/go-hpke-compact v0.0.0-20230211184420-51d4440017ce h1:RvDulxEuYjqIWSphi54mQGXWDAp0yjeCJQKhBj6Qkmc=
|
||||
github.com/jedisct1/go-hpke-compact v0.0.0-20230211184420-51d4440017ce/go.mod h1:T9nvXa0PqmoSt9JhtW0rv9iXg5xoxW/ZfVhdm9Y4QJw=
|
||||
github.com/jedisct1/go-minisign v0.0.0-20230410063418-3d885d71f62c h1:SJIUnIcy3NTjPM1acfLsIDQ6dZkBXkQLt/vrg7pshX0=
|
||||
github.com/jedisct1/go-minisign v0.0.0-20230410063418-3d885d71f62c/go.mod h1:euIjSueBwqJWwVr7rS2bowelVBVoN827tx5n87jnSJM=
|
||||
github.com/jedisct1/xsecretbox v0.0.0-20230211185120-2025cdbb9f0f h1:1qPoL+ur1rCouHMB737ujJGXVFoXGafDY+kmgXjpicA=
|
||||
github.com/jedisct1/xsecretbox v0.0.0-20230211185120-2025cdbb9f0f/go.mod h1:39HtRgNq2rdKzzeqfPNFLY000t4ktVThX3ncyK58lsA=
|
||||
github.com/jedisct1/go-hpke-compact v0.0.0-20230513092519-91c912752223 h1:6q4bclrFDC6XhljyqpgnQQJHB0jJ9JCxamxznYjO6e8=
|
||||
github.com/jedisct1/go-hpke-compact v0.0.0-20230513092519-91c912752223/go.mod h1:WchTSQZ7F2frIm7p+CtDAWQ7HuTj+bTIMC612B0iMKY=
|
||||
github.com/jedisct1/go-minisign v0.0.0-20230513092556-d96eb068239a h1:NuwTR1jHId8kDrB+tYYIb6zLfNFqNh4N5sLJLuFcie0=
|
||||
github.com/jedisct1/go-minisign v0.0.0-20230513092556-d96eb068239a/go.mod h1:o7E4qbRBjPKXV4D4gtm+Eaqsr3obg6zOZyRqQk6JwjQ=
|
||||
github.com/jedisct1/xsecretbox v0.0.0-20230513092623-8c0b2dff5e24 h1:LhA515GzR+6uvKiZUAcAaXWvmcaJcruJ0he7aerypIE=
|
||||
github.com/jedisct1/xsecretbox v0.0.0-20230513092623-8c0b2dff5e24/go.mod h1:MaGh/D9rZfuMUZ3+Qv/OEP7vGGPe404xiGtF1nRqdNk=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/k-sone/critbitgo v1.4.0 h1:l71cTyBGeh6X5ATh6Fibgw3+rtNT80BA0uNNWgkPrbE=
|
||||
@ -73,15 +73,15 @@ github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc8
|
||||
github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
|
||||
github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E=
|
||||
github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
|
||||
github.com/quic-go/quic-go v0.34.0 h1:OvOJ9LFjTySgwOTYUZmNoq0FzVicP8YujpV0kB7m2lU=
|
||||
github.com/quic-go/quic-go v0.34.0/go.mod h1:+4CVgVppm0FNjpG3UcX8Joi/frKOH7/ciD5yGcwOO1g=
|
||||
github.com/quic-go/quic-go v0.35.0 h1:JXIf219xJK+4qGeY52rlnrVqeB2AXUAwfLU9JSoWXwg=
|
||||
github.com/quic-go/quic-go v0.35.0/go.mod h1:+4CVgVppm0FNjpG3UcX8Joi/frKOH7/ciD5yGcwOO1g=
|
||||
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
|
||||
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
||||
github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
|
||||
github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
@ -138,4 +138,5 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
25
vendor/github.com/quic-go/quic-go/README.md
generated
vendored
25
vendor/github.com/quic-go/quic-go/README.md
generated
vendored
@ -45,18 +45,19 @@ http.Client{
|
||||
|
||||
## Projects using quic-go
|
||||
|
||||
| Project | Description | Stars |
|
||||
|-----------------------------------------------------------|---------------------------------------------------------------------------------------------------------|-------|
|
||||
| [AdGuardHome](https://github.com/AdguardTeam/AdGuardHome) | Free and open source, powerful network-wide ads & trackers blocking DNS server. | ![GitHub Repo stars](https://img.shields.io/github/stars/AdguardTeam/AdGuardHome?style=flat-square) |
|
||||
| [algernon](https://github.com/xyproto/algernon) | Small self-contained pure-Go web server with Lua, Markdown, HTTP/2, QUIC, Redis and PostgreSQL support | ![GitHub Repo stars](https://img.shields.io/github/stars/xyproto/algernon?style=flat-square) |
|
||||
| [caddy](https://github.com/caddyserver/caddy/) | Fast, multi-platform web server with automatic HTTPS | ![GitHub Repo stars](https://img.shields.io/github/stars/caddyserver/caddy?style=flat-square) |
|
||||
| [cloudflared](https://github.com/cloudflare/cloudflared) | A tunneling daemon that proxies traffic from the Cloudflare network to your origins | ![GitHub Repo stars](https://img.shields.io/github/stars/cloudflare/cloudflared?style=flat-square) |
|
||||
| [go-libp2p](https://github.com/libp2p/go-libp2p) | libp2p implementation in Go, powering [Kubo](https://github.com/ipfs/kubo) (IPFS) and [Lotus](https://github.com/filecoin-project/lotus) (Filecoin), among others | ![GitHub Repo stars](https://img.shields.io/github/stars/libp2p/go-libp2p?style=flat-square) |
|
||||
| [OONI Probe](https://github.com/ooni/probe-cli) | Next generation OONI Probe. Library and CLI tool. | ![GitHub Repo stars](https://img.shields.io/github/stars/ooni/probe-cli?style=flat-square) |
|
||||
| [syncthing](https://github.com/syncthing/syncthing/) | Open Source Continuous File Synchronization | ![GitHub Repo stars](https://img.shields.io/github/stars/syncthing/syncthing?style=flat-square) |
|
||||
| [traefik](https://github.com/traefik/traefik) | The Cloud Native Application Proxy | ![GitHub Repo stars](https://img.shields.io/github/stars/traefik/traefik?style=flat-square) |
|
||||
| [v2ray-core](https://github.com/v2fly/v2ray-core) | A platform for building proxies to bypass network restrictions | ![GitHub Repo stars](https://img.shields.io/github/stars/v2fly/v2ray-core?style=flat-square) |
|
||||
| [YoMo](https://github.com/yomorun/yomo) | Streaming Serverless Framework for Geo-distributed System | ![GitHub Repo stars](https://img.shields.io/github/stars/yomorun/yomo?style=flat-square) |
|
||||
| Project | Description | Stars |
|
||||
|-----------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------|
|
||||
| [AdGuardHome](https://github.com/AdguardTeam/AdGuardHome) | Free and open source, powerful network-wide ads & trackers blocking DNS server. | ![GitHub Repo stars](https://img.shields.io/github/stars/AdguardTeam/AdGuardHome?style=flat-square) |
|
||||
| [algernon](https://github.com/xyproto/algernon) | Small self-contained pure-Go web server with Lua, Markdown, HTTP/2, QUIC, Redis and PostgreSQL support | ![GitHub Repo stars](https://img.shields.io/github/stars/xyproto/algernon?style=flat-square) |
|
||||
| [caddy](https://github.com/caddyserver/caddy/) | Fast, multi-platform web server with automatic HTTPS | ![GitHub Repo stars](https://img.shields.io/github/stars/caddyserver/caddy?style=flat-square) |
|
||||
| [cloudflared](https://github.com/cloudflare/cloudflared) | A tunneling daemon that proxies traffic from the Cloudflare network to your origins | ![GitHub Repo stars](https://img.shields.io/github/stars/cloudflare/cloudflared?style=flat-square) |
|
||||
| [go-libp2p](https://github.com/libp2p/go-libp2p) | libp2p implementation in Go, powering [Kubo](https://github.com/ipfs/kubo) (IPFS) and [Lotus](https://github.com/filecoin-project/lotus) (Filecoin), among others | ![GitHub Repo stars](https://img.shields.io/github/stars/libp2p/go-libp2p?style=flat-square) |
|
||||
| [Mercure](https://github.com/dunglas/mercure) | An open, easy, fast, reliable and battery-efficient solution for real-time communications | ![GitHub Repo stars](https://img.shields.io/github/stars/dunglas/mercure?style=flat-square) |
|
||||
| [OONI Probe](https://github.com/ooni/probe-cli) | Next generation OONI Probe. Library and CLI tool. | ![GitHub Repo stars](https://img.shields.io/github/stars/ooni/probe-cli?style=flat-square) |
|
||||
| [syncthing](https://github.com/syncthing/syncthing/) | Open Source Continuous File Synchronization | ![GitHub Repo stars](https://img.shields.io/github/stars/syncthing/syncthing?style=flat-square) |
|
||||
| [traefik](https://github.com/traefik/traefik) | The Cloud Native Application Proxy | ![GitHub Repo stars](https://img.shields.io/github/stars/traefik/traefik?style=flat-square) |
|
||||
| [v2ray-core](https://github.com/v2fly/v2ray-core) | A platform for building proxies to bypass network restrictions | ![GitHub Repo stars](https://img.shields.io/github/stars/v2fly/v2ray-core?style=flat-square) |
|
||||
| [YoMo](https://github.com/yomorun/yomo) | Streaming Serverless Framework for Geo-distributed System | ![GitHub Repo stars](https://img.shields.io/github/stars/yomorun/yomo?style=flat-square) |
|
||||
|
||||
## Contributing
|
||||
|
||||
|
316
vendor/github.com/quic-go/quic-go/client.go
generated
vendored
316
vendor/github.com/quic-go/quic-go/client.go
generated
vendored
@ -4,7 +4,6 @@
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
@ -13,20 +12,19 @@
|
||||
)
|
||||
|
||||
type client struct {
|
||||
sconn sendConn
|
||||
// If the client is created with DialAddr, we create a packet conn.
|
||||
// If it is started with Dial, we take a packet conn as a parameter.
|
||||
createdPacketConn bool
|
||||
sendConn sendConn
|
||||
|
||||
use0RTT bool
|
||||
|
||||
packetHandlers packetHandlerManager
|
||||
onClose func()
|
||||
|
||||
tlsConf *tls.Config
|
||||
config *Config
|
||||
|
||||
srcConnID protocol.ConnectionID
|
||||
destConnID protocol.ConnectionID
|
||||
connIDGenerator ConnectionIDGenerator
|
||||
srcConnID protocol.ConnectionID
|
||||
destConnID protocol.ConnectionID
|
||||
|
||||
initialPacketNumber protocol.PacketNumber
|
||||
hasNegotiatedVersion bool
|
||||
@ -46,152 +44,101 @@ type client struct {
|
||||
|
||||
// DialAddr establishes a new QUIC connection to a server.
|
||||
// It uses a new UDP connection and closes this connection when the QUIC connection is closed.
|
||||
// The hostname for SNI is taken from the given address.
|
||||
func DialAddr(
|
||||
addr string,
|
||||
tlsConf *tls.Config,
|
||||
config *Config,
|
||||
) (Connection, error) {
|
||||
return DialAddrContext(context.Background(), addr, tlsConf, config)
|
||||
}
|
||||
|
||||
// DialAddrEarly establishes a new 0-RTT QUIC connection to a server.
|
||||
// It uses a new UDP connection and closes this connection when the QUIC connection is closed.
|
||||
// The hostname for SNI is taken from the given address.
|
||||
func DialAddrEarly(
|
||||
addr string,
|
||||
tlsConf *tls.Config,
|
||||
config *Config,
|
||||
) (EarlyConnection, error) {
|
||||
return DialAddrEarlyContext(context.Background(), addr, tlsConf, config)
|
||||
}
|
||||
|
||||
// DialAddrEarlyContext establishes a new 0-RTT QUIC connection to a server using provided context.
|
||||
// See DialAddrEarly for details
|
||||
func DialAddrEarlyContext(
|
||||
ctx context.Context,
|
||||
addr string,
|
||||
tlsConf *tls.Config,
|
||||
config *Config,
|
||||
) (EarlyConnection, error) {
|
||||
conn, err := dialAddrContext(ctx, addr, tlsConf, config, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
utils.Logger.WithPrefix(utils.DefaultLogger, "client").Debugf("Returning early connection")
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// DialAddrContext establishes a new QUIC connection to a server using the provided context.
|
||||
// See DialAddr for details.
|
||||
func DialAddrContext(
|
||||
ctx context.Context,
|
||||
addr string,
|
||||
tlsConf *tls.Config,
|
||||
config *Config,
|
||||
) (Connection, error) {
|
||||
return dialAddrContext(ctx, addr, tlsConf, config, false)
|
||||
}
|
||||
|
||||
func dialAddrContext(
|
||||
ctx context.Context,
|
||||
addr string,
|
||||
tlsConf *tls.Config,
|
||||
config *Config,
|
||||
use0RTT bool,
|
||||
) (quicConn, error) {
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
func DialAddr(ctx context.Context, addr string, tlsConf *tls.Config, conf *Config) (Connection, error) {
|
||||
udpConn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dialContext(ctx, udpConn, udpAddr, addr, tlsConf, config, use0RTT, true)
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dl, err := setupTransport(udpConn, tlsConf, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dl.Dial(ctx, udpAddr, tlsConf, conf)
|
||||
}
|
||||
|
||||
// DialAddrEarly establishes a new 0-RTT QUIC connection to a server.
|
||||
// It uses a new UDP connection and closes this connection when the QUIC connection is closed.
|
||||
func DialAddrEarly(ctx context.Context, addr string, tlsConf *tls.Config, conf *Config) (EarlyConnection, error) {
|
||||
udpConn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dl, err := setupTransport(udpConn, tlsConf, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn, err := dl.DialEarly(ctx, udpAddr, tlsConf, conf)
|
||||
if err != nil {
|
||||
dl.Close()
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// DialEarly establishes a new 0-RTT QUIC connection to a server using a net.PacketConn using the provided context.
|
||||
// See DialEarly for details.
|
||||
func DialEarly(ctx context.Context, c net.PacketConn, addr net.Addr, tlsConf *tls.Config, conf *Config) (EarlyConnection, error) {
|
||||
dl, err := setupTransport(c, tlsConf, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn, err := dl.DialEarly(ctx, addr, tlsConf, conf)
|
||||
if err != nil {
|
||||
dl.Close()
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// Dial establishes a new QUIC connection to a server using a net.PacketConn. If
|
||||
// the PacketConn satisfies the OOBCapablePacketConn interface (as a net.UDPConn
|
||||
// does), ECN and packet info support will be enabled. In this case, ReadMsgUDP
|
||||
// and WriteMsgUDP will be used instead of ReadFrom and WriteTo to read/write
|
||||
// packets. The same PacketConn can be used for multiple calls to Dial and
|
||||
// Listen, QUIC connection IDs are used for demultiplexing the different
|
||||
// connections. The host parameter is used for SNI. The tls.Config must define
|
||||
// an application protocol (using NextProtos).
|
||||
func Dial(
|
||||
pconn net.PacketConn,
|
||||
remoteAddr net.Addr,
|
||||
host string,
|
||||
tlsConf *tls.Config,
|
||||
config *Config,
|
||||
) (Connection, error) {
|
||||
return dialContext(context.Background(), pconn, remoteAddr, host, tlsConf, config, false, false)
|
||||
}
|
||||
|
||||
// DialEarly establishes a new 0-RTT QUIC connection to a server using a net.PacketConn.
|
||||
// The same PacketConn can be used for multiple calls to Dial and Listen,
|
||||
// QUIC connection IDs are used for demultiplexing the different connections.
|
||||
// The host parameter is used for SNI.
|
||||
// packets.
|
||||
// The tls.Config must define an application protocol (using NextProtos).
|
||||
func DialEarly(
|
||||
pconn net.PacketConn,
|
||||
remoteAddr net.Addr,
|
||||
host string,
|
||||
tlsConf *tls.Config,
|
||||
config *Config,
|
||||
) (EarlyConnection, error) {
|
||||
return DialEarlyContext(context.Background(), pconn, remoteAddr, host, tlsConf, config)
|
||||
}
|
||||
|
||||
// DialEarlyContext establishes a new 0-RTT QUIC connection to a server using a net.PacketConn using the provided context.
|
||||
// See DialEarly for details.
|
||||
func DialEarlyContext(
|
||||
ctx context.Context,
|
||||
pconn net.PacketConn,
|
||||
remoteAddr net.Addr,
|
||||
host string,
|
||||
tlsConf *tls.Config,
|
||||
config *Config,
|
||||
) (EarlyConnection, error) {
|
||||
return dialContext(ctx, pconn, remoteAddr, host, tlsConf, config, true, false)
|
||||
}
|
||||
|
||||
// DialContext establishes a new QUIC connection to a server using a net.PacketConn using the provided context.
|
||||
// See Dial for details.
|
||||
func DialContext(
|
||||
ctx context.Context,
|
||||
pconn net.PacketConn,
|
||||
remoteAddr net.Addr,
|
||||
host string,
|
||||
tlsConf *tls.Config,
|
||||
config *Config,
|
||||
) (Connection, error) {
|
||||
return dialContext(ctx, pconn, remoteAddr, host, tlsConf, config, false, false)
|
||||
}
|
||||
|
||||
func dialContext(
|
||||
ctx context.Context,
|
||||
pconn net.PacketConn,
|
||||
remoteAddr net.Addr,
|
||||
host string,
|
||||
tlsConf *tls.Config,
|
||||
config *Config,
|
||||
use0RTT bool,
|
||||
createdPacketConn bool,
|
||||
) (quicConn, error) {
|
||||
if tlsConf == nil {
|
||||
return nil, errors.New("quic: tls.Config not set")
|
||||
}
|
||||
if err := validateConfig(config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config = populateClientConfig(config, createdPacketConn)
|
||||
packetHandlers, err := getMultiplexer().AddConn(pconn, config.ConnectionIDGenerator.ConnectionIDLen(), config.StatelessResetKey, config.Tracer)
|
||||
func Dial(ctx context.Context, c net.PacketConn, addr net.Addr, tlsConf *tls.Config, conf *Config) (Connection, error) {
|
||||
dl, err := setupTransport(c, tlsConf, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c, err := newClient(pconn, remoteAddr, config, tlsConf, host, use0RTT, createdPacketConn)
|
||||
conn, err := dl.Dial(ctx, addr, tlsConf, conf)
|
||||
if err != nil {
|
||||
dl.Close()
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func setupTransport(c net.PacketConn, tlsConf *tls.Config, createdPacketConn bool) (*Transport, error) {
|
||||
if tlsConf == nil {
|
||||
return nil, errors.New("quic: tls.Config not set")
|
||||
}
|
||||
return &Transport{
|
||||
Conn: c,
|
||||
createdConn: createdPacketConn,
|
||||
isSingleUse: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func dial(
|
||||
ctx context.Context,
|
||||
conn sendConn,
|
||||
connIDGenerator ConnectionIDGenerator,
|
||||
packetHandlers packetHandlerManager,
|
||||
tlsConf *tls.Config,
|
||||
config *Config,
|
||||
onClose func(),
|
||||
use0RTT bool,
|
||||
) (quicConn, error) {
|
||||
c, err := newClient(conn, connIDGenerator, config, tlsConf, onClose, use0RTT)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -199,14 +146,10 @@ func dialContext(
|
||||
|
||||
c.tracingID = nextConnTracingID()
|
||||
if c.config.Tracer != nil {
|
||||
c.tracer = c.config.Tracer.TracerForConnection(
|
||||
context.WithValue(ctx, ConnectionTracingKey, c.tracingID),
|
||||
protocol.PerspectiveClient,
|
||||
c.destConnID,
|
||||
)
|
||||
c.tracer = c.config.Tracer(context.WithValue(ctx, ConnectionTracingKey, c.tracingID), protocol.PerspectiveClient, c.destConnID)
|
||||
}
|
||||
if c.tracer != nil {
|
||||
c.tracer.StartedConnection(c.sconn.LocalAddr(), c.sconn.RemoteAddr(), c.srcConnID, c.destConnID)
|
||||
c.tracer.StartedConnection(c.sendConn.LocalAddr(), c.sendConn.RemoteAddr(), c.srcConnID, c.destConnID)
|
||||
}
|
||||
if err := c.dial(ctx); err != nil {
|
||||
return nil, err
|
||||
@ -214,40 +157,14 @@ func dialContext(
|
||||
return c.conn, nil
|
||||
}
|
||||
|
||||
func newClient(
|
||||
pconn net.PacketConn,
|
||||
remoteAddr net.Addr,
|
||||
config *Config,
|
||||
tlsConf *tls.Config,
|
||||
host string,
|
||||
use0RTT bool,
|
||||
createdPacketConn bool,
|
||||
) (*client, error) {
|
||||
func newClient(sendConn sendConn, connIDGenerator ConnectionIDGenerator, config *Config, tlsConf *tls.Config, onClose func(), use0RTT bool) (*client, error) {
|
||||
if tlsConf == nil {
|
||||
tlsConf = &tls.Config{}
|
||||
} else {
|
||||
tlsConf = tlsConf.Clone()
|
||||
}
|
||||
if tlsConf.ServerName == "" {
|
||||
sni, _, err := net.SplitHostPort(host)
|
||||
if err != nil {
|
||||
// It's ok if net.SplitHostPort returns an error - it could be a hostname/IP address without a port.
|
||||
sni = host
|
||||
}
|
||||
|
||||
tlsConf.ServerName = sni
|
||||
}
|
||||
|
||||
// check that all versions are actually supported
|
||||
if config != nil {
|
||||
for _, v := range config.Versions {
|
||||
if !protocol.IsValidVersion(v) {
|
||||
return nil, fmt.Errorf("%s is not a valid QUIC version", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
srcConnID, err := config.ConnectionIDGenerator.GenerateConnectionID()
|
||||
srcConnID, err := connIDGenerator.GenerateConnectionID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -256,28 +173,30 @@ func newClient(
|
||||
return nil, err
|
||||
}
|
||||
c := &client{
|
||||
srcConnID: srcConnID,
|
||||
destConnID: destConnID,
|
||||
sconn: newSendPconn(pconn, remoteAddr),
|
||||
createdPacketConn: createdPacketConn,
|
||||
use0RTT: use0RTT,
|
||||
tlsConf: tlsConf,
|
||||
config: config,
|
||||
version: config.Versions[0],
|
||||
handshakeChan: make(chan struct{}),
|
||||
logger: utils.DefaultLogger.WithPrefix("client"),
|
||||
connIDGenerator: connIDGenerator,
|
||||
srcConnID: srcConnID,
|
||||
destConnID: destConnID,
|
||||
sendConn: sendConn,
|
||||
use0RTT: use0RTT,
|
||||
onClose: onClose,
|
||||
tlsConf: tlsConf,
|
||||
config: config,
|
||||
version: config.Versions[0],
|
||||
handshakeChan: make(chan struct{}),
|
||||
logger: utils.DefaultLogger.WithPrefix("client"),
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *client) dial(ctx context.Context) error {
|
||||
c.logger.Infof("Starting new connection to %s (%s -> %s), source connection ID %s, destination connection ID %s, version %s", c.tlsConf.ServerName, c.sconn.LocalAddr(), c.sconn.RemoteAddr(), c.srcConnID, c.destConnID, c.version)
|
||||
c.logger.Infof("Starting new connection to %s (%s -> %s), source connection ID %s, destination connection ID %s, version %s", c.tlsConf.ServerName, c.sendConn.LocalAddr(), c.sendConn.RemoteAddr(), c.srcConnID, c.destConnID, c.version)
|
||||
|
||||
c.conn = newClientConnection(
|
||||
c.sconn,
|
||||
c.sendConn,
|
||||
c.packetHandlers,
|
||||
c.destConnID,
|
||||
c.srcConnID,
|
||||
c.connIDGenerator,
|
||||
c.config,
|
||||
c.tlsConf,
|
||||
c.initialPacketNumber,
|
||||
@ -291,13 +210,18 @@ func (c *client) dial(ctx context.Context) error {
|
||||
c.packetHandlers.Add(c.srcConnID, c.conn)
|
||||
|
||||
errorChan := make(chan error, 1)
|
||||
recreateChan := make(chan errCloseForRecreating)
|
||||
go func() {
|
||||
err := c.conn.run() // returns as soon as the connection is closed
|
||||
|
||||
if e := (&errCloseForRecreating{}); !errors.As(err, &e) && c.createdPacketConn {
|
||||
c.packetHandlers.Destroy()
|
||||
err := c.conn.run()
|
||||
var recreateErr *errCloseForRecreating
|
||||
if errors.As(err, &recreateErr) {
|
||||
recreateChan <- *recreateErr
|
||||
return
|
||||
}
|
||||
errorChan <- err
|
||||
if c.onClose != nil {
|
||||
c.onClose()
|
||||
}
|
||||
errorChan <- err // returns as soon as the connection is closed
|
||||
}()
|
||||
|
||||
// only set when we're using 0-RTT
|
||||
@ -312,14 +236,12 @@ func (c *client) dial(ctx context.Context) error {
|
||||
c.conn.shutdown()
|
||||
return ctx.Err()
|
||||
case err := <-errorChan:
|
||||
var recreateErr *errCloseForRecreating
|
||||
if errors.As(err, &recreateErr) {
|
||||
c.initialPacketNumber = recreateErr.nextPacketNumber
|
||||
c.version = recreateErr.nextVersion
|
||||
c.hasNegotiatedVersion = true
|
||||
return c.dial(ctx)
|
||||
}
|
||||
return err
|
||||
case recreateErr := <-recreateChan:
|
||||
c.initialPacketNumber = recreateErr.nextPacketNumber
|
||||
c.version = recreateErr.nextVersion
|
||||
c.hasNegotiatedVersion = true
|
||||
return c.dial(ctx)
|
||||
case <-earlyConnChan:
|
||||
// ready to send 0-RTT data
|
||||
return nil
|
||||
|
35
vendor/github.com/quic-go/quic-go/config.go
generated
vendored
35
vendor/github.com/quic-go/quic-go/config.go
generated
vendored
@ -2,6 +2,7 @@
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
@ -29,13 +30,19 @@ func validateConfig(config *Config) error {
|
||||
if config.MaxIncomingUniStreams > 1<<60 {
|
||||
return errors.New("invalid value for Config.MaxIncomingUniStreams")
|
||||
}
|
||||
// check that all QUIC versions are actually supported
|
||||
for _, v := range config.Versions {
|
||||
if !protocol.IsValidVersion(v) {
|
||||
return fmt.Errorf("invalid QUIC version: %s", v)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// populateServerConfig populates fields in the quic.Config with their default values, if none are set
|
||||
// it may be called with nil
|
||||
func populateServerConfig(config *Config) *Config {
|
||||
config = populateConfig(config, protocol.DefaultConnectionIDLength)
|
||||
config = populateConfig(config)
|
||||
if config.MaxTokenAge == 0 {
|
||||
config.MaxTokenAge = protocol.TokenValidity
|
||||
}
|
||||
@ -48,19 +55,9 @@ func populateServerConfig(config *Config) *Config {
|
||||
return config
|
||||
}
|
||||
|
||||
// populateClientConfig populates fields in the quic.Config with their default values, if none are set
|
||||
// populateConfig populates fields in the quic.Config with their default values, if none are set
|
||||
// it may be called with nil
|
||||
func populateClientConfig(config *Config, createdPacketConn bool) *Config {
|
||||
defaultConnIDLen := protocol.DefaultConnectionIDLength
|
||||
if createdPacketConn {
|
||||
defaultConnIDLen = 0
|
||||
}
|
||||
|
||||
config = populateConfig(config, defaultConnIDLen)
|
||||
return config
|
||||
}
|
||||
|
||||
func populateConfig(config *Config, defaultConnIDLen int) *Config {
|
||||
func populateConfig(config *Config) *Config {
|
||||
if config == nil {
|
||||
config = &Config{}
|
||||
}
|
||||
@ -68,10 +65,6 @@ func populateConfig(config *Config, defaultConnIDLen int) *Config {
|
||||
if len(versions) == 0 {
|
||||
versions = protocol.SupportedVersions
|
||||
}
|
||||
conIDLen := config.ConnectionIDLength
|
||||
if config.ConnectionIDLength == 0 {
|
||||
conIDLen = defaultConnIDLen
|
||||
}
|
||||
handshakeIdleTimeout := protocol.DefaultHandshakeIdleTimeout
|
||||
if config.HandshakeIdleTimeout != 0 {
|
||||
handshakeIdleTimeout = config.HandshakeIdleTimeout
|
||||
@ -108,12 +101,9 @@ func populateConfig(config *Config, defaultConnIDLen int) *Config {
|
||||
} else if maxIncomingUniStreams < 0 {
|
||||
maxIncomingUniStreams = 0
|
||||
}
|
||||
connIDGenerator := config.ConnectionIDGenerator
|
||||
if connIDGenerator == nil {
|
||||
connIDGenerator = &protocol.DefaultConnectionIDGenerator{ConnLen: conIDLen}
|
||||
}
|
||||
|
||||
return &Config{
|
||||
GetConfigForClient: config.GetConfigForClient,
|
||||
Versions: versions,
|
||||
HandshakeIdleTimeout: handshakeIdleTimeout,
|
||||
MaxIdleTimeout: idleTimeout,
|
||||
@ -128,9 +118,6 @@ func populateConfig(config *Config, defaultConnIDLen int) *Config {
|
||||
AllowConnectionWindowIncrease: config.AllowConnectionWindowIncrease,
|
||||
MaxIncomingStreams: maxIncomingStreams,
|
||||
MaxIncomingUniStreams: maxIncomingUniStreams,
|
||||
ConnectionIDLength: conIDLen,
|
||||
ConnectionIDGenerator: connIDGenerator,
|
||||
StatelessResetKey: config.StatelessResetKey,
|
||||
TokenStore: config.TokenStore,
|
||||
EnableDatagrams: config.EnableDatagrams,
|
||||
DisablePathMTUDiscovery: config.DisablePathMTUDiscovery,
|
||||
|
32
vendor/github.com/quic-go/quic-go/connection.go
generated
vendored
32
vendor/github.com/quic-go/quic-go/connection.go
generated
vendored
@ -240,6 +240,7 @@ type connection struct {
|
||||
clientDestConnID protocol.ConnectionID,
|
||||
destConnID protocol.ConnectionID,
|
||||
srcConnID protocol.ConnectionID,
|
||||
connIDGenerator ConnectionIDGenerator,
|
||||
statelessResetToken protocol.StatelessResetToken,
|
||||
conf *Config,
|
||||
tlsConf *tls.Config,
|
||||
@ -283,7 +284,7 @@ func(connID protocol.ConnectionID) { runner.Add(connID, s) },
|
||||
runner.Retire,
|
||||
runner.ReplaceWithClosed,
|
||||
s.queueControlFrame,
|
||||
s.config.ConnectionIDGenerator,
|
||||
connIDGenerator,
|
||||
)
|
||||
s.preSetup()
|
||||
s.ctx, s.ctxCancel = context.WithCancel(context.WithValue(context.Background(), ConnectionTracingKey, tracingID))
|
||||
@ -311,9 +312,14 @@ func(connID protocol.ConnectionID) { runner.Add(connID, s) },
|
||||
DisableActiveMigration: true,
|
||||
StatelessResetToken: &statelessResetToken,
|
||||
OriginalDestinationConnectionID: origDestConnID,
|
||||
ActiveConnectionIDLimit: protocol.MaxActiveConnectionIDs,
|
||||
InitialSourceConnectionID: srcConnID,
|
||||
RetrySourceConnectionID: retrySrcConnID,
|
||||
// For interoperability with quic-go versions before May 2023, this value must be set to a value
|
||||
// different from protocol.DefaultActiveConnectionIDLimit.
|
||||
// If set to the default value, it will be omitted from the transport parameters, which will make
|
||||
// old quic-go versions interpret it as 0, instead of the default value of 2.
|
||||
// See https://github.com/quic-go/quic-go/pull/3806.
|
||||
ActiveConnectionIDLimit: protocol.MaxActiveConnectionIDs,
|
||||
InitialSourceConnectionID: srcConnID,
|
||||
RetrySourceConnectionID: retrySrcConnID,
|
||||
}
|
||||
if s.config.EnableDatagrams {
|
||||
params.MaxDatagramFrameSize = protocol.MaxDatagramFrameSize
|
||||
@ -323,10 +329,6 @@ func(connID protocol.ConnectionID) { runner.Add(connID, s) },
|
||||
if s.tracer != nil {
|
||||
s.tracer.SentTransportParameters(params)
|
||||
}
|
||||
var allow0RTT func() bool
|
||||
if conf.Allow0RTT != nil {
|
||||
allow0RTT = func() bool { return conf.Allow0RTT(conn.RemoteAddr()) }
|
||||
}
|
||||
cs := handshake.NewCryptoSetupServer(
|
||||
initialStream,
|
||||
handshakeStream,
|
||||
@ -344,7 +346,7 @@ func(connID protocol.ConnectionID) { runner.Add(connID, s) },
|
||||
},
|
||||
},
|
||||
tlsConf,
|
||||
allow0RTT,
|
||||
conf.Allow0RTT,
|
||||
s.rttStats,
|
||||
tracer,
|
||||
logger,
|
||||
@ -363,6 +365,7 @@ func(connID protocol.ConnectionID) { runner.Add(connID, s) },
|
||||
runner connRunner,
|
||||
destConnID protocol.ConnectionID,
|
||||
srcConnID protocol.ConnectionID,
|
||||
connIDGenerator ConnectionIDGenerator,
|
||||
conf *Config,
|
||||
tlsConf *tls.Config,
|
||||
initialPacketNumber protocol.PacketNumber,
|
||||
@ -402,7 +405,7 @@ func(connID protocol.ConnectionID) { runner.Add(connID, s) },
|
||||
runner.Retire,
|
||||
runner.ReplaceWithClosed,
|
||||
s.queueControlFrame,
|
||||
s.config.ConnectionIDGenerator,
|
||||
connIDGenerator,
|
||||
)
|
||||
s.preSetup()
|
||||
s.ctx, s.ctxCancel = context.WithCancel(context.WithValue(context.Background(), ConnectionTracingKey, tracingID))
|
||||
@ -428,8 +431,13 @@ func(connID protocol.ConnectionID) { runner.Add(connID, s) },
|
||||
MaxAckDelay: protocol.MaxAckDelayInclGranularity,
|
||||
AckDelayExponent: protocol.AckDelayExponent,
|
||||
DisableActiveMigration: true,
|
||||
ActiveConnectionIDLimit: protocol.MaxActiveConnectionIDs,
|
||||
InitialSourceConnectionID: srcConnID,
|
||||
// For interoperability with quic-go versions before May 2023, this value must be set to a value
|
||||
// different from protocol.DefaultActiveConnectionIDLimit.
|
||||
// If set to the default value, it will be omitted from the transport parameters, which will make
|
||||
// old quic-go versions interpret it as 0, instead of the default value of 2.
|
||||
// See https://github.com/quic-go/quic-go/pull/3806.
|
||||
ActiveConnectionIDLimit: protocol.MaxActiveConnectionIDs,
|
||||
InitialSourceConnectionID: srcConnID,
|
||||
}
|
||||
if s.config.EnableDatagrams {
|
||||
params.MaxDatagramFrameSize = protocol.MaxDatagramFrameSize
|
||||
|
8
vendor/github.com/quic-go/quic-go/http3/client.go
generated
vendored
8
vendor/github.com/quic-go/quic-go/http3/client.go
generated
vendored
@ -33,12 +33,11 @@
|
||||
var defaultQuicConfig = &quic.Config{
|
||||
MaxIncomingStreams: -1, // don't allow the server to create bidirectional streams
|
||||
KeepAlivePeriod: 10 * time.Second,
|
||||
Versions: []protocol.VersionNumber{protocol.Version1},
|
||||
}
|
||||
|
||||
type dialFunc func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error)
|
||||
|
||||
var dialAddr = quic.DialAddrEarlyContext
|
||||
var dialAddr dialFunc = quic.DialAddrEarly
|
||||
|
||||
type roundTripperOpts struct {
|
||||
DisableCompression bool
|
||||
@ -74,9 +73,10 @@ type client struct {
|
||||
func newClient(hostname string, tlsConf *tls.Config, opts *roundTripperOpts, conf *quic.Config, dialer dialFunc) (roundTripCloser, error) {
|
||||
if conf == nil {
|
||||
conf = defaultQuicConfig.Clone()
|
||||
} else if len(conf.Versions) == 0 {
|
||||
}
|
||||
if len(conf.Versions) == 0 {
|
||||
conf = conf.Clone()
|
||||
conf.Versions = []quic.VersionNumber{defaultQuicConfig.Versions[0]}
|
||||
conf.Versions = []quic.VersionNumber{protocol.SupportedVersions[0]}
|
||||
}
|
||||
if len(conf.Versions) != 1 {
|
||||
return nil, errors.New("can only use a single QUIC version for dialing a HTTP/3 connection")
|
||||
|
2
vendor/github.com/quic-go/quic-go/http3/mockgen.go
generated
vendored
2
vendor/github.com/quic-go/quic-go/http3/mockgen.go
generated
vendored
@ -4,3 +4,5 @@
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package http3 -destination mock_roundtripcloser_test.go github.com/quic-go/quic-go/http3 RoundTripCloser"
|
||||
type RoundTripCloser = roundTripCloser
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -package http3 -destination mock_quic_early_listener_test.go github.com/quic-go/quic-go/http3 QUICEarlyListener"
|
||||
|
11
vendor/github.com/quic-go/quic-go/http3/response_writer.go
generated
vendored
11
vendor/github.com/quic-go/quic-go/http3/response_writer.go
generated
vendored
@ -6,6 +6,7 @@
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/quic-go/quic-go"
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
@ -15,6 +16,7 @@
|
||||
|
||||
type responseWriter struct {
|
||||
conn quic.Connection
|
||||
str quic.Stream
|
||||
bufferedStr *bufio.Writer
|
||||
buf []byte
|
||||
|
||||
@ -36,6 +38,7 @@ func newResponseWriter(str quic.Stream, conn quic.Connection, logger utils.Logge
|
||||
header: http.Header{},
|
||||
buf: make([]byte, 16),
|
||||
conn: conn,
|
||||
str: str,
|
||||
bufferedStr: bufio.NewWriter(str),
|
||||
logger: logger,
|
||||
}
|
||||
@ -121,6 +124,14 @@ func (w *responseWriter) StreamCreator() StreamCreator {
|
||||
return w.conn
|
||||
}
|
||||
|
||||
func (w *responseWriter) SetReadDeadline(deadline time.Time) error {
|
||||
return w.str.SetReadDeadline(deadline)
|
||||
}
|
||||
|
||||
func (w *responseWriter) SetWriteDeadline(deadline time.Time) error {
|
||||
return w.str.SetWriteDeadline(deadline)
|
||||
}
|
||||
|
||||
// copied from http2/http2.go
|
||||
// bodyAllowedForStatus reports whether a given response status code
|
||||
// permits a body. See RFC 2616, section 4.4.
|
||||
|
32
vendor/github.com/quic-go/quic-go/http3/roundtrip.go
generated
vendored
32
vendor/github.com/quic-go/quic-go/http3/roundtrip.go
generated
vendored
@ -10,6 +10,7 @@
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"golang.org/x/net/http/httpguts"
|
||||
|
||||
@ -17,7 +18,7 @@
|
||||
)
|
||||
|
||||
// declare this as a variable, such that we can it mock it in the tests
|
||||
var quicDialer = quic.DialEarlyContext
|
||||
var quicDialer = quic.DialEarly
|
||||
|
||||
type roundTripCloser interface {
|
||||
RoundTripOpt(*http.Request, RoundTripOpt) (*http.Response, error)
|
||||
@ -25,6 +26,11 @@ type roundTripCloser interface {
|
||||
io.Closer
|
||||
}
|
||||
|
||||
type roundTripCloserWithCount struct {
|
||||
roundTripCloser
|
||||
useCount atomic.Int64
|
||||
}
|
||||
|
||||
// RoundTripper implements the http.RoundTripper interface
|
||||
type RoundTripper struct {
|
||||
mutex sync.Mutex
|
||||
@ -82,7 +88,7 @@ type RoundTripper struct {
|
||||
MaxResponseHeaderBytes int64
|
||||
|
||||
newClient func(hostname string, tlsConf *tls.Config, opts *roundTripperOpts, conf *quic.Config, dialer dialFunc) (roundTripCloser, error) // so we can mock it in tests
|
||||
clients map[string]roundTripCloser
|
||||
clients map[string]*roundTripCloserWithCount
|
||||
udpConn *net.UDPConn
|
||||
}
|
||||
|
||||
@ -143,6 +149,7 @@ func (r *RoundTripper) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cl.useCount.Add(-1)
|
||||
rsp, err := cl.RoundTripOpt(req, opt)
|
||||
if err != nil {
|
||||
r.removeClient(hostname)
|
||||
@ -160,12 +167,12 @@ func (r *RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
return r.RoundTripOpt(req, RoundTripOpt{})
|
||||
}
|
||||
|
||||
func (r *RoundTripper) getClient(hostname string, onlyCached bool) (rtc roundTripCloser, isReused bool, err error) {
|
||||
func (r *RoundTripper) getClient(hostname string, onlyCached bool) (rtc *roundTripCloserWithCount, isReused bool, err error) {
|
||||
r.mutex.Lock()
|
||||
defer r.mutex.Unlock()
|
||||
|
||||
if r.clients == nil {
|
||||
r.clients = make(map[string]roundTripCloser)
|
||||
r.clients = make(map[string]*roundTripCloserWithCount)
|
||||
}
|
||||
|
||||
client, ok := r.clients[hostname]
|
||||
@ -188,7 +195,7 @@ func (r *RoundTripper) getClient(hostname string, onlyCached bool) (rtc roundTri
|
||||
}
|
||||
dial = r.makeDialer()
|
||||
}
|
||||
client, err = newCl(
|
||||
c, err := newCl(
|
||||
hostname,
|
||||
r.TLSClientConfig,
|
||||
&roundTripperOpts{
|
||||
@ -204,10 +211,12 @@ func (r *RoundTripper) getClient(hostname string, onlyCached bool) (rtc roundTri
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
client = &roundTripCloserWithCount{roundTripCloser: c}
|
||||
r.clients[hostname] = client
|
||||
} else if client.HandshakeComplete() {
|
||||
isReused = true
|
||||
}
|
||||
client.useCount.Add(1)
|
||||
return client, isReused, nil
|
||||
}
|
||||
|
||||
@ -273,6 +282,17 @@ func (r *RoundTripper) makeDialer() func(ctx context.Context, addr string, tlsCf
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return quicDialer(ctx, r.udpConn, udpAddr, addr, tlsCfg, cfg)
|
||||
return quicDialer(ctx, r.udpConn, udpAddr, tlsCfg, cfg)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RoundTripper) CloseIdleConnections() {
|
||||
r.mutex.Lock()
|
||||
defer r.mutex.Unlock()
|
||||
for hostname, client := range r.clients {
|
||||
if client.useCount.Load() == 0 {
|
||||
client.Close()
|
||||
delete(r.clients, hostname)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
38
vendor/github.com/quic-go/quic-go/http3/server.go
generated
vendored
38
vendor/github.com/quic-go/quic-go/http3/server.go
generated
vendored
@ -23,8 +23,12 @@
|
||||
|
||||
// allows mocking of quic.Listen and quic.ListenAddr
|
||||
var (
|
||||
quicListen = quic.ListenEarly
|
||||
quicListenAddr = quic.ListenAddrEarly
|
||||
quicListen = func(conn net.PacketConn, tlsConf *tls.Config, config *quic.Config) (QUICEarlyListener, error) {
|
||||
return quic.ListenEarly(conn, tlsConf, config)
|
||||
}
|
||||
quicListenAddr = func(addr string, tlsConf *tls.Config, config *quic.Config) (QUICEarlyListener, error) {
|
||||
return quic.ListenAddrEarly(addr, tlsConf, config)
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
@ -44,6 +48,15 @@
|
||||
streamTypeQPACKDecoderStream = 3
|
||||
)
|
||||
|
||||
// A QUICEarlyListener listens for incoming QUIC connections.
|
||||
type QUICEarlyListener interface {
|
||||
Accept(context.Context) (quic.EarlyConnection, error)
|
||||
Addr() net.Addr
|
||||
io.Closer
|
||||
}
|
||||
|
||||
var _ QUICEarlyListener = &quic.EarlyListener{}
|
||||
|
||||
func versionToALPN(v protocol.VersionNumber) string {
|
||||
//nolint:exhaustive // These are all the versions we care about.
|
||||
switch v {
|
||||
@ -193,7 +206,7 @@ type Server struct {
|
||||
UniStreamHijacker func(StreamType, quic.Connection, quic.ReceiveStream, error) (hijacked bool)
|
||||
|
||||
mutex sync.RWMutex
|
||||
listeners map[*quic.EarlyListener]listenerInfo
|
||||
listeners map[*QUICEarlyListener]listenerInfo
|
||||
|
||||
closed bool
|
||||
|
||||
@ -249,7 +262,7 @@ func (s *Server) ServeQUICConn(conn quic.Connection) error {
|
||||
// Make sure you use http3.ConfigureTLSConfig to configure a tls.Config
|
||||
// and use it to construct a http3-friendly QUIC listener.
|
||||
// Closing the server does close the listener.
|
||||
func (s *Server) ServeListener(ln quic.EarlyListener) error {
|
||||
func (s *Server) ServeListener(ln QUICEarlyListener) error {
|
||||
if err := s.addListener(&ln); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -275,7 +288,7 @@ func (s *Server) serveConn(tlsConf *tls.Config, conn net.PacketConn) error {
|
||||
baseConf := ConfigureTLSConfig(tlsConf)
|
||||
quicConf := s.QuicConfig
|
||||
if quicConf == nil {
|
||||
quicConf = &quic.Config{Allow0RTT: func(net.Addr) bool { return true }}
|
||||
quicConf = &quic.Config{Allow0RTT: true}
|
||||
} else {
|
||||
quicConf = s.QuicConfig.Clone()
|
||||
}
|
||||
@ -283,7 +296,7 @@ func (s *Server) serveConn(tlsConf *tls.Config, conn net.PacketConn) error {
|
||||
quicConf.EnableDatagrams = true
|
||||
}
|
||||
|
||||
var ln quic.EarlyListener
|
||||
var ln QUICEarlyListener
|
||||
var err error
|
||||
if conn == nil {
|
||||
addr := s.Addr
|
||||
@ -305,7 +318,7 @@ func (s *Server) serveConn(tlsConf *tls.Config, conn net.PacketConn) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Server) serveListener(ln quic.EarlyListener) error {
|
||||
func (s *Server) serveListener(ln QUICEarlyListener) error {
|
||||
for {
|
||||
conn, err := ln.Accept(context.Background())
|
||||
if err != nil {
|
||||
@ -391,7 +404,7 @@ func (s *Server) generateAltSvcHeader() {
|
||||
// We store a pointer to interface in the map set. This is safe because we only
|
||||
// call trackListener via Serve and can track+defer untrack the same pointer to
|
||||
// local variable there. We never need to compare a Listener from another caller.
|
||||
func (s *Server) addListener(l *quic.EarlyListener) error {
|
||||
func (s *Server) addListener(l *QUICEarlyListener) error {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
|
||||
@ -402,25 +415,24 @@ func (s *Server) addListener(l *quic.EarlyListener) error {
|
||||
s.logger = utils.DefaultLogger.WithPrefix("server")
|
||||
}
|
||||
if s.listeners == nil {
|
||||
s.listeners = make(map[*quic.EarlyListener]listenerInfo)
|
||||
s.listeners = make(map[*QUICEarlyListener]listenerInfo)
|
||||
}
|
||||
|
||||
if port, err := extractPort((*l).Addr().String()); err == nil {
|
||||
s.listeners[l] = listenerInfo{port}
|
||||
} else {
|
||||
s.logger.Errorf(
|
||||
"Unable to extract port from listener %+v, will not be announced using SetQuicHeaders: %s", err)
|
||||
s.logger.Errorf("Unable to extract port from listener %+v, will not be announced using SetQuicHeaders: %s", err)
|
||||
s.listeners[l] = listenerInfo{}
|
||||
}
|
||||
s.generateAltSvcHeader()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) removeListener(l *quic.EarlyListener) {
|
||||
func (s *Server) removeListener(l *QUICEarlyListener) {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
delete(s.listeners, l)
|
||||
s.generateAltSvcHeader()
|
||||
s.mutex.Unlock()
|
||||
}
|
||||
|
||||
func (s *Server) handleConn(conn quic.Connection) error {
|
||||
|
51
vendor/github.com/quic-go/quic-go/interface.go
generated
vendored
51
vendor/github.com/quic-go/quic-go/interface.go
generated
vendored
@ -198,7 +198,7 @@ type EarlyConnection interface {
|
||||
|
||||
// HandshakeComplete blocks until the handshake completes (or fails).
|
||||
// For the client, data sent before completion of the handshake is encrypted with 0-RTT keys.
|
||||
// For the serfer, data sent before completion of the handshake is encrypted with 1-RTT keys,
|
||||
// For the server, data sent before completion of the handshake is encrypted with 1-RTT keys,
|
||||
// however the client's identity is only verified once the handshake completes.
|
||||
HandshakeComplete() <-chan struct{}
|
||||
|
||||
@ -239,21 +239,12 @@ type ConnectionIDGenerator interface {
|
||||
|
||||
// Config contains all configuration data needed for a QUIC server or client.
|
||||
type Config struct {
|
||||
// GetConfigForClient is called for incoming connections.
|
||||
// If the error is not nil, the connection attempt is refused.
|
||||
GetConfigForClient func(info *ClientHelloInfo) (*Config, error)
|
||||
// The QUIC versions that can be negotiated.
|
||||
// If not set, it uses all versions available.
|
||||
Versions []VersionNumber
|
||||
// The length of the connection ID in bytes.
|
||||
// It can be 0, or any value between 4 and 18.
|
||||
// If not set, the interpretation depends on where the Config is used:
|
||||
// If used for dialing an address, a 0 byte connection ID will be used.
|
||||
// If used for a server, or dialing on a packet conn, a 4 byte connection ID will be used.
|
||||
// When dialing on a packet conn, the ConnectionIDLength value must be the same for every Dial call.
|
||||
ConnectionIDLength int
|
||||
// An optional ConnectionIDGenerator to be used for ConnectionIDs generated during the lifecycle of a QUIC connection.
|
||||
// The goal is to give some control on how connection IDs, which can be useful in some scenarios, in particular for servers.
|
||||
// By default, if not provided, random connection IDs with the length given by ConnectionIDLength is used.
|
||||
// Otherwise, if one is provided, then ConnectionIDLength is ignored.
|
||||
ConnectionIDGenerator ConnectionIDGenerator
|
||||
// HandshakeIdleTimeout is the idle timeout before completion of the handshake.
|
||||
// Specifically, if we don't receive any packet from the peer within this time, the connection attempt is aborted.
|
||||
// If this value is zero, the timeout is set to 5 seconds.
|
||||
@ -314,9 +305,6 @@ type Config struct {
|
||||
// If not set, it will default to 100.
|
||||
// If set to a negative value, it doesn't allow any unidirectional streams.
|
||||
MaxIncomingUniStreams int64
|
||||
// The StatelessResetKey is used to generate stateless reset tokens.
|
||||
// If no key is configured, sending of stateless resets is disabled.
|
||||
StatelessResetKey *StatelessResetKey
|
||||
// KeepAlivePeriod defines whether this peer will periodically send a packet to keep the connection alive.
|
||||
// If set to 0, then no keep alive is sent. Otherwise, the keep alive is sent on that period (or at most
|
||||
// every half of MaxIdleTimeout, whichever is smaller).
|
||||
@ -330,13 +318,15 @@ type Config struct {
|
||||
// It has no effect for a client.
|
||||
DisableVersionNegotiationPackets bool
|
||||
// Allow0RTT allows the application to decide if a 0-RTT connection attempt should be accepted.
|
||||
// When set, 0-RTT is enabled. When not set, 0-RTT is disabled.
|
||||
// Only valid for the server.
|
||||
// Warning: This API should not be considered stable and might change soon.
|
||||
Allow0RTT func(net.Addr) bool
|
||||
Allow0RTT bool
|
||||
// Enable QUIC datagram support (RFC 9221).
|
||||
EnableDatagrams bool
|
||||
Tracer logging.Tracer
|
||||
Tracer func(context.Context, logging.Perspective, ConnectionID) logging.ConnectionTracer
|
||||
}
|
||||
|
||||
type ClientHelloInfo struct {
|
||||
RemoteAddr net.Addr
|
||||
}
|
||||
|
||||
// ConnectionState records basic details about a QUIC connection
|
||||
@ -345,24 +335,3 @@ type ConnectionState struct {
|
||||
SupportsDatagrams bool
|
||||
Version VersionNumber
|
||||
}
|
||||
|
||||
// A Listener for incoming QUIC connections
|
||||
type Listener interface {
|
||||
// Close the server. All active connections will be closed.
|
||||
Close() error
|
||||
// Addr returns the local network addr that the server is listening on.
|
||||
Addr() net.Addr
|
||||
// Accept returns new connections. It should be called in a loop.
|
||||
Accept(context.Context) (Connection, error)
|
||||
}
|
||||
|
||||
// An EarlyListener listens for incoming QUIC connections,
|
||||
// and returns them before the handshake completes.
|
||||
type EarlyListener interface {
|
||||
// Close the server. All active connections will be closed.
|
||||
Close() error
|
||||
// Addr returns the local network addr that the server is listening on.
|
||||
Addr() net.Addr
|
||||
// Accept returns new early connections. It should be called in a loop.
|
||||
Accept(context.Context) (EarlyConnection, error)
|
||||
}
|
||||
|
2
vendor/github.com/quic-go/quic-go/internal/ackhandler/packet.go
generated
vendored
2
vendor/github.com/quic-go/quic-go/internal/ackhandler/packet.go
generated
vendored
@ -9,12 +9,12 @@
|
||||
|
||||
// A Packet is a packet
|
||||
type Packet struct {
|
||||
SendTime time.Time
|
||||
PacketNumber protocol.PacketNumber
|
||||
Frames []*Frame
|
||||
LargestAcked protocol.PacketNumber // InvalidPacketNumber if the packet doesn't contain an ACK
|
||||
Length protocol.ByteCount
|
||||
EncryptionLevel protocol.EncryptionLevel
|
||||
SendTime time.Time
|
||||
|
||||
IsPathMTUProbePacket bool // We don't report the loss of Path MTU probe packets to the congestion controller.
|
||||
|
||||
|
19
vendor/github.com/quic-go/quic-go/internal/congestion/pacer.go
generated
vendored
19
vendor/github.com/quic-go/quic-go/internal/congestion/pacer.go
generated
vendored
@ -12,16 +12,16 @@
|
||||
|
||||
// The pacer implements a token bucket pacing algorithm.
|
||||
type pacer struct {
|
||||
budgetAtLastSent protocol.ByteCount
|
||||
maxDatagramSize protocol.ByteCount
|
||||
lastSentTime time.Time
|
||||
getAdjustedBandwidth func() uint64 // in bytes/s
|
||||
budgetAtLastSent protocol.ByteCount
|
||||
maxDatagramSize protocol.ByteCount
|
||||
lastSentTime time.Time
|
||||
adjustedBandwidth func() uint64 // in bytes/s
|
||||
}
|
||||
|
||||
func newPacer(getBandwidth func() Bandwidth) *pacer {
|
||||
p := &pacer{
|
||||
maxDatagramSize: initialMaxDatagramSize,
|
||||
getAdjustedBandwidth: func() uint64 {
|
||||
adjustedBandwidth: func() uint64 {
|
||||
// Bandwidth is in bits/s. We need the value in bytes/s.
|
||||
bw := uint64(getBandwidth() / BytesPerSecond)
|
||||
// Use a slightly higher value than the actual measured bandwidth.
|
||||
@ -49,13 +49,16 @@ func (p *pacer) Budget(now time.Time) protocol.ByteCount {
|
||||
if p.lastSentTime.IsZero() {
|
||||
return p.maxBurstSize()
|
||||
}
|
||||
budget := p.budgetAtLastSent + (protocol.ByteCount(p.getAdjustedBandwidth())*protocol.ByteCount(now.Sub(p.lastSentTime).Nanoseconds()))/1e9
|
||||
budget := p.budgetAtLastSent + (protocol.ByteCount(p.adjustedBandwidth())*protocol.ByteCount(now.Sub(p.lastSentTime).Nanoseconds()))/1e9
|
||||
if budget < 0 { // protect against overflows
|
||||
budget = protocol.MaxByteCount
|
||||
}
|
||||
return utils.Min(p.maxBurstSize(), budget)
|
||||
}
|
||||
|
||||
func (p *pacer) maxBurstSize() protocol.ByteCount {
|
||||
return utils.Max(
|
||||
protocol.ByteCount(uint64((protocol.MinPacingDelay+protocol.TimerGranularity).Nanoseconds())*p.getAdjustedBandwidth())/1e9,
|
||||
protocol.ByteCount(uint64((protocol.MinPacingDelay+protocol.TimerGranularity).Nanoseconds())*p.adjustedBandwidth())/1e9,
|
||||
maxBurstSizePackets*p.maxDatagramSize,
|
||||
)
|
||||
}
|
||||
@ -68,7 +71,7 @@ func (p *pacer) TimeUntilSend() time.Time {
|
||||
}
|
||||
return p.lastSentTime.Add(utils.Max(
|
||||
protocol.MinPacingDelay,
|
||||
time.Duration(math.Ceil(float64(p.maxDatagramSize-p.budgetAtLastSent)*1e9/float64(p.getAdjustedBandwidth())))*time.Nanosecond,
|
||||
time.Duration(math.Ceil(float64(p.maxDatagramSize-p.budgetAtLastSent)*1e9/float64(p.adjustedBandwidth())))*time.Nanosecond,
|
||||
))
|
||||
}
|
||||
|
||||
|
10
vendor/github.com/quic-go/quic-go/internal/handshake/crypto_setup.go
generated
vendored
10
vendor/github.com/quic-go/quic-go/internal/handshake/crypto_setup.go
generated
vendored
@ -116,7 +116,7 @@ type cryptoSetup struct {
|
||||
clientHelloWritten bool
|
||||
clientHelloWrittenChan chan struct{} // is closed as soon as the ClientHello is written
|
||||
zeroRTTParametersChan chan<- *wire.TransportParameters
|
||||
allow0RTT func() bool
|
||||
allow0RTT bool
|
||||
|
||||
rttStats *utils.RTTStats
|
||||
|
||||
@ -197,7 +197,7 @@ func NewCryptoSetupServer(
|
||||
tp *wire.TransportParameters,
|
||||
runner handshakeRunner,
|
||||
tlsConf *tls.Config,
|
||||
allow0RTT func() bool,
|
||||
allow0RTT bool,
|
||||
rttStats *utils.RTTStats,
|
||||
tracer logging.ConnectionTracer,
|
||||
logger utils.Logger,
|
||||
@ -210,14 +210,13 @@ func NewCryptoSetupServer(
|
||||
tp,
|
||||
runner,
|
||||
tlsConf,
|
||||
allow0RTT != nil,
|
||||
allow0RTT,
|
||||
rttStats,
|
||||
tracer,
|
||||
logger,
|
||||
protocol.PerspectiveServer,
|
||||
version,
|
||||
)
|
||||
cs.allow0RTT = allow0RTT
|
||||
cs.conn = qtls.Server(newConn(localAddr, remoteAddr), cs.tlsConf, cs.extraConf)
|
||||
return cs
|
||||
}
|
||||
@ -253,6 +252,7 @@ func newCryptoSetup(
|
||||
readEncLevel: protocol.EncryptionInitial,
|
||||
writeEncLevel: protocol.EncryptionInitial,
|
||||
runner: runner,
|
||||
allow0RTT: enable0RTT,
|
||||
ourParams: tp,
|
||||
paramsChan: extHandler.TransportParameters(),
|
||||
rttStats: rttStats,
|
||||
@ -503,7 +503,7 @@ func (h *cryptoSetup) accept0RTT(sessionTicketData []byte) bool {
|
||||
h.logger.Debugf("Transport parameters changed. Rejecting 0-RTT.")
|
||||
return false
|
||||
}
|
||||
if !h.allow0RTT() {
|
||||
if !h.allow0RTT {
|
||||
h.logger.Debugf("0-RTT not allowed. Rejecting 0-RTT.")
|
||||
return false
|
||||
}
|
||||
|
3
vendor/github.com/quic-go/quic-go/internal/protocol/params.go
generated
vendored
3
vendor/github.com/quic-go/quic-go/internal/protocol/params.go
generated
vendored
@ -5,6 +5,9 @@
|
||||
// DesiredReceiveBufferSize is the kernel UDP receive buffer size that we'd like to use.
|
||||
const DesiredReceiveBufferSize = (1 << 20) * 2 // 2 MB
|
||||
|
||||
// DesiredSendBufferSize is the kernel UDP send buffer size that we'd like to use.
|
||||
const DesiredSendBufferSize = (1 << 20) * 2 // 2 MB
|
||||
|
||||
// InitialPacketSizeIPv4 is the maximum packet size that we use for sending IPv4 packets.
|
||||
const InitialPacketSizeIPv4 = 1252
|
||||
|
||||
|
3
vendor/github.com/quic-go/quic-go/internal/protocol/protocol.go
generated
vendored
3
vendor/github.com/quic-go/quic-go/internal/protocol/protocol.go
generated
vendored
@ -77,6 +77,9 @@ func (t PacketType) String() string {
|
||||
// DefaultAckDelayExponent is the default ack delay exponent
|
||||
const DefaultAckDelayExponent = 3
|
||||
|
||||
// DefaultActiveConnectionIDLimit is the default active connection ID limit
|
||||
const DefaultActiveConnectionIDLimit = 2
|
||||
|
||||
// MaxAckDelayExponent is the maximum ack delay exponent
|
||||
const MaxAckDelayExponent = 20
|
||||
|
||||
|
6
vendor/github.com/quic-go/quic-go/internal/utils/rtt_stats.go
generated
vendored
6
vendor/github.com/quic-go/quic-go/internal/utils/rtt_stats.go
generated
vendored
@ -103,8 +103,12 @@ func (r *RTTStats) SetMaxAckDelay(mad time.Duration) {
|
||||
// SetInitialRTT sets the initial RTT.
|
||||
// It is used during the 0-RTT handshake when restoring the RTT stats from the session state.
|
||||
func (r *RTTStats) SetInitialRTT(t time.Duration) {
|
||||
// On the server side, by the time we get to process the session ticket,
|
||||
// we might already have obtained an RTT measurement.
|
||||
// This can happen if we received the ClientHello in multiple pieces, and one of those pieces was lost.
|
||||
// Discard the restored value. A fresh measurement is always better.
|
||||
if r.hasMeasurement {
|
||||
panic("initial RTT set after first measurement")
|
||||
return
|
||||
}
|
||||
r.smoothedRTT = t
|
||||
r.latestRTT = t
|
||||
|
19
vendor/github.com/quic-go/quic-go/internal/wire/ack_frame.go
generated
vendored
19
vendor/github.com/quic-go/quic-go/internal/wire/ack_frame.go
generated
vendored
@ -90,13 +90,22 @@ func parseAckFrame(r *bytes.Reader, typ uint64, ackDelayExponent uint8, _ protoc
|
||||
return nil, errInvalidAckRanges
|
||||
}
|
||||
|
||||
// parse (and skip) the ECN section
|
||||
if ecn {
|
||||
for i := 0; i < 3; i++ {
|
||||
if _, err := quicvarint.Read(r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ect0, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
frame.ECT0 = ect0
|
||||
ect1, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
frame.ECT1 = ect1
|
||||
ecnce, err := quicvarint.Read(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
frame.ECNCE = ecnce
|
||||
}
|
||||
|
||||
return frame, nil
|
||||
|
2
vendor/github.com/quic-go/quic-go/internal/wire/header.go
generated
vendored
2
vendor/github.com/quic-go/quic-go/internal/wire/header.go
generated
vendored
@ -13,8 +13,6 @@
|
||||
)
|
||||
|
||||
// ParseConnectionID parses the destination connection ID of a packet.
|
||||
// It uses the data slice for the connection ID.
|
||||
// That means that the connection ID must not be used after the packet buffer is released.
|
||||
func ParseConnectionID(data []byte, shortHeaderConnIDLen int) (protocol.ConnectionID, error) {
|
||||
if len(data) == 0 {
|
||||
return protocol.ConnectionID{}, io.EOF
|
||||
|
12
vendor/github.com/quic-go/quic-go/internal/wire/transport_parameters.go
generated
vendored
12
vendor/github.com/quic-go/quic-go/internal/wire/transport_parameters.go
generated
vendored
@ -118,6 +118,7 @@ func (p *TransportParameters) unmarshal(r *bytes.Reader, sentBy protocol.Perspec
|
||||
var (
|
||||
readOriginalDestinationConnectionID bool
|
||||
readInitialSourceConnectionID bool
|
||||
readActiveConnectionIDLimit bool
|
||||
)
|
||||
|
||||
p.AckDelayExponent = protocol.DefaultAckDelayExponent
|
||||
@ -139,6 +140,9 @@ func (p *TransportParameters) unmarshal(r *bytes.Reader, sentBy protocol.Perspec
|
||||
}
|
||||
parameterIDs = append(parameterIDs, paramID)
|
||||
switch paramID {
|
||||
case activeConnectionIDLimitParameterID:
|
||||
readActiveConnectionIDLimit = true
|
||||
fallthrough
|
||||
case maxIdleTimeoutParameterID,
|
||||
maxUDPPayloadSizeParameterID,
|
||||
initialMaxDataParameterID,
|
||||
@ -148,7 +152,6 @@ func (p *TransportParameters) unmarshal(r *bytes.Reader, sentBy protocol.Perspec
|
||||
initialMaxStreamsBidiParameterID,
|
||||
initialMaxStreamsUniParameterID,
|
||||
maxAckDelayParameterID,
|
||||
activeConnectionIDLimitParameterID,
|
||||
maxDatagramFrameSizeParameterID,
|
||||
ackDelayExponentParameterID:
|
||||
if err := p.readNumericTransportParameter(r, paramID, int(paramLen)); err != nil {
|
||||
@ -196,6 +199,9 @@ func (p *TransportParameters) unmarshal(r *bytes.Reader, sentBy protocol.Perspec
|
||||
}
|
||||
}
|
||||
|
||||
if !readActiveConnectionIDLimit {
|
||||
p.ActiveConnectionIDLimit = protocol.DefaultActiveConnectionIDLimit
|
||||
}
|
||||
if !fromSessionTicket {
|
||||
if sentBy == protocol.PerspectiveServer && !readOriginalDestinationConnectionID {
|
||||
return errors.New("missing original_destination_connection_id")
|
||||
@ -402,7 +408,9 @@ func (p *TransportParameters) Marshal(pers protocol.Perspective) []byte {
|
||||
}
|
||||
}
|
||||
// active_connection_id_limit
|
||||
b = p.marshalVarintParam(b, activeConnectionIDLimitParameterID, p.ActiveConnectionIDLimit)
|
||||
if p.ActiveConnectionIDLimit != protocol.DefaultActiveConnectionIDLimit {
|
||||
b = p.marshalVarintParam(b, activeConnectionIDLimitParameterID, p.ActiveConnectionIDLimit)
|
||||
}
|
||||
// initial_source_connection_id
|
||||
b = quicvarint.Append(b, uint64(initialSourceConnectionIDParameterID))
|
||||
b = quicvarint.Append(b, uint64(p.InitialSourceConnectionID.Len()))
|
||||
|
7
vendor/github.com/quic-go/quic-go/logging/interface.go
generated
vendored
7
vendor/github.com/quic-go/quic-go/logging/interface.go
generated
vendored
@ -3,7 +3,6 @@
|
||||
package logging
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
@ -101,12 +100,6 @@ type ShortHeader struct {
|
||||
|
||||
// A Tracer traces events.
|
||||
type Tracer interface {
|
||||
// TracerForConnection requests a new tracer for a connection.
|
||||
// The ODCID is the original destination connection ID:
|
||||
// The destination connection ID that the client used on the first Initial packet it sent on this connection.
|
||||
// If nil is returned, tracing will be disabled for this connection.
|
||||
TracerForConnection(ctx context.Context, p Perspective, odcid ConnectionID) ConnectionTracer
|
||||
|
||||
SentPacket(net.Addr, *Header, ByteCount, []Frame)
|
||||
SentVersionNegotiationPacket(_ net.Addr, dest, src ArbitraryLenConnectionID, _ []VersionNumber)
|
||||
DroppedPacket(net.Addr, PacketType, ByteCount, PacketDropReason)
|
||||
|
11
vendor/github.com/quic-go/quic-go/logging/multiplex.go
generated
vendored
11
vendor/github.com/quic-go/quic-go/logging/multiplex.go
generated
vendored
@ -1,7 +1,6 @@
|
||||
package logging
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
@ -23,16 +22,6 @@ func NewMultiplexedTracer(tracers ...Tracer) Tracer {
|
||||
return &tracerMultiplexer{tracers}
|
||||
}
|
||||
|
||||
func (m *tracerMultiplexer) TracerForConnection(ctx context.Context, p Perspective, odcid ConnectionID) ConnectionTracer {
|
||||
var connTracers []ConnectionTracer
|
||||
for _, t := range m.tracers {
|
||||
if ct := t.TracerForConnection(ctx, p, odcid); ct != nil {
|
||||
connTracers = append(connTracers, ct)
|
||||
}
|
||||
}
|
||||
return NewMultiplexedConnectionTracer(connTracers...)
|
||||
}
|
||||
|
||||
func (m *tracerMultiplexer) SentPacket(remote net.Addr, hdr *Header, size ByteCount, frames []Frame) {
|
||||
for _, t := range m.tracers {
|
||||
t.SentPacket(remote, hdr, size, frames)
|
||||
|
4
vendor/github.com/quic-go/quic-go/logging/null_tracer.go
generated
vendored
4
vendor/github.com/quic-go/quic-go/logging/null_tracer.go
generated
vendored
@ -1,7 +1,6 @@
|
||||
package logging
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
@ -12,9 +11,6 @@ type NullTracer struct{
|
||||
|
||||
var _ Tracer = &NullTracer{}
|
||||
|
||||
func (n NullTracer) TracerForConnection(context.Context, Perspective, ConnectionID) ConnectionTracer {
|
||||
return NullConnectionTracer{}
|
||||
}
|
||||
func (n NullTracer) SentPacket(net.Addr, *Header, ByteCount, []Frame) {}
|
||||
func (n NullTracer) SentVersionNegotiationPacket(_ net.Addr, dest, src ArbitraryLenConnectionID, _ []VersionNumber) {
|
||||
}
|
||||
|
3
vendor/github.com/quic-go/quic-go/mockgen.go
generated
vendored
3
vendor/github.com/quic-go/quic-go/mockgen.go
generated
vendored
@ -65,9 +65,6 @@
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_packet_handler_manager_test.go github.com/quic-go/quic-go PacketHandlerManager"
|
||||
type PacketHandlerManager = packetHandlerManager
|
||||
|
||||
//go:generate sh -c "go run github.com/golang/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_multiplexer_test.go github.com/quic-go/quic-go Multiplexer"
|
||||
type Multiplexer = multiplexer
|
||||
|
||||
// Need to use source mode for the batchConn, since reflect mode follows type aliases.
|
||||
// See https://github.com/golang/mock/issues/244 for details.
|
||||
//
|
||||
|
69
vendor/github.com/quic-go/quic-go/multiplexer.go
generated
vendored
69
vendor/github.com/quic-go/quic-go/multiplexer.go
generated
vendored
@ -6,7 +6,6 @@
|
||||
"sync"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
"github.com/quic-go/quic-go/logging"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -14,30 +13,19 @@
|
||||
connMuxer multiplexer
|
||||
)
|
||||
|
||||
type indexableConn interface {
|
||||
LocalAddr() net.Addr
|
||||
}
|
||||
type indexableConn interface{ LocalAddr() net.Addr }
|
||||
|
||||
type multiplexer interface {
|
||||
AddConn(c net.PacketConn, connIDLen int, statelessResetKey *StatelessResetKey, tracer logging.Tracer) (packetHandlerManager, error)
|
||||
AddConn(conn indexableConn)
|
||||
RemoveConn(indexableConn) error
|
||||
}
|
||||
|
||||
type connManager struct {
|
||||
connIDLen int
|
||||
statelessResetKey *StatelessResetKey
|
||||
tracer logging.Tracer
|
||||
manager packetHandlerManager
|
||||
}
|
||||
|
||||
// The connMultiplexer listens on multiple net.PacketConns and dispatches
|
||||
// incoming packets to the connection handler.
|
||||
type connMultiplexer struct {
|
||||
mutex sync.Mutex
|
||||
|
||||
conns map[string] /* LocalAddr().String() */ connManager
|
||||
newPacketHandlerManager func(net.PacketConn, int, *StatelessResetKey, logging.Tracer, utils.Logger) (packetHandlerManager, error) // so it can be replaced in the tests
|
||||
|
||||
conns map[string] /* LocalAddr().String() */ indexableConn
|
||||
logger utils.Logger
|
||||
}
|
||||
|
||||
@ -46,57 +34,38 @@ type connMultiplexer struct {
|
||||
func getMultiplexer() multiplexer {
|
||||
connMuxerOnce.Do(func() {
|
||||
connMuxer = &connMultiplexer{
|
||||
conns: make(map[string]connManager),
|
||||
logger: utils.DefaultLogger.WithPrefix("muxer"),
|
||||
newPacketHandlerManager: newPacketHandlerMap,
|
||||
conns: make(map[string]indexableConn),
|
||||
logger: utils.DefaultLogger.WithPrefix("muxer"),
|
||||
}
|
||||
})
|
||||
return connMuxer
|
||||
}
|
||||
|
||||
func (m *connMultiplexer) AddConn(
|
||||
c net.PacketConn,
|
||||
connIDLen int,
|
||||
statelessResetKey *StatelessResetKey,
|
||||
tracer logging.Tracer,
|
||||
) (packetHandlerManager, error) {
|
||||
func (m *connMultiplexer) index(addr net.Addr) string {
|
||||
return addr.Network() + " " + addr.String()
|
||||
}
|
||||
|
||||
func (m *connMultiplexer) AddConn(c indexableConn) {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
addr := c.LocalAddr()
|
||||
connIndex := addr.Network() + " " + addr.String()
|
||||
connIndex := m.index(c.LocalAddr())
|
||||
p, ok := m.conns[connIndex]
|
||||
if !ok {
|
||||
manager, err := m.newPacketHandlerManager(c, connIDLen, statelessResetKey, tracer, m.logger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p = connManager{
|
||||
connIDLen: connIDLen,
|
||||
statelessResetKey: statelessResetKey,
|
||||
manager: manager,
|
||||
tracer: tracer,
|
||||
}
|
||||
m.conns[connIndex] = p
|
||||
} else {
|
||||
if p.connIDLen != connIDLen {
|
||||
return nil, fmt.Errorf("cannot use %d byte connection IDs on a connection that is already using %d byte connction IDs", connIDLen, p.connIDLen)
|
||||
}
|
||||
if statelessResetKey != nil && p.statelessResetKey != statelessResetKey {
|
||||
return nil, fmt.Errorf("cannot use different stateless reset keys on the same packet conn")
|
||||
}
|
||||
if tracer != p.tracer {
|
||||
return nil, fmt.Errorf("cannot use different tracers on the same packet conn")
|
||||
}
|
||||
if ok {
|
||||
// Panics if we're already listening on this connection.
|
||||
// This is a safeguard because we're introducing a breaking API change, see
|
||||
// https://github.com/quic-go/quic-go/issues/3727 for details.
|
||||
// We'll remove this at a later time, when most users of the library have made the switch.
|
||||
panic("connection already exists") // TODO: write a nice message
|
||||
}
|
||||
return p.manager, nil
|
||||
m.conns[connIndex] = p
|
||||
}
|
||||
|
||||
func (m *connMultiplexer) RemoveConn(c indexableConn) error {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
connIndex := c.LocalAddr().Network() + " " + c.LocalAddr().String()
|
||||
connIndex := m.index(c.LocalAddr())
|
||||
if _, ok := m.conns[connIndex]; !ok {
|
||||
return fmt.Errorf("cannote remove connection, connection is unknown")
|
||||
}
|
||||
|
344
vendor/github.com/quic-go/quic-go/packet_handler_map.go
generated
vendored
344
vendor/github.com/quic-go/quic-go/packet_handler_map.go
generated
vendored
@ -5,28 +5,22 @@
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
"github.com/quic-go/quic-go/internal/wire"
|
||||
"github.com/quic-go/quic-go/logging"
|
||||
)
|
||||
|
||||
// rawConn is a connection that allow reading of a receivedPacket.
|
||||
// rawConn is a connection that allow reading of a receivedPackeh.
|
||||
type rawConn interface {
|
||||
ReadPacket() (*receivedPacket, error)
|
||||
WritePacket(b []byte, addr net.Addr, oob []byte) (int, error)
|
||||
LocalAddr() net.Addr
|
||||
SetReadDeadline(time.Time) error
|
||||
io.Closer
|
||||
}
|
||||
|
||||
@ -36,116 +30,49 @@ type closePacket struct {
|
||||
info *packetInfo
|
||||
}
|
||||
|
||||
// The packetHandlerMap stores packetHandlers, identified by connection ID.
|
||||
// It is used:
|
||||
// * by the server to store connections
|
||||
// * when multiplexing outgoing connections to store clients
|
||||
type unknownPacketHandler interface {
|
||||
handlePacket(*receivedPacket)
|
||||
setCloseError(error)
|
||||
}
|
||||
|
||||
var errListenerAlreadySet = errors.New("listener already set")
|
||||
|
||||
type packetHandlerMap struct {
|
||||
mutex sync.Mutex
|
||||
mutex sync.Mutex
|
||||
handlers map[protocol.ConnectionID]packetHandler
|
||||
resetTokens map[protocol.StatelessResetToken] /* stateless reset token */ packetHandler
|
||||
|
||||
conn rawConn
|
||||
connIDLen int
|
||||
|
||||
closeQueue chan closePacket
|
||||
|
||||
handlers map[protocol.ConnectionID]packetHandler
|
||||
resetTokens map[protocol.StatelessResetToken] /* stateless reset token */ packetHandler
|
||||
server unknownPacketHandler
|
||||
numZeroRTTEntries int
|
||||
|
||||
listening chan struct{} // is closed when listen returns
|
||||
closed bool
|
||||
closeChan chan struct{}
|
||||
|
||||
enqueueClosePacket func(closePacket)
|
||||
|
||||
deleteRetiredConnsAfter time.Duration
|
||||
zeroRTTQueueDuration time.Duration
|
||||
|
||||
statelessResetEnabled bool
|
||||
statelessResetMutex sync.Mutex
|
||||
statelessResetHasher hash.Hash
|
||||
statelessResetMutex sync.Mutex
|
||||
statelessResetHasher hash.Hash
|
||||
|
||||
tracer logging.Tracer
|
||||
logger utils.Logger
|
||||
}
|
||||
|
||||
var _ packetHandlerManager = &packetHandlerMap{}
|
||||
|
||||
func setReceiveBuffer(c net.PacketConn, logger utils.Logger) error {
|
||||
conn, ok := c.(interface{ SetReadBuffer(int) error })
|
||||
if !ok {
|
||||
return errors.New("connection doesn't allow setting of receive buffer size. Not a *net.UDPConn?")
|
||||
}
|
||||
size, err := inspectReadBuffer(c)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to determine receive buffer size: %w", err)
|
||||
}
|
||||
if size >= protocol.DesiredReceiveBufferSize {
|
||||
logger.Debugf("Conn has receive buffer of %d kiB (wanted: at least %d kiB)", size/1024, protocol.DesiredReceiveBufferSize/1024)
|
||||
return nil
|
||||
}
|
||||
if err := conn.SetReadBuffer(protocol.DesiredReceiveBufferSize); err != nil {
|
||||
return fmt.Errorf("failed to increase receive buffer size: %w", err)
|
||||
}
|
||||
newSize, err := inspectReadBuffer(c)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to determine receive buffer size: %w", err)
|
||||
}
|
||||
if newSize == size {
|
||||
return fmt.Errorf("failed to increase receive buffer size (wanted: %d kiB, got %d kiB)", protocol.DesiredReceiveBufferSize/1024, newSize/1024)
|
||||
}
|
||||
if newSize < protocol.DesiredReceiveBufferSize {
|
||||
return fmt.Errorf("failed to sufficiently increase receive buffer size (was: %d kiB, wanted: %d kiB, got: %d kiB)", size/1024, protocol.DesiredReceiveBufferSize/1024, newSize/1024)
|
||||
}
|
||||
logger.Debugf("Increased receive buffer size to %d kiB", newSize/1024)
|
||||
return nil
|
||||
}
|
||||
|
||||
// only print warnings about the UDP receive buffer size once
|
||||
var receiveBufferWarningOnce sync.Once
|
||||
|
||||
func newPacketHandlerMap(
|
||||
c net.PacketConn,
|
||||
connIDLen int,
|
||||
statelessResetKey *StatelessResetKey,
|
||||
tracer logging.Tracer,
|
||||
logger utils.Logger,
|
||||
) (packetHandlerManager, error) {
|
||||
if err := setReceiveBuffer(c, logger); err != nil {
|
||||
if !strings.Contains(err.Error(), "use of closed network connection") {
|
||||
receiveBufferWarningOnce.Do(func() {
|
||||
if disable, _ := strconv.ParseBool(os.Getenv("QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING")); disable {
|
||||
return
|
||||
}
|
||||
log.Printf("%s. See https://github.com/quic-go/quic-go/wiki/UDP-Receive-Buffer-Size for details.", err)
|
||||
})
|
||||
}
|
||||
}
|
||||
conn, err := wrapConn(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m := &packetHandlerMap{
|
||||
conn: conn,
|
||||
connIDLen: connIDLen,
|
||||
listening: make(chan struct{}),
|
||||
func newPacketHandlerMap(key *StatelessResetKey, enqueueClosePacket func(closePacket), logger utils.Logger) *packetHandlerMap {
|
||||
h := &packetHandlerMap{
|
||||
closeChan: make(chan struct{}),
|
||||
handlers: make(map[protocol.ConnectionID]packetHandler),
|
||||
resetTokens: make(map[protocol.StatelessResetToken]packetHandler),
|
||||
deleteRetiredConnsAfter: protocol.RetiredConnectionIDDeleteTimeout,
|
||||
zeroRTTQueueDuration: protocol.Max0RTTQueueingDuration,
|
||||
closeQueue: make(chan closePacket, 4),
|
||||
statelessResetEnabled: statelessResetKey != nil,
|
||||
tracer: tracer,
|
||||
enqueueClosePacket: enqueueClosePacket,
|
||||
logger: logger,
|
||||
}
|
||||
if m.statelessResetEnabled {
|
||||
m.statelessResetHasher = hmac.New(sha256.New, statelessResetKey[:])
|
||||
if key != nil {
|
||||
h.statelessResetHasher = hmac.New(sha256.New, key[:])
|
||||
}
|
||||
go m.listen()
|
||||
go m.runCloseQueue()
|
||||
|
||||
if logger.Debug() {
|
||||
go m.logUsage()
|
||||
if h.logger.Debug() {
|
||||
go h.logUsage()
|
||||
}
|
||||
return m, nil
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *packetHandlerMap) logUsage() {
|
||||
@ -153,7 +80,7 @@ func (h *packetHandlerMap) logUsage() {
|
||||
var printedZero bool
|
||||
for {
|
||||
select {
|
||||
case <-h.listening:
|
||||
case <-h.closeChan:
|
||||
return
|
||||
case <-ticker.C:
|
||||
}
|
||||
@ -174,6 +101,14 @@ func (h *packetHandlerMap) logUsage() {
|
||||
}
|
||||
}
|
||||
|
||||
func (h *packetHandlerMap) Get(id protocol.ConnectionID) (packetHandler, bool) {
|
||||
h.mutex.Lock()
|
||||
defer h.mutex.Unlock()
|
||||
|
||||
handler, ok := h.handlers[id]
|
||||
return handler, ok
|
||||
}
|
||||
|
||||
func (h *packetHandlerMap) Add(id protocol.ConnectionID, handler packetHandler) bool /* was added */ {
|
||||
h.mutex.Lock()
|
||||
defer h.mutex.Unlock()
|
||||
@ -187,26 +122,17 @@ func (h *packetHandlerMap) Add(id protocol.ConnectionID, handler packetHandler)
|
||||
return true
|
||||
}
|
||||
|
||||
func (h *packetHandlerMap) AddWithConnID(clientDestConnID, newConnID protocol.ConnectionID, fn func() packetHandler) bool {
|
||||
func (h *packetHandlerMap) AddWithConnID(clientDestConnID, newConnID protocol.ConnectionID, fn func() (packetHandler, bool)) bool {
|
||||
h.mutex.Lock()
|
||||
defer h.mutex.Unlock()
|
||||
|
||||
var q *zeroRTTQueue
|
||||
if handler, ok := h.handlers[clientDestConnID]; ok {
|
||||
q, ok = handler.(*zeroRTTQueue)
|
||||
if !ok {
|
||||
h.logger.Debugf("Not adding connection ID %s for a new connection, as it already exists.", clientDestConnID)
|
||||
return false
|
||||
}
|
||||
q.retireTimer.Stop()
|
||||
h.numZeroRTTEntries--
|
||||
if h.numZeroRTTEntries < 0 {
|
||||
panic("number of 0-RTT queues < 0")
|
||||
}
|
||||
if _, ok := h.handlers[clientDestConnID]; ok {
|
||||
h.logger.Debugf("Not adding connection ID %s for a new connection, as it already exists.", clientDestConnID)
|
||||
return false
|
||||
}
|
||||
conn := fn()
|
||||
if q != nil {
|
||||
q.EnqueueAll(conn)
|
||||
conn, ok := fn()
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
h.handlers[clientDestConnID] = conn
|
||||
h.handlers[newConnID] = conn
|
||||
@ -240,12 +166,7 @@ func (h *packetHandlerMap) ReplaceWithClosed(ids []protocol.ConnectionID, pers p
|
||||
if connClosePacket != nil {
|
||||
handler = newClosedLocalConn(
|
||||
func(addr net.Addr, info *packetInfo) {
|
||||
select {
|
||||
case h.closeQueue <- closePacket{payload: connClosePacket, addr: addr, info: info}:
|
||||
default:
|
||||
// Oops, we're backlogged.
|
||||
// Just drop the packet, sending CONNECTION_CLOSE copies is best effort anyway.
|
||||
}
|
||||
h.enqueueClosePacket(closePacket{payload: connClosePacket, addr: addr, info: info})
|
||||
},
|
||||
pers,
|
||||
h.logger,
|
||||
@ -272,17 +193,6 @@ func(addr net.Addr, info *packetInfo) {
|
||||
})
|
||||
}
|
||||
|
||||
func (h *packetHandlerMap) runCloseQueue() {
|
||||
for {
|
||||
select {
|
||||
case <-h.listening:
|
||||
return
|
||||
case p := <-h.closeQueue:
|
||||
h.conn.WritePacket(p.payload, p.addr, p.info.OOB())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (h *packetHandlerMap) AddResetToken(token protocol.StatelessResetToken, handler packetHandler) {
|
||||
h.mutex.Lock()
|
||||
h.resetTokens[token] = handler
|
||||
@ -295,19 +205,16 @@ func (h *packetHandlerMap) RemoveResetToken(token protocol.StatelessResetToken)
|
||||
h.mutex.Unlock()
|
||||
}
|
||||
|
||||
func (h *packetHandlerMap) SetServer(s unknownPacketHandler) {
|
||||
func (h *packetHandlerMap) GetByResetToken(token protocol.StatelessResetToken) (packetHandler, bool) {
|
||||
h.mutex.Lock()
|
||||
h.server = s
|
||||
h.mutex.Unlock()
|
||||
defer h.mutex.Unlock()
|
||||
|
||||
handler, ok := h.resetTokens[token]
|
||||
return handler, ok
|
||||
}
|
||||
|
||||
func (h *packetHandlerMap) CloseServer() {
|
||||
h.mutex.Lock()
|
||||
if h.server == nil {
|
||||
h.mutex.Unlock()
|
||||
return
|
||||
}
|
||||
h.server = nil
|
||||
var wg sync.WaitGroup
|
||||
for _, handler := range h.handlers {
|
||||
if handler.getPerspective() == protocol.PerspectiveServer {
|
||||
@ -323,23 +230,16 @@ func (h *packetHandlerMap) CloseServer() {
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// Destroy closes the underlying connection and waits until listen() has returned.
|
||||
// It does not close active connections.
|
||||
func (h *packetHandlerMap) Destroy() error {
|
||||
if err := h.conn.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
<-h.listening // wait until listening returns
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *packetHandlerMap) close(e error) error {
|
||||
func (h *packetHandlerMap) Close(e error) {
|
||||
h.mutex.Lock()
|
||||
|
||||
if h.closed {
|
||||
h.mutex.Unlock()
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
close(h.closeChan)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for _, handler := range h.handlers {
|
||||
wg.Add(1)
|
||||
@ -348,129 +248,14 @@ func (h *packetHandlerMap) close(e error) error {
|
||||
wg.Done()
|
||||
}(handler)
|
||||
}
|
||||
|
||||
if h.server != nil {
|
||||
h.server.setCloseError(e)
|
||||
}
|
||||
h.closed = true
|
||||
h.mutex.Unlock()
|
||||
wg.Wait()
|
||||
return getMultiplexer().RemoveConn(h.conn)
|
||||
}
|
||||
|
||||
func (h *packetHandlerMap) listen() {
|
||||
defer close(h.listening)
|
||||
for {
|
||||
p, err := h.conn.ReadPacket()
|
||||
//nolint:staticcheck // SA1019 ignore this!
|
||||
// TODO: This code is used to ignore wsa errors on Windows.
|
||||
// Since net.Error.Temporary is deprecated as of Go 1.18, we should find a better solution.
|
||||
// See https://github.com/quic-go/quic-go/issues/1737 for details.
|
||||
if nerr, ok := err.(net.Error); ok && nerr.Temporary() {
|
||||
h.logger.Debugf("Temporary error reading from conn: %w", err)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
h.close(err)
|
||||
return
|
||||
}
|
||||
h.handlePacket(p)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *packetHandlerMap) handlePacket(p *receivedPacket) {
|
||||
connID, err := wire.ParseConnectionID(p.data, h.connIDLen)
|
||||
if err != nil {
|
||||
h.logger.Debugf("error parsing connection ID on packet from %s: %s", p.remoteAddr, err)
|
||||
if h.tracer != nil {
|
||||
h.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropHeaderParseError)
|
||||
}
|
||||
p.buffer.MaybeRelease()
|
||||
return
|
||||
}
|
||||
|
||||
h.mutex.Lock()
|
||||
defer h.mutex.Unlock()
|
||||
|
||||
if isStatelessReset := h.maybeHandleStatelessReset(p.data); isStatelessReset {
|
||||
return
|
||||
}
|
||||
|
||||
if handler, ok := h.handlers[connID]; ok {
|
||||
if ha, ok := handler.(*zeroRTTQueue); ok { // only enqueue 0-RTT packets in the 0-RTT queue
|
||||
if wire.Is0RTTPacket(p.data) {
|
||||
ha.handlePacket(p)
|
||||
return
|
||||
}
|
||||
} else { // existing connection
|
||||
handler.handlePacket(p)
|
||||
return
|
||||
}
|
||||
}
|
||||
if !wire.IsLongHeaderPacket(p.data[0]) {
|
||||
go h.maybeSendStatelessReset(p, connID)
|
||||
return
|
||||
}
|
||||
if h.server == nil { // no server set
|
||||
h.logger.Debugf("received a packet with an unexpected connection ID %s", connID)
|
||||
return
|
||||
}
|
||||
if wire.Is0RTTPacket(p.data) {
|
||||
if h.numZeroRTTEntries >= protocol.Max0RTTQueues {
|
||||
if h.tracer != nil {
|
||||
h.tracer.DroppedPacket(p.remoteAddr, logging.PacketType0RTT, p.Size(), logging.PacketDropDOSPrevention)
|
||||
}
|
||||
return
|
||||
}
|
||||
h.numZeroRTTEntries++
|
||||
queue := &zeroRTTQueue{queue: make([]*receivedPacket, 0, 8)}
|
||||
h.handlers[connID] = queue
|
||||
queue.retireTimer = time.AfterFunc(h.zeroRTTQueueDuration, func() {
|
||||
h.mutex.Lock()
|
||||
defer h.mutex.Unlock()
|
||||
// The entry might have been replaced by an actual connection.
|
||||
// Only delete it if it's still a 0-RTT queue.
|
||||
if handler, ok := h.handlers[connID]; ok {
|
||||
if q, ok := handler.(*zeroRTTQueue); ok {
|
||||
delete(h.handlers, connID)
|
||||
h.numZeroRTTEntries--
|
||||
if h.numZeroRTTEntries < 0 {
|
||||
panic("number of 0-RTT queues < 0")
|
||||
}
|
||||
q.Clear()
|
||||
if h.logger.Debug() {
|
||||
h.logger.Debugf("Removing 0-RTT queue for %s.", connID)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
queue.handlePacket(p)
|
||||
return
|
||||
}
|
||||
h.server.handlePacket(p)
|
||||
}
|
||||
|
||||
func (h *packetHandlerMap) maybeHandleStatelessReset(data []byte) bool {
|
||||
// stateless resets are always short header packets
|
||||
if wire.IsLongHeaderPacket(data[0]) {
|
||||
return false
|
||||
}
|
||||
if len(data) < 17 /* type byte + 16 bytes for the reset token */ {
|
||||
return false
|
||||
}
|
||||
|
||||
token := *(*protocol.StatelessResetToken)(data[len(data)-16:])
|
||||
if sess, ok := h.resetTokens[token]; ok {
|
||||
h.logger.Debugf("Received a stateless reset with token %#x. Closing connection.", token)
|
||||
go sess.destroy(&StatelessResetError{Token: token})
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (h *packetHandlerMap) GetStatelessResetToken(connID protocol.ConnectionID) protocol.StatelessResetToken {
|
||||
var token protocol.StatelessResetToken
|
||||
if !h.statelessResetEnabled {
|
||||
if h.statelessResetHasher == nil {
|
||||
// Return a random stateless reset token.
|
||||
// This token will be sent in the server's transport parameters.
|
||||
// By using a random token, an off-path attacker won't be able to disrupt the connection.
|
||||
@ -484,24 +269,3 @@ func (h *packetHandlerMap) GetStatelessResetToken(connID protocol.ConnectionID)
|
||||
h.statelessResetMutex.Unlock()
|
||||
return token
|
||||
}
|
||||
|
||||
func (h *packetHandlerMap) maybeSendStatelessReset(p *receivedPacket, connID protocol.ConnectionID) {
|
||||
defer p.buffer.Release()
|
||||
if !h.statelessResetEnabled {
|
||||
return
|
||||
}
|
||||
// Don't send a stateless reset in response to very small packets.
|
||||
// This includes packets that could be stateless resets.
|
||||
if len(p.data) <= protocol.MinStatelessResetSize {
|
||||
return
|
||||
}
|
||||
token := h.GetStatelessResetToken(connID)
|
||||
h.logger.Debugf("Sending stateless reset to %s (connection ID: %s). Token: %#x", p.remoteAddr, connID, token)
|
||||
data := make([]byte, protocol.MinStatelessResetSize-16, protocol.MinStatelessResetSize)
|
||||
rand.Read(data)
|
||||
data[0] = (data[0] & 0x7f) | 0x40
|
||||
data = append(data, token[:]...)
|
||||
if _, err := h.conn.WritePacket(data, p.remoteAddr, p.info.OOB()); err != nil {
|
||||
h.logger.Debugf("Error sending Stateless Reset: %s", err)
|
||||
}
|
||||
}
|
||||
|
2
vendor/github.com/quic-go/quic-go/packet_packer.go
generated
vendored
2
vendor/github.com/quic-go/quic-go/packet_packer.go
generated
vendored
@ -417,7 +417,7 @@ func (p *packetPacker) PackCoalescedPacket(onlyAck bool, v protocol.VersionNumbe
|
||||
if oneRTTPayload.length > 0 {
|
||||
size += p.shortHeaderPacketLength(connID, oneRTTPacketNumberLen, oneRTTPayload) + protocol.ByteCount(oneRTTSealer.Overhead())
|
||||
}
|
||||
} else if p.perspective == protocol.PerspectiveClient { // 0-RTT
|
||||
} else if p.perspective == protocol.PerspectiveClient && !onlyAck { // 0-RTT packets can't contain ACK frames
|
||||
var err error
|
||||
zeroRTTSealer, err = p.cryptoSetup.Get0RTTSealer()
|
||||
if err != nil && err != handshake.ErrKeysDropped && err != handshake.ErrKeysNotYetAvailable {
|
||||
|
19
vendor/github.com/quic-go/quic-go/quicvarint/varint.go
generated
vendored
19
vendor/github.com/quic-go/quic-go/quicvarint/varint.go
generated
vendored
@ -70,25 +70,6 @@ func Read(r io.ByteReader) (uint64, error) {
|
||||
return uint64(b8) + uint64(b7)<<8 + uint64(b6)<<16 + uint64(b5)<<24 + uint64(b4)<<32 + uint64(b3)<<40 + uint64(b2)<<48 + uint64(b1)<<56, nil
|
||||
}
|
||||
|
||||
// Write writes i in the QUIC varint format to w.
|
||||
// Deprecated: use Append instead.
|
||||
func Write(w Writer, i uint64) {
|
||||
if i <= maxVarInt1 {
|
||||
w.WriteByte(uint8(i))
|
||||
} else if i <= maxVarInt2 {
|
||||
w.Write([]byte{uint8(i>>8) | 0x40, uint8(i)})
|
||||
} else if i <= maxVarInt4 {
|
||||
w.Write([]byte{uint8(i>>24) | 0x80, uint8(i >> 16), uint8(i >> 8), uint8(i)})
|
||||
} else if i <= maxVarInt8 {
|
||||
w.Write([]byte{
|
||||
uint8(i>>56) | 0xc0, uint8(i >> 48), uint8(i >> 40), uint8(i >> 32),
|
||||
uint8(i >> 24), uint8(i >> 16), uint8(i >> 8), uint8(i),
|
||||
})
|
||||
} else {
|
||||
panic(fmt.Sprintf("%#x doesn't fit into 62 bits", i))
|
||||
}
|
||||
}
|
||||
|
||||
// Append appends i in the QUIC varint format.
|
||||
func Append(b []byte, i uint64) []byte {
|
||||
if i <= maxVarInt1 {
|
||||
|
23
vendor/github.com/quic-go/quic-go/send_conn.go
generated
vendored
23
vendor/github.com/quic-go/quic-go/send_conn.go
generated
vendored
@ -22,7 +22,7 @@ type sconn struct {
|
||||
|
||||
var _ sendConn = &sconn{}
|
||||
|
||||
func newSendConn(c rawConn, remote net.Addr, info *packetInfo) sendConn {
|
||||
func newSendConn(c rawConn, remote net.Addr, info *packetInfo) *sconn {
|
||||
return &sconn{
|
||||
rawConn: c,
|
||||
remoteAddr: remote,
|
||||
@ -51,24 +51,3 @@ func (c *sconn) LocalAddr() net.Addr {
|
||||
}
|
||||
return addr
|
||||
}
|
||||
|
||||
type spconn struct {
|
||||
net.PacketConn
|
||||
|
||||
remoteAddr net.Addr
|
||||
}
|
||||
|
||||
var _ sendConn = &spconn{}
|
||||
|
||||
func newSendPconn(c net.PacketConn, remote net.Addr) sendConn {
|
||||
return &spconn{PacketConn: c, remoteAddr: remote}
|
||||
}
|
||||
|
||||
func (c *spconn) Write(p []byte) error {
|
||||
_, err := c.WriteTo(p, c.remoteAddr)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *spconn) RemoteAddr() net.Addr {
|
||||
return c.remoteAddr
|
||||
}
|
||||
|
524
vendor/github.com/quic-go/quic-go/server.go
generated
vendored
524
vendor/github.com/quic-go/quic-go/server.go
generated
vendored
@ -20,7 +20,7 @@
|
||||
)
|
||||
|
||||
// ErrServerClosed is returned by the Listener or EarlyListener's Accept method after a call to Close.
|
||||
var ErrServerClosed = errors.New("quic: Server closed")
|
||||
var ErrServerClosed = errors.New("quic: server closed")
|
||||
|
||||
// packetHandler handles packets
|
||||
type packetHandler interface {
|
||||
@ -30,17 +30,13 @@ type packetHandler interface {
|
||||
getPerspective() protocol.Perspective
|
||||
}
|
||||
|
||||
type unknownPacketHandler interface {
|
||||
handlePacket(*receivedPacket)
|
||||
setCloseError(error)
|
||||
}
|
||||
|
||||
type packetHandlerManager interface {
|
||||
AddWithConnID(protocol.ConnectionID, protocol.ConnectionID, func() packetHandler) bool
|
||||
Destroy() error
|
||||
connRunner
|
||||
SetServer(unknownPacketHandler)
|
||||
Get(protocol.ConnectionID) (packetHandler, bool)
|
||||
GetByResetToken(protocol.StatelessResetToken) (packetHandler, bool)
|
||||
AddWithConnID(protocol.ConnectionID, protocol.ConnectionID, func() (packetHandler, bool)) bool
|
||||
Close(error)
|
||||
CloseServer()
|
||||
connRunner
|
||||
}
|
||||
|
||||
type quicConn interface {
|
||||
@ -54,6 +50,11 @@ type quicConn interface {
|
||||
shutdown()
|
||||
}
|
||||
|
||||
type zeroRTTQueue struct {
|
||||
packets []*receivedPacket
|
||||
expiration time.Time
|
||||
}
|
||||
|
||||
// A Listener of QUIC
|
||||
type baseServer struct {
|
||||
mutex sync.Mutex
|
||||
@ -64,16 +65,18 @@ type baseServer struct {
|
||||
config *Config
|
||||
|
||||
conn rawConn
|
||||
// If the server is started with ListenAddr, we create a packet conn.
|
||||
// If it is started with Listen, we take a packet conn as a parameter.
|
||||
createdPacketConn bool
|
||||
|
||||
tokenGenerator *handshake.TokenGenerator
|
||||
|
||||
connHandler packetHandlerManager
|
||||
connIDGenerator ConnectionIDGenerator
|
||||
connHandler packetHandlerManager
|
||||
onClose func()
|
||||
|
||||
receivedPackets chan *receivedPacket
|
||||
|
||||
nextZeroRTTCleanup time.Time
|
||||
zeroRTTQueues map[protocol.ConnectionID]*zeroRTTQueue // only initialized if acceptEarlyConns == true
|
||||
|
||||
// set as a member, so they can be set in the tests
|
||||
newConn func(
|
||||
sendConn,
|
||||
@ -83,6 +86,7 @@ type baseServer struct {
|
||||
protocol.ConnectionID, /* client dest connection ID */
|
||||
protocol.ConnectionID, /* destination connection ID */
|
||||
protocol.ConnectionID, /* source connection ID */
|
||||
ConnectionIDGenerator,
|
||||
protocol.StatelessResetToken,
|
||||
*Config,
|
||||
*tls.Config,
|
||||
@ -94,61 +98,101 @@ type baseServer struct {
|
||||
protocol.VersionNumber,
|
||||
) quicConn
|
||||
|
||||
serverError error
|
||||
errorChan chan struct{}
|
||||
closed bool
|
||||
running chan struct{} // closed as soon as run() returns
|
||||
serverError error
|
||||
errorChan chan struct{}
|
||||
closed bool
|
||||
running chan struct{} // closed as soon as run() returns
|
||||
versionNegotiationQueue chan *receivedPacket
|
||||
invalidTokenQueue chan *receivedPacket
|
||||
|
||||
connQueue chan quicConn
|
||||
connQueueLen int32 // to be used as an atomic
|
||||
|
||||
tracer logging.Tracer
|
||||
|
||||
logger utils.Logger
|
||||
}
|
||||
|
||||
var (
|
||||
_ Listener = &baseServer{}
|
||||
_ unknownPacketHandler = &baseServer{}
|
||||
)
|
||||
// A Listener listens for incoming QUIC connections.
|
||||
// It returns connections once the handshake has completed.
|
||||
type Listener struct {
|
||||
baseServer *baseServer
|
||||
}
|
||||
|
||||
type earlyServer struct{ *baseServer }
|
||||
// Accept returns new connections. It should be called in a loop.
|
||||
func (l *Listener) Accept(ctx context.Context) (Connection, error) {
|
||||
return l.baseServer.Accept(ctx)
|
||||
}
|
||||
|
||||
var _ EarlyListener = &earlyServer{}
|
||||
// Close the server. All active connections will be closed.
|
||||
func (l *Listener) Close() error {
|
||||
return l.baseServer.Close()
|
||||
}
|
||||
|
||||
func (s *earlyServer) Accept(ctx context.Context) (EarlyConnection, error) {
|
||||
return s.baseServer.accept(ctx)
|
||||
// Addr returns the local network address that the server is listening on.
|
||||
func (l *Listener) Addr() net.Addr {
|
||||
return l.baseServer.Addr()
|
||||
}
|
||||
|
||||
// An EarlyListener listens for incoming QUIC connections, and returns them before the handshake completes.
|
||||
// For connections that don't use 0-RTT, this allows the server to send 0.5-RTT data.
|
||||
// This data is encrypted with forward-secure keys, however, the client's identity has not yet been verified.
|
||||
// For connection using 0-RTT, this allows the server to accept and respond to streams that the client opened in the
|
||||
// 0-RTT data it sent. Note that at this point during the handshake, the live-ness of the
|
||||
// client has not yet been confirmed, and the 0-RTT data could have been replayed by an attacker.
|
||||
type EarlyListener struct {
|
||||
baseServer *baseServer
|
||||
}
|
||||
|
||||
// Accept returns a new connections. It should be called in a loop.
|
||||
func (l *EarlyListener) Accept(ctx context.Context) (EarlyConnection, error) {
|
||||
return l.baseServer.accept(ctx)
|
||||
}
|
||||
|
||||
// Close the server. All active connections will be closed.
|
||||
func (l *EarlyListener) Close() error {
|
||||
return l.baseServer.Close()
|
||||
}
|
||||
|
||||
// Addr returns the local network addr that the server is listening on.
|
||||
func (l *EarlyListener) Addr() net.Addr {
|
||||
return l.baseServer.Addr()
|
||||
}
|
||||
|
||||
// ListenAddr creates a QUIC server listening on a given address.
|
||||
// The tls.Config must not be nil and must contain a certificate configuration.
|
||||
// The quic.Config may be nil, in that case the default values will be used.
|
||||
func ListenAddr(addr string, tlsConf *tls.Config, config *Config) (Listener, error) {
|
||||
return listenAddr(addr, tlsConf, config, false)
|
||||
}
|
||||
|
||||
// ListenAddrEarly works like ListenAddr, but it returns connections before the handshake completes.
|
||||
func ListenAddrEarly(addr string, tlsConf *tls.Config, config *Config) (EarlyListener, error) {
|
||||
s, err := listenAddr(addr, tlsConf, config, true)
|
||||
func ListenAddr(addr string, tlsConf *tls.Config, config *Config) (*Listener, error) {
|
||||
conn, err := listenUDP(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &earlyServer{s}, nil
|
||||
return (&Transport{
|
||||
Conn: conn,
|
||||
createdConn: true,
|
||||
isSingleUse: true,
|
||||
}).Listen(tlsConf, config)
|
||||
}
|
||||
|
||||
func listenAddr(addr string, tlsConf *tls.Config, config *Config, acceptEarly bool) (*baseServer, error) {
|
||||
// ListenAddrEarly works like ListenAddr, but it returns connections before the handshake completes.
|
||||
func ListenAddrEarly(addr string, tlsConf *tls.Config, config *Config) (*EarlyListener, error) {
|
||||
conn, err := listenUDP(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return (&Transport{
|
||||
Conn: conn,
|
||||
createdConn: true,
|
||||
isSingleUse: true,
|
||||
}).ListenEarly(tlsConf, config)
|
||||
}
|
||||
|
||||
func listenUDP(addr string) (*net.UDPConn, error) {
|
||||
udpAddr, err := net.ResolveUDPAddr("udp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn, err := net.ListenUDP("udp", udpAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
serv, err := listen(conn, tlsConf, config, acceptEarly)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
serv.createdPacketConn = true
|
||||
return serv, nil
|
||||
return net.ListenUDP("udp", udpAddr)
|
||||
}
|
||||
|
||||
// Listen listens for QUIC connections on a given net.PacketConn. If the
|
||||
@ -161,61 +205,55 @@ func listenAddr(addr string, tlsConf *tls.Config, config *Config, acceptEarly bo
|
||||
// The tls.Config must not be nil and must contain a certificate configuration.
|
||||
// Furthermore, it must define an application control (using NextProtos).
|
||||
// The quic.Config may be nil, in that case the default values will be used.
|
||||
func Listen(conn net.PacketConn, tlsConf *tls.Config, config *Config) (Listener, error) {
|
||||
return listen(conn, tlsConf, config, false)
|
||||
func Listen(conn net.PacketConn, tlsConf *tls.Config, config *Config) (*Listener, error) {
|
||||
tr := &Transport{Conn: conn, isSingleUse: true}
|
||||
return tr.Listen(tlsConf, config)
|
||||
}
|
||||
|
||||
// ListenEarly works like Listen, but it returns connections before the handshake completes.
|
||||
func ListenEarly(conn net.PacketConn, tlsConf *tls.Config, config *Config) (EarlyListener, error) {
|
||||
s, err := listen(conn, tlsConf, config, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &earlyServer{s}, nil
|
||||
func ListenEarly(conn net.PacketConn, tlsConf *tls.Config, config *Config) (*EarlyListener, error) {
|
||||
tr := &Transport{Conn: conn, isSingleUse: true}
|
||||
return tr.ListenEarly(tlsConf, config)
|
||||
}
|
||||
|
||||
func listen(conn net.PacketConn, tlsConf *tls.Config, config *Config, acceptEarly bool) (*baseServer, error) {
|
||||
if tlsConf == nil {
|
||||
return nil, errors.New("quic: tls.Config not set")
|
||||
}
|
||||
if err := validateConfig(config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config = populateServerConfig(config)
|
||||
for _, v := range config.Versions {
|
||||
if !protocol.IsValidVersion(v) {
|
||||
return nil, fmt.Errorf("%s is not a valid QUIC version", v)
|
||||
}
|
||||
}
|
||||
|
||||
connHandler, err := getMultiplexer().AddConn(conn, config.ConnectionIDGenerator.ConnectionIDLen(), config.StatelessResetKey, config.Tracer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
func newServer(
|
||||
conn rawConn,
|
||||
connHandler packetHandlerManager,
|
||||
connIDGenerator ConnectionIDGenerator,
|
||||
tlsConf *tls.Config,
|
||||
config *Config,
|
||||
tracer logging.Tracer,
|
||||
onClose func(),
|
||||
acceptEarly bool,
|
||||
) (*baseServer, error) {
|
||||
tokenGenerator, err := handshake.NewTokenGenerator(rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c, err := wrapConn(conn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s := &baseServer{
|
||||
conn: c,
|
||||
tlsConf: tlsConf,
|
||||
config: config,
|
||||
tokenGenerator: tokenGenerator,
|
||||
connHandler: connHandler,
|
||||
connQueue: make(chan quicConn),
|
||||
errorChan: make(chan struct{}),
|
||||
running: make(chan struct{}),
|
||||
receivedPackets: make(chan *receivedPacket, protocol.MaxServerUnprocessedPackets),
|
||||
newConn: newConnection,
|
||||
logger: utils.DefaultLogger.WithPrefix("server"),
|
||||
acceptEarlyConns: acceptEarly,
|
||||
conn: conn,
|
||||
tlsConf: tlsConf,
|
||||
config: config,
|
||||
tokenGenerator: tokenGenerator,
|
||||
connIDGenerator: connIDGenerator,
|
||||
connHandler: connHandler,
|
||||
connQueue: make(chan quicConn),
|
||||
errorChan: make(chan struct{}),
|
||||
running: make(chan struct{}),
|
||||
receivedPackets: make(chan *receivedPacket, protocol.MaxServerUnprocessedPackets),
|
||||
versionNegotiationQueue: make(chan *receivedPacket, 4),
|
||||
invalidTokenQueue: make(chan *receivedPacket, 4),
|
||||
newConn: newConnection,
|
||||
tracer: tracer,
|
||||
logger: utils.DefaultLogger.WithPrefix("server"),
|
||||
acceptEarlyConns: acceptEarly,
|
||||
onClose: onClose,
|
||||
}
|
||||
if acceptEarly {
|
||||
s.zeroRTTQueues = map[protocol.ConnectionID]*zeroRTTQueue{}
|
||||
}
|
||||
go s.run()
|
||||
connHandler.SetServer(s)
|
||||
go s.runSendQueue()
|
||||
s.logger.Debugf("Listening for %s connections on %s", conn.LocalAddr().Network(), conn.LocalAddr().String())
|
||||
return s, nil
|
||||
}
|
||||
@ -239,6 +277,19 @@ func (s *baseServer) run() {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *baseServer) runSendQueue() {
|
||||
for {
|
||||
select {
|
||||
case <-s.running:
|
||||
return
|
||||
case p := <-s.versionNegotiationQueue:
|
||||
s.maybeSendVersionNegotiationPacket(p)
|
||||
case p := <-s.invalidTokenQueue:
|
||||
s.maybeSendInvalidToken(p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Accept returns connections that already completed the handshake.
|
||||
// It is only valid if acceptEarlyConns is false.
|
||||
func (s *baseServer) Accept(ctx context.Context) (Connection, error) {
|
||||
@ -267,18 +318,12 @@ func (s *baseServer) Close() error {
|
||||
if s.serverError == nil {
|
||||
s.serverError = ErrServerClosed
|
||||
}
|
||||
// If the server was started with ListenAddr, we created the packet conn.
|
||||
// We need to close it in order to make the go routine reading from that conn return.
|
||||
createdPacketConn := s.createdPacketConn
|
||||
s.closed = true
|
||||
close(s.errorChan)
|
||||
s.mutex.Unlock()
|
||||
|
||||
<-s.running
|
||||
s.connHandler.CloseServer()
|
||||
if createdPacketConn {
|
||||
return s.connHandler.Destroy()
|
||||
}
|
||||
s.onClose()
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -303,17 +348,21 @@ func (s *baseServer) handlePacket(p *receivedPacket) {
|
||||
case s.receivedPackets <- p:
|
||||
default:
|
||||
s.logger.Debugf("Dropping packet from %s (%d bytes). Server receive queue full.", p.remoteAddr, p.Size())
|
||||
if s.config.Tracer != nil {
|
||||
s.config.Tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropDOSPrevention)
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropDOSPrevention)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *baseServer) handlePacketImpl(p *receivedPacket) bool /* is the buffer still in use? */ {
|
||||
if !s.nextZeroRTTCleanup.IsZero() && p.rcvTime.After(s.nextZeroRTTCleanup) {
|
||||
defer s.cleanupZeroRTTQueues(p.rcvTime)
|
||||
}
|
||||
|
||||
if wire.IsVersionNegotiationPacket(p.data) {
|
||||
s.logger.Debugf("Dropping Version Negotiation packet.")
|
||||
if s.config.Tracer != nil {
|
||||
s.config.Tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeVersionNegotiation, p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeVersionNegotiation, p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
}
|
||||
return false
|
||||
}
|
||||
@ -322,42 +371,54 @@ func (s *baseServer) handlePacketImpl(p *receivedPacket) bool /* is the buffer s
|
||||
panic(fmt.Sprintf("misrouted packet: %#v", p.data))
|
||||
}
|
||||
v, err := wire.ParseVersion(p.data)
|
||||
// send a Version Negotiation Packet if the client is speaking a different protocol version
|
||||
if err != nil || !protocol.IsSupportedVersion(s.config.Versions, v) {
|
||||
if err != nil || p.Size() < protocol.MinUnknownVersionPacketSize {
|
||||
s.logger.Debugf("Dropping a packet with an unknown version that is too small (%d bytes)", p.Size())
|
||||
if s.config.Tracer != nil {
|
||||
s.config.Tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
}
|
||||
return false
|
||||
}
|
||||
_, src, dest, err := wire.ParseArbitraryLenConnectionIDs(p.data)
|
||||
if err != nil { // should never happen
|
||||
s.logger.Debugf("Dropping a packet with an unknown version for which we failed to parse connection IDs")
|
||||
if s.config.Tracer != nil {
|
||||
s.config.Tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
}
|
||||
return false
|
||||
}
|
||||
if !s.config.DisableVersionNegotiationPackets {
|
||||
go s.sendVersionNegotiationPacket(p.remoteAddr, src, dest, p.info.OOB(), v)
|
||||
// drop the packet if we failed to parse the protocol version
|
||||
if err != nil {
|
||||
s.logger.Debugf("Dropping a packet with an unknown version")
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
}
|
||||
return false
|
||||
}
|
||||
// send a Version Negotiation Packet if the client is speaking a different protocol version
|
||||
if !protocol.IsSupportedVersion(s.config.Versions, v) {
|
||||
if s.config.DisableVersionNegotiationPackets {
|
||||
return false
|
||||
}
|
||||
|
||||
if p.Size() < protocol.MinUnknownVersionPacketSize {
|
||||
s.logger.Debugf("Dropping a packet with an unsupported version number %d that is too small (%d bytes)", v, p.Size())
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
}
|
||||
return false
|
||||
}
|
||||
return s.enqueueVersionNegotiationPacket(p)
|
||||
}
|
||||
|
||||
if wire.Is0RTTPacket(p.data) {
|
||||
if !s.acceptEarlyConns {
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketType0RTT, p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
}
|
||||
return false
|
||||
}
|
||||
return s.handle0RTTPacket(p)
|
||||
}
|
||||
|
||||
// If we're creating a new connection, the packet will be passed to the connection.
|
||||
// The header will then be parsed again.
|
||||
hdr, _, _, err := wire.ParsePacket(p.data)
|
||||
if err != nil {
|
||||
if s.config.Tracer != nil {
|
||||
s.config.Tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropHeaderParseError)
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropHeaderParseError)
|
||||
}
|
||||
s.logger.Debugf("Error parsing packet: %s", err)
|
||||
return false
|
||||
}
|
||||
if hdr.Type == protocol.PacketTypeInitial && p.Size() < protocol.MinInitialPacketSize {
|
||||
s.logger.Debugf("Dropping a packet that is too small to be a valid Initial (%d bytes)", p.Size())
|
||||
if s.config.Tracer != nil {
|
||||
s.config.Tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeInitial, p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeInitial, p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
}
|
||||
return false
|
||||
}
|
||||
@ -367,8 +428,8 @@ func (s *baseServer) handlePacketImpl(p *receivedPacket) bool /* is the buffer s
|
||||
// There's little point in sending a Stateless Reset, since the client
|
||||
// might not have received the token yet.
|
||||
s.logger.Debugf("Dropping long header packet of type %s (%d bytes)", hdr.Type, len(p.data))
|
||||
if s.config.Tracer != nil {
|
||||
s.config.Tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeFromHeader(hdr), p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeFromHeader(hdr), p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
}
|
||||
return false
|
||||
}
|
||||
@ -383,6 +444,74 @@ func (s *baseServer) handlePacketImpl(p *receivedPacket) bool /* is the buffer s
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *baseServer) handle0RTTPacket(p *receivedPacket) bool {
|
||||
connID, err := wire.ParseConnectionID(p.data, 0)
|
||||
if err != nil {
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketType0RTT, p.Size(), logging.PacketDropHeaderParseError)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// check again if we might have a connection now
|
||||
if handler, ok := s.connHandler.Get(connID); ok {
|
||||
handler.handlePacket(p)
|
||||
return true
|
||||
}
|
||||
|
||||
if q, ok := s.zeroRTTQueues[connID]; ok {
|
||||
if len(q.packets) >= protocol.Max0RTTQueueLen {
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketType0RTT, p.Size(), logging.PacketDropDOSPrevention)
|
||||
}
|
||||
return false
|
||||
}
|
||||
q.packets = append(q.packets, p)
|
||||
return true
|
||||
}
|
||||
|
||||
if len(s.zeroRTTQueues) >= protocol.Max0RTTQueues {
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketType0RTT, p.Size(), logging.PacketDropDOSPrevention)
|
||||
}
|
||||
return false
|
||||
}
|
||||
queue := &zeroRTTQueue{packets: make([]*receivedPacket, 1, 8)}
|
||||
queue.packets[0] = p
|
||||
expiration := p.rcvTime.Add(protocol.Max0RTTQueueingDuration)
|
||||
queue.expiration = expiration
|
||||
if s.nextZeroRTTCleanup.IsZero() || s.nextZeroRTTCleanup.After(expiration) {
|
||||
s.nextZeroRTTCleanup = expiration
|
||||
}
|
||||
s.zeroRTTQueues[connID] = queue
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *baseServer) cleanupZeroRTTQueues(now time.Time) {
|
||||
// Iterate over all queues to find those that are expired.
|
||||
// This is ok since we're placing a pretty low limit on the number of queues.
|
||||
var nextCleanup time.Time
|
||||
for connID, q := range s.zeroRTTQueues {
|
||||
if q.expiration.After(now) {
|
||||
if nextCleanup.IsZero() || nextCleanup.After(q.expiration) {
|
||||
nextCleanup = q.expiration
|
||||
}
|
||||
continue
|
||||
}
|
||||
for _, p := range q.packets {
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketType0RTT, p.Size(), logging.PacketDropDOSPrevention)
|
||||
}
|
||||
p.buffer.Release()
|
||||
}
|
||||
delete(s.zeroRTTQueues, connID)
|
||||
if s.logger.Debug() {
|
||||
s.logger.Debugf("Removing 0-RTT queue for %s.", connID)
|
||||
}
|
||||
}
|
||||
s.nextZeroRTTCleanup = nextCleanup
|
||||
}
|
||||
|
||||
// validateToken returns false if:
|
||||
// - address is invalid
|
||||
// - token is expired
|
||||
@ -406,12 +535,20 @@ func (s *baseServer) validateToken(token *handshake.Token, addr net.Addr) bool {
|
||||
func (s *baseServer) handleInitialImpl(p *receivedPacket, hdr *wire.Header) error {
|
||||
if len(hdr.Token) == 0 && hdr.DestConnectionID.Len() < protocol.MinConnectionIDLenInitial {
|
||||
p.buffer.Release()
|
||||
if s.config.Tracer != nil {
|
||||
s.config.Tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeInitial, p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeInitial, p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
}
|
||||
return errors.New("too short connection ID")
|
||||
}
|
||||
|
||||
// The server queues packets for a while, and we might already have established a connection by now.
|
||||
// This results in a second check in the connection map.
|
||||
// That's ok since it's not the hot path (it's only taken by some Initial and 0-RTT packets).
|
||||
if handler, ok := s.connHandler.Get(hdr.DestConnectionID); ok {
|
||||
handler.handlePacket(p)
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
token *handshake.Token
|
||||
retrySrcConnID *protocol.ConnectionID
|
||||
@ -429,7 +566,6 @@ func (s *baseServer) handleInitialImpl(p *receivedPacket, hdr *wire.Header) erro
|
||||
}
|
||||
|
||||
clientAddrIsValid := s.validateToken(token, p.remoteAddr)
|
||||
|
||||
if token != nil && !clientAddrIsValid {
|
||||
// For invalid and expired non-retry tokens, we don't send an INVALID_TOKEN error.
|
||||
// We just ignore them, and act as if there was no token on this packet at all.
|
||||
@ -440,16 +576,13 @@ func (s *baseServer) handleInitialImpl(p *receivedPacket, hdr *wire.Header) erro
|
||||
// For Retry tokens, we send an INVALID_ERROR if
|
||||
// * the token is too old, or
|
||||
// * the token is invalid, in case of a retry token.
|
||||
go func() {
|
||||
defer p.buffer.Release()
|
||||
if err := s.maybeSendInvalidToken(p, hdr); err != nil {
|
||||
s.logger.Debugf("Error sending INVALID_TOKEN error: %s", err)
|
||||
}
|
||||
}()
|
||||
s.enqueueInvalidToken(p)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if token == nil && s.config.RequireAddressValidation(p.remoteAddr) {
|
||||
// Retry invalidates all 0-RTT packets sent.
|
||||
delete(s.zeroRTTQueues, hdr.DestConnectionID)
|
||||
go func() {
|
||||
defer p.buffer.Release()
|
||||
if err := s.sendRetry(p.remoteAddr, hdr, p.info); err != nil {
|
||||
@ -470,26 +603,31 @@ func (s *baseServer) handleInitialImpl(p *receivedPacket, hdr *wire.Header) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
connID, err := s.config.ConnectionIDGenerator.GenerateConnectionID()
|
||||
connID, err := s.connIDGenerator.GenerateConnectionID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.logger.Debugf("Changing connection ID to %s.", connID)
|
||||
var conn quicConn
|
||||
tracingID := nextConnTracingID()
|
||||
if added := s.connHandler.AddWithConnID(hdr.DestConnectionID, connID, func() packetHandler {
|
||||
if added := s.connHandler.AddWithConnID(hdr.DestConnectionID, connID, func() (packetHandler, bool) {
|
||||
config := s.config
|
||||
if s.config.GetConfigForClient != nil {
|
||||
conf, err := s.config.GetConfigForClient(&ClientHelloInfo{RemoteAddr: p.remoteAddr})
|
||||
if err != nil {
|
||||
s.logger.Debugf("Rejecting new connection due to GetConfigForClient callback")
|
||||
return nil, false
|
||||
}
|
||||
config = populateConfig(conf)
|
||||
}
|
||||
var tracer logging.ConnectionTracer
|
||||
if s.config.Tracer != nil {
|
||||
if config.Tracer != nil {
|
||||
// Use the same connection ID that is passed to the client's GetLogWriter callback.
|
||||
connID := hdr.DestConnectionID
|
||||
if origDestConnID.Len() > 0 {
|
||||
connID = origDestConnID
|
||||
}
|
||||
tracer = s.config.Tracer.TracerForConnection(
|
||||
context.WithValue(context.Background(), ConnectionTracingKey, tracingID),
|
||||
protocol.PerspectiveServer,
|
||||
connID,
|
||||
)
|
||||
tracer = config.Tracer(context.WithValue(context.Background(), ConnectionTracingKey, tracingID), protocol.PerspectiveServer, connID)
|
||||
}
|
||||
conn = s.newConn(
|
||||
newSendConn(s.conn, p.remoteAddr, p.info),
|
||||
@ -499,8 +637,9 @@ func (s *baseServer) handleInitialImpl(p *receivedPacket, hdr *wire.Header) erro
|
||||
hdr.DestConnectionID,
|
||||
hdr.SrcConnectionID,
|
||||
connID,
|
||||
s.connIDGenerator,
|
||||
s.connHandler.GetStatelessResetToken(connID),
|
||||
s.config,
|
||||
config,
|
||||
s.tlsConf,
|
||||
s.tokenGenerator,
|
||||
clientAddrIsValid,
|
||||
@ -510,8 +649,22 @@ func (s *baseServer) handleInitialImpl(p *receivedPacket, hdr *wire.Header) erro
|
||||
hdr.Version,
|
||||
)
|
||||
conn.handlePacket(p)
|
||||
return conn
|
||||
|
||||
if q, ok := s.zeroRTTQueues[hdr.DestConnectionID]; ok {
|
||||
for _, p := range q.packets {
|
||||
conn.handlePacket(p)
|
||||
}
|
||||
delete(s.zeroRTTQueues, hdr.DestConnectionID)
|
||||
}
|
||||
|
||||
return conn, true
|
||||
}); !added {
|
||||
go func() {
|
||||
defer p.buffer.Release()
|
||||
if err := s.sendConnectionRefused(p.remoteAddr, hdr, p.info); err != nil {
|
||||
s.logger.Debugf("Error rejecting connection: %s", err)
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
go conn.run()
|
||||
@ -555,7 +708,7 @@ func (s *baseServer) sendRetry(remoteAddr net.Addr, hdr *wire.Header, info *pack
|
||||
// Log the Initial packet now.
|
||||
// If no Retry is sent, the packet will be logged by the connection.
|
||||
(&wire.ExtendedHeader{Header: *hdr}).Log(s.logger)
|
||||
srcConnID, err := s.config.ConnectionIDGenerator.GenerateConnectionID()
|
||||
srcConnID, err := s.connIDGenerator.GenerateConnectionID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -584,38 +737,58 @@ func (s *baseServer) sendRetry(remoteAddr net.Addr, hdr *wire.Header, info *pack
|
||||
// append the Retry integrity tag
|
||||
tag := handshake.GetRetryIntegrityTag(buf.Data, hdr.DestConnectionID, hdr.Version)
|
||||
buf.Data = append(buf.Data, tag[:]...)
|
||||
if s.config.Tracer != nil {
|
||||
s.config.Tracer.SentPacket(remoteAddr, &replyHdr.Header, protocol.ByteCount(len(buf.Data)), nil)
|
||||
if s.tracer != nil {
|
||||
s.tracer.SentPacket(remoteAddr, &replyHdr.Header, protocol.ByteCount(len(buf.Data)), nil)
|
||||
}
|
||||
_, err = s.conn.WritePacket(buf.Data, remoteAddr, info.OOB())
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *baseServer) maybeSendInvalidToken(p *receivedPacket, hdr *wire.Header) error {
|
||||
func (s *baseServer) enqueueInvalidToken(p *receivedPacket) {
|
||||
select {
|
||||
case s.invalidTokenQueue <- p:
|
||||
default:
|
||||
// it's fine to drop INVALID_TOKEN packets when we are busy
|
||||
p.buffer.Release()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *baseServer) maybeSendInvalidToken(p *receivedPacket) {
|
||||
defer p.buffer.Release()
|
||||
|
||||
hdr, _, _, err := wire.ParsePacket(p.data)
|
||||
if err != nil {
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropHeaderParseError)
|
||||
}
|
||||
s.logger.Debugf("Error parsing packet: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Only send INVALID_TOKEN if we can unprotect the packet.
|
||||
// This makes sure that we won't send it for packets that were corrupted.
|
||||
sealer, opener := handshake.NewInitialAEAD(hdr.DestConnectionID, protocol.PerspectiveServer, hdr.Version)
|
||||
data := p.data[:hdr.ParsedLen()+hdr.Length]
|
||||
extHdr, err := unpackLongHeader(opener, hdr, data, hdr.Version)
|
||||
if err != nil {
|
||||
if s.config.Tracer != nil {
|
||||
s.config.Tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeInitial, p.Size(), logging.PacketDropHeaderParseError)
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeInitial, p.Size(), logging.PacketDropHeaderParseError)
|
||||
}
|
||||
// don't return the error here. Just drop the packet.
|
||||
return nil
|
||||
return
|
||||
}
|
||||
hdrLen := extHdr.ParsedLen()
|
||||
if _, err := opener.Open(data[hdrLen:hdrLen], data[hdrLen:], extHdr.PacketNumber, data[:hdrLen]); err != nil {
|
||||
// don't return the error here. Just drop the packet.
|
||||
if s.config.Tracer != nil {
|
||||
s.config.Tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeInitial, p.Size(), logging.PacketDropPayloadDecryptError)
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeInitial, p.Size(), logging.PacketDropPayloadDecryptError)
|
||||
}
|
||||
return nil
|
||||
return
|
||||
}
|
||||
if s.logger.Debug() {
|
||||
s.logger.Debugf("Client sent an invalid retry token. Sending INVALID_TOKEN to %s.", p.remoteAddr)
|
||||
}
|
||||
return s.sendError(p.remoteAddr, hdr, sealer, qerr.InvalidToken, p.info)
|
||||
if err := s.sendError(p.remoteAddr, hdr, sealer, qerr.InvalidToken, p.info); err != nil {
|
||||
s.logger.Debugf("Error sending INVALID_TOKEN error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *baseServer) sendConnectionRefused(remoteAddr net.Addr, hdr *wire.Header, info *packetInfo) error {
|
||||
@ -661,21 +834,48 @@ func (s *baseServer) sendError(remoteAddr net.Addr, hdr *wire.Header, sealer han
|
||||
|
||||
replyHdr.Log(s.logger)
|
||||
wire.LogFrame(s.logger, ccf, true)
|
||||
if s.config.Tracer != nil {
|
||||
s.config.Tracer.SentPacket(remoteAddr, &replyHdr.Header, protocol.ByteCount(len(b.Data)), []logging.Frame{ccf})
|
||||
if s.tracer != nil {
|
||||
s.tracer.SentPacket(remoteAddr, &replyHdr.Header, protocol.ByteCount(len(b.Data)), []logging.Frame{ccf})
|
||||
}
|
||||
_, err = s.conn.WritePacket(b.Data, remoteAddr, info.OOB())
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *baseServer) sendVersionNegotiationPacket(remote net.Addr, src, dest protocol.ArbitraryLenConnectionID, oob []byte, v protocol.VersionNumber) {
|
||||
func (s *baseServer) enqueueVersionNegotiationPacket(p *receivedPacket) (bufferInUse bool) {
|
||||
select {
|
||||
case s.versionNegotiationQueue <- p:
|
||||
return true
|
||||
default:
|
||||
// it's fine to not send version negotiation packets when we are busy
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *baseServer) maybeSendVersionNegotiationPacket(p *receivedPacket) {
|
||||
defer p.buffer.Release()
|
||||
|
||||
v, err := wire.ParseVersion(p.data)
|
||||
if err != nil {
|
||||
s.logger.Debugf("failed to parse version for sending version negotiation packet: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
_, src, dest, err := wire.ParseArbitraryLenConnectionIDs(p.data)
|
||||
if err != nil { // should never happen
|
||||
s.logger.Debugf("Dropping a packet with an unknown version for which we failed to parse connection IDs")
|
||||
if s.tracer != nil {
|
||||
s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropUnexpectedPacket)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
s.logger.Debugf("Client offered version %s, sending Version Negotiation", v)
|
||||
|
||||
data := wire.ComposeVersionNegotiation(dest, src, s.config.Versions)
|
||||
if s.config.Tracer != nil {
|
||||
s.config.Tracer.SentVersionNegotiationPacket(remote, src, dest, s.config.Versions)
|
||||
if s.tracer != nil {
|
||||
s.tracer.SentVersionNegotiationPacket(p.remoteAddr, src, dest, s.config.Versions)
|
||||
}
|
||||
if _, err := s.conn.WritePacket(data, remote, oob); err != nil {
|
||||
if _, err := s.conn.WritePacket(data, p.remoteAddr, p.info.OOB()); err != nil {
|
||||
s.logger.Debugf("Error sending Version Negotiation: %s", err)
|
||||
}
|
||||
}
|
||||
|
68
vendor/github.com/quic-go/quic-go/sys_conn_buffers.go
generated
vendored
Normal file
68
vendor/github.com/quic-go/quic-go/sys_conn_buffers.go
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
package quic
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
)
|
||||
|
||||
//go:generate sh -c "echo '// Code generated by go generate. DO NOT EDIT.\n// Source: sys_conn_buffers.go\n' > sys_conn_buffers_write.go && sed -e 's/SetReadBuffer/SetWriteBuffer/g' -e 's/setReceiveBuffer/setSendBuffer/g' -e 's/inspectReadBuffer/inspectWriteBuffer/g' -e 's/protocol\\.DesiredReceiveBufferSize/protocol\\.DesiredSendBufferSize/g' -e 's/forceSetReceiveBuffer/forceSetSendBuffer/g' -e 's/receive buffer/send buffer/g' sys_conn_buffers.go | sed '/^\\/\\/go:generate/d' >> sys_conn_buffers_write.go"
|
||||
func setReceiveBuffer(c net.PacketConn, logger utils.Logger) error {
|
||||
conn, ok := c.(interface{ SetReadBuffer(int) error })
|
||||
if !ok {
|
||||
return errors.New("connection doesn't allow setting of receive buffer size. Not a *net.UDPConn?")
|
||||
}
|
||||
|
||||
var syscallConn syscall.RawConn
|
||||
if sc, ok := c.(interface {
|
||||
SyscallConn() (syscall.RawConn, error)
|
||||
}); ok {
|
||||
var err error
|
||||
syscallConn, err = sc.SyscallConn()
|
||||
if err != nil {
|
||||
syscallConn = nil
|
||||
}
|
||||
}
|
||||
// The connection has a SetReadBuffer method, but we couldn't obtain a syscall.RawConn.
|
||||
// This shouldn't happen for a net.UDPConn, but is possible if the connection just implements the
|
||||
// net.PacketConn interface and the SetReadBuffer method.
|
||||
// We have no way of checking if increasing the buffer size actually worked.
|
||||
if syscallConn == nil {
|
||||
return conn.SetReadBuffer(protocol.DesiredReceiveBufferSize)
|
||||
}
|
||||
|
||||
size, err := inspectReadBuffer(syscallConn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to determine receive buffer size: %w", err)
|
||||
}
|
||||
if size >= protocol.DesiredReceiveBufferSize {
|
||||
logger.Debugf("Conn has receive buffer of %d kiB (wanted: at least %d kiB)", size/1024, protocol.DesiredReceiveBufferSize/1024)
|
||||
return nil
|
||||
}
|
||||
// Ignore the error. We check if we succeeded by querying the buffer size afterward.
|
||||
_ = conn.SetReadBuffer(protocol.DesiredReceiveBufferSize)
|
||||
newSize, err := inspectReadBuffer(syscallConn)
|
||||
if newSize < protocol.DesiredReceiveBufferSize {
|
||||
// Try again with RCVBUFFORCE on Linux
|
||||
_ = forceSetReceiveBuffer(syscallConn, protocol.DesiredReceiveBufferSize)
|
||||
newSize, err = inspectReadBuffer(syscallConn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to determine receive buffer size: %w", err)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to determine receive buffer size: %w", err)
|
||||
}
|
||||
if newSize == size {
|
||||
return fmt.Errorf("failed to increase receive buffer size (wanted: %d kiB, got %d kiB)", protocol.DesiredReceiveBufferSize/1024, newSize/1024)
|
||||
}
|
||||
if newSize < protocol.DesiredReceiveBufferSize {
|
||||
return fmt.Errorf("failed to sufficiently increase receive buffer size (was: %d kiB, wanted: %d kiB, got: %d kiB)", size/1024, protocol.DesiredReceiveBufferSize/1024, newSize/1024)
|
||||
}
|
||||
logger.Debugf("Increased receive buffer size to %d kiB", newSize/1024)
|
||||
return nil
|
||||
}
|
70
vendor/github.com/quic-go/quic-go/sys_conn_buffers_write.go
generated
vendored
Normal file
70
vendor/github.com/quic-go/quic-go/sys_conn_buffers_write.go
generated
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
// Code generated by go generate. DO NOT EDIT.
|
||||
// Source: sys_conn_buffers.go
|
||||
|
||||
package quic
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
)
|
||||
|
||||
func setSendBuffer(c net.PacketConn, logger utils.Logger) error {
|
||||
conn, ok := c.(interface{ SetWriteBuffer(int) error })
|
||||
if !ok {
|
||||
return errors.New("connection doesn't allow setting of send buffer size. Not a *net.UDPConn?")
|
||||
}
|
||||
|
||||
var syscallConn syscall.RawConn
|
||||
if sc, ok := c.(interface {
|
||||
SyscallConn() (syscall.RawConn, error)
|
||||
}); ok {
|
||||
var err error
|
||||
syscallConn, err = sc.SyscallConn()
|
||||
if err != nil {
|
||||
syscallConn = nil
|
||||
}
|
||||
}
|
||||
// The connection has a SetWriteBuffer method, but we couldn't obtain a syscall.RawConn.
|
||||
// This shouldn't happen for a net.UDPConn, but is possible if the connection just implements the
|
||||
// net.PacketConn interface and the SetWriteBuffer method.
|
||||
// We have no way of checking if increasing the buffer size actually worked.
|
||||
if syscallConn == nil {
|
||||
return conn.SetWriteBuffer(protocol.DesiredSendBufferSize)
|
||||
}
|
||||
|
||||
size, err := inspectWriteBuffer(syscallConn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to determine send buffer size: %w", err)
|
||||
}
|
||||
if size >= protocol.DesiredSendBufferSize {
|
||||
logger.Debugf("Conn has send buffer of %d kiB (wanted: at least %d kiB)", size/1024, protocol.DesiredSendBufferSize/1024)
|
||||
return nil
|
||||
}
|
||||
// Ignore the error. We check if we succeeded by querying the buffer size afterward.
|
||||
_ = conn.SetWriteBuffer(protocol.DesiredSendBufferSize)
|
||||
newSize, err := inspectWriteBuffer(syscallConn)
|
||||
if newSize < protocol.DesiredSendBufferSize {
|
||||
// Try again with RCVBUFFORCE on Linux
|
||||
_ = forceSetSendBuffer(syscallConn, protocol.DesiredSendBufferSize)
|
||||
newSize, err = inspectWriteBuffer(syscallConn)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to determine send buffer size: %w", err)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to determine send buffer size: %w", err)
|
||||
}
|
||||
if newSize == size {
|
||||
return fmt.Errorf("failed to increase send buffer size (wanted: %d kiB, got %d kiB)", protocol.DesiredSendBufferSize/1024, newSize/1024)
|
||||
}
|
||||
if newSize < protocol.DesiredSendBufferSize {
|
||||
return fmt.Errorf("failed to sufficiently increase send buffer size (was: %d kiB, wanted: %d kiB, got: %d kiB)", size/1024, protocol.DesiredSendBufferSize/1024, newSize/1024)
|
||||
}
|
||||
logger.Debugf("Increased send buffer size to %d kiB", newSize/1024)
|
||||
return nil
|
||||
}
|
26
vendor/github.com/quic-go/quic-go/sys_conn_helper_linux.go
generated
vendored
26
vendor/github.com/quic-go/quic-go/sys_conn_helper_linux.go
generated
vendored
@ -2,7 +2,11 @@
|
||||
|
||||
package quic
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const msgTypeIPTOS = unix.IP_TOS
|
||||
|
||||
@ -17,3 +21,23 @@
|
||||
)
|
||||
|
||||
const batchSize = 8 // needs to smaller than MaxUint8 (otherwise the type of oobConn.readPos has to be changed)
|
||||
|
||||
func forceSetReceiveBuffer(c syscall.RawConn, bytes int) error {
|
||||
var serr error
|
||||
if err := c.Control(func(fd uintptr) {
|
||||
serr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUFFORCE, bytes)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return serr
|
||||
}
|
||||
|
||||
func forceSetSendBuffer(c syscall.RawConn, bytes int) error {
|
||||
var serr error
|
||||
if err := c.Control(func(fd uintptr) {
|
||||
serr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_SNDBUFFORCE, bytes)
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return serr
|
||||
}
|
||||
|
6
vendor/github.com/quic-go/quic-go/sys_conn_helper_nonlinux.go
generated
vendored
Normal file
6
vendor/github.com/quic-go/quic-go/sys_conn_helper_nonlinux.go
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
//go:build !linux
|
||||
|
||||
package quic
|
||||
|
||||
func forceSetReceiveBuffer(c any, bytes int) error { return nil }
|
||||
func forceSetSendBuffer(c any, bytes int) error { return nil }
|
5
vendor/github.com/quic-go/quic-go/sys_conn_no_oob.go
generated
vendored
5
vendor/github.com/quic-go/quic-go/sys_conn_no_oob.go
generated
vendored
@ -8,8 +8,7 @@ func newConn(c net.PacketConn) (rawConn, error) {
|
||||
return &basicConn{PacketConn: c}, nil
|
||||
}
|
||||
|
||||
func inspectReadBuffer(interface{}) (int, error) {
|
||||
return 0, nil
|
||||
}
|
||||
func inspectReadBuffer(any) (int, error) { return 0, nil }
|
||||
func inspectWriteBuffer(any) (int, error) { return 0, nil }
|
||||
|
||||
func (i *packetInfo) OOB() []byte { return nil }
|
||||
|
26
vendor/github.com/quic-go/quic-go/sys_conn_oob.go
generated
vendored
26
vendor/github.com/quic-go/quic-go/sys_conn_oob.go
generated
vendored
@ -5,7 +5,6 @@
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"syscall"
|
||||
"time"
|
||||
@ -32,20 +31,10 @@ type batchConn interface {
|
||||
ReadBatch(ms []ipv4.Message, flags int) (int, error)
|
||||
}
|
||||
|
||||
func inspectReadBuffer(c interface{}) (int, error) {
|
||||
conn, ok := c.(interface {
|
||||
SyscallConn() (syscall.RawConn, error)
|
||||
})
|
||||
if !ok {
|
||||
return 0, errors.New("doesn't have a SyscallConn")
|
||||
}
|
||||
rawConn, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("couldn't get syscall.RawConn: %w", err)
|
||||
}
|
||||
func inspectReadBuffer(c syscall.RawConn) (int, error) {
|
||||
var size int
|
||||
var serr error
|
||||
if err := rawConn.Control(func(fd uintptr) {
|
||||
if err := c.Control(func(fd uintptr) {
|
||||
size, serr = unix.GetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_RCVBUF)
|
||||
}); err != nil {
|
||||
return 0, err
|
||||
@ -53,6 +42,17 @@ func inspectReadBuffer(c interface{}) (int, error) {
|
||||
return size, serr
|
||||
}
|
||||
|
||||
func inspectWriteBuffer(c syscall.RawConn) (int, error) {
|
||||
var size int
|
||||
var serr error
|
||||
if err := c.Control(func(fd uintptr) {
|
||||
size, serr = unix.GetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_SNDBUF)
|
||||
}); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return size, serr
|
||||
}
|
||||
|
||||
type oobConn struct {
|
||||
OOBCapablePacketConn
|
||||
batchConn batchConn
|
||||
|
28
vendor/github.com/quic-go/quic-go/sys_conn_windows.go
generated
vendored
28
vendor/github.com/quic-go/quic-go/sys_conn_windows.go
generated
vendored
@ -3,9 +3,6 @@
|
||||
package quic
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
@ -15,20 +12,10 @@ func newConn(c OOBCapablePacketConn) (rawConn, error) {
|
||||
return &basicConn{PacketConn: c}, nil
|
||||
}
|
||||
|
||||
func inspectReadBuffer(c net.PacketConn) (int, error) {
|
||||
conn, ok := c.(interface {
|
||||
SyscallConn() (syscall.RawConn, error)
|
||||
})
|
||||
if !ok {
|
||||
return 0, errors.New("doesn't have a SyscallConn")
|
||||
}
|
||||
rawConn, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("couldn't get syscall.RawConn: %w", err)
|
||||
}
|
||||
func inspectReadBuffer(c syscall.RawConn) (int, error) {
|
||||
var size int
|
||||
var serr error
|
||||
if err := rawConn.Control(func(fd uintptr) {
|
||||
if err := c.Control(func(fd uintptr) {
|
||||
size, serr = windows.GetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_RCVBUF)
|
||||
}); err != nil {
|
||||
return 0, err
|
||||
@ -36,4 +23,15 @@ func inspectReadBuffer(c net.PacketConn) (int, error) {
|
||||
return size, serr
|
||||
}
|
||||
|
||||
func inspectWriteBuffer(c syscall.RawConn) (int, error) {
|
||||
var size int
|
||||
var serr error
|
||||
if err := c.Control(func(fd uintptr) {
|
||||
size, serr = windows.GetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_SNDBUF)
|
||||
}); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return size, serr
|
||||
}
|
||||
|
||||
func (i *packetInfo) OOB() []byte { return nil }
|
||||
|
416
vendor/github.com/quic-go/quic-go/transport.go
generated
vendored
Normal file
416
vendor/github.com/quic-go/quic-go/transport.go
generated
vendored
Normal file
@ -0,0 +1,416 @@
|
||||
package quic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/wire"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
"github.com/quic-go/quic-go/internal/utils"
|
||||
"github.com/quic-go/quic-go/logging"
|
||||
)
|
||||
|
||||
type Transport struct {
|
||||
// A single net.PacketConn can only be handled by one Transport.
|
||||
// Bad things will happen if passed to multiple Transports.
|
||||
//
|
||||
// If the connection satisfies the OOBCapablePacketConn interface
|
||||
// (as a net.UDPConn does), ECN and packet info support will be enabled.
|
||||
// In this case, optimized syscalls might be used, skipping the
|
||||
// ReadFrom and WriteTo calls to read / write packets.
|
||||
Conn net.PacketConn
|
||||
|
||||
// The length of the connection ID in bytes.
|
||||
// It can be 0, or any value between 4 and 18.
|
||||
// If unset, a 4 byte connection ID will be used.
|
||||
ConnectionIDLength int
|
||||
|
||||
// Use for generating new connection IDs.
|
||||
// This allows the application to control of the connection IDs used,
|
||||
// which allows routing / load balancing based on connection IDs.
|
||||
// All Connection IDs returned by the ConnectionIDGenerator MUST
|
||||
// have the same length.
|
||||
ConnectionIDGenerator ConnectionIDGenerator
|
||||
|
||||
// The StatelessResetKey is used to generate stateless reset tokens.
|
||||
// If no key is configured, sending of stateless resets is disabled.
|
||||
StatelessResetKey *StatelessResetKey
|
||||
|
||||
// A Tracer traces events that don't belong to a single QUIC connection.
|
||||
Tracer logging.Tracer
|
||||
|
||||
handlerMap packetHandlerManager
|
||||
|
||||
mutex sync.Mutex
|
||||
initOnce sync.Once
|
||||
initErr error
|
||||
|
||||
// Set in init.
|
||||
// If no ConnectionIDGenerator is set, this is the ConnectionIDLength.
|
||||
connIDLen int
|
||||
// Set in init.
|
||||
// If no ConnectionIDGenerator is set, this is set to a default.
|
||||
connIDGenerator ConnectionIDGenerator
|
||||
|
||||
server unknownPacketHandler
|
||||
|
||||
conn rawConn
|
||||
|
||||
closeQueue chan closePacket
|
||||
statelessResetQueue chan *receivedPacket
|
||||
|
||||
listening chan struct{} // is closed when listen returns
|
||||
closed bool
|
||||
createdConn bool
|
||||
isSingleUse bool // was created for a single server or client, i.e. by calling quic.Listen or quic.Dial
|
||||
|
||||
logger utils.Logger
|
||||
}
|
||||
|
||||
// Listen starts listening for incoming QUIC connections.
|
||||
// There can only be a single listener on any net.PacketConn.
|
||||
// Listen may only be called again after the current Listener was closed.
|
||||
func (t *Transport) Listen(tlsConf *tls.Config, conf *Config) (*Listener, error) {
|
||||
if tlsConf == nil {
|
||||
return nil, errors.New("quic: tls.Config not set")
|
||||
}
|
||||
if err := validateConfig(conf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t.mutex.Lock()
|
||||
defer t.mutex.Unlock()
|
||||
|
||||
if t.server != nil {
|
||||
return nil, errListenerAlreadySet
|
||||
}
|
||||
conf = populateServerConfig(conf)
|
||||
if err := t.init(true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s, err := newServer(t.conn, t.handlerMap, t.connIDGenerator, tlsConf, conf, t.Tracer, t.closeServer, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.server = s
|
||||
return &Listener{baseServer: s}, nil
|
||||
}
|
||||
|
||||
// ListenEarly starts listening for incoming QUIC connections.
|
||||
// There can only be a single listener on any net.PacketConn.
|
||||
// Listen may only be called again after the current Listener was closed.
|
||||
func (t *Transport) ListenEarly(tlsConf *tls.Config, conf *Config) (*EarlyListener, error) {
|
||||
if tlsConf == nil {
|
||||
return nil, errors.New("quic: tls.Config not set")
|
||||
}
|
||||
if err := validateConfig(conf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
t.mutex.Lock()
|
||||
defer t.mutex.Unlock()
|
||||
|
||||
if t.server != nil {
|
||||
return nil, errListenerAlreadySet
|
||||
}
|
||||
conf = populateServerConfig(conf)
|
||||
if err := t.init(true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s, err := newServer(t.conn, t.handlerMap, t.connIDGenerator, tlsConf, conf, t.Tracer, t.closeServer, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.server = s
|
||||
return &EarlyListener{baseServer: s}, nil
|
||||
}
|
||||
|
||||
// Dial dials a new connection to a remote host (not using 0-RTT).
|
||||
func (t *Transport) Dial(ctx context.Context, addr net.Addr, tlsConf *tls.Config, conf *Config) (Connection, error) {
|
||||
if err := validateConfig(conf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conf = populateConfig(conf)
|
||||
if err := t.init(false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var onClose func()
|
||||
if t.isSingleUse {
|
||||
onClose = func() { t.Close() }
|
||||
}
|
||||
return dial(ctx, newSendConn(t.conn, addr, nil), t.connIDGenerator, t.handlerMap, tlsConf, conf, onClose, false)
|
||||
}
|
||||
|
||||
// DialEarly dials a new connection, attempting to use 0-RTT if possible.
|
||||
func (t *Transport) DialEarly(ctx context.Context, addr net.Addr, tlsConf *tls.Config, conf *Config) (EarlyConnection, error) {
|
||||
if err := validateConfig(conf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conf = populateConfig(conf)
|
||||
if err := t.init(false); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var onClose func()
|
||||
if t.isSingleUse {
|
||||
onClose = func() { t.Close() }
|
||||
}
|
||||
return dial(ctx, newSendConn(t.conn, addr, nil), t.connIDGenerator, t.handlerMap, tlsConf, conf, onClose, true)
|
||||
}
|
||||
|
||||
func (t *Transport) init(isServer bool) error {
|
||||
t.initOnce.Do(func() {
|
||||
getMultiplexer().AddConn(t.Conn)
|
||||
|
||||
conn, err := wrapConn(t.Conn)
|
||||
if err != nil {
|
||||
t.initErr = err
|
||||
return
|
||||
}
|
||||
|
||||
t.logger = utils.DefaultLogger // TODO: make this configurable
|
||||
t.conn = conn
|
||||
t.handlerMap = newPacketHandlerMap(t.StatelessResetKey, t.enqueueClosePacket, t.logger)
|
||||
t.listening = make(chan struct{})
|
||||
|
||||
t.closeQueue = make(chan closePacket, 4)
|
||||
t.statelessResetQueue = make(chan *receivedPacket, 4)
|
||||
|
||||
if t.ConnectionIDGenerator != nil {
|
||||
t.connIDGenerator = t.ConnectionIDGenerator
|
||||
t.connIDLen = t.ConnectionIDGenerator.ConnectionIDLen()
|
||||
} else {
|
||||
connIDLen := t.ConnectionIDLength
|
||||
if t.ConnectionIDLength == 0 && (!t.isSingleUse || isServer) {
|
||||
connIDLen = protocol.DefaultConnectionIDLength
|
||||
}
|
||||
t.connIDLen = connIDLen
|
||||
t.connIDGenerator = &protocol.DefaultConnectionIDGenerator{ConnLen: t.connIDLen}
|
||||
}
|
||||
|
||||
go t.listen(conn)
|
||||
go t.runSendQueue()
|
||||
})
|
||||
return t.initErr
|
||||
}
|
||||
|
||||
func (t *Transport) enqueueClosePacket(p closePacket) {
|
||||
select {
|
||||
case t.closeQueue <- p:
|
||||
default:
|
||||
// Oops, we're backlogged.
|
||||
// Just drop the packet, sending CONNECTION_CLOSE copies is best effort anyway.
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Transport) runSendQueue() {
|
||||
for {
|
||||
select {
|
||||
case <-t.listening:
|
||||
return
|
||||
case p := <-t.closeQueue:
|
||||
t.conn.WritePacket(p.payload, p.addr, p.info.OOB())
|
||||
case p := <-t.statelessResetQueue:
|
||||
t.sendStatelessReset(p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close closes the underlying connection and waits until listen has returned.
|
||||
// It is invalid to start new listeners or connections after that.
|
||||
func (t *Transport) Close() error {
|
||||
t.close(errors.New("closing"))
|
||||
if t.createdConn {
|
||||
if err := t.conn.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
t.conn.SetReadDeadline(time.Now())
|
||||
defer func() { t.conn.SetReadDeadline(time.Time{}) }()
|
||||
}
|
||||
<-t.listening // wait until listening returns
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Transport) closeServer() {
|
||||
t.handlerMap.CloseServer()
|
||||
t.mutex.Lock()
|
||||
t.server = nil
|
||||
if t.isSingleUse {
|
||||
t.closed = true
|
||||
}
|
||||
t.mutex.Unlock()
|
||||
if t.createdConn {
|
||||
t.Conn.Close()
|
||||
}
|
||||
if t.isSingleUse {
|
||||
t.conn.SetReadDeadline(time.Now())
|
||||
defer func() { t.conn.SetReadDeadline(time.Time{}) }()
|
||||
<-t.listening // wait until listening returns
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Transport) close(e error) {
|
||||
t.mutex.Lock()
|
||||
defer t.mutex.Unlock()
|
||||
if t.closed {
|
||||
return
|
||||
}
|
||||
|
||||
t.handlerMap.Close(e)
|
||||
if t.server != nil {
|
||||
t.server.setCloseError(e)
|
||||
}
|
||||
t.closed = true
|
||||
}
|
||||
|
||||
// only print warnings about the UDP receive buffer size once
|
||||
var setBufferWarningOnce sync.Once
|
||||
|
||||
func (t *Transport) listen(conn rawConn) {
|
||||
defer close(t.listening)
|
||||
defer getMultiplexer().RemoveConn(t.Conn)
|
||||
|
||||
if err := setReceiveBuffer(t.Conn, t.logger); err != nil {
|
||||
if !strings.Contains(err.Error(), "use of closed network connection") {
|
||||
setBufferWarningOnce.Do(func() {
|
||||
if disable, _ := strconv.ParseBool(os.Getenv("QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING")); disable {
|
||||
return
|
||||
}
|
||||
log.Printf("%s. See https://github.com/quic-go/quic-go/wiki/UDP-Receive-Buffer-Size for details.", err)
|
||||
})
|
||||
}
|
||||
}
|
||||
if err := setSendBuffer(t.Conn, t.logger); err != nil {
|
||||
if !strings.Contains(err.Error(), "use of closed network connection") {
|
||||
setBufferWarningOnce.Do(func() {
|
||||
if disable, _ := strconv.ParseBool(os.Getenv("QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING")); disable {
|
||||
return
|
||||
}
|
||||
log.Printf("%s. See https://github.com/quic-go/quic-go/wiki/UDP-Receive-Buffer-Size for details.", err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
p, err := conn.ReadPacket()
|
||||
//nolint:staticcheck // SA1019 ignore this!
|
||||
// TODO: This code is used to ignore wsa errors on Windows.
|
||||
// Since net.Error.Temporary is deprecated as of Go 1.18, we should find a better solution.
|
||||
// See https://github.com/quic-go/quic-go/issues/1737 for details.
|
||||
if nerr, ok := err.(net.Error); ok && nerr.Temporary() {
|
||||
t.mutex.Lock()
|
||||
closed := t.closed
|
||||
t.mutex.Unlock()
|
||||
if closed {
|
||||
return
|
||||
}
|
||||
t.logger.Debugf("Temporary error reading from conn: %w", err)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
t.close(err)
|
||||
return
|
||||
}
|
||||
t.handlePacket(p)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Transport) handlePacket(p *receivedPacket) {
|
||||
connID, err := wire.ParseConnectionID(p.data, t.connIDLen)
|
||||
if err != nil {
|
||||
t.logger.Debugf("error parsing connection ID on packet from %s: %s", p.remoteAddr, err)
|
||||
if t.Tracer != nil {
|
||||
t.Tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropHeaderParseError)
|
||||
}
|
||||
p.buffer.MaybeRelease()
|
||||
return
|
||||
}
|
||||
|
||||
if isStatelessReset := t.maybeHandleStatelessReset(p.data); isStatelessReset {
|
||||
return
|
||||
}
|
||||
if handler, ok := t.handlerMap.Get(connID); ok {
|
||||
handler.handlePacket(p)
|
||||
return
|
||||
}
|
||||
if !wire.IsLongHeaderPacket(p.data[0]) {
|
||||
t.maybeSendStatelessReset(p)
|
||||
return
|
||||
}
|
||||
|
||||
t.mutex.Lock()
|
||||
defer t.mutex.Unlock()
|
||||
if t.server == nil { // no server set
|
||||
t.logger.Debugf("received a packet with an unexpected connection ID %s", connID)
|
||||
return
|
||||
}
|
||||
t.server.handlePacket(p)
|
||||
}
|
||||
|
||||
func (t *Transport) maybeSendStatelessReset(p *receivedPacket) {
|
||||
if t.StatelessResetKey == nil {
|
||||
p.buffer.Release()
|
||||
return
|
||||
}
|
||||
|
||||
// Don't send a stateless reset in response to very small packets.
|
||||
// This includes packets that could be stateless resets.
|
||||
if len(p.data) <= protocol.MinStatelessResetSize {
|
||||
p.buffer.Release()
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case t.statelessResetQueue <- p:
|
||||
default:
|
||||
// it's fine to not send a stateless reset when we're busy
|
||||
p.buffer.Release()
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Transport) sendStatelessReset(p *receivedPacket) {
|
||||
defer p.buffer.Release()
|
||||
|
||||
connID, err := wire.ParseConnectionID(p.data, t.connIDLen)
|
||||
if err != nil {
|
||||
t.logger.Errorf("error parsing connection ID on packet from %s: %s", p.remoteAddr, err)
|
||||
return
|
||||
}
|
||||
token := t.handlerMap.GetStatelessResetToken(connID)
|
||||
t.logger.Debugf("Sending stateless reset to %s (connection ID: %s). Token: %#x", p.remoteAddr, connID, token)
|
||||
data := make([]byte, protocol.MinStatelessResetSize-16, protocol.MinStatelessResetSize)
|
||||
rand.Read(data)
|
||||
data[0] = (data[0] & 0x7f) | 0x40
|
||||
data = append(data, token[:]...)
|
||||
if _, err := t.conn.WritePacket(data, p.remoteAddr, p.info.OOB()); err != nil {
|
||||
t.logger.Debugf("Error sending Stateless Reset to %s: %s", p.remoteAddr, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Transport) maybeHandleStatelessReset(data []byte) bool {
|
||||
// stateless resets are always short header packets
|
||||
if wire.IsLongHeaderPacket(data[0]) {
|
||||
return false
|
||||
}
|
||||
if len(data) < 17 /* type byte + 16 bytes for the reset token */ {
|
||||
return false
|
||||
}
|
||||
|
||||
token := *(*protocol.StatelessResetToken)(data[len(data)-16:])
|
||||
if conn, ok := t.handlerMap.GetByResetToken(token); ok {
|
||||
t.logger.Debugf("Received a stateless reset with token %#x. Closing connection.", token)
|
||||
go conn.destroy(&StatelessResetError{Token: token})
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
34
vendor/github.com/quic-go/quic-go/zero_rtt_queue.go
generated
vendored
34
vendor/github.com/quic-go/quic-go/zero_rtt_queue.go
generated
vendored
@ -1,34 +0,0 @@
|
||||
package quic
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/quic-go/quic-go/internal/protocol"
|
||||
)
|
||||
|
||||
type zeroRTTQueue struct {
|
||||
queue []*receivedPacket
|
||||
retireTimer *time.Timer
|
||||
}
|
||||
|
||||
var _ packetHandler = &zeroRTTQueue{}
|
||||
|
||||
func (h *zeroRTTQueue) handlePacket(p *receivedPacket) {
|
||||
if len(h.queue) < protocol.Max0RTTQueueLen {
|
||||
h.queue = append(h.queue, p)
|
||||
}
|
||||
}
|
||||
func (h *zeroRTTQueue) shutdown() {}
|
||||
func (h *zeroRTTQueue) destroy(error) {}
|
||||
func (h *zeroRTTQueue) getPerspective() protocol.Perspective { return protocol.PerspectiveClient }
|
||||
func (h *zeroRTTQueue) EnqueueAll(sess packetHandler) {
|
||||
for _, p := range h.queue {
|
||||
sess.handlePacket(p)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *zeroRTTQueue) Clear() {
|
||||
for _, p := range h.queue {
|
||||
p.buffer.Release()
|
||||
}
|
||||
}
|
16
vendor/modules.txt
vendored
16
vendor/modules.txt
vendored
@ -46,8 +46,8 @@ github.com/hashicorp/golang-lru/simplelru
|
||||
## explicit; go 1.12
|
||||
github.com/hectane/go-acl
|
||||
github.com/hectane/go-acl/api
|
||||
# github.com/jedisct1/dlog v0.0.0-20230211133026-0338add8743f
|
||||
## explicit; go 1.17
|
||||
# github.com/jedisct1/dlog v0.0.0-20230513092435-93bc2a55ad59
|
||||
## explicit; go 1.20
|
||||
github.com/jedisct1/dlog
|
||||
# github.com/jedisct1/go-clocksmith v0.0.0-20230211133011-392c1afea73e
|
||||
## explicit
|
||||
@ -55,14 +55,14 @@ github.com/jedisct1/go-clocksmith
|
||||
# github.com/jedisct1/go-dnsstamps v0.0.0-20230211133001-124a632de565
|
||||
## explicit; go 1.18
|
||||
github.com/jedisct1/go-dnsstamps
|
||||
# github.com/jedisct1/go-hpke-compact v0.0.0-20230211184420-51d4440017ce
|
||||
## explicit; go 1.19
|
||||
# github.com/jedisct1/go-hpke-compact v0.0.0-20230513092519-91c912752223
|
||||
## explicit; go 1.20
|
||||
github.com/jedisct1/go-hpke-compact
|
||||
# github.com/jedisct1/go-minisign v0.0.0-20230410063418-3d885d71f62c
|
||||
# github.com/jedisct1/go-minisign v0.0.0-20230513092556-d96eb068239a
|
||||
## explicit; go 1.20
|
||||
github.com/jedisct1/go-minisign
|
||||
# github.com/jedisct1/xsecretbox v0.0.0-20230211185120-2025cdbb9f0f
|
||||
## explicit; go 1.19
|
||||
# github.com/jedisct1/xsecretbox v0.0.0-20230513092623-8c0b2dff5e24
|
||||
## explicit; go 1.20
|
||||
github.com/jedisct1/xsecretbox
|
||||
# github.com/k-sone/critbitgo v1.4.0
|
||||
## explicit
|
||||
@ -112,7 +112,7 @@ github.com/quic-go/qtls-go1-19
|
||||
# github.com/quic-go/qtls-go1-20 v0.2.2
|
||||
## explicit; go 1.20
|
||||
github.com/quic-go/qtls-go1-20
|
||||
# github.com/quic-go/quic-go v0.34.0
|
||||
# github.com/quic-go/quic-go v0.35.0
|
||||
## explicit; go 1.19
|
||||
github.com/quic-go/quic-go
|
||||
github.com/quic-go/quic-go/http3
|
||||
|
Loading…
Reference in New Issue
Block a user