@@ -13,7 +13,6 @@ import (
1313 "encoding/binary"
1414 "errors"
1515 "sync"
16- "time"
1716
1817 DnsParser "masterdnsvpn-go/internal/dnsparser"
1918 Enums "masterdnsvpn-go/internal/enums"
@@ -31,10 +30,7 @@ const (
3130 defaultUploadMaxCap = 512
3231)
3332
34- type MTUResult struct {
35- UploadBytes int
36- DownloadBytes int
37- }
33+ const mtuProbeFillPattern = "MasterDnsVPN-MTU-Probe-Fill-Pattern-2026"
3834
3935func (c * Client ) RunInitialMTUTests () error {
4036 if len (c .connections ) == 0 {
@@ -51,14 +47,12 @@ func (c *Client) RunInitialMTUTests() error {
5147 jobs := make (chan int , len (c .connections ))
5248 var wg sync.WaitGroup
5349 for range workerCount {
54- wg .Add (1 )
55- go func () {
56- defer wg .Done ()
50+ wg .Go (func () {
5751 for idx := range jobs {
5852 conn := & c .connections [idx ]
5953 c .safeRunConnectionMTUTest (conn , uploadCaps [conn .Domain ])
6054 }
61- }( )
55+ })
6256 }
6357 for idx := range c .connections {
6458 jobs <- idx
@@ -67,22 +61,16 @@ func (c *Client) RunInitialMTUTests() error {
6761 wg .Wait ()
6862 }
6963
70- validCount := 0
71- for _ , conn := range c .connections {
72- if conn .IsValid {
73- validCount ++
74- }
75- }
76-
7764 c .balancer .RefreshValidConnections ()
65+ validCount , minUpload , minDownload , minUploadChars := summarizeConnectionMTUStats (c .connections , c )
7866 if validCount == 0 {
7967 return ErrNoValidConnections
8068 }
8169
8270 c .successMTUChecks = true
83- c .syncedUploadMTU = minConnectionMTU ( c . connections , true )
84- c .syncedDownloadMTU = minConnectionMTU ( c . connections , false )
85- c .syncedUploadChars = minConnectionUploadChars ( c . connections , c )
71+ c .syncedUploadMTU = minUpload
72+ c .syncedDownloadMTU = minDownload
73+ c .syncedUploadChars = minUploadChars
8674 c .initResolverRecheckMeta ()
8775 c .updateMaxPackedBlocks ()
8876 return nil
@@ -194,21 +182,15 @@ func (c *Client) binarySearchMTU(minValue, maxValue int, testFn func(int) (bool,
194182 return 0
195183 }
196184
197- cache := make (map [int ]bool , 8 )
198185 check := func (value int ) bool {
199- if cached , ok := cache [value ]; ok {
200- return cached
201- }
202-
203186 ok := false
204- for attempt := 0 ; attempt < max ( 1 , c . cfg . MTUTestRetries ) ; attempt ++ {
187+ for attempt := 0 ; attempt < c . mtuTestRetries ; attempt ++ {
205188 passed , err := testFn (value )
206189 if err == nil && passed {
207190 ok = true
208191 break
209192 }
210193 }
211- cache [value ] = ok
212194 return ok
213195 }
214196
@@ -242,33 +224,22 @@ func (c *Client) sendUploadMTUProbe(conn *Connection, probeTransport *udpQueryTr
242224 return false , nil
243225 }
244226
245- payload := make ([]byte , mtuSize )
246- payload [0 ] = mtuProbeRawResponse
247- if c .cfg .BaseEncodeData {
248- payload [0 ] = mtuProbeBase64Reply
249- }
250- code , err := randomBytes (mtuProbeCodeLength )
227+ payload , code , useBase64 , err := c .buildMTUProbePayload (mtuSize , 0 )
251228 if err != nil {
252229 return false , err
253230 }
254- copy (payload [1 :1 + mtuProbeCodeLength ], code )
255- if len (payload ) > 1 + mtuProbeCodeLength {
256- if _ , err := rand .Read (payload [1 + mtuProbeCodeLength :]); err != nil {
257- return false , err
258- }
259- }
260231
261232 query , err := c .buildMTUProbeQuery (conn .Domain , Enums .PACKET_MTU_UP_REQ , payload )
262233 if err != nil {
263234 return false , nil
264235 }
265236
266- response , err := exchangeUDPQuery (probeTransport , query , time . Duration ( c . cfg . MTUTestTimeout * float64 ( time . Second )) )
237+ response , err := exchangeUDPQuery (probeTransport , query , c . mtuTestTimeout )
267238 if err != nil {
268239 return false , nil
269240 }
270241
271- packet , err := DnsParser .ExtractVPNResponse (response , payload [ 0 ] == mtuProbeBase64Reply )
242+ packet , err := DnsParser .ExtractVPNResponse (response , useBase64 )
272243 if err != nil {
273244 return false , nil
274245 }
@@ -293,34 +264,23 @@ func (c *Client) sendDownloadMTUProbe(conn *Connection, probeTransport *udpQuery
293264 }
294265
295266 requestLen := max (1 + mtuProbeCodeLength + 2 , uploadMTU )
296- payload := make ([]byte , requestLen )
297- payload [0 ] = mtuProbeRawResponse
298- if c .cfg .BaseEncodeData {
299- payload [0 ] = mtuProbeBase64Reply
300- }
301- code , err := randomBytes (mtuProbeCodeLength )
267+ payload , code , useBase64 , err := c .buildMTUProbePayload (requestLen , 2 )
302268 if err != nil {
303269 return false , err
304270 }
305- copy (payload [1 :1 + mtuProbeCodeLength ], code )
306271 binary .BigEndian .PutUint16 (payload [1 + mtuProbeCodeLength :1 + mtuProbeCodeLength + 2 ], uint16 (mtuSize ))
307- if len (payload ) > 1 + mtuProbeCodeLength + 2 {
308- if _ , err := rand .Read (payload [1 + mtuProbeCodeLength + 2 :]); err != nil {
309- return false , err
310- }
311- }
312272
313273 query , err := c .buildMTUProbeQuery (conn .Domain , Enums .PACKET_MTU_DOWN_REQ , payload )
314274 if err != nil {
315275 return false , nil
316276 }
317277
318- response , err := exchangeUDPQuery (probeTransport , query , time . Duration ( c . cfg . MTUTestTimeout * float64 ( time . Second )) )
278+ response , err := exchangeUDPQuery (probeTransport , query , c . mtuTestTimeout )
319279 if err != nil {
320280 return false , nil
321281 }
322282
323- packet , err := DnsParser .ExtractVPNResponse (response , payload [ 0 ] == mtuProbeBase64Reply )
283+ packet , err := DnsParser .ExtractVPNResponse (response , useBase64 )
324284 if err != nil {
325285 return false , nil
326286 }
@@ -400,6 +360,43 @@ func (c *Client) canBuildUploadPayload(domain string, payloadLen int) bool {
400360 return err == nil
401361}
402362
363+ func (c * Client ) buildMTUProbePayload (length int , reservedTailPrefix int ) ([]byte , []byte , bool , error ) {
364+ if length <= 0 {
365+ return nil , nil , false , nil
366+ }
367+
368+ payload := make ([]byte , length )
369+ useBase64 := c != nil && c .cfg .BaseEncodeData
370+ payload [0 ] = mtuProbeRawResponse
371+ if useBase64 {
372+ payload [0 ] = mtuProbeBase64Reply
373+ }
374+
375+ code , err := randomBytes (mtuProbeCodeLength )
376+ if err != nil {
377+ return nil , nil , false , err
378+ }
379+ copy (payload [1 :1 + mtuProbeCodeLength ], code )
380+
381+ fillOffset := 1 + mtuProbeCodeLength + reservedTailPrefix
382+ if fillOffset < len (payload ) {
383+ fillMTUProbeBytes (payload [fillOffset :])
384+ }
385+
386+ return payload , code , useBase64 , nil
387+ }
388+
389+ func fillMTUProbeBytes (dst []byte ) {
390+ if len (dst ) == 0 {
391+ return
392+ }
393+ pattern := mtuProbeFillPattern
394+ offset := 0
395+ for offset < len (dst ) {
396+ offset += copy (dst [offset :], pattern )
397+ }
398+ }
399+
403400func randomBytes (length int ) ([]byte , error ) {
404401 if length <= 0 {
405402 return []byte {}, nil
@@ -411,41 +408,28 @@ func randomBytes(length int) ([]byte, error) {
411408 return buf , nil
412409}
413410
414- func minConnectionMTU (connections []Connection , upload bool ) int {
415- best := 0
411+ func summarizeConnectionMTUStats (connections []Connection , c * Client ) (validCount int , minUpload int , minDownload int , minUploadChars int ) {
416412 for _ , conn := range connections {
417413 if ! conn .IsValid {
418414 continue
419415 }
420- value := conn .DownloadMTUBytes
421- if upload {
422- value = conn .UploadMTUBytes
423- }
424- if value <= 0 {
425- continue
416+ validCount ++
417+
418+ if conn .UploadMTUBytes > 0 && (minUpload == 0 || conn .UploadMTUBytes < minUpload ) {
419+ minUpload = conn .UploadMTUBytes
426420 }
427- if best == 0 || value < best {
428- best = value
421+ if conn . DownloadMTUBytes > 0 && ( minDownload == 0 || conn . DownloadMTUBytes < minDownload ) {
422+ minDownload = conn . DownloadMTUBytes
429423 }
430- }
431- return best
432- }
433-
434- func minConnectionUploadChars (connections []Connection , c * Client ) int {
435- best := 0
436- for _ , conn := range connections {
437- if ! conn .IsValid || conn .UploadMTUBytes <= 0 {
424+ if conn .UploadMTUBytes <= 0 || c == nil {
438425 continue
439426 }
440427 value := c .encodedCharsForPayload (conn .UploadMTUBytes )
441- if value <= 0 {
442- continue
443- }
444- if best == 0 || value < best {
445- best = value
428+ if value > 0 && (minUploadChars == 0 || value < minUploadChars ) {
429+ minUploadChars = value
446430 }
447431 }
448- return best
432+ return validCount , minUpload , minDownload , minUploadChars
449433}
450434
451435func (c * Client ) encodedCharsForPayload (payloadLen int ) int {
0 commit comments