Skip to content

Commit 7c4304c

Browse files
committed
Basic of Base_ENCODE64
1 parent 8cbb1a8 commit 7c4304c

7 files changed

Lines changed: 261 additions & 23 deletions

File tree

internal/basecodec/rawbase64.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// ==============================================================================
2+
// MasterDnsVPN
3+
// Author: MasterkinG32
4+
// Github: https://github.com/masterking32
5+
// Year: 2026
6+
// ==============================================================================
7+
8+
package basecodec
9+
10+
import "encoding/base64"
11+
12+
func EncodeRawBase64(data []byte) []byte {
13+
if len(data) == 0 {
14+
return []byte{}
15+
}
16+
17+
out := make([]byte, base64.RawStdEncoding.EncodedLen(len(data)))
18+
base64.RawStdEncoding.Encode(out, data)
19+
return out
20+
}
21+
22+
func DecodeRawBase64(data []byte) ([]byte, error) {
23+
if len(data) == 0 {
24+
return []byte{}, nil
25+
}
26+
27+
out := make([]byte, base64.RawStdEncoding.DecodedLen(len(data)))
28+
n, err := base64.RawStdEncoding.Decode(out, data)
29+
if err != nil {
30+
return nil, err
31+
}
32+
return out[:n], nil
33+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// ==============================================================================
2+
// MasterDnsVPN
3+
// Author: MasterkinG32
4+
// Github: https://github.com/masterking32
5+
// Year: 2026
6+
// ==============================================================================
7+
8+
package basecodec
9+
10+
import (
11+
"bytes"
12+
"testing"
13+
)
14+
15+
func TestRawBase64RoundTrip(t *testing.T) {
16+
original := []byte("MasterDnsVPN-response-payload-1234+/")
17+
encoded := EncodeRawBase64(original)
18+
decoded, err := DecodeRawBase64(encoded)
19+
if err != nil {
20+
t.Fatalf("DecodeRawBase64 returned error: %v", err)
21+
}
22+
if !bytes.Equal(decoded, original) {
23+
t.Fatalf("unexpected round trip result: got=%q want=%q", decoded, original)
24+
}
25+
}
26+
27+
func TestRawBase64Empty(t *testing.T) {
28+
encoded := EncodeRawBase64(nil)
29+
if len(encoded) != 0 {
30+
t.Fatalf("unexpected encoded len: got=%d want=0", len(encoded))
31+
}
32+
33+
decoded, err := DecodeRawBase64(nil)
34+
if err != nil {
35+
t.Fatalf("DecodeRawBase64 returned error: %v", err)
36+
}
37+
if len(decoded) != 0 {
38+
t.Fatalf("unexpected decoded len: got=%d want=0", len(decoded))
39+
}
40+
}

internal/client/client.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ type Client struct {
3232
enqueueSeq uint64
3333
syncedUploadMTU int
3434
syncedDownloadMTU int
35+
syncedUploadChars int
3536
}
3637

3738
type Connection struct {
@@ -102,6 +103,10 @@ func (c *Client) SyncedDownloadMTU() int {
102103
return c.syncedDownloadMTU
103104
}
104105

106+
func (c *Client) SyncedUploadChars() int {
107+
return c.syncedUploadChars
108+
}
109+
105110
func (c *Client) ResetRuntimeState(resetSessionCookie bool) {
106111
c.enqueueSeq = 0
107112
c.sessionID = 0
@@ -159,7 +164,16 @@ func (c *Client) GetConnectionByKey(serverKey string) (Connection, bool) {
159164
}
160165

161166
func (c *Client) SetConnectionValidity(serverKey string, valid bool) bool {
162-
return c.balancer.SetConnectionValidity(strings.TrimSpace(serverKey), valid)
167+
key := strings.TrimSpace(serverKey)
168+
idx, ok := c.connectionsByKey[key]
169+
if !ok || idx < 0 || idx >= len(c.connections) {
170+
return false
171+
}
172+
if !c.balancer.SetConnectionValidity(key, valid) {
173+
return false
174+
}
175+
c.connections[idx].IsValid = valid
176+
return true
163177
}
164178

165179
func (c *Client) GetBestConnection() (Connection, bool) {

internal/client/client_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,36 @@ func TestResetRuntimeState(t *testing.T) {
6767
t.Fatalf("reset with cookie reset should clear session cookie: got=%d", c.sessionCookie)
6868
}
6969
}
70+
71+
func TestSetConnectionValidityKeepsClientAndBalancerInSync(t *testing.T) {
72+
cfg := config.ClientConfig{
73+
Domains: []string{"a.example.com"},
74+
Resolvers: []config.ResolverAddress{
75+
{IP: "8.8.8.8", Port: 53},
76+
},
77+
}
78+
79+
c := New(cfg, nil, nil)
80+
c.BuildConnectionMap()
81+
key := c.Connections()[0].Key
82+
83+
if !c.SetConnectionValidity(key, false) {
84+
t.Fatal("SetConnectionValidity returned false")
85+
}
86+
if c.Connections()[0].IsValid {
87+
t.Fatal("client connection validity was not updated")
88+
}
89+
if got := c.Balancer().ValidCount(); got != 0 {
90+
t.Fatalf("unexpected valid count after disable: got=%d want=0", got)
91+
}
92+
93+
if !c.SetConnectionValidity(key, true) {
94+
t.Fatal("SetConnectionValidity returned false when re-enabling")
95+
}
96+
if !c.Connections()[0].IsValid {
97+
t.Fatal("client connection validity was not restored")
98+
}
99+
if got := c.Balancer().ValidCount(); got != 1 {
100+
t.Fatalf("unexpected valid count after enable: got=%d want=1", got)
101+
}
102+
}

internal/client/mtu.go

Lines changed: 79 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ type MTUResult struct {
3535
DownloadBytes int
3636
}
3737

38+
type mtuProbeTransport struct {
39+
conn *net.UDPConn
40+
buffer []byte
41+
}
42+
3843
func (c *Client) RunInitialMTUTests() error {
3944
if len(c.connections) == 0 {
4045
return ErrNoValidConnections
@@ -81,6 +86,7 @@ func (c *Client) RunInitialMTUTests() error {
8186
c.successMTUChecks = true
8287
c.syncedUploadMTU = minConnectionMTU(c.connections, true)
8388
c.syncedDownloadMTU = minConnectionMTU(c.connections, false)
89+
c.syncedUploadChars = minConnectionUploadChars(c.connections, c)
8490
return nil
8591
}
8692

@@ -89,13 +95,20 @@ func (c *Client) runConnectionMTUTest(conn *Connection, maxUploadPayload int) {
8995
return
9096
}
9197

92-
upOK, upBytes, err := c.testUploadMTU(conn, maxUploadPayload)
98+
probeTransport, err := c.newMTUProbeTransport(conn)
99+
if err != nil {
100+
conn.IsValid = false
101+
return
102+
}
103+
defer probeTransport.conn.Close()
104+
105+
upOK, upBytes, err := c.testUploadMTU(conn, probeTransport, maxUploadPayload)
93106
if err != nil || !upOK {
94107
conn.IsValid = false
95108
return
96109
}
97110

98-
downOK, downBytes, err := c.testDownloadMTU(conn, upBytes)
111+
downOK, downBytes, err := c.testDownloadMTU(conn, probeTransport, upBytes)
99112
if err != nil || !downOK {
100113
conn.IsValid = false
101114
return
@@ -116,7 +129,7 @@ func (c *Client) precomputeUploadCaps() map[string]int {
116129
return caps
117130
}
118131

119-
func (c *Client) testUploadMTU(conn *Connection, maxPayload int) (bool, int, error) {
132+
func (c *Client) testUploadMTU(conn *Connection, probeTransport *mtuProbeTransport, maxPayload int) (bool, int, error) {
120133
if maxPayload <= 0 {
121134
return false, 0, nil
122135
}
@@ -133,7 +146,7 @@ func (c *Client) testUploadMTU(conn *Connection, maxPayload int) (bool, int, err
133146
c.cfg.MinUploadMTU,
134147
maxPayload,
135148
func(candidate int) (bool, error) {
136-
return c.sendUploadMTUProbe(conn, candidate)
149+
return c.sendUploadMTUProbe(conn, probeTransport, candidate)
137150
},
138151
)
139152
if best < max(defaultMTUMinFloor, c.cfg.MinUploadMTU) {
@@ -142,12 +155,12 @@ func (c *Client) testUploadMTU(conn *Connection, maxPayload int) (bool, int, err
142155
return true, best, nil
143156
}
144157

145-
func (c *Client) testDownloadMTU(conn *Connection, uploadMTU int) (bool, int, error) {
158+
func (c *Client) testDownloadMTU(conn *Connection, probeTransport *mtuProbeTransport, uploadMTU int) (bool, int, error) {
146159
best := c.binarySearchMTU(
147160
c.cfg.MinDownloadMTU,
148161
c.cfg.MaxDownloadMTU,
149162
func(candidate int) (bool, error) {
150-
return c.sendDownloadMTUProbe(conn, candidate, uploadMTU)
163+
return c.sendDownloadMTUProbe(conn, probeTransport, candidate, uploadMTU)
151164
},
152165
)
153166
if best < max(defaultMTUMinFloor, c.cfg.MinDownloadMTU) {
@@ -210,7 +223,7 @@ func (c *Client) binarySearchMTU(minValue, maxValue int, testFn func(int) (bool,
210223
return best
211224
}
212225

213-
func (c *Client) sendUploadMTUProbe(conn *Connection, mtuSize int) (bool, error) {
226+
func (c *Client) sendUploadMTUProbe(conn *Connection, probeTransport *mtuProbeTransport, mtuSize int) (bool, error) {
214227
if mtuSize < 1 {
215228
return false, nil
216229
}
@@ -230,7 +243,7 @@ func (c *Client) sendUploadMTUProbe(conn *Connection, mtuSize int) (bool, error)
230243
return false, nil
231244
}
232245

233-
response, err := c.sendDNSQuery(conn, query)
246+
response, err := c.sendDNSQuery(probeTransport, query)
234247
if err != nil {
235248
return false, nil
236249
}
@@ -245,7 +258,7 @@ func (c *Client) sendUploadMTUProbe(conn *Connection, mtuSize int) (bool, error)
245258
return bytes.Equal(packet.Payload, key), nil
246259
}
247260

248-
func (c *Client) sendDownloadMTUProbe(conn *Connection, mtuSize int, uploadMTU int) (bool, error) {
261+
func (c *Client) sendDownloadMTUProbe(conn *Connection, probeTransport *mtuProbeTransport, mtuSize int, uploadMTU int) (bool, error) {
249262
if mtuSize < defaultMTUMinFloor {
250263
return false, nil
251264
}
@@ -267,7 +280,7 @@ func (c *Client) sendDownloadMTUProbe(conn *Connection, mtuSize int, uploadMTU i
267280
return false, nil
268281
}
269282

270-
response, err := c.sendDNSQuery(conn, query)
283+
response, err := c.sendDNSQuery(probeTransport, query)
271284
if err != nil {
272285
return false, nil
273286
}
@@ -309,7 +322,7 @@ func (c *Client) buildMTUProbeQuery(domain string, packetType uint8, payload []b
309322
return dnsparser.BuildTXTQuestionPacket(name, enums.DNSRecordTypeTXT, ednsSafeUDPSize)
310323
}
311324

312-
func (c *Client) sendDNSQuery(conn *Connection, packet []byte) ([]byte, error) {
325+
func (c *Client) newMTUProbeTransport(conn *Connection) (*mtuProbeTransport, error) {
313326
addr, err := net.ResolveUDPAddr("udp", conn.ResolverLabel)
314327
if err != nil {
315328
return nil, err
@@ -319,25 +332,32 @@ func (c *Client) sendDNSQuery(conn *Connection, packet []byte) ([]byte, error) {
319332
if err != nil {
320333
return nil, err
321334
}
322-
defer udpConn.Close()
335+
return &mtuProbeTransport{
336+
conn: udpConn,
337+
buffer: make([]byte, ednsSafeUDPSize),
338+
}, nil
339+
}
323340

341+
func (c *Client) sendDNSQuery(probeTransport *mtuProbeTransport, packet []byte) ([]byte, error) {
342+
if probeTransport == nil || probeTransport.conn == nil {
343+
return nil, net.ErrClosed
344+
}
324345
timeout := time.Duration(c.cfg.MTUTestTimeout * float64(time.Second))
325346
if timeout <= 0 {
326347
timeout = time.Second
327348
}
328-
if err := udpConn.SetDeadline(time.Now().Add(timeout)); err != nil {
349+
if err := probeTransport.conn.SetDeadline(time.Now().Add(timeout)); err != nil {
329350
return nil, err
330351
}
331-
if _, err := udpConn.Write(packet); err != nil {
352+
if _, err := probeTransport.conn.Write(packet); err != nil {
332353
return nil, err
333354
}
334355

335-
buffer := make([]byte, ednsSafeUDPSize)
336-
n, err := udpConn.Read(buffer)
356+
n, err := probeTransport.conn.Read(probeTransport.buffer)
337357
if err != nil {
338358
return nil, err
339359
}
340-
return append([]byte(nil), buffer[:n]...), nil
360+
return append([]byte(nil), probeTransport.buffer[:n]...), nil
341361
}
342362

343363
func (c *Client) maxUploadMTUPayload(domain string) int {
@@ -416,6 +436,48 @@ func minConnectionMTU(connections []Connection, upload bool) int {
416436
return best
417437
}
418438

439+
func minConnectionUploadChars(connections []Connection, c *Client) int {
440+
best := 0
441+
for _, conn := range connections {
442+
if !conn.IsValid || conn.UploadMTUBytes <= 0 {
443+
continue
444+
}
445+
value := c.encodedCharsForPayload(conn.UploadMTUBytes)
446+
if value <= 0 {
447+
continue
448+
}
449+
if best == 0 || value < best {
450+
best = value
451+
}
452+
}
453+
return best
454+
}
455+
456+
func (c *Client) encodedCharsForPayload(payloadLen int) int {
457+
if payloadLen <= 0 {
458+
return 0
459+
}
460+
payload := make([]byte, payloadLen)
461+
for i := range payload {
462+
payload[i] = 0xAB
463+
}
464+
encoded, err := vpnproto.BuildEncoded(vpnproto.BuildOptions{
465+
SessionID: 255,
466+
PacketType: enums.PacketStreamData,
467+
SessionCookie: 255,
468+
StreamID: 0xFFFF,
469+
SequenceNum: 0xFFFF,
470+
FragmentID: 0xFF,
471+
TotalFragments: 0xFF,
472+
CompressionType: 0xFF,
473+
Payload: payload,
474+
}, c.codec)
475+
if err != nil {
476+
return 0
477+
}
478+
return len(encoded)
479+
}
480+
419481
func max(a, b int) int {
420482
if a > b {
421483
return a

internal/dnsparser/transport.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const (
2828
maxDNSNameLen = 253
2929
maxDNSLabelLen = 63
3030
maxTXTAnswerPayload = 255
31-
maxTXTEncodedChunk = 160
31+
maxTXTEncodedChunk = 191
3232
)
3333

3434
func BuildTXTQuestionPacket(name string, qType uint16, ednsUDPSize uint16) ([]byte, error) {
@@ -241,8 +241,7 @@ func buildTXTAnswerChunks(rawFrame []byte, baseEncode bool) ([][]byte, error) {
241241
if !baseEncode {
242242
return appendLengthPrefixedTXT(raw)
243243
}
244-
encoded := basecodec.EncodeLowerBase36(raw)
245-
return appendLengthPrefixedTXT([]byte(encoded))
244+
return appendLengthPrefixedTXT(basecodec.EncodeRawBase64(raw))
246245
}
247246

248247
if len(rawFrame) <= maxChunk {
@@ -360,7 +359,7 @@ func assembleVPNResponse(rawAnswers [][]byte, baseEncoded bool) (vpnproto.Packet
360359
if len(rawAnswers) == 1 {
361360
raw := rawAnswers[0]
362361
if baseEncoded {
363-
decoded, err := basecodec.DecodeLowerBase36(raw)
362+
decoded, err := basecodec.DecodeRawBase64(raw)
364363
if err != nil {
365364
return vpnproto.Packet{}, err
366365
}
@@ -377,7 +376,7 @@ func assembleVPNResponse(rawAnswers [][]byte, baseEncoded bool) (vpnproto.Packet
377376

378377
for _, raw := range rawAnswers {
379378
if baseEncoded {
380-
decoded, err := basecodec.DecodeLowerBase36(raw)
379+
decoded, err := basecodec.DecodeRawBase64(raw)
381380
if err != nil {
382381
return vpnproto.Packet{}, err
383382
}

0 commit comments

Comments
 (0)