Skip to content

Commit 70c8b21

Browse files
committed
Fixed some issue of local dns.
1 parent 2b27a8a commit 70c8b21

3 files changed

Lines changed: 87 additions & 18 deletions

File tree

internal/client/dns_inflight.go

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,25 @@ import (
1313
)
1414

1515
type dnsInflightManager struct {
16-
timeout time.Duration
17-
mu sync.Mutex
18-
items map[string]time.Time
16+
timeout time.Duration
17+
cleanupWindow time.Duration
18+
nextCleanupAt time.Time
19+
mu sync.Mutex
20+
items map[string]time.Time
1921
}
2022

2123
func newDNSInflightManager(timeout time.Duration) *dnsInflightManager {
2224
if timeout <= 0 {
2325
timeout = 30 * time.Second
2426
}
27+
cleanupWindow := timeout / 4
28+
if cleanupWindow < time.Second {
29+
cleanupWindow = time.Second
30+
}
2531
return &dnsInflightManager{
26-
timeout: timeout,
27-
items: make(map[string]time.Time),
32+
timeout: timeout,
33+
cleanupWindow: cleanupWindow,
34+
items: make(map[string]time.Time),
2835
}
2936
}
3037

@@ -37,10 +44,13 @@ func (m *dnsInflightManager) Begin(cacheKey []byte, now time.Time) bool {
3744
defer m.mu.Unlock()
3845

3946
key := string(cacheKey)
40-
for existingKey, createdAt := range m.items {
41-
if now.Sub(createdAt) >= m.timeout {
42-
delete(m.items, existingKey)
47+
if m.nextCleanupAt.IsZero() || !now.Before(m.nextCleanupAt) {
48+
for existingKey, createdAt := range m.items {
49+
if now.Sub(createdAt) >= m.timeout {
50+
delete(m.items, existingKey)
51+
}
4352
}
53+
m.nextCleanupAt = now.Add(m.cleanupWindow)
4454
}
4555

4656
if createdAt, ok := m.items[key]; ok && now.Sub(createdAt) < m.timeout {
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// ==============================================================================
2+
// MasterDnsVPN
3+
// Author: MasterkinG32
4+
// Github: https://github.com/masterking32
5+
// Year: 2026
6+
// ==============================================================================
7+
8+
package client
9+
10+
import (
11+
"testing"
12+
"time"
13+
)
14+
15+
func TestDNSInflightBeginDedupesWithinTimeout(t *testing.T) {
16+
manager := newDNSInflightManager(10 * time.Second)
17+
now := time.Unix(1700000000, 0)
18+
key := []byte("example")
19+
20+
if !manager.Begin(key, now) {
21+
t.Fatal("first begin should succeed")
22+
}
23+
if manager.Begin(key, now.Add(5*time.Second)) {
24+
t.Fatal("second begin within timeout should be deduped")
25+
}
26+
if !manager.Begin(key, now.Add(11*time.Second)) {
27+
t.Fatal("begin after timeout should succeed again")
28+
}
29+
}
30+
31+
func TestDNSInflightCompleteReleasesKey(t *testing.T) {
32+
manager := newDNSInflightManager(10 * time.Second)
33+
now := time.Unix(1700000000, 0)
34+
key := []byte("example")
35+
36+
if !manager.Begin(key, now) {
37+
t.Fatal("first begin should succeed")
38+
}
39+
manager.Complete(key)
40+
if !manager.Begin(key, now.Add(time.Second)) {
41+
t.Fatal("begin after complete should succeed")
42+
}
43+
}

internal/client/local_dns.go

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ import (
1616
)
1717

1818
type localDNSRequest struct {
19-
packet []byte
19+
buffer []byte
20+
size int
2021
addr *net.UDPAddr
2122
}
2223

@@ -44,12 +45,18 @@ func (c *Client) RunLocalDNSListener(ctx context.Context) error {
4445
)
4546

4647
queue := make(chan localDNSRequest, c.cfg.LocalDNSQueueSize)
48+
packetPool := sync.Pool{
49+
New: func() any {
50+
return make([]byte, EDnsSafeUDPSize)
51+
},
52+
}
53+
4754
var workerWG sync.WaitGroup
4855
for range c.cfg.LocalDNSWorkers {
4956
workerWG.Add(1)
5057
go func() {
5158
defer workerWG.Done()
52-
c.localDNSWorker(ctx, conn, queue)
59+
c.localDNSWorker(ctx, conn, queue, &packetPool)
5360
}()
5461
}
5562

@@ -59,28 +66,30 @@ func (c *Client) RunLocalDNSListener(ctx context.Context) error {
5966
}()
6067
go c.runLocalDNSCacheFlushLoop(ctx)
6168

62-
buffer := make([]byte, EDnsSafeUDPSize)
6369
for {
70+
buffer := packetPool.Get().([]byte)
6471
n, addr, err := conn.ReadFromUDP(buffer)
6572
if err != nil {
73+
packetPool.Put(buffer)
6674
if ctx.Err() != nil {
6775
break
6876
}
6977
return err
7078
}
7179

72-
packet := append([]byte(nil), buffer[:n]...)
7380
select {
74-
case queue <- localDNSRequest{packet: packet, addr: addr}:
81+
case queue <- localDNSRequest{buffer: buffer, size: n, addr: addr}:
7582
case <-ctx.Done():
83+
packetPool.Put(buffer)
7684
close(queue)
7785
workerWG.Wait()
7886
return nil
7987
default:
80-
response, _ := DnsParser.BuildServerFailureResponse(packet)
88+
response, _ := DnsParser.BuildServerFailureResponse(buffer[:n])
8189
if len(response) != 0 {
8290
_, _ = conn.WriteToUDP(response, addr)
8391
}
92+
packetPool.Put(buffer)
8493
}
8594
}
8695

@@ -89,7 +98,7 @@ func (c *Client) RunLocalDNSListener(ctx context.Context) error {
8998
return nil
9099
}
91100

92-
func (c *Client) localDNSWorker(ctx context.Context, conn *net.UDPConn, queue <-chan localDNSRequest) {
101+
func (c *Client) localDNSWorker(ctx context.Context, conn *net.UDPConn, queue <-chan localDNSRequest, packetPool *sync.Pool) {
93102
for {
94103
select {
95104
case <-ctx.Done():
@@ -100,11 +109,18 @@ func (c *Client) localDNSWorker(ctx context.Context, conn *net.UDPConn, queue <-
100109
}
101110
func() {
102111
defer func() {
103-
if recover() != nil {
104-
return
112+
if packetPool != nil && req.buffer != nil {
113+
packetPool.Put(req.buffer)
114+
}
115+
if recovered := recover(); recovered != nil && c != nil && c.log != nil {
116+
c.log.Errorf(
117+
"💥 <red>Local DNS Handler Panic Recovered</red> <magenta>|</magenta> <yellow>%v</yellow>",
118+
recovered,
119+
)
105120
}
106121
}()
107-
response, _ := c.handleDNSQueryPacket(req.packet)
122+
123+
response, _ := c.handleDNSQueryPacket(req.buffer[:req.size])
108124
if len(response) != 0 {
109125
_, _ = conn.WriteToUDP(response, req.addr)
110126
}

0 commit comments

Comments
 (0)