Skip to content

Commit 6740910

Browse files
committed
Implement dns-hijack
1 parent 06bd3aa commit 6740910

File tree

8 files changed

+252
-108
lines changed

8 files changed

+252
-108
lines changed

cmd/sing-box/cmd_tools.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package main
22

33
import (
4+
"errors"
5+
"os"
6+
47
"github.com/sagernet/sing-box"
58
E "github.com/sagernet/sing/common/exceptions"
69
N "github.com/sagernet/sing/common/network"
@@ -23,7 +26,9 @@ func init() {
2326
func createPreStartedClient() (*box.Box, error) {
2427
options, err := readConfigAndMerge()
2528
if err != nil {
26-
return nil, err
29+
if !(errors.Is(err, os.ErrNotExist) && len(configDirectories) == 0 && len(configPaths) == 1) || configPaths[0] != "config.json" {
30+
return nil, err
31+
}
2732
}
2833
instance, err := box.New(box.Options{Options: options})
2934
if err != nil {

go.mod

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ require (
2727
github.com/sagernet/gvisor v0.0.0-20241021032506-a4324256e4a3
2828
github.com/sagernet/quic-go v0.48.0-beta.1
2929
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
30-
github.com/sagernet/sing v0.5.0-rc.4.0.20241022031908-cd17884118cb
31-
github.com/sagernet/sing-dns v0.3.0-rc.2.0.20241021154031-a59e0fbba3ce
30+
github.com/sagernet/sing v0.5.0-rc.4.0.20241023053048-94f058276959
31+
github.com/sagernet/sing-dns v0.3.0-rc.2.0.20241023053951-feb6d5403f2a
3232
github.com/sagernet/sing-mux v0.2.1-0.20241020175909-fe6153f7a9ec
3333
github.com/sagernet/sing-quic v0.3.0-rc.1
3434
github.com/sagernet/sing-shadowsocks v0.2.7
3535
github.com/sagernet/sing-shadowsocks2 v0.2.0
3636
github.com/sagernet/sing-shadowtls v0.1.4
37-
github.com/sagernet/sing-tun v0.4.0-rc.4.0.20241022132441-8ae8c915af9e
37+
github.com/sagernet/sing-tun v0.4.0-rc.4.0.20241023054150-3b5b396d06f7
3838
github.com/sagernet/sing-vmess v0.1.12
3939
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7
4040
github.com/sagernet/utls v1.6.7
@@ -55,8 +55,6 @@ require (
5555
howett.net/plist v1.0.1
5656
)
5757

58-
//replace github.com/sagernet/sing => ../sing
59-
6058
require (
6159
github.com/ajg/form v1.5.1 // indirect
6260
github.com/andybalholm/brotli v1.0.6 // indirect

go.sum

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,10 @@ github.com/sagernet/quic-go v0.48.0-beta.1/go.mod h1:1WgdDIVD1Gybp40JTWketeSfKA/
115115
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byLGkEnIYp6grlXfo1QYUfiYFGjewIdc=
116116
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
117117
github.com/sagernet/sing v0.2.18/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
118-
github.com/sagernet/sing v0.5.0-rc.4.0.20241022031908-cd17884118cb h1:3IhGq2UmcbQfAcuqyE8RYKFapqEEa3eItS/MrZr+5l8=
119-
github.com/sagernet/sing v0.5.0-rc.4.0.20241022031908-cd17884118cb/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
120-
github.com/sagernet/sing-dns v0.3.0-rc.2.0.20241021154031-a59e0fbba3ce h1:OfpxE5qnXMyU/9LtNgX4M7bGP11lJx4s+KZ3Sijb0HE=
121-
github.com/sagernet/sing-dns v0.3.0-rc.2.0.20241021154031-a59e0fbba3ce/go.mod h1:TqLIelI+FAbVEdiTRolhGLOwvhVjY7oT+wezlOJUQ7M=
118+
github.com/sagernet/sing v0.5.0-rc.4.0.20241023053048-94f058276959 h1:8BzTt5cU8h6HK4CcRq1UQHKsgUi942GjO0by/ntFZIs=
119+
github.com/sagernet/sing v0.5.0-rc.4.0.20241023053048-94f058276959/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
120+
github.com/sagernet/sing-dns v0.3.0-rc.2.0.20241023053951-feb6d5403f2a h1:jpAlbmZxc1LymZrmJacsvHI57Wito5xy8qASZJMWoOQ=
121+
github.com/sagernet/sing-dns v0.3.0-rc.2.0.20241023053951-feb6d5403f2a/go.mod h1:TqLIelI+FAbVEdiTRolhGLOwvhVjY7oT+wezlOJUQ7M=
122122
github.com/sagernet/sing-mux v0.2.1-0.20241020175909-fe6153f7a9ec h1:6Fd/VsEsw9qIjaGi1IBTZSb4b4v5JYtNcoiBtGsQC48=
123123
github.com/sagernet/sing-mux v0.2.1-0.20241020175909-fe6153f7a9ec/go.mod h1:RSwqqHwbtTOX3vs6ms8vMtBGH/0ZNyLm/uwt6TlmR84=
124124
github.com/sagernet/sing-quic v0.3.0-rc.1 h1:SlzL1yfEAKJyRduub8vzOVtbyTLAX7RZEEBZxO5utts=
@@ -129,8 +129,8 @@ github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wK
129129
github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
130130
github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k=
131131
github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4=
132-
github.com/sagernet/sing-tun v0.4.0-rc.4.0.20241022132441-8ae8c915af9e h1:dKvwQKyNc6/tfwsCU3vlvZo1zwGC9ztsJ3qiQghhBpA=
133-
github.com/sagernet/sing-tun v0.4.0-rc.4.0.20241022132441-8ae8c915af9e/go.mod h1:ZDv85YIANyV7ZTuHx9Vn3dBiEBjuOnebVrL7ccXC9CM=
132+
github.com/sagernet/sing-tun v0.4.0-rc.4.0.20241023054150-3b5b396d06f7 h1:wWfRBSP8v0Gc9yUeMgoKCiG+LIs/+bYLWWwVVYSbGFI=
133+
github.com/sagernet/sing-tun v0.4.0-rc.4.0.20241023054150-3b5b396d06f7/go.mod h1:2v1L3BQKzoOpGuKMwC6pcs/5/Xb5PBqzqL6Lq88IoS8=
134134
github.com/sagernet/sing-vmess v0.1.12 h1:2gFD8JJb+eTFMoa8FIVMnknEi+vCSfaiTXTfEYAYAPg=
135135
github.com/sagernet/sing-vmess v0.1.12/go.mod h1:luTSsfyBGAc9VhtCqwjR+dt1QgqBhuYBCONB/POhF8I=
136136
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=

inbound/tun.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ type TUN struct {
3535
router adapter.Router
3636
logger log.ContextLogger
3737
// Deprecated
38-
inboundOptions option.InboundOptions
39-
tunOptions tun.Options
38+
inboundOptions option.InboundOptions
39+
tunOptions tun.Options
40+
// Deprecated
4041
endpointIndependentNat bool
4142
udpTimeout time.Duration
4243
stack string
@@ -316,7 +317,6 @@ func (t *TUN) Start() error {
316317
Context: t.ctx,
317318
Tun: tunInterface,
318319
TunOptions: t.tunOptions,
319-
EndpointIndependentNat: t.endpointIndependentNat,
320320
UDPTimeout: t.udpTimeout,
321321
Handler: t,
322322
Logger: t.logger,

outbound/dns.go

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding/binary"
66
"net"
77
"os"
8+
"time"
89

910
"github.com/sagernet/sing-box/adapter"
1011
C "github.com/sagernet/sing-box/constant"
@@ -50,14 +51,15 @@ func (d *DNS) NewConnection(ctx context.Context, conn net.Conn, metadata adapter
5051
metadata.Destination = M.Socksaddr{}
5152
defer conn.Close()
5253
for {
53-
err := d.handleConnection(ctx, conn, metadata)
54+
conn.SetReadDeadline(time.Now().Add(C.DNSTimeout))
55+
err := HandleStreamDNSRequest(ctx, d.router, conn, metadata)
5456
if err != nil {
5557
return err
5658
}
5759
}
5860
}
5961

60-
func (d *DNS) handleConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
62+
func HandleStreamDNSRequest(ctx context.Context, router adapter.Router, conn net.Conn, metadata adapter.InboundContext) error {
6163
var queryLength uint16
6264
err := binary.Read(conn, binary.BigEndian, &queryLength)
6365
if err != nil {
@@ -79,7 +81,7 @@ func (d *DNS) handleConnection(ctx context.Context, conn net.Conn, metadata adap
7981
}
8082
metadataInQuery := metadata
8183
go func() error {
82-
response, err := d.router.Exchange(adapter.WithContext(ctx, &metadataInQuery), &message)
84+
response, err := router.Exchange(adapter.WithContext(ctx, &metadataInQuery), &message)
8385
if err != nil {
8486
return err
8587
}
@@ -100,10 +102,14 @@ func (d *DNS) handleConnection(ctx context.Context, conn net.Conn, metadata adap
100102

101103
// Deprecated
102104
func (d *DNS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
105+
return NewDNSPacketConnection(ctx, d.router, conn, nil, metadata)
106+
}
107+
108+
func NewDNSPacketConnection(ctx context.Context, router adapter.Router, conn N.PacketConn, cachedPackets []*N.PacketBuffer, metadata adapter.InboundContext) error {
103109
metadata.Destination = M.Socksaddr{}
104110
var reader N.PacketReader = conn
105111
var counters []N.CountFunc
106-
var cachedPackets []*N.PacketBuffer
112+
cachedPackets = common.Reverse(cachedPackets)
107113
for {
108114
reader, counters = N.UnwrapCountPacketReader(reader, counters)
109115
if cachedReader, isCached := reader.(N.CachedPacketReader); isCached {
@@ -115,7 +121,7 @@ func (d *DNS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metada
115121
}
116122
if readWaiter, created := bufio.CreatePacketReadWaiter(reader); created {
117123
readWaiter.InitializeReadWaiter(N.ReadWaitOptions{})
118-
return d.newPacketConnection(ctx, conn, readWaiter, counters, cachedPackets, metadata)
124+
return newDNSPacketConnection(ctx, router, conn, readWaiter, counters, cachedPackets, metadata)
119125
}
120126
break
121127
}
@@ -161,7 +167,7 @@ func (d *DNS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metada
161167
}
162168
metadataInQuery := metadata
163169
go func() error {
164-
response, err := d.router.Exchange(adapter.WithContext(ctx, &metadataInQuery), &message)
170+
response, err := router.Exchange(adapter.WithContext(ctx, &metadataInQuery), &message)
165171
if err != nil {
166172
cancel(err)
167173
return err
@@ -186,7 +192,7 @@ func (d *DNS) NewPacketConnection(ctx context.Context, conn N.PacketConn, metada
186192
return group.Run(fastClose)
187193
}
188194

189-
func (d *DNS) newPacketConnection(ctx context.Context, conn N.PacketConn, readWaiter N.PacketReadWaiter, readCounters []N.CountFunc, cached []*N.PacketBuffer, metadata adapter.InboundContext) error {
195+
func newDNSPacketConnection(ctx context.Context, router adapter.Router, conn N.PacketConn, readWaiter N.PacketReadWaiter, readCounters []N.CountFunc, cached []*N.PacketBuffer, metadata adapter.InboundContext) error {
190196
fastClose, cancel := common.ContextWithCancelCause(ctx)
191197
timeout := canceler.New(fastClose, cancel, C.DNSTimeout)
192198
var group task.Group
@@ -206,11 +212,12 @@ func (d *DNS) newPacketConnection(ctx context.Context, conn N.PacketConn, readWa
206212
}
207213
err = message.Unpack(packet.Buffer.Bytes())
208214
packet.Buffer.Release()
215+
destination = packet.Destination
216+
N.PutPacketBuffer(packet)
209217
if err != nil {
210218
cancel(err)
211219
return err
212220
}
213-
destination = packet.Destination
214221
} else {
215222
buffer, destination, err = readWaiter.WaitReadPacket()
216223
if err != nil {
@@ -230,7 +237,7 @@ func (d *DNS) newPacketConnection(ctx context.Context, conn N.PacketConn, readWa
230237
}
231238
metadataInQuery := metadata
232239
go func() error {
233-
response, err := d.router.Exchange(adapter.WithContext(ctx, &metadataInQuery), &message)
240+
response, err := router.Exchange(adapter.WithContext(ctx, &metadataInQuery), &message)
234241
if err != nil {
235242
cancel(err)
236243
return err

route/dns.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package route
2+
3+
import (
4+
"context"
5+
"net"
6+
"time"
7+
8+
"github.com/sagernet/sing-box/adapter"
9+
C "github.com/sagernet/sing-box/constant"
10+
"github.com/sagernet/sing-box/outbound"
11+
"github.com/sagernet/sing-dns"
12+
"github.com/sagernet/sing/common/buf"
13+
E "github.com/sagernet/sing/common/exceptions"
14+
M "github.com/sagernet/sing/common/metadata"
15+
N "github.com/sagernet/sing/common/network"
16+
"github.com/sagernet/sing/common/udpnat2"
17+
18+
mDNS "github.com/miekg/dns"
19+
)
20+
21+
func (r *Router) hijackDNSStream(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
22+
metadata.Destination = M.Socksaddr{}
23+
for {
24+
conn.SetReadDeadline(time.Now().Add(C.DNSTimeout))
25+
err := outbound.HandleStreamDNSRequest(ctx, r, conn, metadata)
26+
if err != nil {
27+
return err
28+
}
29+
}
30+
}
31+
32+
func (r *Router) hijackDNSPacket(ctx context.Context, conn N.PacketConn, packetBuffers []*N.PacketBuffer, metadata adapter.InboundContext) {
33+
if uConn, isUDPNAT2 := conn.(*udpnat.Conn); isUDPNAT2 {
34+
metadata.Destination = M.Socksaddr{}
35+
for _, packet := range packetBuffers {
36+
buffer := packet.Buffer
37+
destination := packet.Destination
38+
N.PutPacketBuffer(packet)
39+
go ExchangeDNSPacket(ctx, r, uConn, buffer, metadata, destination)
40+
}
41+
uConn.SetHandler(&dnsHijacker{
42+
router: r,
43+
conn: conn,
44+
ctx: ctx,
45+
metadata: metadata,
46+
})
47+
return
48+
}
49+
err := outbound.NewDNSPacketConnection(ctx, r, conn, packetBuffers, metadata)
50+
if err != nil && !E.IsClosedOrCanceled(err) {
51+
r.dnsLogger.ErrorContext(ctx, E.Cause(err, "process packet connection"))
52+
}
53+
}
54+
55+
func ExchangeDNSPacket(ctx context.Context, router *Router, conn N.PacketConn, buffer *buf.Buffer, metadata adapter.InboundContext, destination M.Socksaddr) {
56+
err := exchangeDNSPacket(ctx, router, conn, buffer, metadata, destination)
57+
if err != nil && !E.IsClosedOrCanceled(err) {
58+
router.dnsLogger.ErrorContext(ctx, E.Cause(err, "process packet connection"))
59+
}
60+
}
61+
62+
func exchangeDNSPacket(ctx context.Context, router *Router, conn N.PacketConn, buffer *buf.Buffer, metadata adapter.InboundContext, destination M.Socksaddr) error {
63+
var message mDNS.Msg
64+
err := message.Unpack(buffer.Bytes())
65+
buffer.Release()
66+
if err != nil {
67+
return E.Cause(err, "unpack request")
68+
}
69+
response, err := router.Exchange(adapter.WithContext(ctx, &metadata), &message)
70+
if err != nil {
71+
return err
72+
}
73+
responseBuffer, err := dns.TruncateDNSMessage(&message, response, 1024)
74+
if err != nil {
75+
return err
76+
}
77+
err = conn.WritePacket(responseBuffer, destination)
78+
responseBuffer.Release()
79+
return err
80+
}
81+
82+
type dnsHijacker struct {
83+
router *Router
84+
conn N.PacketConn
85+
ctx context.Context
86+
metadata adapter.InboundContext
87+
}
88+
89+
func (h *dnsHijacker) NewPacketEx(buffer *buf.Buffer, destination M.Socksaddr) {
90+
go ExchangeDNSPacket(h.ctx, h.router, h.conn, buffer, h.metadata, destination)
91+
}

0 commit comments

Comments
 (0)