@@ -896,7 +896,7 @@ impl Readable for NetAddress {
896
896
897
897
/// NetAddress error variants
898
898
#[ cfg( feature = "std" ) ]
899
- #[ derive( Debug ) ]
899
+ #[ derive( Debug , Eq , PartialEq , Clone ) ]
900
900
pub enum NetAddressError {
901
901
/// Socket address(IPv4/IPv6) parsing error
902
902
SocketAdrrParseError ( std:: net:: AddrParseError ) ,
@@ -910,24 +910,24 @@ pub enum NetAddressError {
910
910
911
911
#[ cfg( feature = "std" ) ]
912
912
impl FromStr for NetAddress {
913
- type Err = NetAddressError ;
914
-
915
- fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
916
- match std:: net:: SocketAddr :: from_str ( s) {
917
- Ok ( addr) => {
918
- let port: u16 = addr. port ( ) ;
919
- match addr {
920
- std:: net:: SocketAddr :: V4 ( addr) => {
921
- let addr = addr. ip ( ) . octets ( ) ;
922
- return Ok ( NetAddress :: IPv4 { addr, port } ) ;
923
- } ,
924
- std:: net:: SocketAddr :: V6 ( addr) => {
925
- let addr = addr. ip ( ) . octets ( ) ;
926
- return Ok ( NetAddress :: IPv6 { addr, port } ) ;
927
- } ,
928
- }
929
- } ,
930
- Err ( e) => {
913
+ type Err = NetAddressError ;
914
+
915
+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
916
+ match std:: net:: SocketAddr :: from_str ( s) {
917
+ Ok ( addr) => {
918
+ let port: u16 = addr. port ( ) ;
919
+ match addr {
920
+ std:: net:: SocketAddr :: V4 ( addr) => {
921
+ let addr = addr. ip ( ) . octets ( ) ;
922
+ return Ok ( NetAddress :: IPv4 { addr, port } ) ;
923
+ } ,
924
+ std:: net:: SocketAddr :: V6 ( addr) => {
925
+ let addr = addr. ip ( ) . octets ( ) ;
926
+ return Ok ( NetAddress :: IPv6 { addr, port } ) ;
927
+ } ,
928
+ }
929
+ } ,
930
+ Err ( e) => {
931
931
let trimmed_input = match s. rfind ( ":" ) {
932
932
Some ( pos) => pos,
933
933
None => return Err ( NetAddressError :: InvalidInput ( "Invalid input. Expected format: \" <host>:<port>\" " . to_string ( ) ) ) ,
@@ -937,36 +937,48 @@ impl FromStr for NetAddress {
937
937
Ok ( port) => port,
938
938
Err ( _) => return Err ( NetAddressError :: InvalidPort ) ,
939
939
} ;
940
- if host. ends_with ( ".onion" ) {
941
- let onion = match host. split ( ".onion" ) . nth ( 0 ) {
942
- Some ( onion) => onion,
943
- None => return Err ( NetAddressError :: InvalidOnionV3 ) ,
944
- } ;
945
- let onion = match ( base32:: Alphabet :: RFC4648 { padding : false } . decode ( & onion) ) {
946
- Ok ( onion) => onion,
947
- Err ( _) => return Err ( NetAddressError :: InvalidOnionV3 ) ,
948
- } ;
949
- match ( onion. get ( 0 ) , onion. get ( 1 ) , onion. get ( 2 ) ) {
950
- ( Some ( version) , Some ( first_checksum_flag) , Some ( second_checksum_flag) ) => {
951
- let checksum = u16:: from_be_bytes ( [ * first_checksum_flag, * second_checksum_flag] ) ;
952
- let ed25519_pubkey = match onion[ 3 ..35 ] . try_into ( ) {
953
- Ok ( ed25519_pubkey) => ed25519_pubkey,
954
- Err ( _) => return Err ( NetAddressError :: InvalidOnionV3 ) ,
955
- } ;
956
- return Ok ( NetAddress :: OnionV3 { ed25519_pubkey, checksum, version : * version, port } ) ;
957
-
940
+ let host: Vec < & str > = host. split ( "." ) . collect ( ) ;
941
+ if host. len ( ) == 2 {
942
+ match ( host. get ( 0 ) , host. get ( 1 ) ) {
943
+ ( Some ( domain) , Some ( suffix) ) => {
944
+ if suffix. to_string ( ) == "onion" . to_owned ( ) {
945
+ if domain. len ( ) != 56 {
946
+ return Err ( NetAddressError :: InvalidOnionV3 ) ;
947
+ }
948
+ let onion = match ( base32:: Alphabet :: RFC4648 { padding : false } . decode ( & domain) ) {
949
+ Ok ( onion) => onion,
950
+ Err ( _) => return Err ( NetAddressError :: InvalidOnionV3 ) ,
951
+ } ;
952
+ if onion. len ( ) < 35 {
953
+ return Err ( NetAddressError :: InvalidOnionV3 ) ;
954
+ }
955
+ match ( onion. get ( 0 ) , onion. get ( 1 ) , onion. get ( 2 ) ) {
956
+ ( Some ( version) , Some ( first_checksum_flag) , Some ( second_checksum_flag) ) => {
957
+ let checksum = u16:: from_be_bytes ( [ * first_checksum_flag, * second_checksum_flag] ) ;
958
+ let ed25519_pubkey = match onion[ 3 ..35 ] . try_into ( ) {
959
+ Ok ( ed25519_pubkey) => ed25519_pubkey,
960
+ Err ( _) => return Err ( NetAddressError :: InvalidOnionV3 ) ,
961
+ } ;
962
+ return Ok ( NetAddress :: OnionV3 { ed25519_pubkey, checksum, version : * version, port } ) ;
963
+
964
+ } ,
965
+ _ => return Err ( NetAddressError :: InvalidOnionV3 ) ,
966
+ }
967
+ } else {
968
+ if let Ok ( hostname) = Hostname :: try_from ( s[ ..trimmed_input] . to_string ( ) ) {
969
+ return Ok ( NetAddress :: Hostname { hostname, port } ) ;
970
+ } else {
971
+ return Err ( NetAddressError :: InvalidInput ( "Invalid input. Expected format: \" <host>:<port>\" " . to_string ( ) ) ) ;
972
+ }
973
+ }
958
974
} ,
959
- _ => return Err ( NetAddressError :: InvalidOnionV3 ) ,
960
- }
961
- }
962
-
963
- if let Ok ( hostname) = Hostname :: try_from ( host. to_string ( ) ) {
964
- return Ok ( NetAddress :: Hostname { hostname, port } ) ;
965
- }
966
- return Err ( NetAddressError :: SocketAdrrParseError ( e) )
967
- } ,
968
- }
969
- }
975
+ _ => return Err ( NetAddressError :: SocketAdrrParseError ( e) )
976
+ } ;
977
+ }
978
+ return Err ( NetAddressError :: SocketAdrrParseError ( e) )
979
+ } ,
980
+ }
981
+ }
970
982
}
971
983
972
984
/// Represents the set of gossip messages that require a signature from a node's identity key.
@@ -3816,21 +3828,35 @@ mod tests {
3816
3828
addr: Ipv4Addr :: new( 127 , 0 , 0 , 1 ) . octets( ) ,
3817
3829
port: 1234 ,
3818
3830
} , NetAddress :: from_str( "127.0.0.1:1234" ) . unwrap( ) ) ;
3831
+
3819
3832
assert_eq ! ( NetAddress :: IPv6 {
3820
3833
addr : Ipv6Addr :: new( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 ) . octets( ) ,
3821
3834
port: 1234 ,
3822
3835
} , NetAddress :: from_str( "[0:0:0:0:0:0:0:1]:1234" ) . unwrap( ) ) ;
3836
+
3823
3837
assert_eq ! (
3824
3838
NetAddress :: Hostname {
3825
3839
hostname : Hostname :: try_from( "example.com" . to_string( ) ) . unwrap( ) ,
3826
3840
port: 1234 ,
3827
3841
} , NetAddress :: from_str( "example.com:1234" ) . unwrap( ) ) ;
3842
+
3828
3843
assert_eq ! ( NetAddress :: OnionV3 {
3829
3844
ed25519_pubkey: [ 37 , 24 , 75 , 5 , 25 , 73 , 117 , 194 , 139 , 102 , 182 , 107 , 4 , 105 , 247 , 246 , 85 ,
3830
3845
111 , 177 , 172 , 49 , 137 , 167 , 155 , 64 , 221 , 163 , 47 , 31 , 33 , 71 , 3 ] ,
3831
3846
checksum: 48326 ,
3832
3847
version: 121 ,
3833
3848
port: 1234
3834
3849
} , NetAddress :: from_str( "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion:1234" ) . unwrap( ) ) ;
3850
+
3851
+ let invalid_onion_address = "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6.onion:1234" ;
3852
+ assert_eq ! ( super :: NetAddressError :: InvalidOnionV3 , NetAddress :: from_str( invalid_onion_address) . unwrap_err( ) . into( ) ) ;
3853
+
3854
+ assert_eq ! ( super :: NetAddressError :: InvalidInput ( "Invalid input. Expected format: \" <host>:<port>\" " . to_string( ) ) , NetAddress :: from_str( "127.0.0.1@1234" ) . unwrap_err( ) . into( ) ) ;
3855
+
3856
+ assert ! ( NetAddress :: from_str( "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion.onion:9735:94" ) . is_err( ) ) ;
3857
+
3858
+ assert_eq ! ( super :: NetAddressError :: InvalidInput ( "Invalid input. Expected format: \" <host>:<port>\" " . to_string( ) ) , NetAddress :: from_str( "wrong$%#.com:1234" ) . unwrap_err( ) . into( ) ) ;
3859
+
3860
+ assert_eq ! ( super :: NetAddressError :: InvalidPort , NetAddress :: from_str( "example.com:wrong" ) . unwrap_err( ) . into( ) ) ;
3835
3861
}
3836
3862
}
0 commit comments