mirror of
https://github.com/fumiama/dnskip.git
synced 2026-06-05 00:32:41 +08:00
init
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.DS_Dtore
|
||||||
7
README.md
Normal file
7
README.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# dnskip
|
||||||
|
A simple Golang DoT proxy using TRS.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
```bash
|
||||||
|
go run -ldflags "-checklinkname=0" main.go
|
||||||
|
```
|
||||||
17
go.mod
Normal file
17
go.mod
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
module dnskip
|
||||||
|
|
||||||
|
go 1.20
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/FloatTech/ttl v0.0.0-20250224045156-012b1463287d
|
||||||
|
github.com/fumiama/orbyte v0.0.0-20251002065953-3bb358367eb5
|
||||||
|
github.com/fumiama/terasu v0.0.0-20251003064740-9974bdca12ab
|
||||||
|
github.com/sirupsen/logrus v1.9.3
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/RomiChan/syncx v0.0.0-20240418144900-b7402ffdebc7 // indirect
|
||||||
|
golang.org/x/net v0.24.0 // indirect
|
||||||
|
golang.org/x/sys v0.19.0 // indirect
|
||||||
|
golang.org/x/text v0.14.0 // indirect
|
||||||
|
)
|
||||||
28
go.sum
Normal file
28
go.sum
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
github.com/FloatTech/ttl v0.0.0-20250224045156-012b1463287d h1:mUQ/c3wXKsUGa4Sg9DBy01APXKB68PmobhxOyaJI7lY=
|
||||||
|
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=
|
||||||
|
github.com/fumiama/orbyte v0.0.0-20251002065953-3bb358367eb5/go.mod h1:FOjdw7KdCbK2eH3gRPhwFNCoXKpu9sN5vPH4El/8e0c=
|
||||||
|
github.com/fumiama/terasu v0.0.0-20251003064740-9974bdca12ab h1:PPc1fEgQzQJKl2n9DtiAP0e5DDoRpLSe7780m74K174=
|
||||||
|
github.com/fumiama/terasu v0.0.0-20251003064740-9974bdca12ab/go.mod h1:ltlQhbPE0423K0bNQxJdhtkYgFxXstUobc8k+9LFY88=
|
||||||
|
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=
|
||||||
|
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
||||||
|
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||||
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||||
|
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
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=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
175
main.go
Normal file
175
main.go
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/binary"
|
||||||
|
"flag"
|
||||||
|
"io"
|
||||||
|
"math"
|
||||||
|
"net"
|
||||||
|
"net/netip"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/FloatTech/ttl"
|
||||||
|
"github.com/fumiama/orbyte/pbuf"
|
||||||
|
"github.com/fumiama/terasu"
|
||||||
|
"github.com/fumiama/terasu/dns"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
iphost := flag.String("l", "127.0.0.1:5345", "listen DNS UDP port")
|
||||||
|
frag := flag.Uint("frag", 3, "TLS first fragemt size")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if frag != nil {
|
||||||
|
terasu.DefaultFirstFragmentLen = uint8(*frag)
|
||||||
|
}
|
||||||
|
|
||||||
|
addrport, err := netip.ParseAddrPort(*iphost)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal("ParseAddrPort err:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
laddr := net.UDPAddrFromAddrPort(addrport)
|
||||||
|
|
||||||
|
RECONN:
|
||||||
|
conn, err := net.ListenUDP("udp", laddr)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal("ListenUDP err:", err)
|
||||||
|
}
|
||||||
|
logrus.Infoln("Listen at", conn.LocalAddr())
|
||||||
|
|
||||||
|
// server loop
|
||||||
|
buf := make([]byte, 65536)
|
||||||
|
for {
|
||||||
|
n, addr, err := conn.ReadFromUDP(buf)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnln("ReadFromUDP err:", err)
|
||||||
|
goto RECONN
|
||||||
|
}
|
||||||
|
logrus.Debugln("ReadFromUDP from", addr, "with", n, "bytes payload")
|
||||||
|
payload := pbuf.NewBytes(n)
|
||||||
|
payload.V(func(b []byte) { copy(b, buf[:n]) })
|
||||||
|
cnt := lockfree()
|
||||||
|
if cnt == math.MaxUint8 {
|
||||||
|
logrus.Warnln("Drop request from", addr, "due to rate limit")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
go response(cnt, conn, addr, payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func response(cnt uint8, conn *net.UDPConn, addr *net.UDPAddr, payload pbuf.Bytes) {
|
||||||
|
defer releasefree(cnt)
|
||||||
|
logrus.Debugln(addr, "Run on lock", cnt)
|
||||||
|
|
||||||
|
loopcnt := 0
|
||||||
|
REDAIL:
|
||||||
|
tlsconn, err := dialtls(cnt)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnln(addr, "Dial DNS server err:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logrus.Debugln(addr, "Dial to DNS server", tlsconn.RemoteAddr())
|
||||||
|
|
||||||
|
payload.V(func(b []byte) {
|
||||||
|
var plen [2]byte
|
||||||
|
binary.BigEndian.PutUint16(plen[:], uint16(len(b)))
|
||||||
|
_, err = io.Copy(tlsconn, &net.Buffers{plen[:], b})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logrus.Debugln(addr, "Write to DNS server", tlsconn.RemoteAddr())
|
||||||
|
pbuf.BufferItemToBytes(pbuf.NewBuffer(nil).P(func(b *pbuf.Buffer) {
|
||||||
|
var plen [2]byte
|
||||||
|
_, err = io.ReadFull(tlsconn, plen[:])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
payloadlen := int64(binary.BigEndian.Uint16(plen[:]))
|
||||||
|
logrus.Debugln(addr, "Read payload len", payloadlen, "from DNS server", tlsconn.RemoteAddr())
|
||||||
|
_, err = io.CopyN(b, tlsconn, payloadlen)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logrus.Debugln(addr, "Read", b.Len(), "bytes from DNS server", tlsconn.RemoteAddr())
|
||||||
|
})).V(func(b []byte) {
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = conn.WriteToUDP(b, addr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logrus.Debugln("Write response to", addr)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnln(addr, "Proxy to DNS server err:", err)
|
||||||
|
tlsconnCache.Delete(cnt)
|
||||||
|
loopcnt++
|
||||||
|
if loopcnt < 3 {
|
||||||
|
goto REDAIL
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lockfree is spin update
|
||||||
|
func lockfree() uint8 {
|
||||||
|
old := atomic.LoadUintptr(&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))
|
||||||
|
if ok {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
// update latest
|
||||||
|
old = atomic.LoadUintptr(&freeconn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return math.MaxUint8
|
||||||
|
}
|
||||||
|
|
||||||
|
// releasefree is spin update
|
||||||
|
func releasefree(i uint8) {
|
||||||
|
old := atomic.LoadUintptr(&freeconn)
|
||||||
|
for old&(1<<i) != 0 { // is not free
|
||||||
|
ok := atomic.CompareAndSwapUintptr(&freeconn, old, old&^(1<<i))
|
||||||
|
if ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// update latest
|
||||||
|
old = atomic.LoadUintptr(&freeconn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dialtls(cnt uint8) (net.Conn, error) {
|
||||||
|
conn := tlsconnCache.Get(cnt)
|
||||||
|
if conn != nil {
|
||||||
|
logrus.Debugln("Lock", cnt, "get cached tls conn to", conn.RemoteAddr())
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
// dummy nw and addr
|
||||||
|
conn, err := dns.DefaultResolver.Dial(context.Background(), "", "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tlsconnCache.Set(cnt, conn)
|
||||||
|
logrus.Debugln("Lock", cnt, "set new tls conn to", conn.RemoteAddr())
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user