125
125
//!
126
126
//! See [`SocksConnection`] for detailed usage examples and API documentation.
127
127
128
- use tokio_socks:: { tcp:: Socks5Stream , TargetAddr } ;
129
- use tokio:: io:: { AsyncRead , AsyncWrite } ;
130
- use azure_core:: { http:: Url , error:: Result } ;
131
- use tracing:: { debug, error, trace} ;
132
- use tokio_native_tls:: TlsConnector ;
128
+ use azure_core:: { error:: Result , http:: Url } ;
133
129
use native_tls:: TlsConnector as NativeTlsConnector ;
134
130
use std:: pin:: Pin ;
135
131
use std:: task:: { Context , Poll } ;
132
+ use tokio:: io:: { AsyncRead , AsyncWrite } ;
133
+ use tokio_native_tls:: TlsConnector ;
134
+ use tokio_socks:: { tcp:: Socks5Stream , TargetAddr } ;
135
+ use tracing:: { debug, error, trace} ;
136
136
137
137
/// A trait that combines AsyncRead, AsyncWrite, Unpin, Send and Debug for SOCKS5 streams
138
138
pub trait SocksStream : AsyncRead + AsyncWrite + Unpin + Send + std:: fmt:: Debug + ' static { }
@@ -311,14 +311,14 @@ impl SocksConnection {
311
311
) ;
312
312
return Err ( azure_core:: Error :: with_message (
313
313
azure_core:: error:: ErrorKind :: Other ,
314
- format ! ( "Invalid SOCKS5 scheme: {}" , url. scheme( ) )
314
+ format ! ( "Invalid SOCKS5 scheme: {}" , url. scheme( ) ) ,
315
315
) ) ;
316
316
}
317
317
if url. host_str ( ) . is_none ( ) {
318
318
error ! ( "Missing host in SOCKS5 proxy URL" ) ;
319
319
return Err ( azure_core:: Error :: with_message (
320
320
azure_core:: error:: ErrorKind :: Other ,
321
- "Missing host in SOCKS5 URL"
321
+ "Missing host in SOCKS5 URL" ,
322
322
) ) ;
323
323
}
324
324
Ok ( ( ) )
@@ -406,10 +406,7 @@ impl SocksConnection {
406
406
///
407
407
/// Returns a boxed stream implementing [`SocksStream`] trait, ready for use
408
408
/// with fe2o3-amqp's `Connection::open_with_stream()` method.
409
- pub async fn connect (
410
- proxy_url : & Url ,
411
- target_url : & Url ,
412
- ) -> Result < Box < dyn SocksStream > > {
409
+ pub async fn connect ( proxy_url : & Url , target_url : & Url ) -> Result < Box < dyn SocksStream > > {
413
410
debug ! (
414
411
proxy_url = %Self :: mask_credentials( proxy_url) ,
415
412
target_host = %target_url. host_str( ) . unwrap_or( "unknown" ) ,
@@ -421,14 +418,13 @@ impl SocksConnection {
421
418
Self :: validate_proxy_url ( proxy_url) ?;
422
419
423
420
// DNS resolution happens at proxy server for socks5h:// scheme
424
- let proxy_host = proxy_url. host_str ( )
425
- . ok_or_else ( || {
426
- error ! ( "Missing proxy host in SOCKS5 URL" ) ;
427
- azure_core:: Error :: with_message (
428
- azure_core:: error:: ErrorKind :: Other ,
429
- "Missing proxy host in SOCKS5 URL"
430
- )
431
- } ) ?;
421
+ let proxy_host = proxy_url. host_str ( ) . ok_or_else ( || {
422
+ error ! ( "Missing proxy host in SOCKS5 URL" ) ;
423
+ azure_core:: Error :: with_message (
424
+ azure_core:: error:: ErrorKind :: Other ,
425
+ "Missing proxy host in SOCKS5 URL" ,
426
+ )
427
+ } ) ?;
432
428
let proxy_port = proxy_url. port ( ) . unwrap_or ( 1080 ) ;
433
429
434
430
debug ! (
@@ -441,7 +437,7 @@ impl SocksConnection {
441
437
// Always use domain name - let SOCKS5 proxy handle resolution
442
438
let target_addr = TargetAddr :: Domain (
443
439
target_url. host_str ( ) . unwrap_or ( "" ) . into ( ) ,
444
- target_url. port ( ) . unwrap_or ( 5671 )
440
+ target_url. port ( ) . unwrap_or ( 5671 ) ,
445
441
) ;
446
442
447
443
// Handle authentication if provided in URL
@@ -452,7 +448,7 @@ impl SocksConnection {
452
448
error ! ( "Empty username in SOCKS5 proxy URL" ) ;
453
449
return Err ( azure_core:: Error :: with_message (
454
450
azure_core:: error:: ErrorKind :: Other ,
455
- "Empty username in SOCKS5 URL"
451
+ "Empty username in SOCKS5 URL" ,
456
452
) ) ;
457
453
}
458
454
@@ -465,8 +461,9 @@ impl SocksConnection {
465
461
( proxy_host, proxy_port) ,
466
462
target_addr,
467
463
username,
468
- password
469
- ) . await
464
+ password,
465
+ )
466
+ . await
470
467
} else {
471
468
debug ! ( "Connecting to SOCKS5 proxy without authentication" ) ;
472
469
Socks5Stream :: connect ( ( proxy_host, proxy_port) , target_addr) . await
@@ -479,11 +476,13 @@ impl SocksConnection {
479
476
"SOCKS5 connection establishment failed"
480
477
) ;
481
478
482
- azure_core:: Error :: new (
483
- azure_core:: error:: ErrorKind :: Other ,
484
- Box :: new ( e)
485
- ) . with_context ( format ! ( "SOCKS5 connection failed: proxy={}, target={}" ,
486
- Self :: mask_credentials( proxy_url) , target_url) )
479
+ azure_core:: Error :: new ( azure_core:: error:: ErrorKind :: Other , Box :: new ( e) ) . with_context (
480
+ format ! (
481
+ "SOCKS5 connection failed: proxy={}, target={}" ,
482
+ Self :: mask_credentials( proxy_url) ,
483
+ target_url
484
+ ) ,
485
+ )
487
486
} ) ?;
488
487
489
488
debug ! (
@@ -493,7 +492,8 @@ impl SocksConnection {
493
492
) ;
494
493
495
494
// Check if target URL requires TLS (amqps://)
496
- let requires_tls = target_url. scheme ( ) == "amqps" || target_url. port ( ) . unwrap_or ( 5671 ) == 5671 ;
495
+ let requires_tls =
496
+ target_url. scheme ( ) == "amqps" || target_url. port ( ) . unwrap_or ( 5671 ) == 5671 ;
497
497
498
498
if requires_tls {
499
499
debug ! (
@@ -502,30 +502,30 @@ impl SocksConnection {
502
502
) ;
503
503
504
504
// Create TLS connector with default settings
505
- let native_connector = NativeTlsConnector :: new ( )
506
- . map_err ( |e| {
507
- error ! (
508
- error = %e,
509
- "Failed to create TLS connector"
510
- ) ;
511
- azure_core:: Error :: with_message (
512
- azure_core:: error:: ErrorKind :: Other ,
513
- format ! ( "Failed to create TLS connector: {}" , e)
514
- )
515
- } ) ?;
505
+ let native_connector = NativeTlsConnector :: new ( ) . map_err ( |e| {
506
+ error ! (
507
+ error = %e,
508
+ "Failed to create TLS connector"
509
+ ) ;
510
+ azure_core:: Error :: with_message (
511
+ azure_core:: error:: ErrorKind :: Other ,
512
+ format ! ( "Failed to create TLS connector: {}" , e) ,
513
+ )
514
+ } ) ?;
516
515
517
516
let connector = TlsConnector :: from ( native_connector) ;
518
- let target_host = target_url. host_str ( )
519
- . ok_or_else ( || {
520
- error ! ( "Missing target host for TLS connection" ) ;
521
- azure_core:: Error :: with_message (
522
- azure_core:: error:: ErrorKind :: Other ,
523
- "Missing target host for TLS connection"
524
- )
525
- } ) ?;
517
+ let target_host = target_url. host_str ( ) . ok_or_else ( || {
518
+ error ! ( "Missing target host for TLS connection" ) ;
519
+ azure_core:: Error :: with_message (
520
+ azure_core:: error:: ErrorKind :: Other ,
521
+ "Missing target host for TLS connection" ,
522
+ )
523
+ } ) ?;
526
524
527
525
// Establish TLS connection over SOCKS5 stream
528
- let tls_stream = connector. connect ( target_host, stream. into_inner ( ) ) . await
526
+ let tls_stream = connector
527
+ . connect ( target_host, stream. into_inner ( ) )
528
+ . await
529
529
. map_err ( |e| {
530
530
error ! (
531
531
target_host = %target_host,
@@ -534,7 +534,7 @@ impl SocksConnection {
534
534
) ;
535
535
azure_core:: Error :: with_message (
536
536
azure_core:: error:: ErrorKind :: Other ,
537
- format ! ( "TLS handshake failed: {}" , e)
537
+ format ! ( "TLS handshake failed: {}" , e) ,
538
538
)
539
539
} ) ?;
540
540
@@ -703,7 +703,8 @@ mod tests {
703
703
#[ test]
704
704
fn test_mask_credentials_with_auth ( ) {
705
705
// Username and password should be masked
706
- let url_with_auth =
Url :: parse ( "socks5://username:[email protected] :1080" ) . unwrap ( ) ;
706
+ let url_with_auth =
707
+ Url :: parse ( "socks5://username:[email protected] :1080" ) . unwrap ( ) ;
707
708
let masked = SocksConnection :: mask_credentials ( & url_with_auth) ;
708
709
assert_eq ! ( masked, "socks5://***:***@proxy.example.com:1080" ) ;
709
710
@@ -724,20 +725,26 @@ mod tests {
724
725
#[ test]
725
726
fn test_mask_credentials_special_characters ( ) {
726
727
// Test credentials with special characters (URL encoded)
727
- let url_special =
Url :: parse ( "socks5://user%40domain:p%[email protected] :1080" ) . unwrap ( ) ;
728
+ let url_special =
729
+ Url :: parse ( "socks5://user%40domain:p%[email protected] :1080" ) . unwrap ( ) ;
728
730
let masked = SocksConnection :: mask_credentials ( & url_special) ;
729
731
assert_eq ! ( masked, "socks5://***:***@proxy.example.com:1080" ) ;
730
732
731
733
// Test with complex credentials
732
- let url_complex =
Url :: parse ( "socks5://admin:secretP%[email protected] :8080" ) . unwrap ( ) ;
734
+ let url_complex =
735
+ Url :: parse ( "socks5://admin:secretP%[email protected] :8080" ) . unwrap ( ) ;
733
736
let masked_complex = SocksConnection :: mask_credentials ( & url_complex) ;
734
- assert_eq ! ( masked_complex, "socks5://***:***@proxy-server.corp.com:8080" ) ;
737
+ assert_eq ! (
738
+ masked_complex,
739
+ "socks5://***:***@proxy-server.corp.com:8080"
740
+ ) ;
735
741
}
736
742
737
743
#[ test]
738
744
fn test_mask_credentials_preserves_structure ( ) {
739
745
// Verify that masking preserves host, port, and scheme
740
- let original =
Url :: parse ( "socks5h://testuser:[email protected] :12345" ) . unwrap ( ) ;
746
+ let original =
747
+ Url :: parse ( "socks5h://testuser:[email protected] :12345" ) . unwrap ( ) ;
741
748
let masked = SocksConnection :: mask_credentials ( & original) ;
742
749
743
750
assert ! ( masked. starts_with( "socks5h://" ) ) ;
@@ -777,7 +784,9 @@ mod tests {
777
784
// Verify credentials are not exposed
778
785
assert ! ( !masked. contains( "pass" ) ) ;
779
786
assert ! ( !masked. contains( "secret" ) ) ;
780
- assert ! ( !masked. contains( "admin" ) || url_str. contains( "admin" ) == masked. contains( "admin" ) ) ;
787
+ assert ! (
788
+ !masked. contains( "admin" ) || url_str. contains( "admin" ) == masked. contains( "admin" )
789
+ ) ;
781
790
}
782
791
}
783
- }
792
+ }
0 commit comments