Skip to content

Commit 789bcc7

Browse files
committed
Parse SocketAddress::OnionV2
1 parent edc5490 commit 789bcc7

File tree

2 files changed

+57
-64
lines changed

2 files changed

+57
-64
lines changed

lightning/src/ln/msgs.rs

+56-63
Original file line numberDiff line numberDiff line change
@@ -774,8 +774,13 @@ pub enum SocketAddress {
774774
/// An old-style Tor onion address/port on which the peer is listening.
775775
///
776776
/// This field is deprecated and the Tor network generally no longer supports V2 Onion
777-
/// addresses. Thus, the details are not parsed here.
778-
OnionV2([u8; 12]),
777+
/// addresses.
778+
OnionV2{
779+
/// The base32 of first 80 bits
780+
addr: [u8; 10],
781+
/// The port on which the node is listening
782+
port: u16,
783+
},
779784
/// A new-style Tor onion address/port on which the peer is listening.
780785
///
781786
/// To create the human-readable "hostname", concatenate the ED25519 pubkey, checksum, and version,
@@ -805,7 +810,7 @@ impl SocketAddress {
805810
match self {
806811
&SocketAddress::TcpIpV4 {..} => { 1 },
807812
&SocketAddress::TcpIpV6 {..} => { 2 },
808-
&SocketAddress::OnionV2(_) => { 3 },
813+
&SocketAddress::OnionV2 {..} => { 3 },
809814
&SocketAddress::OnionV3 {..} => { 4 },
810815
&SocketAddress::Hostname {..} => { 5 },
811816
}
@@ -816,7 +821,7 @@ impl SocketAddress {
816821
match self {
817822
&SocketAddress::TcpIpV4 { .. } => { 6 },
818823
&SocketAddress::TcpIpV6 { .. } => { 18 },
819-
&SocketAddress::OnionV2(_) => { 12 },
824+
&SocketAddress::OnionV2 { .. } => { 12 },
820825
&SocketAddress::OnionV3 { .. } => { 37 },
821826
// Consists of 1-byte hostname length, hostname bytes, and 2-byte port.
822827
&SocketAddress::Hostname { ref hostname, .. } => { u16::from(hostname.len()) + 3 },
@@ -842,9 +847,10 @@ impl Writeable for SocketAddress {
842847
addr.write(writer)?;
843848
port.write(writer)?;
844849
},
845-
&SocketAddress::OnionV2(bytes) => {
850+
&SocketAddress::OnionV2{ ref addr, ref port } => {
846851
3u8.write(writer)?;
847-
bytes.write(writer)?;
852+
addr.write(writer)?;
853+
port.write(writer)?;
848854
},
849855
&SocketAddress::OnionV3 { ref ed25519_pubkey, ref checksum, ref version, ref port } => {
850856
4u8.write(writer)?;
@@ -879,7 +885,10 @@ impl Readable for Result<SocketAddress, u8> {
879885
port: Readable::read(reader)?,
880886
}))
881887
},
882-
3 => Ok(Ok(SocketAddress::OnionV2(Readable::read(reader)?))),
888+
3 => Ok(Ok(SocketAddress::OnionV2 {
889+
addr: Readable::read(reader)?,
890+
port: Readable::read(reader)?,
891+
})),
883892
4 => {
884893
Ok(Ok(SocketAddress::OnionV3 {
885894
ed25519_pubkey: Readable::read(reader)?,
@@ -918,10 +927,8 @@ pub enum SocketAddressParseError {
918927
InvalidInput,
919928
/// Invalid port
920929
InvalidPort,
921-
/// Invalid onion v2 address
922-
InvalidOnionV2,
923-
/// Invalid onion v3 address
924-
InvalidOnionV3,
930+
/// Invalid onion address
931+
InvalidOnion,
925932
}
926933

927934
impl fmt::Display for SocketAddressParseError {
@@ -931,8 +938,7 @@ impl fmt::Display for SocketAddressParseError {
931938
SocketAddressParseError::InvalidInput => write!(f, "Invalid input format. \
932939
Expected: \"<ipv4>:<port>\", \"[<ipv6>]:<port>\", \"<onion address>.onion:<port>\" or \"<hostname>:<port>\""),
933940
SocketAddressParseError::InvalidPort => write!(f, "Invalid port"),
934-
SocketAddressParseError::InvalidOnionV2 => write!(f, "Invalid onion v2 address"),
935-
SocketAddressParseError::InvalidOnionV3 => write!(f, "Invalid onion v3 address"),
941+
SocketAddressParseError::InvalidOnion => write!(f, "Invalid onion address"),
936942
}
937943
}
938944
}
@@ -961,39 +967,23 @@ impl From<std::net::SocketAddr> for SocketAddress {
961967
}
962968
}
963969

964-
/// Parses an OnionV2 host and port into a [`SocketAddress::OnionV2`].
970+
/// Parses an Onion host and port into a [`SocketAddress::OnionV3`].
965971
///
966972
/// The host part must end with ".onion".
967-
pub fn parse_onion_v2_address(host: &str) -> Result<SocketAddress, SocketAddressParseError> {
973+
pub fn parse_onion_address(host: &str, port: u16) -> Result<SocketAddress, SocketAddressParseError> {
968974
if host.ends_with(".onion") {
969975
let domain = &host[..host.len() - ".onion".len()];
970-
if domain.len() != 16 {
971-
return Err(SocketAddressParseError::InvalidOnionV2);
976+
if domain.len() != 56 && domain.len() !=16 {
977+
return Err(SocketAddressParseError::InvalidOnion);
972978
}
973-
let onion = base32::Alphabet::RFC4648 { padding: false }.decode(&domain).map_err(|_| SocketAddressParseError::InvalidOnionV2)?;
974-
if onion.len() != 12 {
975-
return Err(SocketAddressParseError::InvalidOnionV2);
979+
let onion = base32::Alphabet::RFC4648 { padding: false }.decode(&domain).map_err(|_| SocketAddressParseError::InvalidOnion)?;
980+
if onion.len() != 35 && onion.len() != 10 {
981+
return Err(SocketAddressParseError::InvalidOnion);
976982
}
977-
let mut bytes = [0; 12];
978-
bytes.copy_from_slice(&onion);
979-
return Ok(SocketAddress::OnionV2(bytes));
980-
} else {
981-
return Err(SocketAddressParseError::InvalidInput);
982-
}
983-
}
984-
985-
/// Parses an OnionV3 host and port into a [`SocketAddress::OnionV3`].
986-
///
987-
/// The host part must end with ".onion".
988-
pub fn parse_onion_v3_address(host: &str, port: u16) -> Result<SocketAddress, SocketAddressParseError> {
989-
if host.ends_with(".onion") {
990-
let domain = &host[..host.len() - ".onion".len()];
991-
if domain.len() != 56 {
992-
return Err(SocketAddressParseError::InvalidOnionV3);
993-
}
994-
let onion = base32::Alphabet::RFC4648 { padding: false }.decode(&domain).map_err(|_| SocketAddressParseError::InvalidOnionV3)?;
995-
if onion.len() != 35 {
996-
return Err(SocketAddressParseError::InvalidOnionV3);
983+
if onion.len() == 10 {
984+
let mut addr = [0; 10];
985+
addr.copy_from_slice(&onion);
986+
return Ok(SocketAddress::OnionV2{ addr, port });
997987
}
998988
let version = onion[0];
999989
let first_checksum_flag = onion[1];
@@ -1009,9 +999,9 @@ pub fn parse_onion_v3_address(host: &str, port: u16) -> Result<SocketAddress, So
1009999
}
10101000

10111001
/// [`SocketAddress::OnionV2`] to onion address string
1012-
pub fn to_onion_v2_string(bytes: &[u8; 12]) -> String {
1013-
let onion = base32::Alphabet::RFC4648 { padding: false }.encode(&bytes[..]);
1014-
format!("{onion}.onion")
1002+
pub fn to_onion_v2_string(addr: &[u8; 10], port: &u16) -> String {
1003+
let onion = base32::Alphabet::RFC4648 { padding: false }.encode(&addr[..]);
1004+
format!("{onion}.onion:{port}")
10151005
}
10161006

10171007
/// [`SocketAddress::OnionV3`] to onion address string
@@ -1029,7 +1019,7 @@ impl Display for SocketAddress {
10291019
match self {
10301020
SocketAddress::TcpIpV4{addr, port} => write!(f, "{}:{port}", std::net::Ipv4Addr::from(*addr))?,
10311021
SocketAddress::TcpIpV6{addr, port} => write!(f, "[{}]:{port}", std::net::Ipv6Addr::from(*addr))?,
1032-
SocketAddress::OnionV2(bytes) => write!(f, "{}", to_onion_v2_string(&bytes))?,
1022+
SocketAddress::OnionV2{addr, port} => write!(f, "{}", to_onion_v2_string(addr, port))?,
10331023
SocketAddress::OnionV3 {
10341024
ed25519_pubkey,
10351025
checksum,
@@ -1052,13 +1042,12 @@ impl FromStr for SocketAddress {
10521042
Err(_) => {
10531043
let trimmed_input = match s.rfind(":") {
10541044
Some(pos) => pos,
1055-
None if s.ends_with(".onion") => return parse_onion_v2_address(s),
1056-
_ => return Err(SocketAddressParseError::InvalidInput),
1045+
None => return Err(SocketAddressParseError::InvalidInput),
10571046
};
10581047
let host = &s[..trimmed_input];
10591048
let port: u16 = s[trimmed_input + 1..].parse().map_err(|_| SocketAddressParseError::InvalidPort)?;
10601049
if host.ends_with(".onion") {
1061-
return parse_onion_v3_address(host, port);
1050+
return parse_onion_address(host, port);
10621051
};
10631052
if let Ok(hostname) = Hostname::try_from(s[..trimmed_input].to_string()) {
10641053
return Ok(SocketAddress::Hostname { hostname, port });
@@ -2915,9 +2904,10 @@ mod tests {
29152904
});
29162905
}
29172906
if onionv2 {
2918-
addresses.push(msgs::SocketAddress::OnionV2(
2919-
[255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 38, 7]
2920-
));
2907+
addresses.push(msgs::SocketAddress::OnionV2 {
2908+
addr: [255, 254, 253, 252, 251, 250, 249, 248, 247, 246],
2909+
port: 9735,
2910+
});
29212911
}
29222912
if onionv3 {
29232913
addresses.push(msgs::SocketAddress::OnionV3 {
@@ -4125,19 +4115,19 @@ mod tests {
41254115
#[test]
41264116
#[cfg(feature = "std")]
41274117
fn test_socket_address_from_str() {
4128-
let v4 = SocketAddress::TcpIpV4 {
4118+
let tcpip_v4 = SocketAddress::TcpIpV4 {
41294119
addr: Ipv4Addr::new(127, 0, 0, 1).octets(),
41304120
port: 1234,
41314121
};
4132-
assert_eq!(v4, SocketAddress::from_str("127.0.0.1:1234").unwrap());
4133-
assert_eq!(v4, SocketAddress::from_str(&v4.to_string()).unwrap());
4122+
assert_eq!(tcpip_v4, SocketAddress::from_str("127.0.0.1:1234").unwrap());
4123+
assert_eq!(tcpip_v4, SocketAddress::from_str(&tcpip_v4.to_string()).unwrap());
41344124

4135-
let v6 = SocketAddress::TcpIpV6 {
4125+
let tcpip_v6 = SocketAddress::TcpIpV6 {
41364126
addr: Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).octets(),
41374127
port: 1234,
41384128
};
4139-
assert_eq!(v6, SocketAddress::from_str("[0:0:0:0:0:0:0:1]:1234").unwrap());
4140-
assert_eq!(v6, SocketAddress::from_str(&v6.to_string()).unwrap());
4129+
assert_eq!(tcpip_v6, SocketAddress::from_str("[0:0:0:0:0:0:0:1]:1234").unwrap());
4130+
assert_eq!(tcpip_v6, SocketAddress::from_str(&tcpip_v6.to_string()).unwrap());
41414131

41424132
let hostname = SocketAddress::Hostname {
41434133
hostname: Hostname::try_from("lightning-node.mydomain.com".to_string()).unwrap(),
@@ -4146,21 +4136,24 @@ mod tests {
41464136
assert_eq!(hostname, SocketAddress::from_str("lightning-node.mydomain.com:1234").unwrap());
41474137
assert_eq!(hostname, SocketAddress::from_str(&hostname.to_string()).unwrap());
41484138

4149-
let v2 = SocketAddress::OnionV2 ([37, 24, 75, 5, 25, 73, 117, 194, 139, 102, 182, 107]);
4150-
assert_eq!(v2, SocketAddress::from_str("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion:1234").unwrap());
4151-
assert_eq!(v2, SocketAddress::from_str(&v2.to_string()).unwrap());
4139+
let onion_v2 = SocketAddress::OnionV2{
4140+
addr: [40, 4, 64, 185, 202, 19, 162, 75, 90, 200],
4141+
port: 80,
4142+
};
4143+
assert_eq!(onion_v2, SocketAddress::from_str("facebookcorewwwi.onion:80").unwrap());
4144+
assert_eq!(onion_v2, SocketAddress::from_str(&onion_v2.to_string()).unwrap());
41524145

4153-
let v3 = SocketAddress::OnionV3 {
4146+
let onion_v3 = SocketAddress::OnionV3 {
41544147
ed25519_pubkey: [37, 24, 75, 5, 25, 73, 117, 194, 139, 102, 182, 107, 4, 105, 247, 246, 85,
41554148
111, 177, 172, 49, 137, 167, 155, 64, 221, 163, 47, 31, 33, 71, 3],
41564149
checksum: 48326,
41574150
version: 121,
41584151
port: 1234
41594152
};
4160-
assert_eq!(v3, SocketAddress::from_str("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion:1234").unwrap());
4161-
assert_eq!(v3, SocketAddress::from_str(&v3.to_string()).unwrap());
4153+
assert_eq!(onion_v3, SocketAddress::from_str("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion:1234").unwrap());
4154+
assert_eq!(onion_v3, SocketAddress::from_str(&onion_v3.to_string()).unwrap());
41624155

4163-
assert_eq!(Err(SocketAddressParseError::InvalidOnionV3), SocketAddress::from_str("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6.onion:1234"));
4156+
assert_eq!(Err(SocketAddressParseError::InvalidOnion), SocketAddress::from_str("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6.onion:1234"));
41644157
assert_eq!(Err(SocketAddressParseError::InvalidInput), SocketAddress::from_str("127.0.0.1@1234"));
41654158
assert_eq!(Err(SocketAddressParseError::InvalidInput), "".parse::<SocketAddress>());
41664159
assert!(SocketAddress::from_str("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion.onion:9735:94").is_err());

lightning/src/util/ser.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@ macro_rules! impl_array {
587587

588588
impl_array!(3, u8); // for rgb, ISO 4712 code
589589
impl_array!(4, u8); // for IPv4
590-
impl_array!(12, u8); // for OnionV2
590+
impl_array!(10, u8); // for OnionV2
591591
impl_array!(16, u8); // for IPv6
592592
impl_array!(32, u8); // for channel id & hmac
593593
impl_array!(PUBLIC_KEY_SIZE, u8); // for PublicKey

0 commit comments

Comments
 (0)