@@ -3,13 +3,16 @@ package tun
33import (
44 "context"
55 "encoding/binary"
6+ "fmt"
67 "io"
78 "net"
89 "sync"
910)
1011
1112type FakeDNSProxy struct {
1213 RealSocksAddr string
14+ SocksUser string
15+ SocksPass string
1316 LocalPort int
1417 dnsMap * DNSMapper
1518 listener net.Listener
@@ -18,16 +21,91 @@ type FakeDNSProxy struct {
1821 wg sync.WaitGroup
1922}
2023
21- func NewFakeDNSProxy (realSocksAddr string , dnsMap * DNSMapper ) * FakeDNSProxy {
24+ func NewFakeDNSProxy (realSocksAddr , socksUser , socksPass string , dnsMap * DNSMapper ) * FakeDNSProxy {
2225 ctx , cancel := context .WithCancel (context .Background ())
2326 return & FakeDNSProxy {
2427 RealSocksAddr : realSocksAddr ,
28+ SocksUser : socksUser ,
29+ SocksPass : socksPass ,
2530 dnsMap : dnsMap ,
2631 ctx : ctx ,
2732 cancel : cancel ,
2833 }
2934}
3035
36+ // dialRealSocks opens a TCP connection to the upstream SOCKS5 server and
37+ // completes the auth handshake. If [SocksUser] and [SocksPass] are both
38+ // set, the user/pass method (0x02) is offered; otherwise NO_AUTH (0x00).
39+ // Returns the negotiated upstream connection, or nil + an error.
40+ func (p * FakeDNSProxy ) dialRealSocks () (net.Conn , error ) {
41+ realConn , err := net .Dial ("tcp" , p .RealSocksAddr )
42+ if err != nil {
43+ return nil , err
44+ }
45+
46+ // Greeting: offer NO_AUTH and (if configured) USERNAME/PASSWORD.
47+ // RFC 1928 + RFC 1929.
48+ var greeting []byte
49+ if p .SocksUser != "" && p .SocksPass != "" {
50+ greeting = []byte {5 , 2 , 0 , 2 } // VER=5, NMETHODS=2, NO_AUTH, USER/PASS
51+ } else {
52+ greeting = []byte {5 , 1 , 0 } // VER=5, NMETHODS=1, NO_AUTH
53+ }
54+ if _ , err := realConn .Write (greeting ); err != nil {
55+ realConn .Close ()
56+ return nil , err
57+ }
58+
59+ resp := make ([]byte , 2 )
60+ if _ , err := io .ReadFull (realConn , resp ); err != nil {
61+ realConn .Close ()
62+ return nil , err
63+ }
64+ if resp [0 ] != 5 {
65+ realConn .Close ()
66+ return nil , fmt .Errorf ("upstream SOCKS5 version mismatch: %d" , resp [0 ])
67+ }
68+
69+ switch resp [1 ] {
70+ case 0 :
71+ // NO_AUTH selected. Done.
72+ return realConn , nil
73+ case 2 :
74+ // USERNAME/PASSWORD selected — proceed with RFC 1929 sub-negotiation.
75+ if p .SocksUser == "" || p .SocksPass == "" {
76+ realConn .Close ()
77+ return nil , fmt .Errorf ("upstream requires auth but no credentials configured" )
78+ }
79+ user := []byte (p .SocksUser )
80+ pass := []byte (p .SocksPass )
81+ if len (user ) > 255 || len (pass ) > 255 {
82+ realConn .Close ()
83+ return nil , fmt .Errorf ("socks credentials too long" )
84+ }
85+ req := []byte {1 , byte (len (user ))}
86+ req = append (req , user ... )
87+ req = append (req , byte (len (pass )))
88+ req = append (req , pass ... )
89+ if _ , err := realConn .Write (req ); err != nil {
90+ realConn .Close ()
91+ return nil , err
92+ }
93+ authResp := make ([]byte , 2 )
94+ if _ , err := io .ReadFull (realConn , authResp ); err != nil {
95+ realConn .Close ()
96+ return nil , err
97+ }
98+ if authResp [1 ] != 0 {
99+ realConn .Close ()
100+ return nil , fmt .Errorf ("socks auth rejected (status %d)" , authResp [1 ])
101+ }
102+ return realConn , nil
103+ default :
104+ realConn .Close ()
105+ return nil , fmt .Errorf ("upstream selected unsupported auth method %d" , resp [1 ])
106+ }
107+ }
108+
31109func (p * FakeDNSProxy ) Start () (string , error ) {
32110 l , err := net .Listen ("tcp" , "127.0.0.1:0" )
33111 if err != nil {
@@ -139,22 +217,14 @@ func (p *FakeDNSProxy) handleConnection(conn net.Conn) {
139217 return
140218 }
141219
142- // Dial Real SOCKS
143- realConn , err := net . Dial ( "tcp" , p . RealSocksAddr )
220+ // Dial Real SOCKS (with auth if configured)
221+ realConn , err := p . dialRealSocks ( )
144222 if err != nil {
145- conn .Write ([]byte {5 , 1 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 })
223+ _ , _ = conn .Write ([]byte {5 , 1 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 })
146224 return
147225 }
148226 defer realConn .Close ()
149227
150- if _ , err := realConn .Write ([]byte {5 , 1 , 0 }); err != nil {
151- return
152- }
153- authResp := make ([]byte , 2 )
154- if _ , err := io .ReadFull (realConn , authResp ); err != nil {
155- return
156- }
157-
158228 req := []byte {5 , 1 , 0 , atyp }
159229 req = append (req , targetAddr ... )
160230 req = append (req , targetPort ... )
@@ -195,21 +265,13 @@ func (p *FakeDNSProxy) handleConnection(conn net.Conn) {
195265}
196266
197267func (p * FakeDNSProxy ) handleUDPAssociate (tcpConn net.Conn , atyp byte , targetAddr []byte , targetPort []byte ) {
198- realConn , err := net . Dial ( "tcp" , p . RealSocksAddr )
268+ realConn , err := p . dialRealSocks ( )
199269 if err != nil {
200- tcpConn .Write ([]byte {5 , 1 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 })
270+ _ , _ = tcpConn .Write ([]byte {5 , 1 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 })
201271 return
202272 }
203273 defer realConn .Close ()
204274
205- if _ , err := realConn .Write ([]byte {5 , 1 , 0 }); err != nil {
206- return
207- }
208- authResp := make ([]byte , 2 )
209- if _ , err := io .ReadFull (realConn , authResp ); err != nil {
210- return
211- }
212-
213275 req := []byte {5 , 3 , 0 , atyp }
214276 req = append (req , targetAddr ... )
215277 req = append (req , targetPort ... )
0 commit comments