@@ -513,7 +513,13 @@ async fn socks5_connect(
513513 const SOCKS5_REQUEST_REPLY_MAX_LEN : usize = 1 /* VER */ + 1 /* CMD for request, REP for reply */ + 1 /* RSV */
514514 + 1 /* ATYP */ + 1 /* HOSTNAME len */ + 255 /* HOSTNAME */ + 2 /* PORT */ ;
515515 const SOCKS5_REQUEST_REPLY_MIN_LEN : usize = 1 /* VER */ + 1 /* CMD for request, REP for reply */ + 1 /* RSV */
516- + 1 /* ATYP */ + 4 /* IPV4 ADDR */ + 2 /* PORT */ ;
516+ + 1 /* ATYP */ + 1 /* HOSTNAME len */ + 1 /* HOSTNAME */ + 2 /* PORT */ ;
517+ const SOCKS5_IPV4_REQUEST_LEN : usize = 1 /* VER */ + 1 /* CMD */ + 1 /* RSV */ + 1 /* ATYP */
518+ + 4 /* IPV4 DST.ADDR */ + 2 /* DST.PORT */ ;
519+ const SOCKS5_IPV6_REQUEST_LEN : usize = 1 /* VER */ + 1 /* CMD */ + 1 /* RSV */ + 1 /* ATYP */
520+ + 16 /* IPV4 DST.ADDR */ + 2 /* DST.PORT */ ;
521+ const SOCKS5_HOSTNAME_REQUEST_STATIC_FIELDS_LEN : usize = 1 /* VER */ + 1 /* CMD */ + 1 /* RSV */ + 1 /* ATYP */
522+ + 1 /* HOSTNAME len */ + 2 /* DST.PORT */ ;
517523
518524 let method_selection_message = [ VERSION , NMETHODS , NO_AUTH ] ;
519525 let mut tcp_stream = TcpStream :: connect ( & socks5_proxy_addr) . await . map_err ( |_| ( ) ) ?;
@@ -525,48 +531,73 @@ async fn socks5_connect(
525531 return Err ( ( ) ) ;
526532 }
527533
528- let mut socks5_request: Vec < u8 > = Vec :: with_capacity ( SOCKS5_REQUEST_REPLY_MAX_LEN ) ;
534+ let mut socks5_request = [ 0u8 ; SOCKS5_REQUEST_REPLY_MAX_LEN ] ;
535+ let request_size;
529536
530- socks5_request. push ( VERSION ) ;
531- socks5_request. push ( CMD_CONNECT ) ;
532- socks5_request. push ( RSV ) ;
537+ socks5_request[ 0 ..3 ] . copy_from_slice ( & [ VERSION , CMD_CONNECT , RSV ] ) ;
533538
534539 match addr {
535540 SocketAddress :: TcpIpV4 { addr, port } => {
536- socks5_request. push ( ATYP_IPV4 ) ;
537- socks5_request. extend_from_slice ( & addr) ;
538- socks5_request. extend_from_slice ( & port. to_be_bytes ( ) ) ;
541+ socks5_request[ 3 ] = ATYP_IPV4 ;
542+ socks5_request[ 4 ..8 ] . copy_from_slice ( & addr) ;
543+ socks5_request[ 8 ..10 ] . copy_from_slice ( & port. to_be_bytes ( ) ) ;
544+ request_size = SOCKS5_IPV4_REQUEST_LEN ;
539545 } ,
540546 SocketAddress :: TcpIpV6 { addr, port } => {
541- socks5_request. push ( ATYP_IPV6 ) ;
542- socks5_request. extend_from_slice ( & addr) ;
543- socks5_request. extend_from_slice ( & port. to_be_bytes ( ) ) ;
547+ socks5_request[ 3 ] = ATYP_IPV6 ;
548+ socks5_request[ 4 ..20 ] . copy_from_slice ( & addr) ;
549+ socks5_request[ 20 ..22 ] . copy_from_slice ( & port. to_be_bytes ( ) ) ;
550+ request_size = SOCKS5_IPV6_REQUEST_LEN ;
544551 } ,
545552 ref onion_v3 @ SocketAddress :: OnionV3 { port, .. } => {
546553 let onion_v3_url = onion_v3. to_string ( ) ;
547554 let hostname = onion_v3_url. split_once ( ':' ) . ok_or ( ( ) ) ?. 0 . as_bytes ( ) ;
548- socks5_request. push ( ATYP_DOMAINNAME ) ;
549- socks5_request. extend_from_slice ( & [ hostname. len ( ) as u8 ] ) ;
550- socks5_request. extend_from_slice ( hostname) ;
551- socks5_request. extend_from_slice ( & port. to_be_bytes ( ) ) ;
555+ socks5_request[ 3 ] = ATYP_DOMAINNAME ;
556+ socks5_request[ 4 ] = hostname. len ( ) as u8 ;
557+ let port_index = 5 + hostname. len ( ) ;
558+ socks5_request[ 5 ..port_index] . copy_from_slice ( hostname) ;
559+ socks5_request[ port_index..port_index + 2 ] . copy_from_slice ( & port. to_be_bytes ( ) ) ;
560+ request_size = SOCKS5_HOSTNAME_REQUEST_STATIC_FIELDS_LEN + hostname. len ( ) ;
552561 } ,
553562 SocketAddress :: Hostname { hostname, port } => {
554- socks5_request. push ( ATYP_DOMAINNAME ) ;
555- socks5_request. extend_from_slice ( & [ hostname. len ( ) as u8 ] ) ;
556- socks5_request. extend_from_slice ( hostname. as_bytes ( ) ) ;
557- socks5_request. extend_from_slice ( & port. to_be_bytes ( ) ) ;
563+ socks5_request[ 3 ] = ATYP_DOMAINNAME ;
564+ socks5_request[ 4 ] = hostname. len ( ) ;
565+ let port_index = 5 + hostname. len ( ) as usize ;
566+ socks5_request[ 5 ..port_index] . copy_from_slice ( hostname. as_bytes ( ) ) ;
567+ socks5_request[ port_index..port_index + 2 ] . copy_from_slice ( & port. to_be_bytes ( ) ) ;
568+ request_size = SOCKS5_HOSTNAME_REQUEST_STATIC_FIELDS_LEN + hostname. len ( ) as usize ;
558569 } ,
559570 SocketAddress :: OnionV2 { .. } => return Err ( ( ) ) ,
560571 } ;
561572
562- tcp_stream. write_all ( & socks5_request) . await . map_err ( |_| ( ) ) ?;
573+ tcp_stream. write_all ( & socks5_request[ ..request_size] ) . await . map_err ( |_| ( ) ) ?;
574+
575+ let mut buffer = [ 0u8 ; SOCKS5_REQUEST_REPLY_MAX_LEN ] ;
576+ // First pull some bytes into the buffer
577+ let mut total_read = tcp_stream. read ( & mut buffer) . await . map_err ( |_| ( ) ) ?;
578+ // Then make sure we've reached EOF, otherwise keep appending until the max size of the buffer
579+ while total_read < SOCKS5_REQUEST_REPLY_MAX_LEN {
580+ let n_read = match tcp_stream. try_read ( & mut buffer[ total_read..] ) {
581+ Ok ( n) => n,
582+ Err ( e) if e. kind ( ) == std:: io:: ErrorKind :: WouldBlock => 0 ,
583+ Err ( _e) => return Err ( ( ) ) ,
584+ } ;
585+ if n_read == 0 {
586+ break ;
587+ }
588+ total_read += n_read;
589+ }
590+ // If we've filled the buffer, return `Err` if we receive more bytes than the max allowed by the RFC
591+ if total_read == SOCKS5_REQUEST_REPLY_MAX_LEN {
592+ match tcp_stream. try_read ( & mut [ 0u8 ; 1 ] ) {
593+ Ok ( 0 ) => ( ) ,
594+ Ok ( 1 ..) => return Err ( ( ) ) ,
595+ Err ( e) if e. kind ( ) == std:: io:: ErrorKind :: WouldBlock => ( ) ,
596+ Err ( _e) => return Err ( ( ) ) ,
597+ }
598+ }
563599
564- let mut buffer: Vec < u8 > = Vec :: with_capacity ( SOCKS5_REQUEST_REPLY_MAX_LEN ) ;
565- let n_read = tcp_stream. read_to_end ( & mut buffer) . await . map_err ( |_| ( ) ) ?;
566- if n_read < SOCKS5_REQUEST_REPLY_MIN_LEN
567- || n_read > SOCKS5_REQUEST_REPLY_MAX_LEN
568- || buffer[ ..3 ] != [ VERSION , SUCCEEDED , RSV ]
569- {
600+ if total_read < SOCKS5_REQUEST_REPLY_MIN_LEN || buffer[ ..3 ] != [ VERSION , SUCCEEDED , RSV ] {
570601 return Err ( ( ) ) ;
571602 }
572603
0 commit comments