@@ -22,7 +22,6 @@ import (
2222 "net/url"
2323 "os"
2424 "path/filepath"
25- "slices"
2625 "strconv"
2726 "strings"
2827 "sync"
@@ -50,12 +49,14 @@ import (
5049var Conf = struct {
5150 DialerTimeout time.Duration
5251 RouterLruSize int
52+ Socks5LruSize int
5353}{
5454 DialerTimeout : time .Second * 8 ,
5555 // A single cache entry represents a single host or DNS name lookup. Make the cache as large as the maximum number
5656 // of clients that access your web site concurrently. Note that setting the cache size too high is a waste of
5757 // memory and degrades performance.
5858 RouterLruSize : 64 ,
59+ Socks5LruSize : 8 ,
5960}
6061
6162// ResolverDns returns a DNS resolver.
@@ -409,6 +410,28 @@ func (l *Locale) ServeSocks5TCP(ctx *Context, cli io.ReadWriteCloser, dst string
409410 return err
410411}
411412
413+ // ServeSocks5UDPRead handles the reading and forwarding of udp data.
414+ func (l * Locale ) ServeSocks5UDPRead (srv io.Reader , bnd * net.UDPConn , app * net.UDPAddr , pre []byte ) error {
415+ var (
416+ buf = make ([]byte , 2048 )
417+ err error
418+ m = len (pre )
419+ n int
420+ )
421+ copy (buf [:m ], pre )
422+ for {
423+ n , err = srv .Read (buf [m :])
424+ if err != nil {
425+ break
426+ }
427+ _ , err = bnd .WriteToUDP (buf [:m + n ], app )
428+ if err != nil {
429+ break
430+ }
431+ }
432+ return err
433+ }
434+
412435// ServeSocks5UDP serves socks5 UDP protocol.
413436func (l * Locale ) ServeSocks5UDP (ctx * Context , cli io.ReadWriteCloser ) error {
414437 var (
@@ -420,7 +443,7 @@ func (l *Locale) ServeSocks5UDP(ctx *Context, cli io.ReadWriteCloser) error {
420443 bndPort uint16
421444 bnd * net.UDPConn
422445 buf = make ([]byte , 2048 )
423- cpl = map [string ] io.ReadWriteCloser {}
446+ cpl = lru. New [string , io.ReadWriteCloser ]( Conf . Socks5LruSize )
424447 dstHost string
425448 dstPort uint16
426449 dst string
@@ -437,6 +460,9 @@ func (l *Locale) ServeSocks5UDP(ctx *Context, cli io.ReadWriteCloser) error {
437460 if err != nil {
438461 return err
439462 }
463+ cpl .Drop = func (k string , v io.ReadWriteCloser ) {
464+ v .Close ()
465+ }
440466
441467 // https://datatracker.ietf.org/doc/html/rfc1928, Page 7, UDP ASSOCIATE:
442468 // A UDP association terminates when the TCP connection that the UDP ASSOCIATE request arrived on terminates.
@@ -492,30 +518,26 @@ func (l *Locale) ServeSocks5UDP(ctx *Context, cli io.ReadWriteCloser) error {
492518 dstPort = binary .BigEndian .Uint16 (appHead [20 :22 ])
493519 }
494520 dst = dstHost + ":" + strconv .Itoa (int (dstPort ))
495- srv = cpl [dst ]
496- if srv == nil {
521+ if ! cpl .Has (dst ) {
497522 log .Printf ("conn: %08x proto format=socks5" , ctx .Cid )
498523 srv , err = l .Dialer .Dial (ctx , "udp" , dst )
499524 if err != nil {
500525 log .Printf ("conn: %08x error %s" , ctx .Cid , err )
501526 continue
502527 }
503- cpl [dst ] = srv
504- retHead := slices .Clone (appHead )
505- go ReadCall (srv , func (data []byte ) error {
506- return doa .Err (bnd .WriteToUDP (append (retHead , data ... ), appAddr ))
507- })
528+ cpl .Set (dst , srv )
529+ go l .ServeSocks5UDPRead (srv , bnd , appAddr , appHead )
508530 }
531+ srv = cpl .Get (dst )
509532 _ , err = srv .Write (buf [appHeadSize :appSize ])
510533 if err != nil {
511534 log .Printf ("conn: %08x error %s" , ctx .Cid , err )
512- srv .Close ()
513- delete (cpl , dst )
535+ cpl .Del (dst )
514536 continue
515537 }
516538 }
517- for _ , e := range cpl {
518- e . Close ( )
539+ for k := range cpl . C {
540+ cpl . Del ( k )
519541 }
520542 return nil
521543}
@@ -1030,25 +1052,6 @@ func (r *RandomReader) Read(p []byte) (int, error) {
10301052 return len (p ), nil
10311053}
10321054
1033- // ReadCall reads data from the given io.Reader and passes it to the provided call function.
1034- func ReadCall (conn io.Reader , call func ([]byte ) error ) error {
1035- var (
1036- buf = make ([]byte , 2048 )
1037- err error
1038- n int
1039- )
1040- for {
1041- n , err = conn .Read (buf )
1042- if err != nil {
1043- break
1044- }
1045- if err = call (buf [:n ]); err != nil {
1046- break
1047- }
1048- }
1049- return err
1050- }
1051-
10521055// Salt converts the stupid password passed in by the user to 32-sized byte array.
10531056func Salt (s string ) []byte {
10541057 h := sha256 .Sum256 ([]byte (s ))
0 commit comments