@@ -906,7 +906,7 @@ impl Readable for NetAddress {
906
906
907
907
/// NetAddress error variants
908
908
#[ cfg( feature = "std" ) ]
909
- #[ derive( Debug ) ]
909
+ #[ derive( Debug , Eq , PartialEq , Clone ) ]
910
910
pub enum NetAddressError {
911
911
/// Socket address(IPv4/IPv6) parsing error
912
912
SocketAdrrParseError ( std:: net:: AddrParseError ) ,
@@ -920,24 +920,24 @@ pub enum NetAddressError {
920
920
921
921
#[ cfg( feature = "std" ) ]
922
922
impl FromStr for NetAddress {
923
- type Err = NetAddressError ;
924
-
925
- fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
926
- match std:: net:: SocketAddr :: from_str ( s) {
927
- Ok ( addr) => {
928
- let port: u16 = addr. port ( ) ;
929
- match addr {
930
- std:: net:: SocketAddr :: V4 ( addr) => {
931
- let addr = addr. ip ( ) . octets ( ) ;
932
- return Ok ( NetAddress :: IPv4 { addr, port } ) ;
933
- } ,
934
- std:: net:: SocketAddr :: V6 ( addr) => {
935
- let addr = addr. ip ( ) . octets ( ) ;
936
- return Ok ( NetAddress :: IPv6 { addr, port } ) ;
937
- } ,
938
- }
939
- } ,
940
- Err ( e) => {
923
+ type Err = NetAddressError ;
924
+
925
+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
926
+ match std:: net:: SocketAddr :: from_str ( s) {
927
+ Ok ( addr) => {
928
+ let port: u16 = addr. port ( ) ;
929
+ match addr {
930
+ std:: net:: SocketAddr :: V4 ( addr) => {
931
+ let addr = addr. ip ( ) . octets ( ) ;
932
+ return Ok ( NetAddress :: IPv4 { addr, port } ) ;
933
+ } ,
934
+ std:: net:: SocketAddr :: V6 ( addr) => {
935
+ let addr = addr. ip ( ) . octets ( ) ;
936
+ return Ok ( NetAddress :: IPv6 { addr, port } ) ;
937
+ } ,
938
+ }
939
+ } ,
940
+ Err ( e) => {
941
941
let trimmed_input = match s. rfind ( ":" ) {
942
942
Some ( pos) => pos,
943
943
None => return Err ( NetAddressError :: InvalidInput ( "Invalid input. Expected format: \" <host>:<port>\" " . to_string ( ) ) ) ,
@@ -947,36 +947,48 @@ impl FromStr for NetAddress {
947
947
Ok ( port) => port,
948
948
Err ( _) => return Err ( NetAddressError :: InvalidPort ) ,
949
949
} ;
950
- if host. ends_with ( ".onion" ) {
951
- let onion = match host. split ( ".onion" ) . nth ( 0 ) {
952
- Some ( onion) => onion,
953
- None => return Err ( NetAddressError :: InvalidOnionV3 ) ,
954
- } ;
955
- let onion = match ( base32:: Alphabet :: RFC4648 { padding : false } . decode ( & onion) ) {
956
- Ok ( onion) => onion,
957
- Err ( _) => return Err ( NetAddressError :: InvalidOnionV3 ) ,
958
- } ;
959
- match ( onion. get ( 0 ) , onion. get ( 1 ) , onion. get ( 2 ) ) {
960
- ( Some ( version) , Some ( first_checksum_flag) , Some ( second_checksum_flag) ) => {
961
- let checksum = u16:: from_be_bytes ( [ * first_checksum_flag, * second_checksum_flag] ) ;
962
- let ed25519_pubkey = match onion[ 3 ..35 ] . try_into ( ) {
963
- Ok ( ed25519_pubkey) => ed25519_pubkey,
964
- Err ( _) => return Err ( NetAddressError :: InvalidOnionV3 ) ,
965
- } ;
966
- return Ok ( NetAddress :: OnionV3 { ed25519_pubkey, checksum, version : * version, port } ) ;
967
-
950
+ let host: Vec < & str > = host. split ( "." ) . collect ( ) ;
951
+ if host. len ( ) == 2 {
952
+ match ( host. get ( 0 ) , host. get ( 1 ) ) {
953
+ ( Some ( domain) , Some ( suffix) ) => {
954
+ if suffix. to_string ( ) == "onion" . to_owned ( ) {
955
+ if domain. len ( ) != 56 {
956
+ return Err ( NetAddressError :: InvalidOnionV3 ) ;
957
+ }
958
+ let onion = match ( base32:: Alphabet :: RFC4648 { padding : false } . decode ( & domain) ) {
959
+ Ok ( onion) => onion,
960
+ Err ( _) => return Err ( NetAddressError :: InvalidOnionV3 ) ,
961
+ } ;
962
+ if onion. len ( ) < 35 {
963
+ return Err ( NetAddressError :: InvalidOnionV3 ) ;
964
+ }
965
+ match ( onion. get ( 0 ) , onion. get ( 1 ) , onion. get ( 2 ) ) {
966
+ ( Some ( version) , Some ( first_checksum_flag) , Some ( second_checksum_flag) ) => {
967
+ let checksum = u16:: from_be_bytes ( [ * first_checksum_flag, * second_checksum_flag] ) ;
968
+ let ed25519_pubkey = match onion[ 3 ..35 ] . try_into ( ) {
969
+ Ok ( ed25519_pubkey) => ed25519_pubkey,
970
+ Err ( _) => return Err ( NetAddressError :: InvalidOnionV3 ) ,
971
+ } ;
972
+ return Ok ( NetAddress :: OnionV3 { ed25519_pubkey, checksum, version : * version, port } ) ;
973
+
974
+ } ,
975
+ _ => return Err ( NetAddressError :: InvalidOnionV3 ) ,
976
+ }
977
+ } else {
978
+ if let Ok ( hostname) = Hostname :: try_from ( s[ ..trimmed_input] . to_string ( ) ) {
979
+ return Ok ( NetAddress :: Hostname { hostname, port } ) ;
980
+ } else {
981
+ return Err ( NetAddressError :: InvalidInput ( "Invalid input. Expected format: \" <host>:<port>\" " . to_string ( ) ) ) ;
982
+ }
983
+ }
968
984
} ,
969
- _ => return Err ( NetAddressError :: InvalidOnionV3 ) ,
970
- }
971
- }
972
-
973
- if let Ok ( hostname) = Hostname :: try_from ( host. to_string ( ) ) {
974
- return Ok ( NetAddress :: Hostname { hostname, port } ) ;
975
- }
976
- return Err ( NetAddressError :: SocketAdrrParseError ( e) )
977
- } ,
978
- }
979
- }
985
+ _ => return Err ( NetAddressError :: SocketAdrrParseError ( e) )
986
+ } ;
987
+ }
988
+ return Err ( NetAddressError :: SocketAdrrParseError ( e) )
989
+ } ,
990
+ }
991
+ }
980
992
}
981
993
982
994
/// Represents the set of gossip messages that require a signature from a node's identity key.
@@ -3854,21 +3866,35 @@ mod tests {
3854
3866
addr: Ipv4Addr :: new( 127 , 0 , 0 , 1 ) . octets( ) ,
3855
3867
port: 1234 ,
3856
3868
} , NetAddress :: from_str( "127.0.0.1:1234" ) . unwrap( ) ) ;
3869
+
3857
3870
assert_eq ! ( NetAddress :: IPv6 {
3858
3871
addr : Ipv6Addr :: new( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 ) . octets( ) ,
3859
3872
port: 1234 ,
3860
3873
} , NetAddress :: from_str( "[0:0:0:0:0:0:0:1]:1234" ) . unwrap( ) ) ;
3874
+
3861
3875
assert_eq ! (
3862
3876
NetAddress :: Hostname {
3863
3877
hostname : Hostname :: try_from( "example.com" . to_string( ) ) . unwrap( ) ,
3864
3878
port: 1234 ,
3865
3879
} , NetAddress :: from_str( "example.com:1234" ) . unwrap( ) ) ;
3880
+
3866
3881
assert_eq ! ( NetAddress :: OnionV3 {
3867
3882
ed25519_pubkey: [ 37 , 24 , 75 , 5 , 25 , 73 , 117 , 194 , 139 , 102 , 182 , 107 , 4 , 105 , 247 , 246 , 85 ,
3868
3883
111 , 177 , 172 , 49 , 137 , 167 , 155 , 64 , 221 , 163 , 47 , 31 , 33 , 71 , 3 ] ,
3869
3884
checksum: 48326 ,
3870
3885
version: 121 ,
3871
3886
port: 1234
3872
3887
} , NetAddress :: from_str( "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion:1234" ) . unwrap( ) ) ;
3888
+
3889
+ let invalid_onion_address = "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6.onion:1234" ;
3890
+ assert_eq ! ( super :: NetAddressError :: InvalidOnionV3 , NetAddress :: from_str( invalid_onion_address) . unwrap_err( ) . into( ) ) ;
3891
+
3892
+ assert_eq ! ( super :: NetAddressError :: InvalidInput ( "Invalid input. Expected format: \" <host>:<port>\" " . to_string( ) ) , NetAddress :: from_str( "127.0.0.1@1234" ) . unwrap_err( ) . into( ) ) ;
3893
+
3894
+ assert ! ( NetAddress :: from_str( "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion.onion:9735:94" ) . is_err( ) ) ;
3895
+
3896
+ assert_eq ! ( super :: NetAddressError :: InvalidInput ( "Invalid input. Expected format: \" <host>:<port>\" " . to_string( ) ) , NetAddress :: from_str( "wrong$%#.com:1234" ) . unwrap_err( ) . into( ) ) ;
3897
+
3898
+ assert_eq ! ( super :: NetAddressError :: InvalidPort , NetAddress :: from_str( "example.com:wrong" ) . unwrap_err( ) . into( ) ) ;
3873
3899
}
3874
3900
}
0 commit comments