aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Borg <jakob@kastelo.net>2023-08-21 15:25:52 +0200
committerGitHub <noreply@github.com>2023-08-21 15:25:52 +0200
commitcbf0e31f69bf44bb49c6c1d18196556900b8083b (patch)
treeb4bf5c63968e0b5a2950652ae144ee2be33a1030
parentc40dae315b90157503bccad55bcb9887253f95ff (diff)
downloadsyncthing-cbf0e31f69bf44bb49c6c1d18196556900b8083b.tar.gz
syncthing-cbf0e31f69bf44bb49c6c1d18196556900b8083b.zip
all: Use Go 1.21, new QUIC API (#9040)
-rw-r--r--.github/workflows/build-infra-dockers.yaml2
-rw-r--r--.github/workflows/build-syncthing.yaml4
-rw-r--r--go.mod22
-rw-r--r--go.sum40
-rw-r--r--lib/connections/quic_dial.go16
-rw-r--r--lib/connections/quic_listen.go17
-rw-r--r--lib/connections/quic_misc.go78
-rw-r--r--lib/stun/stun.go82
8 files changed, 139 insertions, 122 deletions
diff --git a/.github/workflows/build-infra-dockers.yaml b/.github/workflows/build-infra-dockers.yaml
index 2295fedb1..cc507fe33 100644
--- a/.github/workflows/build-infra-dockers.yaml
+++ b/.github/workflows/build-infra-dockers.yaml
@@ -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
diff --git a/.github/workflows/build-syncthing.yaml b/.github/workflows/build-syncthing.yaml
index 35ed2827c..c198c38dc 100644
--- a/.github/workflows/build-syncthing.yaml
+++ b/.github/workflows/build-syncthing.yaml
@@ -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
diff --git a/go.mod b/go.mod
index 62e120623..006573b36 100644
--- a/go.mod
+++ b/go.mod
@@ -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
diff --git a/go.sum b/go.sum
index 73d660e72..b359efa46 100644
--- a/go.sum
+++ b/go.sum
@@ -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=
diff --git a/lib/connections/quic_dial.go b/lib/connections/quic_dial.go
index 6c9a03670..7466f8ca3 100644
--- a/lib/connections/quic_dial.go
+++ b/lib/connections/quic_dial.go
@@ -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()
diff --git a/lib/connections/quic_listen.go b/lib/connections/quic_listen.go
index 9eab87026..930376777 100644
--- a/lib/connections/quic_listen.go
+++ b/lib/connections/quic_listen.go
@@ -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
diff --git a/lib/connections/quic_misc.go b/lib/connections/quic_misc.go
index d5f0b0dfd..238e48210 100644
--- a/lib/connections/quic_misc.go
+++ b/lib/connections/quic_misc.go
@@ -10,20 +10,22 @@
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,
+ MaxIdleTimeout: 30 * time.Second,
+ KeepAlivePeriod: 15 * time.Second,
}
func quicNetwork(uri *url.URL) string {
@@ -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
+}
diff --git a/lib/stun/stun.go b/lib/stun/stun.go
index db96502cd..191b39c5b 100644
--- a/lib/stun/stun.go
+++ b/lib/stun/stun.go
@@ -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()
}
}