Skip to content

Commit 7581c26

Browse files
committed
fixup: force usage of the stream isolation parameter
1 parent 9489738 commit 7581c26

File tree

1 file changed

+50
-54
lines changed

1 file changed

+50
-54
lines changed

lightning-net-tokio/src/lib.rs

Lines changed: 50 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -474,16 +474,20 @@ where
474474
}
475475
}
476476

477-
/// Same as [`connect_outbound`], using a SOCKS5 proxy
478-
pub async fn socks5_connect_outbound<PM: Deref + 'static + Send + Sync + Clone>(
477+
/// Same as [`connect_outbound`], using a Tor SOCKS5 proxy. The stream isolation parameter is a
478+
/// username-password tuple which will be passed to the Tor SOCKS5 proxy during connection
479+
/// establishment. See https://spec.torproject.org/socks-extensions.html for further details.
480+
pub async fn tor_socks5_connect_outbound<PM: Deref + 'static + Send + Sync + Clone>(
479481
peer_manager: PM, their_node_id: PublicKey, socks5_proxy_addr: SocketAddr, addr: SocketAddress,
480-
user_pass: Option<(&str, &str)>,
482+
stream_isolation_parameter: (&str, &str),
481483
) -> Option<impl std::future::Future<Output = ()>>
482484
where
483485
PM::Target: APeerManager<Descriptor = SocketDescriptor>,
484486
{
485487
let connect_fut = async {
486-
socks5_connect(socks5_proxy_addr, addr, user_pass).await.map(|s| s.into_std().unwrap())
488+
tor_socks5_connect(socks5_proxy_addr, addr, stream_isolation_parameter)
489+
.await
490+
.map(|s| s.into_std().unwrap())
487491
};
488492
if let Ok(Ok(stream)) =
489493
time::timeout(Duration::from_secs(SOCKS5_CONNECT_OUTBOUND_TIMEOUT), connect_fut).await
@@ -494,8 +498,8 @@ where
494498
}
495499
}
496500

497-
async fn socks5_connect(
498-
socks5_proxy_addr: SocketAddr, addr: SocketAddress, user_pass: Option<(&str, &str)>,
501+
async fn tor_socks5_connect(
502+
socks5_proxy_addr: SocketAddr, addr: SocketAddress, stream_isolation_parameter: (&str, &str),
499503
) -> Result<TcpStream, ()> {
500504
use std::io::{Cursor, Write};
501505
use tokio::io::AsyncReadExt;
@@ -507,7 +511,6 @@ async fn socks5_connect(
507511
// Constants defined in RFC 1928 and RFC 1929
508512
const VERSION: u8 = 5;
509513
const NMETHODS: u8 = 1;
510-
const NO_AUTH: u8 = 0;
511514
const USERNAME_PASSWORD_AUTH: u8 = 2;
512515
const METHOD_SELECT_REPLY_LEN: usize = 2;
513516
const USERNAME_PASSWORD_VERSION: u8 = 1;
@@ -526,40 +529,38 @@ async fn socks5_connect(
526529
const SOCKS5_REQUEST_MAX_LEN: usize = 1 /* VER */ + 1 /* CMD */ + 1 /* RSV */ + 1 /* ATYP */
527530
+ 1 /* HOSTNAME len */ + HOSTNAME_MAX_LEN /* HOSTNAME */ + 2 /* PORT */;
528531

529-
let selected_auth = if user_pass.is_some() { USERNAME_PASSWORD_AUTH } else { NO_AUTH };
530-
let method_selection_request = [VERSION, NMETHODS, selected_auth];
532+
let (username, password) = stream_isolation_parameter;
533+
if username.len() > USERNAME_MAX_LEN || password.len() > PASSWORD_MAX_LEN {
534+
return Err(());
535+
}
536+
537+
let method_selection_request = [VERSION, NMETHODS, USERNAME_PASSWORD_AUTH];
531538
let mut tcp_stream = TcpStream::connect(&socks5_proxy_addr).await.map_err(|_| ())?;
532539
tokio::io::AsyncWriteExt::write_all(&mut tcp_stream, &method_selection_request)
533540
.await
534541
.map_err(|_| ())?;
535542

536543
let mut method_selection_reply = [0u8; METHOD_SELECT_REPLY_LEN];
537544
tcp_stream.read_exact(&mut method_selection_reply).await.map_err(|_| ())?;
538-
if method_selection_reply != [VERSION, selected_auth] {
545+
if method_selection_reply != [VERSION, USERNAME_PASSWORD_AUTH] {
539546
return Err(());
540547
}
541548

542-
if let Some((username, password)) = user_pass {
543-
if username.len() > USERNAME_MAX_LEN || password.len() > PASSWORD_MAX_LEN {
544-
return Err(());
545-
}
546-
547-
let mut username_password_request = [0u8; USERNAME_PASSWORD_REQUEST_MAX_LEN];
548-
let mut writer = Cursor::new(&mut username_password_request[..]);
549-
writer.write_all(&[USERNAME_PASSWORD_VERSION, username.len() as u8]).map_err(|_| ())?;
550-
writer.write_all(username.as_bytes()).map_err(|_| ())?;
551-
writer.write_all(&[password.len() as u8]).map_err(|_| ())?;
552-
writer.write_all(password.as_bytes()).map_err(|_| ())?;
553-
let pos = writer.position() as usize;
554-
tokio::io::AsyncWriteExt::write_all(&mut tcp_stream, &username_password_request[..pos])
555-
.await
556-
.map_err(|_| ())?;
549+
let mut username_password_request = [0u8; USERNAME_PASSWORD_REQUEST_MAX_LEN];
550+
let mut writer = Cursor::new(&mut username_password_request[..]);
551+
writer.write_all(&[USERNAME_PASSWORD_VERSION, username.len() as u8]).map_err(|_| ())?;
552+
writer.write_all(username.as_bytes()).map_err(|_| ())?;
553+
writer.write_all(&[password.len() as u8]).map_err(|_| ())?;
554+
writer.write_all(password.as_bytes()).map_err(|_| ())?;
555+
let pos = writer.position() as usize;
556+
tokio::io::AsyncWriteExt::write_all(&mut tcp_stream, &username_password_request[..pos])
557+
.await
558+
.map_err(|_| ())?;
557559

558-
let mut username_password_reply = [0u8; USERNAME_PASSWORD_REPLY_LEN];
559-
tcp_stream.read_exact(&mut username_password_reply).await.map_err(|_| ())?;
560-
if username_password_reply != [USERNAME_PASSWORD_VERSION, SUCCESS] {
561-
return Err(());
562-
}
560+
let mut username_password_reply = [0u8; USERNAME_PASSWORD_REPLY_LEN];
561+
tcp_stream.read_exact(&mut username_password_reply).await.map_err(|_| ())?;
562+
if username_password_reply != [USERNAME_PASSWORD_VERSION, SUCCESS] {
563+
return Err(());
563564
}
564565

565566
let mut socks5_request = [0u8; SOCKS5_REQUEST_MAX_LEN];
@@ -755,7 +756,7 @@ impl Hash for SocketDescriptor {
755756
#[cfg(test)]
756757
mod tests {
757758
#[cfg(tor_socks5)]
758-
use super::socks5_connect;
759+
use super::tor_socks5_connect;
759760

760761
use bitcoin::constants::ChainHash;
761762
use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
@@ -1095,32 +1096,30 @@ mod tests {
10951096

10961097
#[cfg(tor_socks5)]
10971098
#[tokio::test]
1098-
async fn test_socks5_connect() {
1099+
async fn test_tor_socks5_connect() {
10991100
// Set TOR_SOCKS5_PROXY=127.0.0.1:9050
11001101
let socks5_proxy_addr: SocketAddr = std::env!("TOR_SOCKS5_PROXY").parse().unwrap();
11011102

11021103
// Success cases
11031104

1104-
for (addr_str, user_pass) in [
1105+
for (addr_str, stream_isolation_parameter) in [
11051106
// google.com
1106-
("142.250.189.196:80", None),
1107+
("142.250.189.196:80", ("<torS0X>0", "")),
11071108
// google.com
1108-
("[2607:f8b0:4005:813::2004]:80", None),
1109+
("[2607:f8b0:4005:813::2004]:80", ("<torS0X>0", "123")),
11091110
// torproject.org
1110-
("torproject.org:80", None),
1111+
("torproject.org:80", ("<torS0X>1abc", "")),
11111112
// torproject.org
1112-
("2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion:80", None),
1113-
// Same vectors as above, with a username and password
1114-
("142.250.189.196:80", Some(("<torS0X>0", ""))),
1115-
("[2607:f8b0:4005:813::2004]:80", Some(("<torS0X>0", "123"))),
1116-
("torproject.org:80", Some(("<torS0X>1abc", ""))),
11171113
(
11181114
"2gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion:80",
1119-
Some(("<torS0X>1abc", "123")),
1115+
("<torS0X>1abc", "123"),
11201116
),
11211117
] {
11221118
let addr: SocketAddress = addr_str.parse().unwrap();
1123-
let tcp_stream = socks5_connect(socks5_proxy_addr, addr, user_pass).await.unwrap();
1119+
let tcp_stream =
1120+
tor_socks5_connect(socks5_proxy_addr, addr, stream_isolation_parameter)
1121+
.await
1122+
.unwrap();
11241123
assert_eq!(
11251124
tcp_stream.try_read(&mut [0u8; 1]).unwrap_err().kind(),
11261125
std::io::ErrorKind::WouldBlock
@@ -1129,22 +1128,17 @@ mod tests {
11291128

11301129
// Failure cases
11311130

1132-
for (addr_str, user_pass) in [
1131+
for (addr_str, stream_isolation_parameter) in [
11331132
// google.com, with some invalid port
1134-
("142.250.189.196:1234", None),
1133+
("142.250.189.196:1234", ("<torS0X>0", "")),
11351134
// google.com, with some invalid port
1136-
("[2607:f8b0:4005:813::2004]:1234", None),
1135+
("[2607:f8b0:4005:813::2004]:1234", ("<torS0X>0", "123")),
11371136
// torproject.org, with some invalid port
1138-
("torproject.org:1234", None),
1137+
("torproject.org:1234", ("<torS0X>1abc", "")),
11391138
// torproject.org, with a typo
1140-
("3gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion:80", None),
1141-
// Same vectors as above, with a username and password
1142-
("142.250.189.196:1234", Some(("<torS0X>0", ""))),
1143-
("[2607:f8b0:4005:813::2004]:1234", Some(("<torS0X>0", "123"))),
1144-
("torproject.org:1234", Some(("<torS0X>1abc", ""))),
11451139
(
11461140
"3gzyxa5ihm7nsggfxnu52rck2vv4rvmdlkiu3zzui5du4xyclen53wid.onion:80",
1147-
Some(("<torS0X>1abc", "123")),
1141+
("<torS0X>1abc", "123"),
11481142
),
11491143
/* TODO: Uncomment when format types 30 and 31 land in tor stable, see https://spec.torproject.org/socks-extensions.html,
11501144
these are invalid usernames according to those standards.
@@ -1155,7 +1149,9 @@ mod tests {
11551149
*/
11561150
] {
11571151
let addr: SocketAddress = addr_str.parse().unwrap();
1158-
assert!(socks5_connect(socks5_proxy_addr, addr, user_pass).await.is_err());
1152+
assert!(tor_socks5_connect(socks5_proxy_addr, addr, stream_isolation_parameter)
1153+
.await
1154+
.is_err());
11591155
}
11601156
}
11611157
}

0 commit comments

Comments
 (0)