all: Use Go 1.21, new QUIC API (#9040)

This commit is contained in:
Jakob Borg 2023-08-21 15:25:52 +02:00 committed by GitHub
parent c40dae315b
commit cbf0e31f69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 139 additions and 122 deletions

View File

@ -6,7 +6,7 @@ on:
- infrastructure
env:
GO_VERSION: "^1.20.5"
GO_VERSION: "^1.21.0"
CGO_ENABLED: "0"
BUILD_USER: docker
BUILD_HOST: github.syncthing.net

View File

@ -12,7 +12,7 @@ env:
# The go version to use for builds. We set check-latest to true when
# installing, so we get the latest patch version that matches the
# expression.
GO_VERSION: "~1.20.7"
GO_VERSION: "~1.21.0"
# Optimize compatibility on the slow archictures.
GO386: softfloat
@ -48,7 +48,7 @@ jobs:
runner: ["windows-latest", "ubuntu-latest", "macos-latest"]
# The oldest version in this list should match what we have in our go.mod.
# Variables don't seem to be supported here, or we could have done something nice.
go: ["1.19", "1.20"]
go: ["1.20", "1.21"]
runs-on: ${{ matrix.runner }}
steps:
- name: Set git to use LF

22
go.mod
View File

@ -1,9 +1,8 @@
module github.com/syncthing/syncthing
go 1.19
go 1.20
require (
github.com/AudriusButkevicius/pfilter v0.0.11
github.com/AudriusButkevicius/recli v0.0.7-0.20220911121932-d000ce8fbf0f
github.com/alecthomas/kong v0.8.0
github.com/calmh/incontainer v0.0.0-20221224152218-b3e71b103d7a
@ -39,7 +38,7 @@ require (
github.com/prometheus/client_golang v1.16.0
github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.11.0 // indirect
github.com/quic-go/quic-go v0.34.0
github.com/quic-go/quic-go v0.37.2-0.20230819081917-fe3c4f271df1
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475
github.com/sasha-s/go-deadlock v0.3.1
github.com/shirou/gopsutil/v3 v3.23.6
@ -48,13 +47,14 @@ require (
github.com/thejerf/suture/v4 v4.0.2
github.com/urfave/cli v1.22.14
github.com/vitrun/qart v0.0.0-20160531060029-bf64b92db6b0
golang.org/x/crypto v0.11.0
golang.org/x/crypto v0.12.0
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.12.0
golang.org/x/sys v0.10.0
golang.org/x/text v0.11.0
golang.org/x/net v0.14.0
golang.org/x/sys v0.11.0
golang.org/x/text v0.12.0
golang.org/x/time v0.3.0
golang.org/x/tools v0.11.0
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846
google.golang.org/protobuf v1.31.0
)
@ -65,18 +65,16 @@ require (
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 // indirect
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/onsi/ginkgo/v2 v2.11.0 // indirect
github.com/oschwald/maxminddb-golang v1.11.0 // indirect
github.com/petermattis/goid v0.0.0-20230518223814-80aa455d8761 // indirect
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
github.com/prometheus/client_model v0.4.0 // indirect
github.com/quic-go/qtls-go1-19 v0.3.2 // indirect
github.com/quic-go/qtls-go1-20 v0.2.2 // indirect
github.com/quic-go/qtls-go1-20 v0.3.2 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
golang.org/x/exp v0.0.0-20230711023510-fffb14384f22 // indirect
)
// https://github.com/gobwas/glob/pull/55

40
go.sum
View File

@ -1,5 +1,3 @@
github.com/AudriusButkevicius/pfilter v0.0.11 h1:6emuvqNeH1gGlqkML35pEizyPcaxdAN4JO9sdgwcx78=
github.com/AudriusButkevicius/pfilter v0.0.11/go.mod h1:4eF1UYuEhoycTlr9IOP1sb0lL9u4nfAIouRqt2xJbzM=
github.com/AudriusButkevicius/recli v0.0.7-0.20220911121932-d000ce8fbf0f h1:GmH5lT+moM7PbAJFBq57nH9WJ+wRnBXr/tyaYWbSAx8=
github.com/AudriusButkevicius/recli v0.0.7-0.20220911121932-d000ce8fbf0f/go.mod h1:Nhfib1j/VFnLrXL9cHgA+/n2O6P5THuWelOnbfPNd78=
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
@ -81,8 +79,8 @@ github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 h1:n6vlPhxsA+BW/XsS5+uqi7GyzaLa5MH7qlSLBZtRdiA=
github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA=
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b h1:h9U78+dx9a4BKdQkBBos92HalKpaGKHrp+3Uo6yTodo=
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/greatroar/blobloom v0.7.2 h1:F30MGLHOcb4zr0pwCPTcKdlTM70rEgkf+LzdUPc5ss8=
github.com/greatroar/blobloom v0.7.2/go.mod h1:mjMJ1hh1wjGVfr93QIHJ6FfDNVrA0IELv8OvMHJxHKs=
github.com/hashicorp/golang-lru/v2 v2.0.4 h1:7GHuZcgid37q8o5i3QI9KMT4nCWQQ3Kx3Ov6bb9MfK0=
@ -159,12 +157,10 @@ github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdO
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
github.com/prometheus/procfs v0.11.0 h1:5EAgkfkMl659uZPbe9AS2N68a7Cc1TJbPEuGzFuRbyk=
github.com/prometheus/procfs v0.11.0/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U=
github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E=
github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
github.com/quic-go/quic-go v0.34.0 h1:OvOJ9LFjTySgwOTYUZmNoq0FzVicP8YujpV0kB7m2lU=
github.com/quic-go/quic-go v0.34.0/go.mod h1:+4CVgVppm0FNjpG3UcX8Joi/frKOH7/ciD5yGcwOO1g=
github.com/quic-go/qtls-go1-20 v0.3.2 h1:rRgN3WfnKbyik4dBV8A6girlJVxGand/d+jVKbQq5GI=
github.com/quic-go/qtls-go1-20 v0.3.2/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
github.com/quic-go/quic-go v0.37.2-0.20230819081917-fe3c4f271df1 h1:SipxgcO/6iOMI9xVRY0zRQWClQuOVms7JVRQyqbdqiE=
github.com/quic-go/quic-go v0.37.2-0.20230819081917-fe3c4f271df1/go.mod h1:MPCuRq7KBK2hNcfKj/1iD1BGuN3eAYMeNxp3T42LRUg=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
@ -210,10 +206,10 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/exp v0.0.0-20230711023510-fffb14384f22 h1:FqrVOBQxQ8r/UwwXibI0KMolVhvFiGobSfdE33deHJM=
golang.org/x/exp v0.0.0-20230711023510-fffb14384f22/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ=
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@ -235,8 +231,8 @@ golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -275,8 +271,8 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@ -287,8 +283,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -299,8 +295,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8=
golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8=
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E=
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@ -52,27 +52,23 @@ func (d *quicDialer) Dial(ctx context.Context, _ protocol.DeviceID, uri *url.URL
return internalConn{}, err
}
var conn net.PacketConn
// We need to track who created the conn.
// Given we always pass the connection to quic, it assumes it's a remote connection it never closes it,
// So our wrapper around it needs to close it, but it only needs to close it if it's not the listening connection.
// If we created the conn we need to close it at the end. If we got a
// Transport from the registry we have no conn to close.
var createdConn net.PacketConn
listenConn := d.registry.Get(uri.Scheme, packetConnUnspecified)
if listenConn != nil {
conn = listenConn.(net.PacketConn)
} else {
transport, _ := d.registry.Get(uri.Scheme, transportConnUnspecified).(*quic.Transport)
if transport == nil {
if packetConn, err := net.ListenPacket("udp", ":0"); err != nil {
return internalConn{}, err
} else {
conn = packetConn
createdConn = packetConn
transport = &quic.Transport{Conn: packetConn}
}
}
ctx, cancel := context.WithTimeout(ctx, quicOperationTimeout)
defer cancel()
session, err := quic.DialContext(ctx, conn, addr, uri.Host, d.tlsCfg, quicConfig)
session, err := transport.Dial(ctx, addr, d.tlsCfg, quicConfig)
if err != nil {
if createdConn != nil {
_ = createdConn.Close()

View File

@ -95,17 +95,22 @@ func (t *quicListener) serve(ctx context.Context) error {
l.Infoln("Listen (BEP/quic):", err)
return err
}
defer func() { _ = udpConn.Close() }()
defer udpConn.Close()
svc, conn := stun.New(t.cfg, t, udpConn)
defer conn.Close()
tracer := &writeTrackingTracer{}
quicTransport := &quic.Transport{
Conn: udpConn,
Tracer: tracer,
}
defer quicTransport.Close()
svc := stun.New(t.cfg, t, &transportPacketConn{tran: quicTransport}, tracer)
go svc.Serve(ctx)
t.registry.Register(t.uri.Scheme, conn)
defer t.registry.Unregister(t.uri.Scheme, conn)
t.registry.Register(t.uri.Scheme, quicTransport)
defer t.registry.Unregister(t.uri.Scheme, quicTransport)
listener, err := quic.Listen(conn, t.tlsCfg, quicConfig)
listener, err := quicTransport.Listen(t.tlsCfg, quicConfig)
if err != nil {
l.Infoln("Listen (BEP/quic):", err)
return err

View File

@ -10,18 +10,20 @@
package connections
import (
"context"
"crypto/tls"
"net"
"net/url"
"sync/atomic"
"time"
"github.com/quic-go/quic-go"
"github.com/quic-go/quic-go/logging"
"github.com/syncthing/syncthing/lib/osutil"
)
var quicConfig = &quic.Config{
ConnectionIDLength: 4,
MaxIdleTimeout: 30 * time.Second,
KeepAlivePeriod: 15 * time.Second,
}
@ -61,11 +63,75 @@ func (q *quicTlsConn) Close() error {
}
func (q *quicTlsConn) ConnectionState() tls.ConnectionState {
return q.Connection.ConnectionState().TLS.ConnectionState
return q.Connection.ConnectionState().TLS
}
func packetConnUnspecified(conn interface{}) bool {
addr := conn.(net.PacketConn).LocalAddr()
func transportConnUnspecified(conn any) bool {
tran, ok := conn.(*quic.Transport)
if !ok {
return false
}
addr := tran.Conn.LocalAddr()
ip, err := osutil.IPFromAddr(addr)
return err == nil && ip.IsUnspecified()
}
type writeTrackingTracer struct {
lastWrite atomic.Int64 // unix nanos
}
func (t *writeTrackingTracer) SentPacket(net.Addr, *logging.Header, logging.ByteCount, []logging.Frame) {
t.lastWrite.Store(time.Now().UnixNano())
}
func (t *writeTrackingTracer) SentVersionNegotiationPacket(_ net.Addr, dest, src logging.ArbitraryLenConnectionID, _ []quic.VersionNumber) {
t.lastWrite.Store(time.Now().UnixNano())
}
func (t *writeTrackingTracer) DroppedPacket(net.Addr, logging.PacketType, logging.ByteCount, logging.PacketDropReason) {
}
func (t *writeTrackingTracer) LastWrite() time.Time {
return time.Unix(0, t.lastWrite.Load())
}
// A transportPacketConn is a net.PacketConn that uses a quic.Transport.
type transportPacketConn struct {
tran *quic.Transport
readDeadline atomic.Value // time.Time
}
func (t *transportPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
ctx := context.Background()
if deadline, ok := t.readDeadline.Load().(time.Time); ok && !deadline.IsZero() {
var cancel context.CancelFunc
ctx, cancel = context.WithDeadline(ctx, deadline)
defer cancel()
}
return t.tran.ReadNonQUICPacket(ctx, p)
}
func (t *transportPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
return t.tran.WriteTo(p, addr)
}
func (t *transportPacketConn) Close() error {
return errUnsupported
}
func (t *transportPacketConn) LocalAddr() net.Addr {
return t.tran.Conn.LocalAddr()
}
func (t *transportPacketConn) SetDeadline(deadline time.Time) error {
return t.SetReadDeadline(deadline)
}
func (t *transportPacketConn) SetReadDeadline(deadline time.Time) error {
t.readDeadline.Store(deadline)
return nil
}
func (t *transportPacketConn) SetWriteDeadline(_ time.Time) error {
return nil // yolo
}

View File

@ -9,10 +9,8 @@ package stun
import (
"context"
"net"
"sync/atomic"
"time"
"github.com/AudriusButkevicius/pfilter"
"github.com/ccding/go-stun/stun"
"github.com/syncthing/syncthing/lib/config"
@ -21,8 +19,10 @@ import (
const stunRetryInterval = 5 * time.Minute
type Host = stun.Host
type NATType = stun.NATType
type (
Host = stun.Host
NATType = stun.NATType
)
// NAT types.
@ -38,38 +38,6 @@ const (
NATSymmetricUDPFirewall = stun.NATSymmetricUDPFirewall
)
type writeTrackingUdpConn struct {
// Needs to be UDPConn not PacketConn, as pfilter checks for WriteMsgUDP/ReadMsgUDP
// and even if we embed UDPConn here, in place of a PacketConn, seems the interface
// check fails.
*net.UDPConn
lastWrite atomic.Int64
}
func (c *writeTrackingUdpConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
c.lastWrite.Store(time.Now().Unix())
return c.UDPConn.WriteTo(p, addr)
}
func (c *writeTrackingUdpConn) WriteMsgUDP(b, oob []byte, addr *net.UDPAddr) (n, oobn int, err error) {
c.lastWrite.Store(time.Now().Unix())
return c.UDPConn.WriteMsgUDP(b, oob, addr)
}
func (c *writeTrackingUdpConn) WriteToUDP(b []byte, addr *net.UDPAddr) (int, error) {
c.lastWrite.Store(time.Now().Unix())
return c.UDPConn.WriteToUDP(b, addr)
}
func (c *writeTrackingUdpConn) Write(b []byte) (int, error) {
c.lastWrite.Store(time.Now().Unix())
return c.UDPConn.Write(b)
}
func (c *writeTrackingUdpConn) getLastWrite() time.Time {
return time.Unix(c.lastWrite.Load(), 0)
}
type Subscriber interface {
OnNATTypeChanged(natType NATType)
OnExternalAddressChanged(address *Host, via string)
@ -79,30 +47,21 @@ type Service struct {
name string
cfg config.Wrapper
subscriber Subscriber
stunConn net.PacketConn
client *stun.Client
writeTrackingUdpConn *writeTrackingUdpConn
lastWriter LastWriter
natType NATType
addr *Host
}
func New(cfg config.Wrapper, subscriber Subscriber, conn *net.UDPConn) (*Service, net.PacketConn) {
// Wrap the original connection to track writes on it
writeTrackingUdpConn := &writeTrackingUdpConn{UDPConn: conn}
// Wrap it in a filter and split it up, so that stun packets arrive on stun conn, others arrive on the data conn
filterConn := pfilter.NewPacketFilter(writeTrackingUdpConn)
otherDataConn := filterConn.NewConn(otherDataPriority, nil)
stunConn := filterConn.NewConn(stunFilterPriority, &stunFilter{
ids: make(map[string]time.Time),
})
filterConn.Start()
type LastWriter interface {
LastWrite() time.Time
}
func New(cfg config.Wrapper, subscriber Subscriber, conn net.PacketConn, lastWriter LastWriter) *Service {
// Construct the client to use the stun conn
client := stun.NewClientWithConnection(stunConn)
client := stun.NewClientWithConnection(conn)
client.SetSoftwareName("") // Explicitly unset this, seems to freak some servers out.
// Return the service and the other conn to the client
@ -117,15 +76,14 @@ func New(cfg config.Wrapper, subscriber Subscriber, conn *net.UDPConn) (*Service
cfg: cfg,
subscriber: subscriber,
stunConn: stunConn,
client: client,
writeTrackingUdpConn: writeTrackingUdpConn,
lastWriter: lastWriter,
natType: NATUnknown,
addr: nil,
}
return s, otherDataConn
return s
}
func (s *Service) Serve(ctx context.Context) error {
@ -134,13 +92,6 @@ func (s *Service) Serve(ctx context.Context) error {
s.setExternalAddress(nil, "")
}()
// Closing s.stunConn unblocks operations that use the connection
// (Discover, Keepalive) and might otherwise block us from returning.
go func() {
<-ctx.Done()
_ = s.stunConn.Close()
}()
timer := time.NewTimer(time.Millisecond)
for {
@ -244,6 +195,7 @@ func (s *Service) stunKeepAlive(ctx context.Context, addr string, extAddr *Host)
l.Debugf("%s starting stun keepalive via %s, next sleep %s", s, addr, nextSleep)
var ourLastWrite time.Time
for {
if areDifferent(s.addr, extAddr) {
// If the port has changed (addresses are not equal but the hosts are equal),
@ -264,7 +216,10 @@ func (s *Service) stunKeepAlive(ctx context.Context, addr string, extAddr *Host)
}
// Adjust the keepalives to fire only nextSleep after last write.
lastWrite := s.writeTrackingUdpConn.getLastWrite()
lastWrite := ourLastWrite
if quicLastWrite := s.lastWriter.LastWrite(); quicLastWrite.After(lastWrite) {
lastWrite = quicLastWrite
}
minSleep := time.Duration(s.cfg.Options().StunKeepaliveMinS) * time.Second
if nextSleep < minSleep {
nextSleep = minSleep
@ -293,7 +248,7 @@ func (s *Service) stunKeepAlive(ctx context.Context, addr string, extAddr *Host)
}
// Check if any writes happened while we were sleeping, if they did, sleep again
lastWrite = s.writeTrackingUdpConn.getLastWrite()
lastWrite = s.lastWriter.LastWrite()
if gap := time.Since(lastWrite); gap < nextSleep {
l.Debugf("%s stun last write gap less than next sleep: %s < %s. Will try later", s, gap, nextSleep)
goto tryLater
@ -306,6 +261,7 @@ func (s *Service) stunKeepAlive(ctx context.Context, addr string, extAddr *Host)
l.Debugf("%s stun keepalive on %s: %s (%v)", s, addr, err, extAddr)
return
}
ourLastWrite = time.Now()
}
}