@@ -23,6 +23,7 @@ use serde::{de::Unexpected, Deserialize, Deserializer, Serialize};
2323use serde_with:: skip_serializing_none;
2424use strsim:: jaro_winkler;
2525use typed_builder:: TypedBuilder ;
26+ use std:: net:: { IpAddr , Ipv4Addr , Ipv6Addr } ;
2627
2728#[ cfg( any(
2829 feature = "zstd-compression" ,
@@ -197,64 +198,78 @@ impl ServerAddress {
197198 } ) ;
198199 }
199200 }
200- let mut parts = address. split ( ':' ) ;
201- let hostname = match parts. next ( ) {
202- Some ( part) => {
203- if part. is_empty ( ) {
201+
202+ // Check if the address is IPv6, indicated by square brackets
203+ let ( hostname, port_str) = if address. starts_with ( '[' ) {
204+ match address. rfind ( ']' ) {
205+ Some ( bracket_pos) => {
206+ let addr_without_brackets = & address[ 1 ..bracket_pos] ;
207+ let port = if bracket_pos + 1 < address. len ( ) {
208+ if !address[ bracket_pos + 1 ..] . starts_with ( ':' ) {
209+ return Err ( ErrorKind :: InvalidArgument {
210+ message : format ! ( "invalid IPv6 address format: expected ':' after ']' in \" {}\" " , address) ,
211+ } . into ( ) ) ;
212+ }
213+ Some ( & address[ bracket_pos + 2 ..] )
214+ } else {
215+ None
216+ } ;
217+ ( addr_without_brackets, port)
218+ } ,
219+ None => {
204220 return Err ( ErrorKind :: InvalidArgument {
205- message : format ! (
206- "invalid server address: \" {}\" ; hostname cannot be empty" ,
207- address
208- ) ,
209- }
210- . into ( ) ) ;
221+ message : format ! ( "invalid IPv6 address format: missing closing bracket in \" {}\" " , address) ,
222+ } . into ( ) ) ;
211223 }
212- part
213224 }
214- None => {
215- return Err ( ErrorKind :: InvalidArgument {
216- message : format ! ( "invalid server address: \" {}\" " , address) ,
225+ } else {
226+ match address. rsplit_once ( ':' ) {
227+ Some ( ( host, port) ) => ( host, Some ( port) ) ,
228+ None => {
229+ return Err ( ErrorKind :: InvalidArgument {
230+ message : format ! ( "invalid server address: \" {}\" ; port is required" , address) ,
231+ } . into ( ) )
217232 }
218- . into ( ) )
219233 }
220234 } ;
221235
222- let port = match parts. next ( ) {
223- Some ( part) => {
224- let port = u16:: from_str ( part) . map_err ( |_| ErrorKind :: InvalidArgument {
225- message : format ! (
226- "port must be valid 16-bit unsigned integer, instead got: {}" ,
227- part
228- ) ,
229- } ) ?;
236+ // Validate that the hostname is either a valid IPv4 or IPv6 address
237+ let is_ipv4 = Ipv4Addr :: from_str ( hostname) . is_ok ( ) ;
238+ let is_ipv6 = Ipv6Addr :: from_str ( hostname) . is_ok ( ) ;
239+ let localhost_v4 = IpAddr :: V4 ( Ipv4Addr :: new ( 127 , 0 , 0 , 1 ) ) ;
240+ let localhost_v6 = IpAddr :: V6 ( Ipv6Addr :: new ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 ) ) ;
241+ if !is_ipv4 && !is_ipv6 && "127.0.0.1" . parse ( ) != Ok ( localhost_v4) && "::1" . parse ( ) != Ok ( localhost_v6) {
242+ return Err ( ErrorKind :: InvalidArgument {
243+ message : format ! ( "invalid hostname: \" {}\" " , hostname) ,
244+ }
245+ . into ( ) )
246+ }
230247
231- if port == 0 {
248+ // Validate port
249+ let port = match port_str {
250+ None => {
251+ return Err ( ErrorKind :: InvalidArgument {
252+ message : format ! ( "invalid server address: \" {}\" ; port is required" , address) ,
253+ } . into ( ) )
254+ }
255+ Some ( port_str) => match port_str. parse :: < u16 > ( ) {
256+ Ok ( 0 ) => {
232257 return Err ( ErrorKind :: InvalidArgument {
233- message : format ! (
234- "invalid server address: \" {}\" ; port must be non-zero" ,
235- address
236- ) ,
237- }
238- . into ( ) ) ;
258+ message : format ! ( "invalid server address: \" {}\" ; port cannot be 0" , address) ,
259+ } . into ( ) )
239260 }
240- if parts. next ( ) . is_some ( ) {
261+ Ok ( port) => port,
262+ Err ( _) => {
241263 return Err ( ErrorKind :: InvalidArgument {
242- message : format ! (
243- "address \" {}\" contains more than one unescaped ':'" ,
244- address
245- ) ,
246- }
247- . into ( ) ) ;
264+ message : format ! ( "invalid server address: \" {}\" ; invalid port number" , address) ,
265+ } . into ( ) )
248266 }
249-
250- Some ( port)
251267 }
252- None => None ,
253268 } ;
254269
255270 Ok ( ServerAddress :: Tcp {
256271 host : hostname. to_lowercase ( ) ,
257- port,
272+ port : Some ( port ) ,
258273 } )
259274 }
260275
@@ -266,6 +281,7 @@ impl ServerAddress {
266281 Self :: Unix { path } => path. to_string_lossy ( ) ,
267282 }
268283 }
284+ }
269285}
270286
271287impl fmt:: Display for ServerAddress {
0 commit comments