@@ -20,55 +20,102 @@ func TestProxy(t *testing.T) {
2020 listenAddr := pickFreeAddr (t )
2121 socksServer := NewServer ()
2222 socksServer .SetRules (NewRulePermitAll ())
23- socksClient , err := NewClient (listenAddr )
23+ socksClient , err := NewClient (listenAddr , "" , "" )
2424 require .NoError (t , err )
2525
2626 wg := & sync.WaitGroup {}
2727 wg .Add (1 )
2828 go func () {
2929 defer wg .Done ()
30-
3130 conn := <- socksClient .ConnsChan ()
3231 socksServer .ServeConn (conn )
3332 }()
3433
35- upstreamAddr := pickFreeAddr (t )
36- mux := http .NewServeMux ()
37- mux .HandleFunc ("/test" , func (w http.ResponseWriter , r * http.Request ) {
38- _ , _ = fmt .Fprintf (w , "test text" )
39- })
40- //nolint
41- httpServer := & http.Server {Addr : upstreamAddr , Handler : mux }
34+ upstreamAddr := startUpstreamServer (t )
35+ httpClient , transport := newSOCKS5HttpClient (listenAddr , nil )
36+
37+ response , err := httpClient .Get (fmt .Sprintf ("http://%s/test" , upstreamAddr ))
38+ require .NoError (t , err )
39+ body , err := io .ReadAll (response .Body )
40+ require .NoError (t , err )
41+ err = response .Body .Close ()
42+ require .NoError (t , err )
43+
44+ require .Equal (t , "test text" , string (body ))
45+
46+ transport .CloseIdleConnections ()
47+ wg .Wait ()
48+ }
49+
50+ func TestProxyWithAuth (t * testing.T ) {
51+ listenAddr := pickFreeAddr (t )
52+ socksServer := NewServer ()
53+ socksServer .SetRules (NewRulePermitAll ())
54+ socksClient , err := NewClient (listenAddr , "testuser" , "testpass" )
55+ require .NoError (t , err )
56+
57+ wg := & sync.WaitGroup {}
58+ wg .Add (1 )
4259 go func () {
43- _ = httpServer .ListenAndServe ()
44- }()
45- defer func () {
46- httpServer .Shutdown (context .Background ())
60+ defer wg .Done ()
61+ conn := <- socksClient .ConnsChan ()
62+ socksServer .ServeConn (conn )
4763 }()
4864
49- httpTransport := & http.Transport {
50- Proxy : func (* http.Request ) (* url.URL , error ) {
51- return & url.URL {
52- Scheme : "socks5" ,
53- Host : listenAddr ,
54- }, nil
55- },
56- }
57- httpClient := http.Client {Transport : httpTransport }
65+ upstreamAddr := startUpstreamServer (t )
66+ httpClient , transport := newSOCKS5HttpClient (listenAddr , url .UserPassword ("testuser" , "testpass" ))
5867
5968 response , err := httpClient .Get (fmt .Sprintf ("http://%s/test" , upstreamAddr ))
6069 require .NoError (t , err )
6170 body , err := io .ReadAll (response .Body )
6271 require .NoError (t , err )
6372 err = response .Body .Close ()
6473 require .NoError (t , err )
65-
6674 require .Equal (t , "test text" , string (body ))
6775
68- httpTransport .CloseIdleConnections ()
76+ transport .CloseIdleConnections ()
6977 wg .Wait ()
7078}
7179
80+ func TestProxyWithAuthRejection (t * testing.T ) {
81+ tests := []struct {
82+ name string
83+ userinfo * url.Userinfo
84+ }{
85+ {"WrongPassword" , url .UserPassword ("testuser" , "wrongpass" )},
86+ {"NoCredentials" , nil },
87+ }
88+
89+ for _ , tt := range tests {
90+ t .Run (tt .name , func (t * testing.T ) {
91+ listenAddr := pickFreeAddr (t )
92+ socksClient , err := NewClient (listenAddr , "testuser" , "testpass" )
93+ require .NoError (t , err )
94+
95+ wg := & sync.WaitGroup {}
96+ wg .Add (1 )
97+ go func () {
98+ defer wg .Done ()
99+ conn := <- socksClient .ConnsChan ()
100+ _ = socksClient .HandleLocalAuth (conn )
101+ conn .Close ()
102+ }()
103+
104+ upstreamAddr := startUpstreamServer (t )
105+ httpClient , transport := newSOCKS5HttpClient (listenAddr , tt .userinfo )
106+
107+ resp , err := httpClient .Get (fmt .Sprintf ("http://%s/test" , upstreamAddr ))
108+ if resp != nil {
109+ resp .Body .Close ()
110+ }
111+ require .Error (t , err )
112+
113+ transport .CloseIdleConnections ()
114+ wg .Wait ()
115+ })
116+ }
117+ }
118+
72119func pickFreeAddr (t testing.TB ) string {
73120 l , err := net .Listen ("tcp" , "127.0.0.1:0" )
74121 if err != nil {
@@ -78,3 +125,36 @@ func pickFreeAddr(t testing.TB) string {
78125
79126 return l .Addr ().String ()
80127}
128+
129+ // startUpstreamServer starts an HTTP server that responds with "test text" on /test.
130+ func startUpstreamServer (t testing.TB ) string {
131+ addr := pickFreeAddr (t )
132+ mux := http .NewServeMux ()
133+ mux .HandleFunc ("/test" , func (w http.ResponseWriter , r * http.Request ) {
134+ _ , _ = fmt .Fprintf (w , "test text" )
135+ })
136+ //nolint
137+ httpServer := & http.Server {Addr : addr , Handler : mux }
138+ go func () {
139+ _ = httpServer .ListenAndServe ()
140+ }()
141+ t .Cleanup (func () {
142+ httpServer .Shutdown (context .Background ())
143+ })
144+ return addr
145+ }
146+
147+ // newSOCKS5HttpClient creates an HTTP client that routes through a SOCKS5 proxy.
148+ // Pass nil userinfo for no auth credentials.
149+ func newSOCKS5HttpClient (proxyAddr string , userinfo * url.Userinfo ) (http.Client , * http.Transport ) {
150+ transport := & http.Transport {
151+ Proxy : func (* http.Request ) (* url.URL , error ) {
152+ return & url.URL {
153+ Scheme : "socks5" ,
154+ User : userinfo ,
155+ Host : proxyAddr ,
156+ }, nil
157+ },
158+ }
159+ return http.Client {Transport : transport }, transport
160+ }
0 commit comments