@@ -774,8 +774,12 @@ pub enum SocketAddress {
774
774
/// An old-style Tor onion address/port on which the peer is listening.
775
775
///
776
776
/// 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
+ port : u16 ,
782
+ } ,
779
783
/// A new-style Tor onion address/port on which the peer is listening.
780
784
///
781
785
/// To create the human-readable "hostname", concatenate the ED25519 pubkey, checksum, and version,
@@ -805,7 +809,7 @@ impl SocketAddress {
805
809
match self {
806
810
& SocketAddress :: TcpIpV4 { ..} => { 1 } ,
807
811
& SocketAddress :: TcpIpV6 { ..} => { 2 } ,
808
- & SocketAddress :: OnionV2 ( _ ) => { 3 } ,
812
+ & SocketAddress :: OnionV2 { .. } => { 3 } ,
809
813
& SocketAddress :: OnionV3 { ..} => { 4 } ,
810
814
& SocketAddress :: Hostname { ..} => { 5 } ,
811
815
}
@@ -816,7 +820,7 @@ impl SocketAddress {
816
820
match self {
817
821
& SocketAddress :: TcpIpV4 { .. } => { 6 } ,
818
822
& SocketAddress :: TcpIpV6 { .. } => { 18 } ,
819
- & SocketAddress :: OnionV2 ( _ ) => { 12 } ,
823
+ & SocketAddress :: OnionV2 { .. } => { 12 } ,
820
824
& SocketAddress :: OnionV3 { .. } => { 37 } ,
821
825
// Consists of 1-byte hostname length, hostname bytes, and 2-byte port.
822
826
& SocketAddress :: Hostname { ref hostname, .. } => { u16:: from ( hostname. len ( ) ) + 3 } ,
@@ -842,9 +846,10 @@ impl Writeable for SocketAddress {
842
846
addr. write ( writer) ?;
843
847
port. write ( writer) ?;
844
848
} ,
845
- & SocketAddress :: OnionV2 ( bytes ) => {
849
+ & SocketAddress :: OnionV2 { ref addr , ref port } => {
846
850
3u8 . write ( writer) ?;
847
- bytes. write ( writer) ?;
851
+ addr. write ( writer) ?;
852
+ port. write ( writer) ?;
848
853
} ,
849
854
& SocketAddress :: OnionV3 { ref ed25519_pubkey, ref checksum, ref version, ref port } => {
850
855
4u8 . write ( writer) ?;
@@ -879,7 +884,10 @@ impl Readable for Result<SocketAddress, u8> {
879
884
port : Readable :: read ( reader) ?,
880
885
} ) )
881
886
} ,
882
- 3 => Ok ( Ok ( SocketAddress :: OnionV2 ( Readable :: read ( reader) ?) ) ) ,
887
+ 3 => Ok ( Ok ( SocketAddress :: OnionV2 {
888
+ addr : Readable :: read ( reader) ?,
889
+ port : Readable :: read ( reader) ?,
890
+ } ) ) ,
883
891
4 => {
884
892
Ok ( Ok ( SocketAddress :: OnionV3 {
885
893
ed25519_pubkey : Readable :: read ( reader) ?,
@@ -961,40 +969,24 @@ impl From<std::net::SocketAddr> for SocketAddress {
961
969
}
962
970
}
963
971
964
- /// Parses an OnionV2 host and port into a [`SocketAddress::OnionV2`].
965
- ///
966
- /// The host part must end with ".onion".
967
- pub fn parse_onion_v2_address ( host : & str ) -> Result < SocketAddress , SocketAddressParseError > {
968
- if host. ends_with ( ".onion" ) {
969
- let domain = & host[ ..host. len ( ) - ".onion" . len ( ) ] ;
970
- if domain. len ( ) != 16 {
971
- return Err ( SocketAddressParseError :: InvalidOnionV2 ) ;
972
- }
973
- let onion = base32:: Alphabet :: RFC4648 { padding : false } . decode ( & domain) . map_err ( |_| SocketAddressParseError :: InvalidOnionV2 ) ?;
974
- if onion. len ( ) != 12 {
975
- return Err ( SocketAddressParseError :: InvalidOnionV2 ) ;
976
- }
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`].
972
+ /// Parses an Onion host and port into a [`SocketAddress::OnionV3`].
986
973
///
987
974
/// The host part must end with ".onion".
988
- pub fn parse_onion_v3_address ( host : & str , port : u16 ) -> Result < SocketAddress , SocketAddressParseError > {
975
+ pub fn parse_onion_address ( host : & str , port : u16 ) -> Result < SocketAddress , SocketAddressParseError > {
989
976
if host. ends_with ( ".onion" ) {
990
977
let domain = & host[ ..host. len ( ) - ".onion" . len ( ) ] ;
991
- if domain. len ( ) != 56 {
978
+ if domain. len ( ) != 56 && domain . len ( ) != 16 {
992
979
return Err ( SocketAddressParseError :: InvalidOnionV3 ) ;
993
980
}
994
981
let onion = base32:: Alphabet :: RFC4648 { padding : false } . decode ( & domain) . map_err ( |_| SocketAddressParseError :: InvalidOnionV3 ) ?;
995
- if onion. len ( ) != 35 {
982
+ if onion. len ( ) != 35 && onion . len ( ) != 10 {
996
983
return Err ( SocketAddressParseError :: InvalidOnionV3 ) ;
997
984
}
985
+ if onion. len ( ) == 10 {
986
+ let mut addr = [ 0 ; 10 ] ;
987
+ addr. copy_from_slice ( & onion) ;
988
+ return Ok ( SocketAddress :: OnionV2 { addr, port } ) ;
989
+ }
998
990
let version = onion[ 0 ] ;
999
991
let first_checksum_flag = onion[ 1 ] ;
1000
992
let second_checksum_flag = onion[ 2 ] ;
@@ -1009,9 +1001,9 @@ pub fn parse_onion_v3_address(host: &str, port: u16) -> Result<SocketAddress, So
1009
1001
}
1010
1002
1011
1003
/// [`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" )
1004
+ pub fn to_onion_v2_string ( addr : & [ u8 ; 10 ] , port : & u16 ) -> String {
1005
+ let onion = base32:: Alphabet :: RFC4648 { padding : false } . encode ( & addr [ ..] ) ;
1006
+ format ! ( "{onion}.onion:{port} " )
1015
1007
}
1016
1008
1017
1009
/// [`SocketAddress::OnionV3`] to onion address string
@@ -1029,7 +1021,7 @@ impl Display for SocketAddress {
1029
1021
match self {
1030
1022
SocketAddress :: TcpIpV4 { addr, port} => write ! ( f, "{}:{port}" , std:: net:: Ipv4Addr :: from( * addr) ) ?,
1031
1023
SocketAddress :: TcpIpV6 { addr, port} => write ! ( f, "[{}]:{port}" , std:: net:: Ipv6Addr :: from( * addr) ) ?,
1032
- SocketAddress :: OnionV2 ( bytes ) => write ! ( f, "{}" , to_onion_v2_string( & bytes ) ) ?,
1024
+ SocketAddress :: OnionV2 { addr , port } => write ! ( f, "{}" , to_onion_v2_string( addr , port ) ) ?,
1033
1025
SocketAddress :: OnionV3 {
1034
1026
ed25519_pubkey,
1035
1027
checksum,
@@ -1052,13 +1044,12 @@ impl FromStr for SocketAddress {
1052
1044
Err ( _) => {
1053
1045
let trimmed_input = match s. rfind ( ":" ) {
1054
1046
Some ( pos) => pos,
1055
- None if s. ends_with ( ".onion" ) => return parse_onion_v2_address ( s) ,
1056
- _ => return Err ( SocketAddressParseError :: InvalidInput ) ,
1047
+ None => return Err ( SocketAddressParseError :: InvalidInput ) ,
1057
1048
} ;
1058
1049
let host = & s[ ..trimmed_input] ;
1059
1050
let port: u16 = s[ trimmed_input + 1 ..] . parse ( ) . map_err ( |_| SocketAddressParseError :: InvalidPort ) ?;
1060
1051
if host. ends_with ( ".onion" ) {
1061
- return parse_onion_v3_address ( host, port) ;
1052
+ return parse_onion_address ( host, port) ;
1062
1053
} ;
1063
1054
if let Ok ( hostname) = Hostname :: try_from ( s[ ..trimmed_input] . to_string ( ) ) {
1064
1055
return Ok ( SocketAddress :: Hostname { hostname, port } ) ;
@@ -2915,9 +2906,10 @@ mod tests {
2915
2906
} ) ;
2916
2907
}
2917
2908
if onionv2 {
2918
- addresses. push ( msgs:: SocketAddress :: OnionV2 (
2919
- [ 255 , 254 , 253 , 252 , 251 , 250 , 249 , 248 , 247 , 246 , 38 , 7 ]
2920
- ) ) ;
2909
+ addresses. push ( msgs:: SocketAddress :: OnionV2 {
2910
+ addr : [ 255 , 254 , 253 , 252 , 251 , 250 , 249 , 248 , 247 , 246 ] ,
2911
+ port : 9735 ,
2912
+ } ) ;
2921
2913
}
2922
2914
if onionv3 {
2923
2915
addresses. push ( msgs:: SocketAddress :: OnionV3 {
@@ -4125,19 +4117,19 @@ mod tests {
4125
4117
#[ test]
4126
4118
#[ cfg( feature = "std" ) ]
4127
4119
fn test_socket_address_from_str ( ) {
4128
- let v4 = SocketAddress :: TcpIpV4 {
4120
+ let tcpip_v4 = SocketAddress :: TcpIpV4 {
4129
4121
addr : Ipv4Addr :: new ( 127 , 0 , 0 , 1 ) . octets ( ) ,
4130
4122
port : 1234 ,
4131
4123
} ;
4132
- assert_eq ! ( v4 , SocketAddress :: from_str( "127.0.0.1:1234" ) . unwrap( ) ) ;
4133
- assert_eq ! ( v4 , SocketAddress :: from_str( & v4 . to_string( ) ) . unwrap( ) ) ;
4124
+ assert_eq ! ( tcpip_v4 , SocketAddress :: from_str( "127.0.0.1:1234" ) . unwrap( ) ) ;
4125
+ assert_eq ! ( tcpip_v4 , SocketAddress :: from_str( & tcpip_v4 . to_string( ) ) . unwrap( ) ) ;
4134
4126
4135
- let v6 = SocketAddress :: TcpIpV6 {
4127
+ let tcpip_v6 = SocketAddress :: TcpIpV6 {
4136
4128
addr : Ipv6Addr :: new ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 ) . octets ( ) ,
4137
4129
port : 1234 ,
4138
4130
} ;
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( ) ) ;
4131
+ assert_eq ! ( tcpip_v6 , SocketAddress :: from_str( "[0:0:0:0:0:0:0:1]:1234" ) . unwrap( ) ) ;
4132
+ assert_eq ! ( tcpip_v6 , SocketAddress :: from_str( & tcpip_v6 . to_string( ) ) . unwrap( ) ) ;
4141
4133
4142
4134
let hostname = SocketAddress :: Hostname {
4143
4135
hostname : Hostname :: try_from ( "lightning-node.mydomain.com" . to_string ( ) ) . unwrap ( ) ,
@@ -4146,19 +4138,22 @@ mod tests {
4146
4138
assert_eq ! ( hostname, SocketAddress :: from_str( "lightning-node.mydomain.com:1234" ) . unwrap( ) ) ;
4147
4139
assert_eq ! ( hostname, SocketAddress :: from_str( & hostname. to_string( ) ) . unwrap( ) ) ;
4148
4140
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( ) ) ;
4141
+ let onion_v2 = SocketAddress :: OnionV2 {
4142
+ addr : [ 40 , 4 , 64 , 185 , 202 , 19 , 162 , 75 , 90 , 200 ] ,
4143
+ port : 80 ,
4144
+ } ;
4145
+ assert_eq ! ( onion_v2, SocketAddress :: from_str( "facebookcorewwwi.onion:80" ) . unwrap( ) ) ;
4146
+ assert_eq ! ( onion_v2, SocketAddress :: from_str( & onion_v2. to_string( ) ) . unwrap( ) ) ;
4152
4147
4153
- let v3 = SocketAddress :: OnionV3 {
4148
+ let onion_v3 = SocketAddress :: OnionV3 {
4154
4149
ed25519_pubkey : [ 37 , 24 , 75 , 5 , 25 , 73 , 117 , 194 , 139 , 102 , 182 , 107 , 4 , 105 , 247 , 246 , 85 ,
4155
4150
111 , 177 , 172 , 49 , 137 , 167 , 155 , 64 , 221 , 163 , 47 , 31 , 33 , 71 , 3 ] ,
4156
4151
checksum : 48326 ,
4157
4152
version : 121 ,
4158
4153
port : 1234
4159
4154
} ;
4160
- assert_eq ! ( v3 , SocketAddress :: from_str( "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion:1234" ) . unwrap( ) ) ;
4161
- assert_eq ! ( v3 , SocketAddress :: from_str( & v3 . to_string( ) ) . unwrap( ) ) ;
4155
+ assert_eq ! ( onion_v3 , SocketAddress :: from_str( "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion:1234" ) . unwrap( ) ) ;
4156
+ assert_eq ! ( onion_v3 , SocketAddress :: from_str( & onion_v3 . to_string( ) ) . unwrap( ) ) ;
4162
4157
4163
4158
assert_eq ! ( Err ( SocketAddressParseError :: InvalidOnionV3 ) , SocketAddress :: from_str( "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6.onion:1234" ) ) ;
4164
4159
assert_eq ! ( Err ( SocketAddressParseError :: InvalidInput ) , SocketAddress :: from_str( "127.0.0.1@1234" ) ) ;
0 commit comments