1
0
mirror of https://github.com/fumiama/dnskip.git synced 2026-06-05 00:32:41 +08:00

fix: too many conn in parallel

This commit is contained in:
源文雨
2026-01-20 22:52:24 +08:00
parent d25b80df48
commit 7d1257379b
3 changed files with 71 additions and 50 deletions

12
go.mod
View File

@@ -1,17 +1,17 @@
module github.com/fumiama/dnskip
go 1.22
go 1.24.0
require (
github.com/FloatTech/ttl v0.0.0-20250224045156-012b1463287d
github.com/fumiama/orbyte v0.0.0-20251002065953-3bb358367eb5
github.com/fumiama/terasu v1.0.2
github.com/sirupsen/logrus v1.9.3
github.com/sirupsen/logrus v1.9.4
)
require (
github.com/FloatTech/ttl v0.0.0-20250224045156-012b1463287d // indirect
github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/sys v0.23.0 // indirect
golang.org/x/text v0.17.0 // indirect
golang.org/x/net v0.49.0 // indirect
golang.org/x/sys v0.40.0 // indirect
golang.org/x/text v0.33.0 // indirect
)

26
go.sum
View File

@@ -2,7 +2,6 @@ github.com/FloatTech/ttl v0.0.0-20250224045156-012b1463287d h1:mUQ/c3wXKsUGa4Sg9
github.com/FloatTech/ttl v0.0.0-20250224045156-012b1463287d/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs=
github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7 h1:S/ferNiehVjNaBMNNBxUjLtVmP/YWD6Yh79RfPv4ehU=
github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7/go.mod h1:vD7Ra3Q9onRtojoY5sMCLQ7JBgjUsrXDnDKyFxqpf9w=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fumiama/orbyte v0.0.0-20251002065953-3bb358367eb5 h1:j9o0XVvdAeLwrBYMnh0SerrMc9CgNU6AGszbsvFzoc0=
@@ -11,20 +10,15 @@ github.com/fumiama/terasu v1.0.2 h1:Dxj2vPIgLHyeMlBd61xYHx5Jg8v7k24yg7taNLlK8/8=
github.com/fumiama/terasu v1.0.2/go.mod h1:1eHzpL/GJVcOnqEkh1vUbKu2zo6gojSuueUNJ9yHJE0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

83
main.go
View File

@@ -2,6 +2,7 @@ package main
import (
"context"
"crypto/tls"
"encoding/binary"
"errors"
"flag"
@@ -9,11 +10,12 @@ import (
"math"
"net"
"net/netip"
"runtime"
"sync"
"sync/atomic"
"time"
"unsafe"
"github.com/FloatTech/ttl"
"github.com/fumiama/orbyte/pbuf"
"github.com/fumiama/terasu"
"github.com/fumiama/terasu/dns"
@@ -22,14 +24,6 @@ import (
)
var (
freeconn = uintptr(0)
tlsconnCache = ttl.NewCacheOn(
5*time.Minute, [4]func(uint8, net.Conn){
nil, nil, func(_ uint8, c net.Conn) {
logrus.Warnln("Close idle/error tls conn to", c.RemoteAddr())
_ = c.Close()
}, nil,
})
fallback *net.UDPAddr
forcefb bool
timeout uint
@@ -103,7 +97,8 @@ RECONN:
func response(cnt uint8, conn *net.UDPConn, addr *net.UDPAddr, payload pbuf.Bytes) {
var (
err error
tlsconn net.Conn
cl func()
tlsconn *tls.Conn
loopcnt = 0
ctx context.Context
cancel context.CancelFunc
@@ -114,12 +109,12 @@ func response(cnt uint8, conn *net.UDPConn, addr *net.UDPAddr, payload pbuf.Byte
}
defer releasefree(cnt)
logrus.Debugln(addr, "Run on lock", cnt)
logrus.Debugln(addr, "Run thread", cnt)
REDAIL:
ctx, cancel = context.WithTimeout(context.Background(), time.Second*time.Duration(timeout))
defer cancel()
tlsconn, err = dialtls(cnt, ctx)
tlsconn, cl, err = dialtls(cnt, ctx)
if err != nil {
logrus.Warnln(addr, "Dial DNS server err:", err)
return
@@ -127,6 +122,8 @@ REDAIL:
logrus.Debugln(addr, "Dial to DNS server", tlsconn.RemoteAddr())
payload.V(func(b []byte) {
defer cl()
var plen [2]byte
binary.BigEndian.PutUint16(plen[:], uint16(len(b)))
_, err = io.Copy(tlsconn, &net.Buffers{plen[:], b})
@@ -162,7 +159,10 @@ REDAIL:
return
}
logrus.Warnln(addr, "Proxy to DNS server err:", err)
tlsconnCache.Delete(cnt)
atomic.StorePointer(
(*unsafe.Pointer)(unsafe.Pointer(&remoconn)),
unsafe.Pointer(nil),
)
loopcnt++
if loopcnt < 2 {
goto REDAIL
@@ -214,17 +214,21 @@ FALLBACK:
})
}
var (
freeconn = uint32(0)
)
// lockfree is spin update
func lockfree() uint8 {
old := atomic.LoadUintptr(&freeconn)
old := atomic.LoadUint32(&freeconn)
for i := uint8(0); i < uint8(unsafe.Sizeof(uintptr(0)))*8; i++ {
for old&(1<<i) == 0 { // is free
ok := atomic.CompareAndSwapUintptr(&freeconn, old, old|(1<<i))
ok := atomic.CompareAndSwapUint32(&freeconn, old, old|(1<<i))
if ok {
return i
}
// update latest
old = atomic.LoadUintptr(&freeconn)
old = atomic.LoadUint32(&freeconn)
}
}
return math.MaxUint8
@@ -232,29 +236,52 @@ func lockfree() uint8 {
// releasefree is spin update
func releasefree(i uint8) {
old := atomic.LoadUintptr(&freeconn)
old := atomic.LoadUint32(&freeconn)
for old&(1<<i) != 0 { // is not free
ok := atomic.CompareAndSwapUintptr(&freeconn, old, old&^(1<<i))
ok := atomic.CompareAndSwapUint32(&freeconn, old, old&^(1<<i))
if ok {
return
}
// update latest
old = atomic.LoadUintptr(&freeconn)
old = atomic.LoadUint32(&freeconn)
}
logrus.Debugln("Free thread", i)
}
func dialtls(cnt uint8, ctx context.Context) (net.Conn, error) {
conn := tlsconnCache.Get(cnt)
var (
remoconn *tls.Conn
connmu sync.Mutex
)
func dialtls(cnt uint8, ctx context.Context) (*tls.Conn, func(), error) {
conn := (*tls.Conn)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&remoconn))))
if conn != nil {
logrus.Debugln("Lock", cnt, "get cached tls conn to", conn.RemoteAddr())
return conn, nil
logrus.Debugln("Thread", cnt, "get cached tls conn to", conn.RemoteAddr())
connmu.Lock()
return conn, connmu.Unlock, nil
}
// slow path
connmu.Lock()
conn = (*tls.Conn)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&remoconn))))
if conn != nil {
logrus.Debugln("Thread", cnt, "slowly get cached tls conn to", conn.RemoteAddr())
return conn, connmu.Unlock, nil
}
// dummy nw and addr
conn, err := dns.DefaultResolver.Dial(ctx, "", "")
connintf, err := dns.DefaultResolver.Dial(ctx, "", "")
if err != nil {
return nil, err
connmu.Unlock()
return nil, nil, err
}
tlsconnCache.Set(cnt, conn)
logrus.Debugln("Lock", cnt, "set new tls conn to", conn.RemoteAddr())
return conn, nil
conn = connintf.(*tls.Conn)
atomic.StorePointer(
(*unsafe.Pointer)(unsafe.Pointer(&remoconn)),
unsafe.Pointer(conn),
)
runtime.SetFinalizer(conn, func(conn *tls.Conn) {
logrus.Warnln("Cleanup unused conn to", conn.RemoteAddr())
_ = conn.Close()
})
logrus.Debugln("Thread", cnt, "set new tls conn to", conn.RemoteAddr())
return conn, connmu.Unlock, nil
}