Update deps

This commit is contained in:
Frank Denis 2023-11-15 15:51:48 -08:00
parent cb80bf33e8
commit 0ba728b6ce
547 changed files with 1110 additions and 1182 deletions

16
go.mod
View File

@ -1,6 +1,6 @@
module github.com/dnscrypt/dnscrypt-proxy module github.com/dnscrypt/dnscrypt-proxy
go 1.21.3 go 1.21.4
require ( require (
github.com/BurntSushi/toml v1.3.2 github.com/BurntSushi/toml v1.3.2
@ -18,12 +18,12 @@ require (
github.com/jedisct1/xsecretbox v0.0.0-20230811132812-b950633f9f1f github.com/jedisct1/xsecretbox v0.0.0-20230811132812-b950633f9f1f
github.com/k-sone/critbitgo v1.4.0 github.com/k-sone/critbitgo v1.4.0
github.com/kardianos/service v1.2.2 github.com/kardianos/service v1.2.2
github.com/miekg/dns v1.1.56 github.com/miekg/dns v1.1.57
github.com/powerman/check v1.7.0 github.com/powerman/check v1.7.0
github.com/quic-go/quic-go v0.39.0 github.com/quic-go/quic-go v0.40.0
golang.org/x/crypto v0.14.0 golang.org/x/crypto v0.15.0
golang.org/x/net v0.17.0 golang.org/x/net v0.18.0
golang.org/x/sys v0.13.0 golang.org/x/sys v0.14.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/natefinch/lumberjack.v2 v2.2.1
) )
@ -38,12 +38,12 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/powerman/deepequal v0.1.0 // indirect github.com/powerman/deepequal v0.1.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qtls-go1-20 v0.3.4 // indirect github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
github.com/smartystreets/goconvey v1.7.2 // indirect github.com/smartystreets/goconvey v1.7.2 // indirect
go.uber.org/mock v0.3.0 // indirect go.uber.org/mock v0.3.0 // indirect
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
golang.org/x/mod v0.12.0 // indirect golang.org/x/mod v0.12.0 // indirect
golang.org/x/text v0.13.0 // indirect golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.13.0 // indirect golang.org/x/tools v0.13.0 // indirect
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
google.golang.org/grpc v1.53.0 // indirect google.golang.org/grpc v1.53.0 // indirect

32
go.sum
View File

@ -56,8 +56,8 @@ github.com/k-sone/critbitgo v1.4.0 h1:l71cTyBGeh6X5ATh6Fibgw3+rtNT80BA0uNNWgkPrb
github.com/k-sone/critbitgo v1.4.0/go.mod h1:7E6pyoyADnFxlUBEKcnfS49b7SUAQGMK+OAp/UQvo0s= github.com/k-sone/critbitgo v1.4.0/go.mod h1:7E6pyoyADnFxlUBEKcnfS49b7SUAQGMK+OAp/UQvo0s=
github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60= github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60=
github.com/kardianos/service v1.2.2/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= github.com/kardianos/service v1.2.2/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q=
github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k=
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
@ -72,10 +72,10 @@ github.com/powerman/deepequal v0.1.0 h1:sVwtyTsBuYIvdbLR1O2wzRY63YgPqdGZmk/o80l+
github.com/powerman/deepequal v0.1.0/go.mod h1:3k7aG/slufBhUANdN67o/UPg8i5YaiJ6FmibWX0cn04= github.com/powerman/deepequal v0.1.0/go.mod h1:3k7aG/slufBhUANdN67o/UPg8i5YaiJ6FmibWX0cn04=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg= github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs=
github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
github.com/quic-go/quic-go v0.39.0 h1:AgP40iThFMY0bj8jGxROhw3S0FMGa8ryqsmi9tBH3So= github.com/quic-go/quic-go v0.40.0 h1:GYd1iznlKm7dpHD7pOVpUvItgMPo/jrMgDWZhMCecqw=
github.com/quic-go/quic-go v0.39.0/go.mod h1:T09QsDQWjLiQ74ZmacDfqZmhY/NLnw5BC40MANNNZ1Q= github.com/quic-go/quic-go v0.40.0/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c=
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= 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/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 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
@ -86,26 +86,26 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo=
go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o= golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o=
golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190529164535-6a60838ec259/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190529164535-6a60838ec259/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=

View File

@ -10,8 +10,6 @@ type MsgAcceptFunc func(dh Header) MsgAcceptAction
// //
// * opcode isn't OpcodeQuery or OpcodeNotify // * opcode isn't OpcodeQuery or OpcodeNotify
// //
// * Zero bit isn't zero
//
// * does not have exactly 1 question in the question section // * does not have exactly 1 question in the question section
// //
// * has more than 1 RR in the Answer section // * has more than 1 RR in the Answer section

View File

@ -5,7 +5,6 @@ import (
"net" "net"
"strconv" "strconv"
"strings" "strings"
"unicode"
) )
const hexDigit = "0123456789abcdef" const hexDigit = "0123456789abcdef"
@ -23,8 +22,7 @@ func (dns *Msg) SetReply(request *Msg) *Msg {
} }
dns.Rcode = RcodeSuccess dns.Rcode = RcodeSuccess
if len(request.Question) > 0 { if len(request.Question) > 0 {
dns.Question = make([]Question, 1) dns.Question = []Question{request.Question[0]}
dns.Question[0] = request.Question[0]
} }
return dns return dns
} }
@ -293,24 +291,17 @@ func IsFqdn(s string) bool {
return (len(s)-i)%2 != 0 return (len(s)-i)%2 != 0
} }
// IsRRset checks if a set of RRs is a valid RRset as defined by RFC 2181. // IsRRset reports whether a set of RRs is a valid RRset as defined by RFC 2181.
// This means the RRs need to have the same type, name, and class. Returns true // This means the RRs need to have the same type, name, and class.
// if the RR set is valid, otherwise false.
func IsRRset(rrset []RR) bool { func IsRRset(rrset []RR) bool {
if len(rrset) == 0 { if len(rrset) == 0 {
return false return false
} }
if len(rrset) == 1 {
return true
}
rrHeader := rrset[0].Header()
rrType := rrHeader.Rrtype
rrClass := rrHeader.Class
rrName := rrHeader.Name
baseH := rrset[0].Header()
for _, rr := range rrset[1:] { for _, rr := range rrset[1:] {
curRRHeader := rr.Header() curH := rr.Header()
if curRRHeader.Rrtype != rrType || curRRHeader.Class != rrClass || curRRHeader.Name != rrName { if curH.Rrtype != baseH.Rrtype || curH.Class != baseH.Class || curH.Name != baseH.Name {
// Mismatch between the records, so this is not a valid rrset for // Mismatch between the records, so this is not a valid rrset for
// signing/verifying // signing/verifying
return false return false
@ -330,19 +321,15 @@ func Fqdn(s string) string {
} }
// CanonicalName returns the domain name in canonical form. A name in canonical // CanonicalName returns the domain name in canonical form. A name in canonical
// form is lowercase and fully qualified. See Section 6.2 in RFC 4034. // form is lowercase and fully qualified. Only US-ASCII letters are affected. See
// According to the RFC all uppercase US-ASCII letters in the owner name of the // Section 6.2 in RFC 4034.
// RR areeplaced by the corresponding lowercase US-ASCII letters.
func CanonicalName(s string) string { func CanonicalName(s string) string {
var result strings.Builder return strings.Map(func(r rune) rune {
for _, ch := range s { if r >= 'A' && r <= 'Z' {
if unicode.IsUpper(ch) && (ch >= 0x00 && ch <= 0x7F) { r += 'a' - 'A'
result.WriteRune(unicode.ToLower(ch))
} else {
result.WriteRune(ch)
} }
} return r
return Fqdn(result.String()) }, Fqdn(s))
} }
// Copied from the official Go code. // Copied from the official Go code.

View File

@ -37,7 +37,8 @@ func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (crypto.PrivateKey, er
return nil, ErrPrivKey return nil, ErrPrivKey
} }
// TODO(mg): check if the pubkey matches the private key // TODO(mg): check if the pubkey matches the private key
algo, err := strconv.ParseUint(strings.SplitN(m["algorithm"], " ", 2)[0], 10, 8) algoStr, _, _ := strings.Cut(m["algorithm"], " ")
algo, err := strconv.ParseUint(algoStr, 10, 8)
if err != nil { if err != nil {
return nil, ErrPrivKey return nil, ErrPrivKey
} }

View File

@ -185,7 +185,7 @@ func (rr *OPT) Do() bool {
// SetDo sets the DO (DNSSEC OK) bit. // SetDo sets the DO (DNSSEC OK) bit.
// If we pass an argument, set the DO bit to that value. // If we pass an argument, set the DO bit to that value.
// It is possible to pass 2 or more arguments. Any arguments after the 1st is silently ignored. // It is possible to pass 2 or more arguments, but they will be ignored.
func (rr *OPT) SetDo(do ...bool) { func (rr *OPT) SetDo(do ...bool) {
if len(do) == 1 { if len(do) == 1 {
if do[0] { if do[0] {
@ -508,6 +508,7 @@ func (e *EDNS0_LLQ) String() string {
" " + strconv.FormatUint(uint64(e.LeaseLife), 10) " " + strconv.FormatUint(uint64(e.LeaseLife), 10)
return s return s
} }
func (e *EDNS0_LLQ) copy() EDNS0 { func (e *EDNS0_LLQ) copy() EDNS0 {
return &EDNS0_LLQ{e.Code, e.Version, e.Opcode, e.Error, e.Id, e.LeaseLife} return &EDNS0_LLQ{e.Code, e.Version, e.Opcode, e.Error, e.Id, e.LeaseLife}
} }

View File

@ -35,17 +35,17 @@ func (zp *ZoneParser) generate(l lex) (RR, bool) {
token = token[:i] token = token[:i]
} }
sx := strings.SplitN(token, "-", 2) startStr, endStr, ok := strings.Cut(token, "-")
if len(sx) != 2 { if !ok {
return zp.setParseError("bad start-stop in $GENERATE range", l) return zp.setParseError("bad start-stop in $GENERATE range", l)
} }
start, err := strconv.ParseInt(sx[0], 10, 64) start, err := strconv.ParseInt(startStr, 10, 64)
if err != nil { if err != nil {
return zp.setParseError("bad start in $GENERATE range", l) return zp.setParseError("bad start in $GENERATE range", l)
} }
end, err := strconv.ParseInt(sx[1], 10, 64) end, err := strconv.ParseInt(endStr, 10, 64)
if err != nil { if err != nil {
return zp.setParseError("bad stop in $GENERATE range", l) return zp.setParseError("bad stop in $GENERATE range", l)
} }
@ -54,7 +54,7 @@ func (zp *ZoneParser) generate(l lex) (RR, bool) {
} }
// _BLANK // _BLANK
l, ok := zp.c.Next() l, ok = zp.c.Next()
if !ok || l.value != zBlank { if !ok || l.value != zBlank {
return zp.setParseError("garbage after $GENERATE range", l) return zp.setParseError("garbage after $GENERATE range", l)
} }
@ -211,15 +211,16 @@ func (r *generateReader) ReadByte() (byte, error) {
func modToPrintf(s string) (string, int64, string) { func modToPrintf(s string) (string, int64, string) {
// Modifier is { offset [ ,width [ ,base ] ] } - provide default // Modifier is { offset [ ,width [ ,base ] ] } - provide default
// values for optional width and type, if necessary. // values for optional width and type, if necessary.
var offStr, widthStr, base string offStr, s, ok0 := strings.Cut(s, ",")
switch xs := strings.Split(s, ","); len(xs) { widthStr, s, ok1 := strings.Cut(s, ",")
case 1: base, _, ok2 := strings.Cut(s, ",")
offStr, widthStr, base = xs[0], "0", "d" if !ok0 {
case 2: widthStr = "0"
offStr, widthStr, base = xs[0], xs[1], "d" }
case 3: if !ok1 {
offStr, widthStr, base = xs[0], xs[1], xs[2] base = "d"
default: }
if ok2 {
return "", 0, "bad modifier in $GENERATE" return "", 0, "bad modifier in $GENERATE"
} }
@ -234,8 +235,8 @@ func modToPrintf(s string) (string, int64, string) {
return "", 0, "bad offset in $GENERATE" return "", 0, "bad offset in $GENERATE"
} }
width, err := strconv.ParseInt(widthStr, 10, 64) width, err := strconv.ParseUint(widthStr, 10, 8)
if err != nil || width < 0 || width > 255 { if err != nil {
return "", 0, "bad width in $GENERATE" return "", 0, "bad width in $GENERATE"
} }

View File

@ -7,16 +7,18 @@ import "net"
const supportsReusePort = false const supportsReusePort = false
func listenTCP(network, addr string, reuseport bool) (net.Listener, error) { func listenTCP(network, addr string, reuseport, reuseaddr bool) (net.Listener, error) {
if reuseport { if reuseport || reuseaddr {
// TODO(tmthrgd): return an error? // TODO(tmthrgd): return an error?
} }
return net.Listen(network, addr) return net.Listen(network, addr)
} }
func listenUDP(network, addr string, reuseport bool) (net.PacketConn, error) { const supportsReuseAddr = false
if reuseport {
func listenUDP(network, addr string, reuseport, reuseaddr bool) (net.PacketConn, error) {
if reuseport || reuseaddr {
// TODO(tmthrgd): return an error? // TODO(tmthrgd): return an error?
} }

View File

@ -25,19 +25,41 @@ func reuseportControl(network, address string, c syscall.RawConn) error {
return opErr return opErr
} }
func listenTCP(network, addr string, reuseport bool) (net.Listener, error) { const supportsReuseAddr = true
func reuseaddrControl(network, address string, c syscall.RawConn) error {
var opErr error
err := c.Control(func(fd uintptr) {
opErr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1)
})
if err != nil {
return err
}
return opErr
}
func listenTCP(network, addr string, reuseport, reuseaddr bool) (net.Listener, error) {
var lc net.ListenConfig var lc net.ListenConfig
if reuseport { switch {
case reuseaddr && reuseport:
case reuseport:
lc.Control = reuseportControl lc.Control = reuseportControl
case reuseaddr:
lc.Control = reuseaddrControl
} }
return lc.Listen(context.Background(), network, addr) return lc.Listen(context.Background(), network, addr)
} }
func listenUDP(network, addr string, reuseport bool) (net.PacketConn, error) { func listenUDP(network, addr string, reuseport, reuseaddr bool) (net.PacketConn, error) {
var lc net.ListenConfig var lc net.ListenConfig
if reuseport { switch {
case reuseaddr && reuseport:
case reuseport:
lc.Control = reuseportControl lc.Control = reuseportControl
case reuseaddr:
lc.Control = reuseaddrControl
} }
return lc.ListenPacket(context.Background(), network, addr) return lc.ListenPacket(context.Background(), network, addr)

20
vendor/github.com/miekg/dns/msg.go generated vendored
View File

@ -501,30 +501,28 @@ func packTxtString(s string, msg []byte, offset int) (int, error) {
return offset, nil return offset, nil
} }
func packOctetString(s string, msg []byte, offset int, tmp []byte) (int, error) { func packOctetString(s string, msg []byte, offset int) (int, error) {
if offset >= len(msg) || len(s) > len(tmp) { if offset >= len(msg) || len(s) > 256*4+1 {
return offset, ErrBuf return offset, ErrBuf
} }
bs := tmp[:len(s)] for i := 0; i < len(s); i++ {
copy(bs, s)
for i := 0; i < len(bs); i++ {
if len(msg) <= offset { if len(msg) <= offset {
return offset, ErrBuf return offset, ErrBuf
} }
if bs[i] == '\\' { if s[i] == '\\' {
i++ i++
if i == len(bs) { if i == len(s) {
break break
} }
// check for \DDD // check for \DDD
if isDDD(bs[i:]) { if isDDD(s[i:]) {
msg[offset] = dddToByte(bs[i:]) msg[offset] = dddToByte(s[i:])
i += 2 i += 2
} else { } else {
msg[offset] = bs[i] msg[offset] = s[i]
} }
} else { } else {
msg[offset] = bs[i] msg[offset] = s[i]
} }
offset++ offset++
} }

View File

@ -20,9 +20,7 @@ func unpackDataA(msg []byte, off int) (net.IP, int, error) {
if off+net.IPv4len > len(msg) { if off+net.IPv4len > len(msg) {
return nil, len(msg), &Error{err: "overflow unpacking a"} return nil, len(msg), &Error{err: "overflow unpacking a"}
} }
a := append(make(net.IP, 0, net.IPv4len), msg[off:off+net.IPv4len]...) return cloneSlice(msg[off : off+net.IPv4len]), off + net.IPv4len, nil
off += net.IPv4len
return a, off, nil
} }
func packDataA(a net.IP, msg []byte, off int) (int, error) { func packDataA(a net.IP, msg []byte, off int) (int, error) {
@ -47,9 +45,7 @@ func unpackDataAAAA(msg []byte, off int) (net.IP, int, error) {
if off+net.IPv6len > len(msg) { if off+net.IPv6len > len(msg) {
return nil, len(msg), &Error{err: "overflow unpacking aaaa"} return nil, len(msg), &Error{err: "overflow unpacking aaaa"}
} }
aaaa := append(make(net.IP, 0, net.IPv6len), msg[off:off+net.IPv6len]...) return cloneSlice(msg[off : off+net.IPv6len]), off + net.IPv6len, nil
off += net.IPv6len
return aaaa, off, nil
} }
func packDataAAAA(aaaa net.IP, msg []byte, off int) (int, error) { func packDataAAAA(aaaa net.IP, msg []byte, off int) (int, error) {
@ -410,29 +406,24 @@ func packStringTxt(s []string, msg []byte, off int) (int, error) {
func unpackDataOpt(msg []byte, off int) ([]EDNS0, int, error) { func unpackDataOpt(msg []byte, off int) ([]EDNS0, int, error) {
var edns []EDNS0 var edns []EDNS0
Option: for off < len(msg) {
var code uint16
if off+4 > len(msg) { if off+4 > len(msg) {
return nil, len(msg), &Error{err: "overflow unpacking opt"} return nil, len(msg), &Error{err: "overflow unpacking opt"}
} }
code = binary.BigEndian.Uint16(msg[off:]) code := binary.BigEndian.Uint16(msg[off:])
off += 2 off += 2
optlen := binary.BigEndian.Uint16(msg[off:]) optlen := binary.BigEndian.Uint16(msg[off:])
off += 2 off += 2
if off+int(optlen) > len(msg) { if off+int(optlen) > len(msg) {
return nil, len(msg), &Error{err: "overflow unpacking opt"} return nil, len(msg), &Error{err: "overflow unpacking opt"}
} }
e := makeDataOpt(code) opt := makeDataOpt(code)
if err := e.unpack(msg[off : off+int(optlen)]); err != nil { if err := opt.unpack(msg[off : off+int(optlen)]); err != nil {
return nil, len(msg), err return nil, len(msg), err
} }
edns = append(edns, e) edns = append(edns, opt)
off += int(optlen) off += int(optlen)
if off < len(msg) {
goto Option
} }
return edns, off, nil return edns, off, nil
} }
@ -461,8 +452,7 @@ func unpackStringOctet(msg []byte, off int) (string, int, error) {
} }
func packStringOctet(s string, msg []byte, off int) (int, error) { func packStringOctet(s string, msg []byte, off int) (int, error) {
txtTmp := make([]byte, 256*4+1) off, err := packOctetString(s, msg, off)
off, err := packOctetString(s, msg, off, txtTmp)
if err != nil { if err != nil {
return len(msg), err return len(msg), err
} }

43
vendor/github.com/miekg/dns/scan.go generated vendored
View File

@ -605,8 +605,6 @@ func (zp *ZoneParser) Next() (RR, bool) {
if !isPrivate && zp.c.Peek().token == "" { if !isPrivate && zp.c.Peek().token == "" {
// This is a dynamic update rr. // This is a dynamic update rr.
// TODO(tmthrgd): Previously slurpRemainder was only called
// for certain RR types, which may have been important.
if err := slurpRemainder(zp.c); err != nil { if err := slurpRemainder(zp.c); err != nil {
return zp.setParseError(err.err, err.lex) return zp.setParseError(err.err, err.lex)
} }
@ -1216,42 +1214,34 @@ func stringToCm(token string) (e, m uint8, ok bool) {
if token[len(token)-1] == 'M' || token[len(token)-1] == 'm' { if token[len(token)-1] == 'M' || token[len(token)-1] == 'm' {
token = token[0 : len(token)-1] token = token[0 : len(token)-1]
} }
s := strings.SplitN(token, ".", 2)
var meters, cmeters, val int var (
var err error meters, cmeters, val int
switch len(s) { err error
case 2: )
if cmeters, err = strconv.Atoi(s[1]); err != nil { mStr, cmStr, hasCM := strings.Cut(token, ".")
return if hasCM {
}
// There's no point in having more than 2 digits in this part, and would rather make the implementation complicated ('123' should be treated as '12'). // There's no point in having more than 2 digits in this part, and would rather make the implementation complicated ('123' should be treated as '12').
// So we simply reject it. // So we simply reject it.
// We also make sure the first character is a digit to reject '+-' signs. // We also make sure the first character is a digit to reject '+-' signs.
if len(s[1]) > 2 || s[1][0] < '0' || s[1][0] > '9' { cmeters, err = strconv.Atoi(cmStr)
if err != nil || len(cmStr) > 2 || cmStr[0] < '0' || cmStr[0] > '9' {
return return
} }
if len(s[1]) == 1 { if len(cmStr) == 1 {
// 'nn.1' must be treated as 'nn-meters and 10cm, not 1cm. // 'nn.1' must be treated as 'nn-meters and 10cm, not 1cm.
cmeters *= 10 cmeters *= 10
} }
if s[0] == "" {
// This will allow omitting the 'meter' part, like .01 (meaning 0.01m = 1cm).
break
}
fallthrough
case 1:
if meters, err = strconv.Atoi(s[0]); err != nil {
return
} }
// This slighly ugly condition will allow omitting the 'meter' part, like .01 (meaning 0.01m = 1cm).
if !hasCM || mStr != "" {
meters, err = strconv.Atoi(mStr)
// RFC1876 states the max value is 90000000.00. The latter two conditions enforce it. // RFC1876 states the max value is 90000000.00. The latter two conditions enforce it.
if s[0][0] < '0' || s[0][0] > '9' || meters > 90000000 || (meters == 90000000 && cmeters != 0) { if err != nil || mStr[0] < '0' || mStr[0] > '9' || meters > 90000000 || (meters == 90000000 && cmeters != 0) {
return return
} }
case 0:
// huh?
return 0, 0, false
} }
ok = true
if meters > 0 { if meters > 0 {
e = 2 e = 2
val = meters val = meters
@ -1263,8 +1253,7 @@ func stringToCm(token string) (e, m uint8, ok bool) {
e++ e++
val /= 10 val /= 10
} }
m = uint8(val) return e, uint8(val), true
return
} }
func toAbsoluteName(name, origin string) (absolute string, ok bool) { func toAbsoluteName(name, origin string) (absolute string, ok bool) {

View File

@ -1,7 +1,6 @@
package dns package dns
import ( import (
"bytes"
"encoding/base64" "encoding/base64"
"errors" "errors"
"net" "net"
@ -12,15 +11,15 @@ import (
// A remainder of the rdata with embedded spaces, return the parsed string (sans the spaces) // A remainder of the rdata with embedded spaces, return the parsed string (sans the spaces)
// or an error // or an error
func endingToString(c *zlexer, errstr string) (string, *ParseError) { func endingToString(c *zlexer, errstr string) (string, *ParseError) {
var buffer bytes.Buffer var s strings.Builder
l, _ := c.Next() // zString l, _ := c.Next() // zString
for l.value != zNewline && l.value != zEOF { for l.value != zNewline && l.value != zEOF {
if l.err { if l.err {
return buffer.String(), &ParseError{"", errstr, l} return s.String(), &ParseError{"", errstr, l}
} }
switch l.value { switch l.value {
case zString: case zString:
buffer.WriteString(l.token) s.WriteString(l.token)
case zBlank: // Ok case zBlank: // Ok
default: default:
return "", &ParseError{"", errstr, l} return "", &ParseError{"", errstr, l}
@ -28,7 +27,7 @@ func endingToString(c *zlexer, errstr string) (string, *ParseError) {
l, _ = c.Next() l, _ = c.Next()
} }
return buffer.String(), nil return s.String(), nil
} }
// A remainder of the rdata with embedded spaces, split on unquoted whitespace // A remainder of the rdata with embedded spaces, split on unquoted whitespace

View File

@ -226,6 +226,10 @@ type Server struct {
// Whether to set the SO_REUSEPORT socket option, allowing multiple listeners to be bound to a single address. // Whether to set the SO_REUSEPORT socket option, allowing multiple listeners to be bound to a single address.
// It is only supported on certain GOOSes and when using ListenAndServe. // It is only supported on certain GOOSes and when using ListenAndServe.
ReusePort bool ReusePort bool
// Whether to set the SO_REUSEADDR socket option, allowing multiple listeners to be bound to a single address.
// Crucially this allows binding when an existing server is listening on `0.0.0.0` or `::`.
// It is only supported on certain GOOSes and when using ListenAndServe.
ReuseAddr bool
// AcceptMsgFunc will check the incoming message and will reject it early in the process. // AcceptMsgFunc will check the incoming message and will reject it early in the process.
// By default DefaultMsgAcceptFunc will be used. // By default DefaultMsgAcceptFunc will be used.
MsgAcceptFunc MsgAcceptFunc MsgAcceptFunc MsgAcceptFunc
@ -304,7 +308,7 @@ func (srv *Server) ListenAndServe() error {
switch srv.Net { switch srv.Net {
case "tcp", "tcp4", "tcp6": case "tcp", "tcp4", "tcp6":
l, err := listenTCP(srv.Net, addr, srv.ReusePort) l, err := listenTCP(srv.Net, addr, srv.ReusePort, srv.ReuseAddr)
if err != nil { if err != nil {
return err return err
} }
@ -317,7 +321,7 @@ func (srv *Server) ListenAndServe() error {
return errors.New("dns: neither Certificates nor GetCertificate set in Config") return errors.New("dns: neither Certificates nor GetCertificate set in Config")
} }
network := strings.TrimSuffix(srv.Net, "-tls") network := strings.TrimSuffix(srv.Net, "-tls")
l, err := listenTCP(network, addr, srv.ReusePort) l, err := listenTCP(network, addr, srv.ReusePort, srv.ReuseAddr)
if err != nil { if err != nil {
return err return err
} }
@ -327,7 +331,7 @@ func (srv *Server) ListenAndServe() error {
unlock() unlock()
return srv.serveTCP(l) return srv.serveTCP(l)
case "udp", "udp4", "udp6": case "udp", "udp4", "udp6":
l, err := listenUDP(srv.Net, addr, srv.ReusePort) l, err := listenUDP(srv.Net, addr, srv.ReusePort, srv.ReuseAddr)
if err != nil { if err != nil {
return err return err
} }

39
vendor/github.com/miekg/dns/svcb.go generated vendored
View File

@ -314,10 +314,11 @@ func (s *SVCBMandatory) unpack(b []byte) error {
} }
func (s *SVCBMandatory) parse(b string) error { func (s *SVCBMandatory) parse(b string) error {
str := strings.Split(b, ",") codes := make([]SVCBKey, 0, strings.Count(b, ",")+1)
codes := make([]SVCBKey, 0, len(str)) for len(b) > 0 {
for _, e := range str { var key string
codes = append(codes, svcbStringToKey(e)) key, b, _ = strings.Cut(b, ",")
codes = append(codes, svcbStringToKey(key))
} }
s.Code = codes s.Code = codes
return nil return nil
@ -613,19 +614,24 @@ func (s *SVCBIPv4Hint) String() string {
} }
func (s *SVCBIPv4Hint) parse(b string) error { func (s *SVCBIPv4Hint) parse(b string) error {
if b == "" {
return errors.New("dns: svcbipv4hint: empty hint")
}
if strings.Contains(b, ":") { if strings.Contains(b, ":") {
return errors.New("dns: svcbipv4hint: expected ipv4, got ipv6") return errors.New("dns: svcbipv4hint: expected ipv4, got ipv6")
} }
str := strings.Split(b, ",")
dst := make([]net.IP, len(str)) hint := make([]net.IP, 0, strings.Count(b, ",")+1)
for i, e := range str { for len(b) > 0 {
var e string
e, b, _ = strings.Cut(b, ",")
ip := net.ParseIP(e).To4() ip := net.ParseIP(e).To4()
if ip == nil { if ip == nil {
return errors.New("dns: svcbipv4hint: bad ip") return errors.New("dns: svcbipv4hint: bad ip")
} }
dst[i] = ip hint = append(hint, ip)
} }
s.Hint = dst s.Hint = hint
return nil return nil
} }
@ -733,9 +739,14 @@ func (s *SVCBIPv6Hint) String() string {
} }
func (s *SVCBIPv6Hint) parse(b string) error { func (s *SVCBIPv6Hint) parse(b string) error {
str := strings.Split(b, ",") if b == "" {
dst := make([]net.IP, len(str)) return errors.New("dns: svcbipv6hint: empty hint")
for i, e := range str { }
hint := make([]net.IP, 0, strings.Count(b, ",")+1)
for len(b) > 0 {
var e string
e, b, _ = strings.Cut(b, ",")
ip := net.ParseIP(e) ip := net.ParseIP(e)
if ip == nil { if ip == nil {
return errors.New("dns: svcbipv6hint: bad ip") return errors.New("dns: svcbipv6hint: bad ip")
@ -743,9 +754,9 @@ func (s *SVCBIPv6Hint) parse(b string) error {
if ip.To4() != nil { if ip.To4() != nil {
return errors.New("dns: svcbipv6hint: expected ipv6, got ipv4-mapped-ipv6") return errors.New("dns: svcbipv6hint: expected ipv6, got ipv4-mapped-ipv6")
} }
dst[i] = ip hint = append(hint, ip)
} }
s.Hint = dst s.Hint = hint
return nil return nil
} }

View File

@ -3,7 +3,7 @@ package dns
import "fmt" import "fmt"
// Version is current version of this library. // Version is current version of this library.
var Version = v{1, 1, 56} var Version = v{1, 1, 57}
// v holds the version of this library. // v holds the version of this library.
type v struct { type v struct {

18
vendor/github.com/miekg/dns/xfr.go generated vendored
View File

@ -80,8 +80,13 @@ func (t *Transfer) In(q *Msg, a string) (env chan *Envelope, err error) {
func (t *Transfer) inAxfr(q *Msg, c chan *Envelope) { func (t *Transfer) inAxfr(q *Msg, c chan *Envelope) {
first := true first := true
defer t.Close() defer func() {
defer close(c) // First close the connection, then the channel. This allows functions blocked on
// the channel to assume that the connection is closed and no further operations are
// pending when they resume.
t.Close()
close(c)
}()
timeout := dnsTimeout timeout := dnsTimeout
if t.ReadTimeout != 0 { if t.ReadTimeout != 0 {
timeout = t.ReadTimeout timeout = t.ReadTimeout
@ -131,8 +136,13 @@ func (t *Transfer) inIxfr(q *Msg, c chan *Envelope) {
axfr := true axfr := true
n := 0 n := 0
qser := q.Ns[0].(*SOA).Serial qser := q.Ns[0].(*SOA).Serial
defer t.Close() defer func() {
defer close(c) // First close the connection, then the channel. This allows functions blocked on
// the channel to assume that the connection is closed and no further operations are
// pending when they resume.
t.Close()
close(c)
}()
timeout := dnsTimeout timeout := dnsTimeout
if t.ReadTimeout != 0 { if t.ReadTimeout != 0 {
timeout = t.ReadTimeout timeout = t.ReadTimeout

View File

@ -739,7 +739,7 @@ type ExtraConfig struct {
// Is called when the client uses a session ticket. // Is called when the client uses a session ticket.
// Restores the application data that was saved earlier on GetAppDataForSessionTicket. // Restores the application data that was saved earlier on GetAppDataForSessionTicket.
SetAppDataFromSessionState func([]byte) SetAppDataFromSessionState func([]byte) (allowEarlyData bool)
} }
// Clone clones. // Clone clones.

View File

@ -418,8 +418,12 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
} }
if c.quic != nil && maxEarlyData > 0 { if c.quic != nil && maxEarlyData > 0 {
var earlyData bool
if session.vers == VersionTLS13 && c.extraConfig != nil && c.extraConfig.SetAppDataFromSessionState != nil {
earlyData = c.extraConfig.SetAppDataFromSessionState(appData)
}
// For 0-RTT, the cipher suite has to match exactly. // For 0-RTT, the cipher suite has to match exactly.
if mutualCipherSuiteTLS13(hello.cipherSuites, session.cipherSuite) != nil { if earlyData && mutualCipherSuiteTLS13(hello.cipherSuites, session.cipherSuite) != nil {
hello.earlyData = true hello.earlyData = true
} }
} }
@ -449,9 +453,6 @@ func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
return "", nil, nil, nil, err return "", nil, nil, nil, err
} }
if session.vers == VersionTLS13 && c.extraConfig != nil && c.extraConfig.SetAppDataFromSessionState != nil {
c.extraConfig.SetAppDataFromSessionState(appData)
}
return return
} }

View File

@ -219,8 +219,15 @@ GroupSelection:
} }
if c.quic != nil { if c.quic != nil {
if hs.clientHello.quicTransportParameters == nil { // RFC 9001 Section 4.2: Clients MUST NOT offer TLS versions older than 1.3.
for _, v := range hs.clientHello.supportedVersions {
if v < VersionTLS13 {
c.sendAlert(alertProtocolVersion)
return errors.New("tls: client offered TLS version older than TLS 1.3")
}
}
// RFC 9001 Section 8.2. // RFC 9001 Section 8.2.
if hs.clientHello.quicTransportParameters == nil {
c.sendAlert(alertMissingExtension) c.sendAlert(alertMissingExtension)
return errors.New("tls: client did not send a quic_transport_parameters extension") return errors.New("tls: client did not send a quic_transport_parameters extension")
} }

View File

@ -12,6 +12,9 @@ In addition to these base RFCs, it also implements the following RFCs:
* Unreliable Datagram Extension ([RFC 9221](https://datatracker.ietf.org/doc/html/rfc9221)) * Unreliable Datagram Extension ([RFC 9221](https://datatracker.ietf.org/doc/html/rfc9221))
* Datagram Packetization Layer Path MTU Discovery (DPLPMTUD, [RFC 8899](https://datatracker.ietf.org/doc/html/rfc8899)) * Datagram Packetization Layer Path MTU Discovery (DPLPMTUD, [RFC 8899](https://datatracker.ietf.org/doc/html/rfc8899))
* QUIC Version 2 ([RFC 9369](https://datatracker.ietf.org/doc/html/rfc9369)) * QUIC Version 2 ([RFC 9369](https://datatracker.ietf.org/doc/html/rfc9369))
* QUIC Event Logging using qlog ([draft-ietf-quic-qlog-main-schema](https://datatracker.ietf.org/doc/draft-ietf-quic-qlog-main-schema/) and [draft-ietf-quic-qlog-quic-events](https://datatracker.ietf.org/doc/draft-ietf-quic-qlog-quic-events/))
Support for WebTransport over HTTP/3 ([draft-ietf-webtrans-http3](https://datatracker.ietf.org/doc/draft-ietf-webtrans-http3/)) is implemented in [webtransport-go](https://github.com/quic-go/webtransport-go).
## Using QUIC ## Using QUIC
@ -158,22 +161,46 @@ On the receiver side, this is surfaced as a `quic.ApplicationError`.
Unreliable datagrams are a QUIC extension ([RFC 9221](https://datatracker.ietf.org/doc/html/rfc9221)) that is negotiated during the handshake. Support can be enabled by setting the `quic.Config.EnableDatagram` flag. Note that this doesn't guarantee that the peer also supports datagrams. Whether or not the feature negotiation succeeded can be learned from the `quic.ConnectionState.SupportsDatagrams` obtained from `quic.Connection.ConnectionState()`. Unreliable datagrams are a QUIC extension ([RFC 9221](https://datatracker.ietf.org/doc/html/rfc9221)) that is negotiated during the handshake. Support can be enabled by setting the `quic.Config.EnableDatagram` flag. Note that this doesn't guarantee that the peer also supports datagrams. Whether or not the feature negotiation succeeded can be learned from the `quic.ConnectionState.SupportsDatagrams` obtained from `quic.Connection.ConnectionState()`.
QUIC DATAGRAMs are a new QUIC frame type sent in QUIC 1-RTT packets (i.e. after completion of the handshake). Therefore, they're end-to-end encrypted and congestion-controlled. However, if a DATAGRAM frame is deemed lost by QUIC's loss detection mechanism, they are not automatically retransmitted. QUIC DATAGRAMs are a new QUIC frame type sent in QUIC 1-RTT packets (i.e. after completion of the handshake). Therefore, they're end-to-end encrypted and congestion-controlled. However, if a DATAGRAM frame is deemed lost by QUIC's loss detection mechanism, they are not retransmitted.
Datagrams are sent using the `SendMessage` method on the `quic.Connection`: Datagrams are sent using the `SendDatagram` method on the `quic.Connection`:
```go ```go
conn.SendMessage([]byte("foobar")) conn.SendDatagram([]byte("foobar"))
``` ```
And received using `ReceiveMessage`: And received using `ReceiveDatagram`:
```go ```go
msg, err := conn.ReceiveMessage() msg, err := conn.ReceiveDatagram()
``` ```
Note that this code path is currently not optimized. It works for datagrams that are sent occasionally, but it doesn't achieve the same throughput as writing data on a stream. Please get in touch on issue #3766 if your use case relies on high datagram throughput, or if you'd like to help fix this issue. There are also some restrictions regarding the maximum message size (see #3599). Note that this code path is currently not optimized. It works for datagrams that are sent occasionally, but it doesn't achieve the same throughput as writing data on a stream. Please get in touch on issue #3766 if your use case relies on high datagram throughput, or if you'd like to help fix this issue. There are also some restrictions regarding the maximum message size (see #3599).
### QUIC Event Logging using qlog
quic-go logs a wide range of events defined in [draft-ietf-quic-qlog-quic-events](https://datatracker.ietf.org/doc/draft-ietf-quic-qlog-quic-events/), providing comprehensive insights in the internals of a QUIC connection.
qlog files can be processed by a number of 3rd-party tools. [qviz](https://qvis.quictools.info/) has proven very useful for debugging all kinds of QUIC connection failures.
qlog is activated by setting a `Tracer` callback on the `Config`. It is called as soon as quic-go decides to starts the QUIC handshake on a new connection.
A useful implementation of this callback could look like this:
```go
quic.Config{
Tracer: func(ctx context.Context, p logging.Perspective, connID quic.ConnectionID) *logging.ConnectionTracer {
role := "server"
if p == logging.PerspectiveClient {
role = "client"
}
filename := fmt.Sprintf("./log_%x_%s.qlog", connID, role)
f, err := os.Create(filename)
// handle the error
return qlog.NewConnectionTracer(f, p, connID)
}
}
```
This implementation of the callback creates a new qlog file in the current directory named `log_<client / server>_<QUIC connection ID>.qlog`.
## Using HTTP/3 ## Using HTTP/3

View File

@ -2343,7 +2343,7 @@ func (s *connection) onStreamCompleted(id protocol.StreamID) {
} }
} }
func (s *connection) SendMessage(p []byte) error { func (s *connection) SendDatagram(p []byte) error {
if !s.supportsDatagrams() { if !s.supportsDatagrams() {
return errors.New("datagram support disabled") return errors.New("datagram support disabled")
} }
@ -2357,7 +2357,7 @@ func (s *connection) SendMessage(p []byte) error {
return s.datagramQueue.AddAndWait(f) return s.datagramQueue.AddAndWait(f)
} }
func (s *connection) ReceiveMessage(ctx context.Context) ([]byte, error) { func (s *connection) ReceiveDatagram(ctx context.Context) ([]byte, error) {
if !s.config.EnableDatagrams { if !s.config.EnableDatagrams {
return nil, errors.New("datagram support disabled") return nil, errors.New("datagram support disabled")
} }

View File

@ -2,7 +2,7 @@
package http3 package http3
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package http3 -destination mock_roundtripcloser_test.go github.com/quic-go/quic-go/http3 RoundTripCloser" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package http3 -destination mock_roundtripcloser_test.go github.com/quic-go/quic-go/http3 RoundTripCloser"
type RoundTripCloser = roundTripCloser type RoundTripCloser = roundTripCloser
//go:generate sh -c "go run go.uber.org/mock/mockgen -package http3 -destination mock_quic_early_listener_test.go github.com/quic-go/quic-go/http3 QUICEarlyListener" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -package http3 -destination mock_quic_early_listener_test.go github.com/quic-go/quic-go/http3 QUICEarlyListener"

View File

@ -67,9 +67,10 @@ type responseWriter struct {
bufferedStr *bufio.Writer bufferedStr *bufio.Writer
buf []byte buf []byte
headerWritten bool
contentLen int64 // if handler set valid Content-Length header contentLen int64 // if handler set valid Content-Length header
numWritten int64 // bytes written numWritten int64 // bytes written
headerWritten bool
isHead bool
} }
var ( var (
@ -162,6 +163,10 @@ func (w *responseWriter) Write(p []byte) (int, error) {
return 0, http.ErrContentLength return 0, http.ErrContentLength
} }
if w.isHead {
return len(p), nil
}
df := &dataFrame{Length: uint64(len(p))} df := &dataFrame{Length: uint64(len(p))}
w.buf = w.buf[:0] w.buf = w.buf[:0]
w.buf = df.Append(w.buf) w.buf = df.Append(w.buf)

View File

@ -599,6 +599,9 @@ func (s *Server) handleRequest(conn quic.Connection, str quic.Stream, decoder *q
ctx = context.WithValue(ctx, http.LocalAddrContextKey, conn.LocalAddr()) ctx = context.WithValue(ctx, http.LocalAddrContextKey, conn.LocalAddr())
req = req.WithContext(ctx) req = req.WithContext(ctx)
r := newResponseWriter(str, conn, s.logger) r := newResponseWriter(str, conn, s.logger)
if req.Method == http.MethodHead {
r.isHead = true
}
handler := s.Handler handler := s.Handler
if handler == nil { if handler == nil {
handler = http.DefaultServeMux handler = http.DefaultServeMux

View File

@ -187,10 +187,10 @@ type Connection interface {
// Warning: This API should not be considered stable and might change soon. // Warning: This API should not be considered stable and might change soon.
ConnectionState() ConnectionState ConnectionState() ConnectionState
// SendMessage sends a message as a datagram, as specified in RFC 9221. // SendDatagram sends a message as a datagram, as specified in RFC 9221.
SendMessage([]byte) error SendDatagram([]byte) error
// ReceiveMessage gets a message received in a datagram, as specified in RFC 9221. // ReceiveDatagram gets a message received in a datagram, as specified in RFC 9221.
ReceiveMessage(context.Context) ([]byte, error) ReceiveDatagram(context.Context) ([]byte, error)
} }
// An EarlyConnection is a connection that is handshaking. // An EarlyConnection is a connection that is handshaking.
@ -338,7 +338,7 @@ type ConnectionState struct {
// SupportsDatagrams says if support for QUIC datagrams (RFC 9221) was negotiated. // SupportsDatagrams says if support for QUIC datagrams (RFC 9221) was negotiated.
// This requires both nodes to support and enable the datagram extensions (via Config.EnableDatagrams). // This requires both nodes to support and enable the datagram extensions (via Config.EnableDatagrams).
// If datagram support was negotiated, datagrams can be sent and received using the // If datagram support was negotiated, datagrams can be sent and received using the
// SendMessage and ReceiveMessage methods on the Connection. // SendDatagram and ReceiveDatagram methods on the Connection.
SupportsDatagrams bool SupportsDatagrams bool
// Used0RTT says if 0-RTT resumption was used. // Used0RTT says if 0-RTT resumption was used.
Used0RTT bool Used0RTT bool

View File

@ -2,7 +2,7 @@
package ackhandler package ackhandler
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package ackhandler -destination mock_sent_packet_tracker_test.go github.com/quic-go/quic-go/internal/ackhandler SentPacketTracker" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package ackhandler -destination mock_sent_packet_tracker_test.go github.com/quic-go/quic-go/internal/ackhandler SentPacketTracker"
type SentPacketTracker = sentPacketTracker type SentPacketTracker = sentPacketTracker
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package ackhandler -destination mock_ecn_handler_test.go github.com/quic-go/quic-go/internal/ackhandler ECNHandler" //go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package ackhandler -destination mock_ecn_handler_test.go github.com/quic-go/quic-go/internal/ackhandler ECNHandler"

View File

@ -96,6 +96,7 @@ func NewCryptoSetupClient(
quicConf := &qtls.QUICConfig{TLSConfig: tlsConf} quicConf := &qtls.QUICConfig{TLSConfig: tlsConf}
qtls.SetupConfigForClient(quicConf, cs.marshalDataForSessionState, cs.handleDataFromSessionState) qtls.SetupConfigForClient(quicConf, cs.marshalDataForSessionState, cs.handleDataFromSessionState)
cs.tlsConf = tlsConf cs.tlsConf = tlsConf
cs.allow0RTT = enable0RTT
cs.conn = qtls.QUICClient(quicConf) cs.conn = qtls.QUICClient(quicConf)
cs.conn.SetTransportParameters(cs.ourParams.Marshal(protocol.PerspectiveClient)) cs.conn.SetTransportParameters(cs.ourParams.Marshal(protocol.PerspectiveClient))
@ -146,6 +147,9 @@ func addConnToClientHelloInfo(conf *tls.Config, localAddr, remoteAddr net.Addr)
info.Conn = &conn{localAddr: localAddr, remoteAddr: remoteAddr} info.Conn = &conn{localAddr: localAddr, remoteAddr: remoteAddr}
c, err := gcfc(info) c, err := gcfc(info)
if c != nil { if c != nil {
c = c.Clone()
// This won't be necessary anymore once https://github.com/golang/go/issues/63722 is accepted.
c.MinVersion = tls.VersionTLS13
// We're returning a tls.Config here, so we need to apply this recursively. // We're returning a tls.Config here, so we need to apply this recursively.
addConnToClientHelloInfo(c, localAddr, remoteAddr) addConnToClientHelloInfo(c, localAddr, remoteAddr)
} }
@ -316,13 +320,20 @@ func (h *cryptoSetup) marshalDataForSessionState() []byte {
return h.peerParams.MarshalForSessionTicket(b) return h.peerParams.MarshalForSessionTicket(b)
} }
func (h *cryptoSetup) handleDataFromSessionState(data []byte) { func (h *cryptoSetup) handleDataFromSessionState(data []byte) (allowEarlyData bool) {
tp, err := h.handleDataFromSessionStateImpl(data) tp, err := h.handleDataFromSessionStateImpl(data)
if err != nil { if err != nil {
h.logger.Debugf("Restoring of transport parameters from session ticket failed: %s", err.Error()) h.logger.Debugf("Restoring of transport parameters from session ticket failed: %s", err.Error())
return return
} }
// The session ticket might have been saved from a connection that allowed 0-RTT,
// and therefore contain transport parameters.
// Only use them if 0-RTT is actually used on the new connection.
if tp != nil && h.allow0RTT {
h.zeroRTTParameters = tp h.zeroRTTParameters = tp
return true
}
return false
} }
func (h *cryptoSetup) handleDataFromSessionStateImpl(data []byte) (*wire.TransportParameters, error) { func (h *cryptoSetup) handleDataFromSessionStateImpl(data []byte) (*wire.TransportParameters, error) {
@ -383,7 +394,9 @@ func (h *cryptoSetup) GetSessionTicket() ([]byte, error) {
} }
// handleSessionTicket is called for the server when receiving the client's session ticket. // handleSessionTicket is called for the server when receiving the client's session ticket.
// It reads parameters from the session ticket and decides whether to accept 0-RTT when the session ticket is used for 0-RTT. // It reads parameters from the session ticket and checks whether to accept 0-RTT if the session ticket enabled 0-RTT.
// Note that the fact that the session ticket allows 0-RTT doesn't mean that the actual TLS handshake enables 0-RTT:
// A client may use a 0-RTT enabled session to resume a TLS session without using 0-RTT.
func (h *cryptoSetup) handleSessionTicket(sessionTicketData []byte, using0RTT bool) bool { func (h *cryptoSetup) handleSessionTicket(sessionTicketData []byte, using0RTT bool) bool {
var t sessionTicket var t sessionTicket
if err := t.Unmarshal(sessionTicketData, using0RTT); err != nil { if err := t.Unmarshal(sessionTicketData, using0RTT); err != nil {

View File

@ -8,7 +8,7 @@ import (
type clientSessionCache struct { type clientSessionCache struct {
getData func() []byte getData func() []byte
setData func([]byte) setData func([]byte) (allowEarlyData bool)
wrapped tls.ClientSessionCache wrapped tls.ClientSessionCache
} }
@ -46,10 +46,12 @@ func (c clientSessionCache) Get(key string) (*tls.ClientSessionState, bool) {
c.wrapped.Put(key, nil) c.wrapped.Put(key, nil)
return nil, false return nil, false
} }
var earlyData bool
// restore QUIC transport parameters and RTT stored in state.Extra // restore QUIC transport parameters and RTT stored in state.Extra
if extra := findExtraData(state.Extra); extra != nil { if extra := findExtraData(state.Extra); extra != nil {
c.setData(extra) earlyData = c.setData(extra)
} }
state.EarlyData = earlyData
session, err := tls.NewResumptionState(ticket, state) session, err := tls.NewResumptionState(ticket, state)
if err != nil { if err != nil {
// It's not clear why this would error. // It's not clear why this would error.

View File

@ -52,7 +52,7 @@ func SetupConfigForServer(conf *QUICConfig, enable0RTT bool, getDataForSessionTi
} }
} }
func SetupConfigForClient(conf *QUICConfig, getDataForSessionState func() []byte, setDataFromSessionState func([]byte)) { func SetupConfigForClient(conf *QUICConfig, getDataForSessionState func() []byte, setDataFromSessionState func([]byte) bool) {
conf.ExtraConfig = &qtls.ExtraConfig{ conf.ExtraConfig = &qtls.ExtraConfig{
GetAppDataForSessionState: getDataForSessionState, GetAppDataForSessionState: getDataForSessionState,
SetAppDataFromSessionState: setDataFromSessionState, SetAppDataFromSessionState: setDataFromSessionState,

View File

@ -93,7 +93,7 @@ func SetupConfigForServer(qconf *QUICConfig, _ bool, getData func() []byte, hand
} }
} }
func SetupConfigForClient(qconf *QUICConfig, getData func() []byte, setData func([]byte)) { func SetupConfigForClient(qconf *QUICConfig, getData func() []byte, setData func([]byte) bool) {
conf := qconf.TLSConfig conf := qconf.TLSConfig
if conf.ClientSessionCache != nil { if conf.ClientSessionCache != nil {
origCache := conf.ClientSessionCache origCache := conf.ClientSessionCache

View File

@ -2,73 +2,75 @@
package quic package quic
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_send_conn_test.go github.com/quic-go/quic-go SendConn" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_send_conn_test.go github.com/quic-go/quic-go SendConn"
type SendConn = sendConn type SendConn = sendConn
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_raw_conn_test.go github.com/quic-go/quic-go RawConn" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_raw_conn_test.go github.com/quic-go/quic-go RawConn"
type RawConn = rawConn type RawConn = rawConn
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_sender_test.go github.com/quic-go/quic-go Sender" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_sender_test.go github.com/quic-go/quic-go Sender"
type Sender = sender type Sender = sender
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_internal_test.go github.com/quic-go/quic-go StreamI" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_internal_test.go github.com/quic-go/quic-go StreamI"
type StreamI = streamI type StreamI = streamI
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_crypto_stream_test.go github.com/quic-go/quic-go CryptoStream" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_crypto_stream_test.go github.com/quic-go/quic-go CryptoStream"
type CryptoStream = cryptoStream type CryptoStream = cryptoStream
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_receive_stream_internal_test.go github.com/quic-go/quic-go ReceiveStreamI" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_receive_stream_internal_test.go github.com/quic-go/quic-go ReceiveStreamI"
type ReceiveStreamI = receiveStreamI type ReceiveStreamI = receiveStreamI
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_send_stream_internal_test.go github.com/quic-go/quic-go SendStreamI" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_send_stream_internal_test.go github.com/quic-go/quic-go SendStreamI"
type SendStreamI = sendStreamI type SendStreamI = sendStreamI
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_getter_test.go github.com/quic-go/quic-go StreamGetter" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_getter_test.go github.com/quic-go/quic-go StreamGetter"
type StreamGetter = streamGetter type StreamGetter = streamGetter
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_sender_test.go github.com/quic-go/quic-go StreamSender" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_sender_test.go github.com/quic-go/quic-go StreamSender"
type StreamSender = streamSender type StreamSender = streamSender
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_crypto_data_handler_test.go github.com/quic-go/quic-go CryptoDataHandler" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_crypto_data_handler_test.go github.com/quic-go/quic-go CryptoDataHandler"
type CryptoDataHandler = cryptoDataHandler type CryptoDataHandler = cryptoDataHandler
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_frame_source_test.go github.com/quic-go/quic-go FrameSource" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_frame_source_test.go github.com/quic-go/quic-go FrameSource"
type FrameSource = frameSource type FrameSource = frameSource
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_ack_frame_source_test.go github.com/quic-go/quic-go AckFrameSource" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_ack_frame_source_test.go github.com/quic-go/quic-go AckFrameSource"
type AckFrameSource = ackFrameSource type AckFrameSource = ackFrameSource
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_manager_test.go github.com/quic-go/quic-go StreamManager" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_stream_manager_test.go github.com/quic-go/quic-go StreamManager"
type StreamManager = streamManager type StreamManager = streamManager
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_sealing_manager_test.go github.com/quic-go/quic-go SealingManager" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_sealing_manager_test.go github.com/quic-go/quic-go SealingManager"
type SealingManager = sealingManager type SealingManager = sealingManager
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_unpacker_test.go github.com/quic-go/quic-go Unpacker" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_unpacker_test.go github.com/quic-go/quic-go Unpacker"
type Unpacker = unpacker type Unpacker = unpacker
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_packer_test.go github.com/quic-go/quic-go Packer" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_packer_test.go github.com/quic-go/quic-go Packer"
type Packer = packer type Packer = packer
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_mtu_discoverer_test.go github.com/quic-go/quic-go MTUDiscoverer" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_mtu_discoverer_test.go github.com/quic-go/quic-go MTUDiscoverer"
type MTUDiscoverer = mtuDiscoverer type MTUDiscoverer = mtuDiscoverer
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_conn_runner_test.go github.com/quic-go/quic-go ConnRunner" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_conn_runner_test.go github.com/quic-go/quic-go ConnRunner"
type ConnRunner = connRunner type ConnRunner = connRunner
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_quic_conn_test.go github.com/quic-go/quic-go QUICConn" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_quic_conn_test.go github.com/quic-go/quic-go QUICConn"
type QUICConn = quicConn type QUICConn = quicConn
//go:generate sh -c "go run go.uber.org/mock/mockgen -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_packet_handler_test.go github.com/quic-go/quic-go PacketHandler" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -build_flags=\"-tags=gomock\" -package quic -self_package github.com/quic-go/quic-go -destination mock_packet_handler_test.go github.com/quic-go/quic-go PacketHandler"
type PacketHandler = packetHandler type PacketHandler = packetHandler
//go:generate sh -c "go run go.uber.org/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" //go:generate sh -c "go run go.uber.org/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"
//go:generate sh -c "go run go.uber.org/mock/mockgen -typed -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 type PacketHandlerManager = packetHandlerManager
// Need to use source mode for the batchConn, since reflect mode follows type aliases. // Need to use source mode for the batchConn, since reflect mode follows type aliases.
// See https://github.com/golang/mock/issues/244 for details. // See https://github.com/golang/mock/issues/244 for details.
// //
//go:generate sh -c "go run go.uber.org/mock/mockgen -package quic -self_package github.com/quic-go/quic-go -source sys_conn_oob.go -destination mock_batch_conn_test.go -mock_names batchConn=MockBatchConn" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -package quic -self_package github.com/quic-go/quic-go -source sys_conn_oob.go -destination mock_batch_conn_test.go -mock_names batchConn=MockBatchConn"
//go:generate sh -c "go run go.uber.org/mock/mockgen -package quic -self_package github.com/quic-go/quic-go -self_package github.com/quic-go/quic-go -destination mock_token_store_test.go github.com/quic-go/quic-go TokenStore" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -package quic -self_package github.com/quic-go/quic-go -self_package github.com/quic-go/quic-go -destination mock_token_store_test.go github.com/quic-go/quic-go TokenStore"
//go:generate sh -c "go run go.uber.org/mock/mockgen -package quic -self_package github.com/quic-go/quic-go -self_package github.com/quic-go/quic-go -destination mock_packetconn_test.go net PacketConn" //go:generate sh -c "go run go.uber.org/mock/mockgen -typed -package quic -self_package github.com/quic-go/quic-go -self_package github.com/quic-go/quic-go -destination mock_packetconn_test.go net PacketConn"

View File

@ -220,23 +220,6 @@ func (h *packetHandlerMap) GetByResetToken(token protocol.StatelessResetToken) (
return handler, ok return handler, ok
} }
func (h *packetHandlerMap) CloseServer() {
h.mutex.Lock()
var wg sync.WaitGroup
for _, handler := range h.handlers {
if handler.getPerspective() == protocol.PerspectiveServer {
wg.Add(1)
go func(handler packetHandler) {
// blocks until the CONNECTION_CLOSE has been sent and the run-loop has stopped
handler.shutdown()
wg.Done()
}(handler)
}
}
h.mutex.Unlock()
wg.Wait()
}
func (h *packetHandlerMap) Close(e error) { func (h *packetHandlerMap) Close(e error) {
h.mutex.Lock() h.mutex.Lock()

View File

@ -28,6 +28,9 @@ type sconn struct {
packetInfoOOB []byte packetInfoOOB []byte
// If GSO enabled, and we receive a GSO error for this remote address, GSO is disabled. // If GSO enabled, and we receive a GSO error for this remote address, GSO is disabled.
gotGSOError bool gotGSOError bool
// Used to catch the error sometimes returned by the first sendmsg call on Linux,
// see https://github.com/golang/go/issues/63322.
wroteFirstPacket bool
} }
var _ sendConn = &sconn{} var _ sendConn = &sconn{}
@ -56,7 +59,7 @@ func newSendConn(c rawConn, remote net.Addr, info packetInfo, logger utils.Logge
} }
func (c *sconn) Write(p []byte, gsoSize uint16, ecn protocol.ECN) error { func (c *sconn) Write(p []byte, gsoSize uint16, ecn protocol.ECN) error {
_, err := c.WritePacket(p, c.remoteAddr, c.packetInfoOOB, gsoSize, ecn) err := c.writePacket(p, c.remoteAddr, c.packetInfoOOB, gsoSize, ecn)
if err != nil && isGSOError(err) { if err != nil && isGSOError(err) {
// disable GSO for future calls // disable GSO for future calls
c.gotGSOError = true c.gotGSOError = true
@ -69,7 +72,7 @@ func (c *sconn) Write(p []byte, gsoSize uint16, ecn protocol.ECN) error {
if l > int(gsoSize) { if l > int(gsoSize) {
l = int(gsoSize) l = int(gsoSize)
} }
if _, err := c.WritePacket(p[:l], c.remoteAddr, c.packetInfoOOB, 0, ecn); err != nil { if err := c.writePacket(p[:l], c.remoteAddr, c.packetInfoOOB, 0, ecn); err != nil {
return err return err
} }
p = p[l:] p = p[l:]
@ -79,6 +82,15 @@ func (c *sconn) Write(p []byte, gsoSize uint16, ecn protocol.ECN) error {
return err return err
} }
func (c *sconn) writePacket(p []byte, addr net.Addr, oob []byte, gsoSize uint16, ecn protocol.ECN) error {
_, err := c.WritePacket(p, addr, oob, gsoSize, ecn)
if err != nil && !c.wroteFirstPacket && isPermissionError(err) {
_, err = c.WritePacket(p, addr, oob, gsoSize, ecn)
}
c.wroteFirstPacket = true
return err
}
func (c *sconn) capabilities() connCapabilities { func (c *sconn) capabilities() connCapabilities {
capabilities := c.rawConn.capabilities() capabilities := c.rawConn.capabilities()
if capabilities.GSO { if capabilities.GSO {

View File

@ -34,7 +34,6 @@ type packetHandlerManager interface {
GetByResetToken(protocol.StatelessResetToken) (packetHandler, bool) GetByResetToken(protocol.StatelessResetToken) (packetHandler, bool)
AddWithConnID(protocol.ConnectionID, protocol.ConnectionID, func() (packetHandler, bool)) bool AddWithConnID(protocol.ConnectionID, protocol.ConnectionID, func() (packetHandler, bool)) bool
Close(error) Close(error)
CloseServer()
connRunner connRunner
} }
@ -54,10 +53,13 @@ type zeroRTTQueue struct {
expiration time.Time expiration time.Time
} }
type rejectedPacket struct {
receivedPacket
hdr *wire.Header
}
// A Listener of QUIC // A Listener of QUIC
type baseServer struct { type baseServer struct {
mutex sync.Mutex
disableVersionNegotiation bool disableVersionNegotiation bool
acceptEarlyConns bool acceptEarlyConns bool
@ -99,12 +101,15 @@ type baseServer struct {
protocol.VersionNumber, protocol.VersionNumber,
) quicConn ) quicConn
serverError error closeOnce sync.Once
errorChan chan struct{} errorChan chan struct{} // is closed when the server is closed
closed bool closeErr error
running chan struct{} // closed as soon as run() returns running chan struct{} // closed as soon as run() returns
versionNegotiationQueue chan receivedPacket versionNegotiationQueue chan receivedPacket
invalidTokenQueue chan receivedPacket invalidTokenQueue chan rejectedPacket
connectionRefusedQueue chan rejectedPacket
retryQueue chan rejectedPacket
connQueue chan quicConn connQueue chan quicConn
connQueueLen int32 // to be used as an atomic connQueueLen int32 // to be used as an atomic
@ -125,7 +130,12 @@ func (l *Listener) Accept(ctx context.Context) (Connection, error) {
return l.baseServer.Accept(ctx) return l.baseServer.Accept(ctx)
} }
// Close the server. All active connections will be closed. // Close closes the listener.
// Accept will return ErrServerClosed as soon as all connections in the accept queue have been accepted.
// QUIC handshakes that are still in flight will be rejected with a CONNECTION_REFUSED error.
// The effect of closing the listener depends on how it was created:
// * if it was created using Transport.Listen, already established connections will be unaffected
// * if it was created using the Listen convenience method, all established connection will be closed immediately
func (l *Listener) Close() error { func (l *Listener) Close() error {
return l.baseServer.Close() return l.baseServer.Close()
} }
@ -208,6 +218,7 @@ func listenUDP(addr string) (*net.UDPConn, error) {
// This is a convenience function. More advanced use cases should instantiate a Transport, // This is a convenience function. More advanced use cases should instantiate a Transport,
// which offers configuration options for a more fine-grained control of the connection establishment, // which offers configuration options for a more fine-grained control of the connection establishment,
// including reusing the underlying UDP socket for outgoing QUIC connections. // including reusing the underlying UDP socket for outgoing QUIC connections.
// When closing a listener created with Listen, all established QUIC connections will be closed immediately.
func Listen(conn net.PacketConn, tlsConf *tls.Config, config *Config) (*Listener, error) { func Listen(conn net.PacketConn, tlsConf *tls.Config, config *Config) (*Listener, error) {
tr := &Transport{Conn: conn, isSingleUse: true} tr := &Transport{Conn: conn, isSingleUse: true}
return tr.Listen(tlsConf, config) return tr.Listen(tlsConf, config)
@ -245,7 +256,9 @@ func newServer(
running: make(chan struct{}), running: make(chan struct{}),
receivedPackets: make(chan receivedPacket, protocol.MaxServerUnprocessedPackets), receivedPackets: make(chan receivedPacket, protocol.MaxServerUnprocessedPackets),
versionNegotiationQueue: make(chan receivedPacket, 4), versionNegotiationQueue: make(chan receivedPacket, 4),
invalidTokenQueue: make(chan receivedPacket, 4), invalidTokenQueue: make(chan rejectedPacket, 4),
connectionRefusedQueue: make(chan rejectedPacket, 4),
retryQueue: make(chan rejectedPacket, 8),
newConn: newConnection, newConn: newConnection,
tracer: tracer, tracer: tracer,
logger: utils.DefaultLogger.WithPrefix("server"), logger: utils.DefaultLogger.WithPrefix("server"),
@ -290,6 +303,10 @@ func (s *baseServer) runSendQueue() {
s.maybeSendVersionNegotiationPacket(p) s.maybeSendVersionNegotiationPacket(p)
case p := <-s.invalidTokenQueue: case p := <-s.invalidTokenQueue:
s.maybeSendInvalidToken(p) s.maybeSendInvalidToken(p)
case p := <-s.connectionRefusedQueue:
s.sendConnectionRefused(p)
case p := <-s.retryQueue:
s.sendRetry(p)
} }
} }
} }
@ -308,38 +325,25 @@ func (s *baseServer) accept(ctx context.Context) (quicConn, error) {
atomic.AddInt32(&s.connQueueLen, -1) atomic.AddInt32(&s.connQueueLen, -1)
return conn, nil return conn, nil
case <-s.errorChan: case <-s.errorChan:
return nil, s.serverError return nil, s.closeErr
} }
} }
// Close the server
func (s *baseServer) Close() error { func (s *baseServer) Close() error {
s.mutex.Lock() s.close(ErrServerClosed, true)
if s.closed {
s.mutex.Unlock()
return nil return nil
} }
if s.serverError == nil {
s.serverError = ErrServerClosed func (s *baseServer) close(e error, notifyOnClose bool) {
} s.closeOnce.Do(func() {
s.closed = true s.closeErr = e
close(s.errorChan) close(s.errorChan)
s.mutex.Unlock()
<-s.running <-s.running
if notifyOnClose {
s.onClose() s.onClose()
return nil
} }
})
func (s *baseServer) setCloseError(e error) {
s.mutex.Lock()
defer s.mutex.Unlock()
if s.closed {
return
}
s.closed = true
s.serverError = e
close(s.errorChan)
} }
// Addr returns the server's network address // Addr returns the server's network address
@ -580,30 +584,35 @@ func (s *baseServer) handleInitialImpl(p receivedPacket, hdr *wire.Header) error
// For Retry tokens, we send an INVALID_ERROR if // For Retry tokens, we send an INVALID_ERROR if
// * the token is too old, or // * the token is too old, or
// * the token is invalid, in case of a retry token. // * the token is invalid, in case of a retry token.
s.enqueueInvalidToken(p) select {
case s.invalidTokenQueue <- rejectedPacket{receivedPacket: p, hdr: hdr}:
default:
// drop packet if we can't send out the INVALID_TOKEN packets fast enough
p.buffer.Release()
}
return nil return nil
} }
} }
if token == nil && s.config.RequireAddressValidation(p.remoteAddr) { if token == nil && s.config.RequireAddressValidation(p.remoteAddr) {
// Retry invalidates all 0-RTT packets sent. // Retry invalidates all 0-RTT packets sent.
delete(s.zeroRTTQueues, hdr.DestConnectionID) delete(s.zeroRTTQueues, hdr.DestConnectionID)
go func() { select {
defer p.buffer.Release() case s.retryQueue <- rejectedPacket{receivedPacket: p, hdr: hdr}:
if err := s.sendRetry(p.remoteAddr, hdr, p.info); err != nil { default:
s.logger.Debugf("Error sending Retry: %s", err) // drop packet if we can't send out Retry packets fast enough
p.buffer.Release()
} }
}()
return nil return nil
} }
if queueLen := atomic.LoadInt32(&s.connQueueLen); queueLen >= protocol.MaxAcceptQueueSize { if queueLen := atomic.LoadInt32(&s.connQueueLen); queueLen >= protocol.MaxAcceptQueueSize {
s.logger.Debugf("Rejecting new connection. Server currently busy. Accept queue length: %d (max %d)", queueLen, protocol.MaxAcceptQueueSize) s.logger.Debugf("Rejecting new connection. Server currently busy. Accept queue length: %d (max %d)", queueLen, protocol.MaxAcceptQueueSize)
go func() { select {
defer p.buffer.Release() case s.connectionRefusedQueue <- rejectedPacket{receivedPacket: p, hdr: hdr}:
if err := s.sendConnectionRefused(p.remoteAddr, hdr, p.info); err != nil { default:
s.logger.Debugf("Error rejecting connection: %s", err) // drop packet if we can't send out the CONNECTION_REFUSED fast enough
p.buffer.Release()
} }
}()
return nil return nil
} }
@ -663,12 +672,12 @@ func (s *baseServer) handleInitialImpl(p receivedPacket, hdr *wire.Header) error
return conn, true return conn, true
}); !added { }); !added {
go func() { select {
defer p.buffer.Release() case s.connectionRefusedQueue <- rejectedPacket{receivedPacket: p, hdr: hdr}:
if err := s.sendConnectionRefused(p.remoteAddr, hdr, p.info); err != nil { default:
s.logger.Debugf("Error rejecting connection: %s", err) // drop packet if we can't send out the CONNECTION_REFUSED fast enough
p.buffer.Release()
} }
}()
return nil return nil
} }
go conn.run() go conn.run()
@ -683,8 +692,11 @@ func (s *baseServer) handleInitialImpl(p receivedPacket, hdr *wire.Header) error
func (s *baseServer) handleNewConn(conn quicConn) { func (s *baseServer) handleNewConn(conn quicConn) {
connCtx := conn.Context() connCtx := conn.Context()
if s.acceptEarlyConns { if s.acceptEarlyConns {
// wait until the early connection is ready (or the handshake fails) // wait until the early connection is ready, the handshake fails, or the server is closed
select { select {
case <-s.errorChan:
conn.destroy(&qerr.TransportError{ErrorCode: ConnectionRefused})
return
case <-conn.earlyConnReady(): case <-conn.earlyConnReady():
case <-connCtx.Done(): case <-connCtx.Done():
return return
@ -692,6 +704,9 @@ func (s *baseServer) handleNewConn(conn quicConn) {
} else { } else {
// wait until the handshake is complete (or fails) // wait until the handshake is complete (or fails)
select { select {
case <-s.errorChan:
conn.destroy(&qerr.TransportError{ErrorCode: ConnectionRefused})
return
case <-conn.HandshakeComplete(): case <-conn.HandshakeComplete():
case <-connCtx.Done(): case <-connCtx.Done():
return return
@ -708,7 +723,14 @@ func (s *baseServer) handleNewConn(conn quicConn) {
} }
} }
func (s *baseServer) sendRetry(remoteAddr net.Addr, hdr *wire.Header, info packetInfo) error { func (s *baseServer) sendRetry(p rejectedPacket) {
if err := s.sendRetryPacket(p); err != nil {
s.logger.Debugf("Error sending Retry packet: %s", err)
}
}
func (s *baseServer) sendRetryPacket(p rejectedPacket) error {
hdr := p.hdr
// Log the Initial packet now. // Log the Initial packet now.
// If no Retry is sent, the packet will be logged by the connection. // If no Retry is sent, the packet will be logged by the connection.
(&wire.ExtendedHeader{Header: *hdr}).Log(s.logger) (&wire.ExtendedHeader{Header: *hdr}).Log(s.logger)
@ -716,7 +738,7 @@ func (s *baseServer) sendRetry(remoteAddr net.Addr, hdr *wire.Header, info packe
if err != nil { if err != nil {
return err return err
} }
token, err := s.tokenGenerator.NewRetryToken(remoteAddr, hdr.DestConnectionID, srcConnID) token, err := s.tokenGenerator.NewRetryToken(p.remoteAddr, hdr.DestConnectionID, srcConnID)
if err != nil { if err != nil {
return err return err
} }
@ -742,35 +764,18 @@ func (s *baseServer) sendRetry(remoteAddr net.Addr, hdr *wire.Header, info packe
tag := handshake.GetRetryIntegrityTag(buf.Data, hdr.DestConnectionID, hdr.Version) tag := handshake.GetRetryIntegrityTag(buf.Data, hdr.DestConnectionID, hdr.Version)
buf.Data = append(buf.Data, tag[:]...) buf.Data = append(buf.Data, tag[:]...)
if s.tracer != nil && s.tracer.SentPacket != nil { if s.tracer != nil && s.tracer.SentPacket != nil {
s.tracer.SentPacket(remoteAddr, &replyHdr.Header, protocol.ByteCount(len(buf.Data)), nil) s.tracer.SentPacket(p.remoteAddr, &replyHdr.Header, protocol.ByteCount(len(buf.Data)), nil)
} }
_, err = s.conn.WritePacket(buf.Data, remoteAddr, info.OOB(), 0, protocol.ECNUnsupported) _, err = s.conn.WritePacket(buf.Data, p.remoteAddr, p.info.OOB(), 0, protocol.ECNUnsupported)
return err return err
} }
func (s *baseServer) enqueueInvalidToken(p receivedPacket) { func (s *baseServer) maybeSendInvalidToken(p rejectedPacket) {
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() defer p.buffer.Release()
hdr, _, _, err := wire.ParsePacket(p.data)
if err != nil {
if s.tracer != nil && s.tracer.DroppedPacket != 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. // Only send INVALID_TOKEN if we can unprotect the packet.
// This makes sure that we won't send it for packets that were corrupted. // This makes sure that we won't send it for packets that were corrupted.
hdr := p.hdr
sealer, opener := handshake.NewInitialAEAD(hdr.DestConnectionID, protocol.PerspectiveServer, hdr.Version) sealer, opener := handshake.NewInitialAEAD(hdr.DestConnectionID, protocol.PerspectiveServer, hdr.Version)
data := p.data[:hdr.ParsedLen()+hdr.Length] data := p.data[:hdr.ParsedLen()+hdr.Length]
extHdr, err := unpackLongHeader(opener, hdr, data, hdr.Version) extHdr, err := unpackLongHeader(opener, hdr, data, hdr.Version)
@ -797,9 +802,12 @@ func (s *baseServer) maybeSendInvalidToken(p receivedPacket) {
} }
} }
func (s *baseServer) sendConnectionRefused(remoteAddr net.Addr, hdr *wire.Header, info packetInfo) error { func (s *baseServer) sendConnectionRefused(p rejectedPacket) {
sealer, _ := handshake.NewInitialAEAD(hdr.DestConnectionID, protocol.PerspectiveServer, hdr.Version) defer p.buffer.Release()
return s.sendError(remoteAddr, hdr, sealer, qerr.ConnectionRefused, info) sealer, _ := handshake.NewInitialAEAD(p.hdr.DestConnectionID, protocol.PerspectiveServer, p.hdr.Version)
if err := s.sendError(p.remoteAddr, p.hdr, sealer, qerr.ConnectionRefused, p.info); err != nil {
s.logger.Debugf("Error sending CONNECTION_REFUSED error: %s", err)
}
} }
// sendError sends the error as a response to the packet received with header hdr // sendError sends the error as a response to the packet received with header hdr

View File

@ -14,7 +14,7 @@ const (
ipv4PKTINFO = 0x7 ipv4PKTINFO = 0x7
) )
const ecnIPv4DataLen = 4 const ecnIPv4DataLen = 1
const batchSize = 8 const batchSize = 8

View File

@ -19,7 +19,7 @@ const (
ipv4PKTINFO = unix.IP_PKTINFO ipv4PKTINFO = unix.IP_PKTINFO
) )
const ecnIPv4DataLen = 4 const ecnIPv4DataLen = 1
const batchSize = 8 // needs to smaller than MaxUint8 (otherwise the type of oobConn.readPos has to be changed) const batchSize = 8 // needs to smaller than MaxUint8 (otherwise the type of oobConn.readPos has to be changed)
@ -97,3 +97,14 @@ func isGSOError(err error) bool {
} }
return false return false
} }
// The first sendmsg call on a new UDP socket sometimes errors on Linux.
// It's not clear why this happens.
// See https://github.com/golang/go/issues/63322.
func isPermissionError(err error) bool {
var serr *os.SyscallError
if errors.As(err, &serr) {
return serr.Syscall == "sendmsg" && serr.Err == unix.EPERM
}
return false
}

View File

@ -7,3 +7,4 @@ func forceSetSendBuffer(c any, bytes int) error { return nil }
func appendUDPSegmentSizeMsg([]byte, uint16) []byte { return nil } func appendUDPSegmentSizeMsg([]byte, uint16) []byte { return nil }
func isGSOError(error) bool { return false } func isGSOError(error) bool { return false }
func isPermissionError(err error) bool { return false }

View File

@ -275,7 +275,8 @@ func (t *Transport) runSendQueue() {
} }
} }
// Close closes the underlying connection and waits until listen has returned. // Close closes the underlying connection.
// If any listener was started, it will be closed as well.
// It is invalid to start new listeners or connections after that. // It is invalid to start new listeners or connections after that.
func (t *Transport) Close() error { func (t *Transport) Close() error {
t.close(errors.New("closing")) t.close(errors.New("closing"))
@ -294,7 +295,6 @@ func (t *Transport) Close() error {
} }
func (t *Transport) closeServer() { func (t *Transport) closeServer() {
t.handlerMap.CloseServer()
t.mutex.Lock() t.mutex.Lock()
t.server = nil t.server = nil
if t.isSingleUse { if t.isSingleUse {
@ -322,7 +322,7 @@ func (t *Transport) close(e error) {
t.handlerMap.Close(e) t.handlerMap.Close(e)
} }
if t.server != nil { if t.server != nil {
t.server.setCloseError(e) t.server.close(e, false)
} }
t.closed = true t.closed = true
} }

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build go1.7 && amd64 && gc && !purego //go:build go1.7 && amd64 && gc && !purego
// +build go1.7,amd64,gc,!purego
package blake2b package blake2b

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build go1.7 && amd64 && gc && !purego //go:build go1.7 && amd64 && gc && !purego
// +build go1.7,amd64,gc,!purego
#include "textflag.h" #include "textflag.h"

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !go1.7 && amd64 && gc && !purego //go:build !go1.7 && amd64 && gc && !purego
// +build !go1.7,amd64,gc,!purego
package blake2b package blake2b

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build amd64 && gc && !purego //go:build amd64 && gc && !purego
// +build amd64,gc,!purego
#include "textflag.h" #include "textflag.h"

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !amd64 || purego || !gc //go:build !amd64 || purego || !gc
// +build !amd64 purego !gc
package blake2b package blake2b

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build go1.9 //go:build go1.9
// +build go1.9
package blake2b package blake2b

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
package chacha20 package chacha20

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
#include "textflag.h" #include "textflag.h"

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build (!arm64 && !s390x && !ppc64le) || !gc || purego //go:build (!arm64 && !s390x && !ppc64le) || !gc || purego
// +build !arm64,!s390x,!ppc64le !gc purego
package chacha20 package chacha20

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
package chacha20 package chacha20

View File

@ -20,7 +20,6 @@
// due to the calling conventions and initialization of constants. // due to the calling conventions and initialization of constants.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
#include "textflag.h" #include "textflag.h"

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
package chacha20 package chacha20

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
#include "go_asm.h" #include "go_asm.h"
#include "textflag.h" #include "textflag.h"

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
package chacha20poly1305 package chacha20poly1305

View File

@ -5,7 +5,6 @@
// This file was originally from https://golang.org/cl/24717 by Vlad Krasnov of CloudFlare. // This file was originally from https://golang.org/cl/24717 by Vlad Krasnov of CloudFlare.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
#include "textflag.h" #include "textflag.h"
// General register allocation // General register allocation
@ -184,11 +183,31 @@ GLOBL ·andMask<>(SB), (NOPTR+RODATA), $240
#define shiftD1Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xd2; BYTE $0x04 // PALIGNR $4, X10, X10 #define shiftD1Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xd2; BYTE $0x04 // PALIGNR $4, X10, X10
#define shiftD2Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x04 // PALIGNR $4, X11, X11 #define shiftD2Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xdb; BYTE $0x04 // PALIGNR $4, X11, X11
#define shiftD3Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xff; BYTE $0x04 // PALIGNR $4, X15, X15 #define shiftD3Right BYTE $0x66; BYTE $0x45; BYTE $0x0f; BYTE $0x3a; BYTE $0x0f; BYTE $0xff; BYTE $0x04 // PALIGNR $4, X15, X15
// Some macros // Some macros
// ROL rotates the uint32s in register R left by N bits, using temporary T.
#define ROL(N, R, T) \
MOVO R, T; PSLLL $(N), T; PSRLL $(32-(N)), R; PXOR T, R
// ROL16 rotates the uint32s in register R left by 16, using temporary T if needed.
#ifdef GOAMD64_v2
#define ROL16(R, T) PSHUFB ·rol16<>(SB), R
#else
#define ROL16(R, T) ROL(16, R, T)
#endif
// ROL8 rotates the uint32s in register R left by 8, using temporary T if needed.
#ifdef GOAMD64_v2
#define ROL8(R, T) PSHUFB ·rol8<>(SB), R
#else
#define ROL8(R, T) ROL(8, R, T)
#endif
#define chachaQR(A, B, C, D, T) \ #define chachaQR(A, B, C, D, T) \
PADDD B, A; PXOR A, D; PSHUFB ·rol16<>(SB), D \ PADDD B, A; PXOR A, D; ROL16(D, T) \
PADDD D, C; PXOR C, B; MOVO B, T; PSLLL $12, T; PSRLL $20, B; PXOR T, B \ PADDD D, C; PXOR C, B; MOVO B, T; PSLLL $12, T; PSRLL $20, B; PXOR T, B \
PADDD B, A; PXOR A, D; PSHUFB ·rol8<>(SB), D \ PADDD B, A; PXOR A, D; ROL8(D, T) \
PADDD D, C; PXOR C, B; MOVO B, T; PSLLL $7, T; PSRLL $25, B; PXOR T, B PADDD D, C; PXOR C, B; MOVO B, T; PSLLL $7, T; PSRLL $25, B; PXOR T, B
#define chachaQR_AVX2(A, B, C, D, T) \ #define chachaQR_AVX2(A, B, C, D, T) \

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !amd64 || !gc || purego //go:build !amd64 || !gc || purego
// +build !amd64 !gc purego
package chacha20poly1305 package chacha20poly1305

View File

@ -1,7 +1,6 @@
// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT. // Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
//go:build amd64 && gc && !purego //go:build amd64 && gc && !purego
// +build amd64,gc,!purego
package field package field

View File

@ -1,7 +1,6 @@
// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT. // Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
//go:build amd64 && gc && !purego //go:build amd64 && gc && !purego
// +build amd64,gc,!purego
#include "textflag.h" #include "textflag.h"

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !amd64 || !gc || purego //go:build !amd64 || !gc || purego
// +build !amd64 !gc purego
package field package field

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build arm64 && gc && !purego //go:build arm64 && gc && !purego
// +build arm64,gc,!purego
package field package field

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build arm64 && gc && !purego //go:build arm64 && gc && !purego
// +build arm64,gc,!purego
#include "textflag.h" #include "textflag.h"

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !arm64 || !gc || purego //go:build !arm64 || !gc || purego
// +build !arm64 !gc purego
package field package field

View File

@ -56,7 +56,9 @@ func (f *hkdf) Read(p []byte) (int, error) {
// Fill the rest of the buffer // Fill the rest of the buffer
for len(p) > 0 { for len(p) > 0 {
if f.counter > 1 {
f.expander.Reset() f.expander.Reset()
}
f.expander.Write(f.prev) f.expander.Write(f.prev)
f.expander.Write(f.info) f.expander.Write(f.info)
f.expander.Write([]byte{f.counter}) f.expander.Write([]byte{f.counter})

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !purego //go:build !purego
// +build !purego
// Package alias implements memory aliasing tests. // Package alias implements memory aliasing tests.
package alias package alias

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build purego //go:build purego
// +build purego
// Package alias implements memory aliasing tests. // Package alias implements memory aliasing tests.
package alias package alias

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !go1.13 //go:build !go1.13
// +build !go1.13
package poly1305 package poly1305

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build go1.13 //go:build go1.13
// +build go1.13
package poly1305 package poly1305

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build (!amd64 && !ppc64le && !s390x) || !gc || purego //go:build (!amd64 && !ppc64le && !s390x) || !gc || purego
// +build !amd64,!ppc64le,!s390x !gc purego
package poly1305 package poly1305

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
package poly1305 package poly1305

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
#include "textflag.h" #include "textflag.h"

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
package poly1305 package poly1305

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
#include "textflag.h" #include "textflag.h"

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
package poly1305 package poly1305

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build gc && !purego //go:build gc && !purego
// +build gc,!purego
#include "textflag.h" #include "textflag.h"

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build amd64 && !purego && gc //go:build amd64 && !purego && gc
// +build amd64,!purego,gc
package salsa package salsa

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build amd64 && !purego && gc //go:build amd64 && !purego && gc
// +build amd64,!purego,gc
// This code was translated into a form compatible with 6a from the public // This code was translated into a form compatible with 6a from the public
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html // domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !amd64 || purego || !gc //go:build !amd64 || purego || !gc
// +build !amd64 purego !gc
package salsa package salsa

View File

@ -20,42 +20,45 @@ import (
// TODO: Benchmark to determine if the pools are necessary. The GC may have // TODO: Benchmark to determine if the pools are necessary. The GC may have
// improved enough that we can instead allocate chunks like this: // improved enough that we can instead allocate chunks like this:
// make([]byte, max(16<<10, expectedBytesRemaining)) // make([]byte, max(16<<10, expectedBytesRemaining))
var ( var dataChunkPools = [...]sync.Pool{
dataChunkSizeClasses = []int{ {New: func() interface{} { return new([1 << 10]byte) }},
1 << 10, {New: func() interface{} { return new([2 << 10]byte) }},
2 << 10, {New: func() interface{} { return new([4 << 10]byte) }},
4 << 10, {New: func() interface{} { return new([8 << 10]byte) }},
8 << 10, {New: func() interface{} { return new([16 << 10]byte) }},
16 << 10,
} }
dataChunkPools = [...]sync.Pool{
{New: func() interface{} { return make([]byte, 1<<10) }},
{New: func() interface{} { return make([]byte, 2<<10) }},
{New: func() interface{} { return make([]byte, 4<<10) }},
{New: func() interface{} { return make([]byte, 8<<10) }},
{New: func() interface{} { return make([]byte, 16<<10) }},
}
)
func getDataBufferChunk(size int64) []byte { func getDataBufferChunk(size int64) []byte {
i := 0 switch {
for ; i < len(dataChunkSizeClasses)-1; i++ { case size <= 1<<10:
if size <= int64(dataChunkSizeClasses[i]) { return dataChunkPools[0].Get().(*[1 << 10]byte)[:]
break case size <= 2<<10:
return dataChunkPools[1].Get().(*[2 << 10]byte)[:]
case size <= 4<<10:
return dataChunkPools[2].Get().(*[4 << 10]byte)[:]
case size <= 8<<10:
return dataChunkPools[3].Get().(*[8 << 10]byte)[:]
default:
return dataChunkPools[4].Get().(*[16 << 10]byte)[:]
} }
} }
return dataChunkPools[i].Get().([]byte)
}
func putDataBufferChunk(p []byte) { func putDataBufferChunk(p []byte) {
for i, n := range dataChunkSizeClasses { switch len(p) {
if len(p) == n { case 1 << 10:
dataChunkPools[i].Put(p) dataChunkPools[0].Put((*[1 << 10]byte)(p))
return case 2 << 10:
} dataChunkPools[1].Put((*[2 << 10]byte)(p))
} case 4 << 10:
dataChunkPools[2].Put((*[4 << 10]byte)(p))
case 8 << 10:
dataChunkPools[3].Put((*[8 << 10]byte)(p))
case 16 << 10:
dataChunkPools[4].Put((*[16 << 10]byte)(p))
default:
panic(fmt.Sprintf("unexpected buffer len=%v", len(p))) panic(fmt.Sprintf("unexpected buffer len=%v", len(p)))
} }
}
// dataBuffer is an io.ReadWriter backed by a list of data chunks. // dataBuffer is an io.ReadWriter backed by a list of data chunks.
// Each dataBuffer is used to read DATA frames on a single stream. // Each dataBuffer is used to read DATA frames on a single stream.

View File

@ -1,30 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.11
// +build go1.11
package http2
import (
"net/http/httptrace"
"net/textproto"
)
func traceHasWroteHeaderField(trace *httptrace.ClientTrace) bool {
return trace != nil && trace.WroteHeaderField != nil
}
func traceWroteHeaderField(trace *httptrace.ClientTrace, k, v string) {
if trace != nil && trace.WroteHeaderField != nil {
trace.WroteHeaderField(k, []string{v})
}
}
func traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textproto.MIMEHeader) error {
if trace != nil {
return trace.Got1xxResponse
}
return nil
}

View File

@ -1,27 +0,0 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.15
// +build go1.15
package http2
import (
"context"
"crypto/tls"
)
// dialTLSWithContext uses tls.Dialer, added in Go 1.15, to open a TLS
// connection.
func (t *Transport) dialTLSWithContext(ctx context.Context, network, addr string, cfg *tls.Config) (*tls.Conn, error) {
dialer := &tls.Dialer{
Config: cfg,
}
cn, err := dialer.DialContext(ctx, network, addr)
if err != nil {
return nil, err
}
tlsCn := cn.(*tls.Conn) // DialContext comment promises this will always succeed
return tlsCn, nil
}

View File

@ -1,17 +0,0 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.18
// +build go1.18
package http2
import (
"crypto/tls"
"net"
)
func tlsUnderlyingConn(tc *tls.Conn) net.Conn {
return tc.NetConn()
}

View File

@ -1,21 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !go1.11
// +build !go1.11
package http2
import (
"net/http/httptrace"
"net/textproto"
)
func traceHasWroteHeaderField(trace *httptrace.ClientTrace) bool { return false }
func traceWroteHeaderField(trace *httptrace.ClientTrace, k, v string) {}
func traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textproto.MIMEHeader) error {
return nil
}

View File

@ -1,31 +0,0 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !go1.15
// +build !go1.15
package http2
import (
"context"
"crypto/tls"
)
// dialTLSWithContext opens a TLS connection.
func (t *Transport) dialTLSWithContext(ctx context.Context, network, addr string, cfg *tls.Config) (*tls.Conn, error) {
cn, err := tls.Dial(network, addr, cfg)
if err != nil {
return nil, err
}
if err := cn.Handshake(); err != nil {
return nil, err
}
if cfg.InsecureSkipVerify {
return cn, nil
}
if err := cn.VerifyHostname(cfg.ServerName); err != nil {
return nil, err
}
return cn, nil
}

View File

@ -1,17 +0,0 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !go1.18
// +build !go1.18
package http2
import (
"crypto/tls"
"net"
)
func tlsUnderlyingConn(tc *tls.Conn) net.Conn {
return nil
}

View File

@ -2549,7 +2549,6 @@ type responseWriterState struct {
wroteHeader bool // WriteHeader called (explicitly or implicitly). Not necessarily sent to user yet. wroteHeader bool // WriteHeader called (explicitly or implicitly). Not necessarily sent to user yet.
sentHeader bool // have we sent the header frame? sentHeader bool // have we sent the header frame?
handlerDone bool // handler has finished handlerDone bool // handler has finished
dirty bool // a Write failed; don't reuse this responseWriterState
sentContentLen int64 // non-zero if handler set a Content-Length header sentContentLen int64 // non-zero if handler set a Content-Length header
wroteBytes int64 wroteBytes int64
@ -2669,7 +2668,6 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
date: date, date: date,
}) })
if err != nil { if err != nil {
rws.dirty = true
return 0, err return 0, err
} }
if endStream { if endStream {
@ -2690,7 +2688,6 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
if len(p) > 0 || endStream { if len(p) > 0 || endStream {
// only send a 0 byte DATA frame if we're ending the stream. // only send a 0 byte DATA frame if we're ending the stream.
if err := rws.conn.writeDataFromHandler(rws.stream, p, endStream); err != nil { if err := rws.conn.writeDataFromHandler(rws.stream, p, endStream); err != nil {
rws.dirty = true
return 0, err return 0, err
} }
} }
@ -2702,9 +2699,6 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
trailers: rws.trailers, trailers: rws.trailers,
endStream: true, endStream: true,
}) })
if err != nil {
rws.dirty = true
}
return len(p), err return len(p), err
} }
return len(p), nil return len(p), nil
@ -2920,14 +2914,12 @@ func (rws *responseWriterState) writeHeader(code int) {
h.Del("Transfer-Encoding") h.Del("Transfer-Encoding")
} }
if rws.conn.writeHeaders(rws.stream, &writeResHeaders{ rws.conn.writeHeaders(rws.stream, &writeResHeaders{
streamID: rws.stream.id, streamID: rws.stream.id,
httpResCode: code, httpResCode: code,
h: h, h: h,
endStream: rws.handlerDone && !rws.hasTrailers(), endStream: rws.handlerDone && !rws.hasTrailers(),
}) != nil { })
rws.dirty = true
}
return return
} }
@ -2992,20 +2984,11 @@ func (w *responseWriter) write(lenData int, dataB []byte, dataS string) (n int,
func (w *responseWriter) handlerDone() { func (w *responseWriter) handlerDone() {
rws := w.rws rws := w.rws
dirty := rws.dirty
rws.handlerDone = true rws.handlerDone = true
w.Flush() w.Flush()
w.rws = nil w.rws = nil
if !dirty {
// Only recycle the pool if all prior Write calls to
// the serverConn goroutine completed successfully. If
// they returned earlier due to resets from the peer
// there might still be write goroutines outstanding
// from the serverConn referencing the rws memory. See
// issue 20704.
responseWriterStatePool.Put(rws) responseWriterStatePool.Put(rws)
} }
}
// Push errors. // Push errors.
var ( var (
@ -3187,6 +3170,7 @@ func (sc *serverConn) startPush(msg *startPushRequest) {
panic(fmt.Sprintf("newWriterAndRequestNoBody(%+v): %v", msg.url, err)) panic(fmt.Sprintf("newWriterAndRequestNoBody(%+v): %v", msg.url, err))
} }
sc.curHandlers++
go sc.runHandler(rw, req, sc.handler.ServeHTTP) go sc.runHandler(rw, req, sc.handler.ServeHTTP)
return promisedID, nil return promisedID, nil
} }

View File

@ -1018,7 +1018,7 @@ func (cc *ClientConn) forceCloseConn() {
if !ok { if !ok {
return return
} }
if nc := tlsUnderlyingConn(tc); nc != nil { if nc := tc.NetConn(); nc != nil {
nc.Close() nc.Close()
} }
} }
@ -3201,3 +3201,34 @@ func traceFirstResponseByte(trace *httptrace.ClientTrace) {
trace.GotFirstResponseByte() trace.GotFirstResponseByte()
} }
} }
func traceHasWroteHeaderField(trace *httptrace.ClientTrace) bool {
return trace != nil && trace.WroteHeaderField != nil
}
func traceWroteHeaderField(trace *httptrace.ClientTrace, k, v string) {
if trace != nil && trace.WroteHeaderField != nil {
trace.WroteHeaderField(k, []string{v})
}
}
func traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textproto.MIMEHeader) error {
if trace != nil {
return trace.Got1xxResponse
}
return nil
}
// dialTLSWithContext uses tls.Dialer, added in Go 1.15, to open a TLS
// connection.
func (t *Transport) dialTLSWithContext(ctx context.Context, network, addr string, cfg *tls.Config) (*tls.Conn, error) {
dialer := &tls.Dialer{
Config: cfg,
}
cn, err := dialer.DialContext(ctx, network, addr)
if err != nil {
return nil, err
}
tlsCn := cn.(*tls.Conn) // DialContext comment promises this will always succeed
return tlsCn, nil
}

View File

@ -5,7 +5,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build go1.18 //go:build go1.18
// +build go1.18
package idna package idna

View File

@ -5,7 +5,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build go1.10 //go:build go1.10
// +build go1.10
// Package idna implements IDNA2008 using the compatibility processing // Package idna implements IDNA2008 using the compatibility processing
// defined by UTS (Unicode Technical Standard) #46, which defines a standard to // defined by UTS (Unicode Technical Standard) #46, which defines a standard to

View File

@ -5,7 +5,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !go1.10 //go:build !go1.10
// +build !go1.10
// Package idna implements IDNA2008 using the compatibility processing // Package idna implements IDNA2008 using the compatibility processing
// defined by UTS (Unicode Technical Standard) #46, which defines a standard to // defined by UTS (Unicode Technical Standard) #46, which defines a standard to

View File

@ -5,7 +5,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !go1.18 //go:build !go1.18
// +build !go1.18
package idna package idna

View File

@ -1,7 +1,6 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.10 && !go1.13 //go:build go1.10 && !go1.13
// +build go1.10,!go1.13
package idna package idna

View File

@ -1,7 +1,6 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.13 && !go1.14 //go:build go1.13 && !go1.14
// +build go1.13,!go1.14
package idna package idna

View File

@ -1,7 +1,6 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.14 && !go1.16 //go:build go1.14 && !go1.16
// +build go1.14,!go1.16
package idna package idna

View File

@ -1,7 +1,6 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.16 && !go1.21 //go:build go1.16 && !go1.21
// +build go1.16,!go1.21
package idna package idna

View File

@ -1,7 +1,6 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build go1.21 //go:build go1.21
// +build go1.21
package idna package idna

View File

@ -1,7 +1,6 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
//go:build !go1.10 //go:build !go1.10
// +build !go1.10
package idna package idna

View File

@ -5,7 +5,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !go1.16 //go:build !go1.16
// +build !go1.16
package idna package idna

View File

@ -5,7 +5,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build go1.16 //go:build go1.16
// +build go1.16
package idna package idna

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
package socket package socket

View File

@ -3,7 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build aix || darwin || dragonfly || freebsd || netbsd || openbsd //go:build aix || darwin || dragonfly || freebsd || netbsd || openbsd
// +build aix darwin dragonfly freebsd netbsd openbsd
package socket package socket

View File

@ -3,8 +3,6 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build (arm || mips || mipsle || 386 || ppc) && linux //go:build (arm || mips || mipsle || 386 || ppc) && linux
// +build arm mips mipsle 386 ppc
// +build linux
package socket package socket

Some files were not shown because too many files have changed in this diff Show More