Skip to content

Commit d135d0f

Browse files
committed
Update tfo-go usage
1 parent b183ccf commit d135d0f

File tree

6 files changed

+228
-21
lines changed

6 files changed

+228
-21
lines changed

common/dialer/default.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import (
1515
M "github.com/sagernet/sing/common/metadata"
1616
N "github.com/sagernet/sing/common/network"
1717

18-
"github.com/database64128/tfo-go"
18+
"github.com/database64128/tfo-go/v2"
1919
)
2020

2121
var warnBindInterfaceOnUnsupportedPlatform = warning.New(
@@ -146,7 +146,7 @@ func (d *DefaultDialer) DialContext(ctx context.Context, network string, address
146146
case N.NetworkUDP:
147147
return d.udpDialer.DialContext(ctx, network, address.String())
148148
}
149-
return d.dialer.DialContext(ctx, network, address.String())
149+
return DialSlowContext(&d.dialer, ctx, network, address)
150150
}
151151

152152
func (d *DefaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {

common/dialer/tfo.go

+135
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package dialer
2+
3+
import (
4+
"context"
5+
"io"
6+
"net"
7+
"os"
8+
"time"
9+
10+
"github.com/sagernet/sing/common"
11+
"github.com/sagernet/sing/common/bufio"
12+
M "github.com/sagernet/sing/common/metadata"
13+
N "github.com/sagernet/sing/common/network"
14+
15+
"github.com/database64128/tfo-go/v2"
16+
)
17+
18+
type slowOpenConn struct {
19+
dialer *tfo.Dialer
20+
ctx context.Context
21+
network string
22+
destination M.Socksaddr
23+
conn net.Conn
24+
create chan struct{}
25+
err error
26+
}
27+
28+
func DialSlowContext(dialer *tfo.Dialer, ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
29+
if dialer.DisableTFO || N.NetworkName(network) != N.NetworkTCP {
30+
return dialer.DialContext(ctx, network, destination.String(), nil)
31+
}
32+
return &slowOpenConn{
33+
dialer: dialer,
34+
ctx: ctx,
35+
network: network,
36+
destination: destination,
37+
create: make(chan struct{}),
38+
}, nil
39+
}
40+
41+
func (c *slowOpenConn) Read(b []byte) (n int, err error) {
42+
if c.conn == nil {
43+
select {
44+
case <-c.create:
45+
if c.err != nil {
46+
return 0, c.err
47+
}
48+
case <-c.ctx.Done():
49+
return 0, c.ctx.Err()
50+
}
51+
}
52+
return c.conn.Read(b)
53+
}
54+
55+
func (c *slowOpenConn) Write(b []byte) (n int, err error) {
56+
if c.conn == nil {
57+
c.conn, err = c.dialer.DialContext(c.ctx, c.network, c.destination.String(), b)
58+
c.err = err
59+
close(c.create)
60+
return
61+
}
62+
return c.conn.Write(b)
63+
}
64+
65+
func (c *slowOpenConn) Close() error {
66+
return common.Close(c.conn)
67+
}
68+
69+
func (c *slowOpenConn) LocalAddr() net.Addr {
70+
if c.conn == nil {
71+
return M.Socksaddr{}
72+
}
73+
return c.conn.LocalAddr()
74+
}
75+
76+
func (c *slowOpenConn) RemoteAddr() net.Addr {
77+
if c.conn == nil {
78+
return M.Socksaddr{}
79+
}
80+
return c.conn.RemoteAddr()
81+
}
82+
83+
func (c *slowOpenConn) SetDeadline(t time.Time) error {
84+
if c.conn == nil {
85+
return os.ErrInvalid
86+
}
87+
return c.conn.SetDeadline(t)
88+
}
89+
90+
func (c *slowOpenConn) SetReadDeadline(t time.Time) error {
91+
if c.conn == nil {
92+
return os.ErrInvalid
93+
}
94+
return c.conn.SetReadDeadline(t)
95+
}
96+
97+
func (c *slowOpenConn) SetWriteDeadline(t time.Time) error {
98+
if c.conn == nil {
99+
return os.ErrInvalid
100+
}
101+
return c.conn.SetWriteDeadline(t)
102+
}
103+
104+
func (c *slowOpenConn) Upstream() any {
105+
return c.conn
106+
}
107+
108+
func (c *slowOpenConn) ReaderReplaceable() bool {
109+
return c.conn != nil
110+
}
111+
112+
func (c *slowOpenConn) WriterReplaceable() bool {
113+
return c.conn != nil
114+
}
115+
116+
func (c *slowOpenConn) ReadFrom(r io.Reader) (n int64, err error) {
117+
if c.conn != nil {
118+
return bufio.Copy(c.conn, r)
119+
}
120+
return bufio.ReadFrom0(c, r)
121+
}
122+
123+
func (c *slowOpenConn) WriteTo(w io.Writer) (n int64, err error) {
124+
if c.conn == nil {
125+
select {
126+
case <-c.create:
127+
if c.err != nil {
128+
return 0, c.err
129+
}
130+
case <-c.ctx.Done():
131+
return 0, c.ctx.Err()
132+
}
133+
}
134+
return bufio.Copy(w, c.conn)
135+
}

go.mod

+6-6
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ go 1.18
55
require (
66
berty.tech/go-libtor v1.0.385
77
github.com/Dreamacro/clash v1.11.8
8-
github.com/caddyserver/certmagic v0.17.1
8+
github.com/caddyserver/certmagic v0.17.2
99
github.com/cloudflare/circl v1.2.1-0.20220831060716-4cf0150356fc
1010
github.com/cretz/bine v0.2.0
11-
github.com/database64128/tfo-go v1.1.2
11+
github.com/database64128/tfo-go/v2 v2.0.1
1212
github.com/dustin/go-humanize v1.0.0
1313
github.com/fsnotify/fsnotify v1.5.4
1414
github.com/go-chi/chi/v5 v5.0.7
@@ -35,8 +35,8 @@ require (
3535
go.etcd.io/bbolt v1.3.6
3636
go.uber.org/atomic v1.10.0
3737
go4.org/netipx v0.0.0-20220925034521-797b0c90d8ab
38-
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be
39-
golang.org/x/net v0.0.0-20220927171203-f486391704dc
38+
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b
39+
golang.org/x/net v0.0.0-20221004154528-8021a29435af
4040
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec
4141
golang.zx2c4.com/wireguard v0.0.0-20220829161405-d1d08426b27b
4242
google.golang.org/grpc v1.49.0
@@ -56,7 +56,7 @@ require (
5656
github.com/google/btree v1.0.1 // indirect
5757
github.com/inconshreveable/mousetrap v1.0.0 // indirect
5858
github.com/klauspost/compress v1.13.6 // indirect
59-
github.com/klauspost/cpuid/v2 v2.1.0 // indirect
59+
github.com/klauspost/cpuid/v2 v2.1.1 // indirect
6060
github.com/libdns/libdns v0.2.1 // indirect
6161
github.com/marten-seemann/qpack v0.2.1 // indirect
6262
github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect
@@ -70,7 +70,7 @@ require (
7070
github.com/spf13/pflag v1.0.5 // indirect
7171
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
7272
go.uber.org/multierr v1.6.0 // indirect
73-
go.uber.org/zap v1.22.0 // indirect
73+
go.uber.org/zap v1.23.0 // indirect
7474
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
7575
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
7676
golang.org/x/text v0.3.7 // indirect

go.sum

+12-12
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHG
1212
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
1313
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
1414
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
15-
github.com/caddyserver/certmagic v0.17.1 h1:VrWANhQAj3brK7jAUKyN6XBHg56WsyorI/84Ilq1tCQ=
16-
github.com/caddyserver/certmagic v0.17.1/go.mod h1:pSS2aZcdKlrTZrb2DKuRafckx20o5Fz1EdDKEB8KOQM=
15+
github.com/caddyserver/certmagic v0.17.2 h1:o30seC1T/dBqBCNNGNHWwj2i5/I/FMjBbTAhjADP3nE=
16+
github.com/caddyserver/certmagic v0.17.2/go.mod h1:ouWUuC490GOLJzkyN35eXfV8bSbwMwSf4bdhkIxtdQE=
1717
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
1818
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
1919
github.com/cloudflare/circl v1.2.1-0.20220831060716-4cf0150356fc h1:307gdRLiZ08dwOIKwc5lAQ19DRFaQQvdhHalyB4Asx8=
@@ -25,8 +25,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t
2525
github.com/cretz/bine v0.1.0/go.mod h1:6PF6fWAvYtwjRGkAuDEJeWNOv3a2hUouSP/yRYXmvHw=
2626
github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
2727
github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI=
28-
github.com/database64128/tfo-go v1.1.2 h1:GwxtJp09BdUTVEoeT421t231eNZoGOCRkklbl4WI1kU=
29-
github.com/database64128/tfo-go v1.1.2/go.mod h1:jgrSUPyOvTGQyn6irCOpk7L2W/q/0VLZZcovQiMi+bI=
28+
github.com/database64128/tfo-go/v2 v2.0.1 h1:VFfturVoq6NmPGfhXO1K15x82KR19aAfw1RYtTzyVv4=
29+
github.com/database64128/tfo-go/v2 v2.0.1/go.mod h1:FDdt4JaAsRU66wsYHxSVytYimPkKIHupVsxM+5DhvjY=
3030
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3131
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3232
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -90,8 +90,8 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt
9090
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
9191
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
9292
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
93-
github.com/klauspost/cpuid/v2 v2.1.0 h1:eyi1Ad2aNJMW95zcSbmGg7Cg6cq3ADwLpMAP96d8rF0=
94-
github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
93+
github.com/klauspost/cpuid/v2 v2.1.1 h1:t0wUqjowdm8ezddV5k0tLWVklVuvLJpoHeb4WBdydm0=
94+
github.com/klauspost/cpuid/v2 v2.1.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
9595
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
9696
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
9797
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -186,8 +186,8 @@ go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ
186186
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
187187
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
188188
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
189-
go.uber.org/zap v1.22.0 h1:Zcye5DUgBloQ9BaT4qc9BnjOFog5TvBSAGkJ3Nf70c0=
190-
go.uber.org/zap v1.22.0/go.mod h1:H4siCOZOrAolnUPJEkfaSjDqyP+BDS0DdDWzwcgt3+U=
189+
go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY=
190+
go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
191191
go4.org/netipx v0.0.0-20220925034521-797b0c90d8ab h1:+yW1yrZ09EYNu1spCUOHBBNRbrLnfmutwyhbhCv3b6Q=
192192
go4.org/netipx v0.0.0-20220925034521-797b0c90d8ab/go.mod h1:tgPU4N2u9RByaTN3NC2p9xOzyFpte4jYwsIIRF7XlSc=
193193
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -196,8 +196,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
196196
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
197197
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
198198
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
199-
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be h1:fmw3UbQh+nxngCAHrDCCztao/kbYFnWjoqop8dHx05A=
200-
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
199+
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b h1:huxqepDufQpLLIRXiVkTvnxrzJlpwmIWAObmcCcUFr0=
200+
golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
201201
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
202202
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
203203
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
@@ -229,8 +229,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx
229229
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
230230
golang.org/x/net v0.0.0-20211111160137-58aab5ef257a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
231231
golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
232-
golang.org/x/net v0.0.0-20220927171203-f486391704dc h1:FxpXZdoBqT8RjqTy6i1E8nXHhW21wK7ptQ/EPIGxzPQ=
233-
golang.org/x/net v0.0.0-20220927171203-f486391704dc/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
232+
golang.org/x/net v0.0.0-20221004154528-8021a29435af h1:wv66FM3rLZGPdxpYL+ApnDe2HzHcTFta3z5nsc13wI4=
233+
golang.org/x/net v0.0.0-20221004154528-8021a29435af/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
234234
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
235235
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
236236
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=

inbound/default_tcp.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
M "github.com/sagernet/sing/common/metadata"
1313
N "github.com/sagernet/sing/common/network"
1414

15-
"github.com/database64128/tfo-go"
15+
"github.com/database64128/tfo-go/v2"
1616
)
1717

1818
func (a *myInboundAdapter) ListenTCP() (net.Listener, error) {

test/tfo_test.go

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package main
2+
3+
import (
4+
"net/netip"
5+
"testing"
6+
7+
C "github.com/sagernet/sing-box/constant"
8+
"github.com/sagernet/sing-box/option"
9+
"github.com/sagernet/sing-shadowsocks/shadowaead"
10+
)
11+
12+
func TestTCPSlowOpen(t *testing.T) {
13+
method := shadowaead.List[0]
14+
password := mkBase64(t, 16)
15+
startInstance(t, option.Options{
16+
Inbounds: []option.Inbound{
17+
{
18+
Type: C.TypeMixed,
19+
Tag: "mixed-in",
20+
MixedOptions: option.HTTPMixedInboundOptions{
21+
ListenOptions: option.ListenOptions{
22+
Listen: option.ListenAddress(netip.IPv4Unspecified()),
23+
ListenPort: clientPort,
24+
},
25+
},
26+
},
27+
{
28+
Type: C.TypeShadowsocks,
29+
ShadowsocksOptions: option.ShadowsocksInboundOptions{
30+
ListenOptions: option.ListenOptions{
31+
Listen: option.ListenAddress(netip.IPv4Unspecified()),
32+
ListenPort: serverPort,
33+
TCPFastOpen: true,
34+
},
35+
Method: method,
36+
Password: password,
37+
},
38+
},
39+
},
40+
Outbounds: []option.Outbound{
41+
{
42+
Type: C.TypeDirect,
43+
},
44+
{
45+
Type: C.TypeShadowsocks,
46+
Tag: "ss-out",
47+
ShadowsocksOptions: option.ShadowsocksOutboundOptions{
48+
ServerOptions: option.ServerOptions{
49+
Server: "127.0.0.1",
50+
ServerPort: serverPort,
51+
},
52+
DialerOptions: option.DialerOptions{
53+
TCPFastOpen: true,
54+
},
55+
Method: method,
56+
Password: password,
57+
},
58+
},
59+
},
60+
Route: &option.RouteOptions{
61+
Rules: []option.Rule{
62+
{
63+
DefaultOptions: option.DefaultRule{
64+
Inbound: []string{"mixed-in"},
65+
Outbound: "ss-out",
66+
},
67+
},
68+
},
69+
},
70+
})
71+
testSuit(t, clientPort, testPort)
72+
}

0 commit comments

Comments
 (0)