@@ -774,8 +774,13 @@ 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
+ /// The port on which the node is listening
782
+ port : u16 ,
783
+ } ,
779
784
/// A new-style Tor onion address/port on which the peer is listening.
780
785
///
781
786
/// To create the human-readable "hostname", concatenate the ED25519 pubkey, checksum, and version,
@@ -805,7 +810,7 @@ impl SocketAddress {
805
810
match self {
806
811
& SocketAddress :: TcpIpV4 { ..} => { 1 } ,
807
812
& SocketAddress :: TcpIpV6 { ..} => { 2 } ,
808
- & SocketAddress :: OnionV2 ( _ ) => { 3 } ,
813
+ & SocketAddress :: OnionV2 { .. } => { 3 } ,
809
814
& SocketAddress :: OnionV3 { ..} => { 4 } ,
810
815
& SocketAddress :: Hostname { ..} => { 5 } ,
811
816
}
@@ -816,7 +821,7 @@ impl SocketAddress {
816
821
match self {
817
822
& SocketAddress :: TcpIpV4 { .. } => { 6 } ,
818
823
& SocketAddress :: TcpIpV6 { .. } => { 18 } ,
819
- & SocketAddress :: OnionV2 ( _ ) => { 12 } ,
824
+ & SocketAddress :: OnionV2 { .. } => { 12 } ,
820
825
& SocketAddress :: OnionV3 { .. } => { 37 } ,
821
826
// Consists of 1-byte hostname length, hostname bytes, and 2-byte port.
822
827
& SocketAddress :: Hostname { ref hostname, .. } => { u16:: from ( hostname. len ( ) ) + 3 } ,
@@ -842,9 +847,10 @@ impl Writeable for SocketAddress {
842
847
addr. write ( writer) ?;
843
848
port. write ( writer) ?;
844
849
} ,
845
- & SocketAddress :: OnionV2 ( bytes ) => {
850
+ & SocketAddress :: OnionV2 { ref addr , ref port } => {
846
851
3u8 . write ( writer) ?;
847
- bytes. write ( writer) ?;
852
+ addr. write ( writer) ?;
853
+ port. write ( writer) ?;
848
854
} ,
849
855
& SocketAddress :: OnionV3 { ref ed25519_pubkey, ref checksum, ref version, ref port } => {
850
856
4u8 . write ( writer) ?;
@@ -879,7 +885,10 @@ impl Readable for Result<SocketAddress, u8> {
879
885
port : Readable :: read ( reader) ?,
880
886
} ) )
881
887
} ,
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
+ } ) ) ,
883
892
4 => {
884
893
Ok ( Ok ( SocketAddress :: OnionV3 {
885
894
ed25519_pubkey : Readable :: read ( reader) ?,
@@ -918,10 +927,8 @@ pub enum SocketAddressParseError {
918
927
InvalidInput ,
919
928
/// Invalid port
920
929
InvalidPort ,
921
- /// Invalid onion v2 address
922
- InvalidOnionV2 ,
923
- /// Invalid onion v3 address
924
- InvalidOnionV3 ,
930
+ /// Invalid onion address
931
+ InvalidOnion ,
925
932
}
926
933
927
934
impl fmt:: Display for SocketAddressParseError {
@@ -931,8 +938,7 @@ impl fmt::Display for SocketAddressParseError {
931
938
SocketAddressParseError :: InvalidInput => write ! ( f, "Invalid input format. \
932
939
Expected: \" <ipv4>:<port>\" , \" [<ipv6>]:<port>\" , \" <onion address>.onion:<port>\" or \" <hostname>:<port>\" ") ,
933
940
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" ) ,
936
942
}
937
943
}
938
944
}
@@ -961,39 +967,23 @@ impl From<std::net::SocketAddr> for SocketAddress {
961
967
}
962
968
}
963
969
964
- /// Parses an OnionV2 host and port into a [`SocketAddress::OnionV2 `].
970
+ /// Parses an Onion host and port into a [`SocketAddress::OnionV3 `].
965
971
///
966
972
/// 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 > {
968
974
if host. ends_with ( ".onion" ) {
969
975
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 ) ;
972
978
}
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 ) ;
976
982
}
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 } ) ;
997
987
}
998
988
let version = onion[ 0 ] ;
999
989
let first_checksum_flag = onion[ 1 ] ;
@@ -1009,9 +999,9 @@ pub fn parse_onion_v3_address(host: &str, port: u16) -> Result<SocketAddress, So
1009
999
}
1010
1000
1011
1001
/// [`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} " )
1015
1005
}
1016
1006
1017
1007
/// [`SocketAddress::OnionV3`] to onion address string
@@ -1029,7 +1019,7 @@ impl Display for SocketAddress {
1029
1019
match self {
1030
1020
SocketAddress :: TcpIpV4 { addr, port} => write ! ( f, "{}:{port}" , std:: net:: Ipv4Addr :: from( * addr) ) ?,
1031
1021
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 ) ) ?,
1033
1023
SocketAddress :: OnionV3 {
1034
1024
ed25519_pubkey,
1035
1025
checksum,
@@ -1052,13 +1042,12 @@ impl FromStr for SocketAddress {
1052
1042
Err ( _) => {
1053
1043
let trimmed_input = match s. rfind ( ":" ) {
1054
1044
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 ) ,
1057
1046
} ;
1058
1047
let host = & s[ ..trimmed_input] ;
1059
1048
let port: u16 = s[ trimmed_input + 1 ..] . parse ( ) . map_err ( |_| SocketAddressParseError :: InvalidPort ) ?;
1060
1049
if host. ends_with ( ".onion" ) {
1061
- return parse_onion_v3_address ( host, port) ;
1050
+ return parse_onion_address ( host, port) ;
1062
1051
} ;
1063
1052
if let Ok ( hostname) = Hostname :: try_from ( s[ ..trimmed_input] . to_string ( ) ) {
1064
1053
return Ok ( SocketAddress :: Hostname { hostname, port } ) ;
@@ -2915,9 +2904,10 @@ mod tests {
2915
2904
} ) ;
2916
2905
}
2917
2906
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
+ } ) ;
2921
2911
}
2922
2912
if onionv3 {
2923
2913
addresses. push ( msgs:: SocketAddress :: OnionV3 {
@@ -4125,19 +4115,19 @@ mod tests {
4125
4115
#[ test]
4126
4116
#[ cfg( feature = "std" ) ]
4127
4117
fn test_socket_address_from_str ( ) {
4128
- let v4 = SocketAddress :: TcpIpV4 {
4118
+ let tcpip_v4 = SocketAddress :: TcpIpV4 {
4129
4119
addr : Ipv4Addr :: new ( 127 , 0 , 0 , 1 ) . octets ( ) ,
4130
4120
port : 1234 ,
4131
4121
} ;
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( ) ) ;
4134
4124
4135
- let v6 = SocketAddress :: TcpIpV6 {
4125
+ let tcpip_v6 = SocketAddress :: TcpIpV6 {
4136
4126
addr : Ipv6Addr :: new ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 ) . octets ( ) ,
4137
4127
port : 1234 ,
4138
4128
} ;
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( ) ) ;
4141
4131
4142
4132
let hostname = SocketAddress :: Hostname {
4143
4133
hostname : Hostname :: try_from ( "lightning-node.mydomain.com" . to_string ( ) ) . unwrap ( ) ,
@@ -4146,21 +4136,24 @@ mod tests {
4146
4136
assert_eq ! ( hostname, SocketAddress :: from_str( "lightning-node.mydomain.com:1234" ) . unwrap( ) ) ;
4147
4137
assert_eq ! ( hostname, SocketAddress :: from_str( & hostname. to_string( ) ) . unwrap( ) ) ;
4148
4138
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( ) ) ;
4152
4145
4153
- let v3 = SocketAddress :: OnionV3 {
4146
+ let onion_v3 = SocketAddress :: OnionV3 {
4154
4147
ed25519_pubkey : [ 37 , 24 , 75 , 5 , 25 , 73 , 117 , 194 , 139 , 102 , 182 , 107 , 4 , 105 , 247 , 246 , 85 ,
4155
4148
111 , 177 , 172 , 49 , 137 , 167 , 155 , 64 , 221 , 163 , 47 , 31 , 33 , 71 , 3 ] ,
4156
4149
checksum : 48326 ,
4157
4150
version : 121 ,
4158
4151
port : 1234
4159
4152
} ;
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( ) ) ;
4162
4155
4163
- assert_eq ! ( Err ( SocketAddressParseError :: InvalidOnionV3 ) , SocketAddress :: from_str( "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6.onion:1234" ) ) ;
4156
+ assert_eq ! ( Err ( SocketAddressParseError :: InvalidOnion ) , SocketAddress :: from_str( "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6.onion:1234" ) ) ;
4164
4157
assert_eq ! ( Err ( SocketAddressParseError :: InvalidInput ) , SocketAddress :: from_str( "127.0.0.1@1234" ) ) ;
4165
4158
assert_eq ! ( Err ( SocketAddressParseError :: InvalidInput ) , "" . parse:: <SocketAddress >( ) ) ;
4166
4159
assert ! ( SocketAddress :: from_str( "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion.onion:9735:94" ) . is_err( ) ) ;
0 commit comments