1 use std::hash::Hash; 2 use std::mem::{self, size_of, MaybeUninit}; 3 use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6}; 4 use std::path::Path; 5 use std::{fmt, io, ptr}; 6 7 #[cfg(windows)] 8 use windows_sys::Win32::Networking::WinSock::SOCKADDR_IN6_0; 9 10 use crate::sys::{ 11 c_int, sa_family_t, sockaddr, sockaddr_in, sockaddr_in6, sockaddr_storage, socklen_t, AF_INET, 12 AF_INET6, AF_UNIX, 13 }; 14 use crate::Domain; 15 16 /// The address of a socket. 17 /// 18 /// `SockAddr`s may be constructed directly to and from the standard library 19 /// [`SocketAddr`], [`SocketAddrV4`], and [`SocketAddrV6`] types. 20 #[derive(Clone)] 21 pub struct SockAddr { 22 storage: sockaddr_storage, 23 len: socklen_t, 24 } 25 26 #[allow(clippy::len_without_is_empty)] 27 impl SockAddr { 28 /// Create a `SockAddr` from the underlying storage and its length. 29 /// 30 /// # Safety 31 /// 32 /// Caller must ensure that the address family and length match the type of 33 /// storage address. For example if `storage.ss_family` is set to `AF_INET` 34 /// the `storage` must be initialised as `sockaddr_in`, setting the content 35 /// and length appropriately. 36 /// 37 /// # Examples 38 /// 39 /// ``` 40 /// # fn main() -> std::io::Result<()> { 41 /// # #[cfg(unix)] { 42 /// use std::io; 43 /// use std::mem; 44 /// use std::os::unix::io::AsRawFd; 45 /// 46 /// use socket2::{SockAddr, Socket, Domain, Type}; 47 /// 48 /// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?; 49 /// 50 /// // Initialise a `SocketAddr` byte calling `getsockname(2)`. 51 /// let mut addr_storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; 52 /// let mut len = mem::size_of_val(&addr_storage) as libc::socklen_t; 53 /// 54 /// // The `getsockname(2)` system call will intiliase `storage` for 55 /// // us, setting `len` to the correct length. 56 /// let res = unsafe { 57 /// libc::getsockname( 58 /// socket.as_raw_fd(), 59 /// (&mut addr_storage as *mut libc::sockaddr_storage).cast(), 60 /// &mut len, 61 /// ) 62 /// }; 63 /// if res == -1 { 64 /// return Err(io::Error::last_os_error()); 65 /// } 66 /// 67 /// let address = unsafe { SockAddr::new(addr_storage, len) }; 68 /// # drop(address); 69 /// # } 70 /// # Ok(()) 71 /// # } 72 /// ``` new(storage: sockaddr_storage, len: socklen_t) -> SockAddr73 pub const unsafe fn new(storage: sockaddr_storage, len: socklen_t) -> SockAddr { 74 SockAddr { storage, len } 75 } 76 77 /// Initialise a `SockAddr` by calling the function `init`. 78 /// 79 /// The type of the address storage and length passed to the function `init` 80 /// is OS/architecture specific. 81 /// 82 /// The address is zeroed before `init` is called and is thus valid to 83 /// dereference and read from. The length initialised to the maximum length 84 /// of the storage. 85 /// 86 /// # Safety 87 /// 88 /// Caller must ensure that the address family and length match the type of 89 /// storage address. For example if `storage.ss_family` is set to `AF_INET` 90 /// the `storage` must be initialised as `sockaddr_in`, setting the content 91 /// and length appropriately. 92 /// 93 /// # Examples 94 /// 95 /// ``` 96 /// # fn main() -> std::io::Result<()> { 97 /// # #[cfg(unix)] { 98 /// use std::io; 99 /// use std::os::unix::io::AsRawFd; 100 /// 101 /// use socket2::{SockAddr, Socket, Domain, Type}; 102 /// 103 /// let socket = Socket::new(Domain::IPV4, Type::STREAM, None)?; 104 /// 105 /// // Initialise a `SocketAddr` byte calling `getsockname(2)`. 106 /// let (_, address) = unsafe { 107 /// SockAddr::try_init(|addr_storage, len| { 108 /// // The `getsockname(2)` system call will intiliase `storage` for 109 /// // us, setting `len` to the correct length. 110 /// if libc::getsockname(socket.as_raw_fd(), addr_storage.cast(), len) == -1 { 111 /// Err(io::Error::last_os_error()) 112 /// } else { 113 /// Ok(()) 114 /// } 115 /// }) 116 /// }?; 117 /// # drop(address); 118 /// # } 119 /// # Ok(()) 120 /// # } 121 /// ``` try_init<F, T>(init: F) -> io::Result<(T, SockAddr)> where F: FnOnce(*mut sockaddr_storage, *mut socklen_t) -> io::Result<T>,122 pub unsafe fn try_init<F, T>(init: F) -> io::Result<(T, SockAddr)> 123 where 124 F: FnOnce(*mut sockaddr_storage, *mut socklen_t) -> io::Result<T>, 125 { 126 const STORAGE_SIZE: socklen_t = size_of::<sockaddr_storage>() as socklen_t; 127 // NOTE: `SockAddr::unix` depends on the storage being zeroed before 128 // calling `init`. 129 // NOTE: calling `recvfrom` with an empty buffer also depends on the 130 // storage being zeroed before calling `init` as the OS might not 131 // initialise it. 132 let mut storage = MaybeUninit::<sockaddr_storage>::zeroed(); 133 let mut len = STORAGE_SIZE; 134 init(storage.as_mut_ptr(), &mut len).map(|res| { 135 debug_assert!(len <= STORAGE_SIZE, "overflown address storage"); 136 let addr = SockAddr { 137 // Safety: zeroed-out `sockaddr_storage` is valid, caller must 138 // ensure at least `len` bytes are valid. 139 storage: storage.assume_init(), 140 len, 141 }; 142 (res, addr) 143 }) 144 } 145 146 /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path. 147 /// 148 /// Returns an error if the path is longer than `SUN_LEN`. unix<P>(path: P) -> io::Result<SockAddr> where P: AsRef<Path>,149 pub fn unix<P>(path: P) -> io::Result<SockAddr> 150 where 151 P: AsRef<Path>, 152 { 153 crate::sys::unix_sockaddr(path.as_ref()) 154 } 155 156 /// Set the length of the address. 157 /// 158 /// # Safety 159 /// 160 /// Caller must ensure that the address up to `length` bytes are properly 161 /// initialised. set_length(&mut self, length: socklen_t)162 pub unsafe fn set_length(&mut self, length: socklen_t) { 163 self.len = length; 164 } 165 166 /// Returns this address's family. family(&self) -> sa_family_t167 pub const fn family(&self) -> sa_family_t { 168 self.storage.ss_family 169 } 170 171 /// Returns this address's `Domain`. domain(&self) -> Domain172 pub const fn domain(&self) -> Domain { 173 Domain(self.storage.ss_family as c_int) 174 } 175 176 /// Returns the size of this address in bytes. len(&self) -> socklen_t177 pub const fn len(&self) -> socklen_t { 178 self.len 179 } 180 181 /// Returns a raw pointer to the address. as_ptr(&self) -> *const sockaddr182 pub const fn as_ptr(&self) -> *const sockaddr { 183 ptr::addr_of!(self.storage).cast() 184 } 185 186 /// Retuns the address as the storage. as_storage(self) -> sockaddr_storage187 pub const fn as_storage(self) -> sockaddr_storage { 188 self.storage 189 } 190 191 /// Returns true if this address is in the `AF_INET` (IPv4) family, false otherwise. is_ipv4(&self) -> bool192 pub const fn is_ipv4(&self) -> bool { 193 self.storage.ss_family == AF_INET as sa_family_t 194 } 195 196 /// Returns true if this address is in the `AF_INET6` (IPv6) family, false 197 /// otherwise. is_ipv6(&self) -> bool198 pub const fn is_ipv6(&self) -> bool { 199 self.storage.ss_family == AF_INET6 as sa_family_t 200 } 201 202 /// Returns true if this address is of a unix socket (for local interprocess communication), 203 /// i.e. it is from the `AF_UNIX` family, false otherwise. is_unix(&self) -> bool204 pub fn is_unix(&self) -> bool { 205 self.storage.ss_family == AF_UNIX as sa_family_t 206 } 207 208 /// Returns this address as a `SocketAddr` if it is in the `AF_INET` (IPv4) 209 /// or `AF_INET6` (IPv6) family, otherwise returns `None`. as_socket(&self) -> Option<SocketAddr>210 pub fn as_socket(&self) -> Option<SocketAddr> { 211 if self.storage.ss_family == AF_INET as sa_family_t { 212 // SAFETY: if the `ss_family` field is `AF_INET` then storage must 213 // be a `sockaddr_in`. 214 let addr = unsafe { &*(ptr::addr_of!(self.storage).cast::<sockaddr_in>()) }; 215 let ip = crate::sys::from_in_addr(addr.sin_addr); 216 let port = u16::from_be(addr.sin_port); 217 Some(SocketAddr::V4(SocketAddrV4::new(ip, port))) 218 } else if self.storage.ss_family == AF_INET6 as sa_family_t { 219 // SAFETY: if the `ss_family` field is `AF_INET6` then storage must 220 // be a `sockaddr_in6`. 221 let addr = unsafe { &*(ptr::addr_of!(self.storage).cast::<sockaddr_in6>()) }; 222 let ip = crate::sys::from_in6_addr(addr.sin6_addr); 223 let port = u16::from_be(addr.sin6_port); 224 Some(SocketAddr::V6(SocketAddrV6::new( 225 ip, 226 port, 227 addr.sin6_flowinfo, 228 #[cfg(unix)] 229 addr.sin6_scope_id, 230 #[cfg(windows)] 231 unsafe { 232 addr.Anonymous.sin6_scope_id 233 }, 234 ))) 235 } else { 236 None 237 } 238 } 239 240 /// Returns this address as a [`SocketAddrV4`] if it is in the `AF_INET` 241 /// family. as_socket_ipv4(&self) -> Option<SocketAddrV4>242 pub fn as_socket_ipv4(&self) -> Option<SocketAddrV4> { 243 match self.as_socket() { 244 Some(SocketAddr::V4(addr)) => Some(addr), 245 _ => None, 246 } 247 } 248 249 /// Returns this address as a [`SocketAddrV6`] if it is in the `AF_INET6` 250 /// family. as_socket_ipv6(&self) -> Option<SocketAddrV6>251 pub fn as_socket_ipv6(&self) -> Option<SocketAddrV6> { 252 match self.as_socket() { 253 Some(SocketAddr::V6(addr)) => Some(addr), 254 _ => None, 255 } 256 } 257 258 /// Returns the initialised storage bytes. as_bytes(&self) -> &[u8]259 fn as_bytes(&self) -> &[u8] { 260 // SAFETY: `self.storage` is a C struct which can always be treated a 261 // slice of bytes. Futhermore we ensure we don't read any unitialised 262 // bytes by using `self.len`. 263 unsafe { std::slice::from_raw_parts(self.as_ptr().cast(), self.len as usize) } 264 } 265 } 266 267 impl From<SocketAddr> for SockAddr { from(addr: SocketAddr) -> SockAddr268 fn from(addr: SocketAddr) -> SockAddr { 269 match addr { 270 SocketAddr::V4(addr) => addr.into(), 271 SocketAddr::V6(addr) => addr.into(), 272 } 273 } 274 } 275 276 impl From<SocketAddrV4> for SockAddr { from(addr: SocketAddrV4) -> SockAddr277 fn from(addr: SocketAddrV4) -> SockAddr { 278 // SAFETY: a `sockaddr_storage` of all zeros is valid. 279 let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() }; 280 let len = { 281 let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::<sockaddr_in>() }; 282 storage.sin_family = AF_INET as sa_family_t; 283 storage.sin_port = addr.port().to_be(); 284 storage.sin_addr = crate::sys::to_in_addr(addr.ip()); 285 storage.sin_zero = Default::default(); 286 mem::size_of::<sockaddr_in>() as socklen_t 287 }; 288 #[cfg(any( 289 target_os = "dragonfly", 290 target_os = "freebsd", 291 target_os = "haiku", 292 target_os = "hermit", 293 target_os = "ios", 294 target_os = "macos", 295 target_os = "netbsd", 296 target_os = "nto", 297 target_os = "openbsd", 298 target_os = "tvos", 299 target_os = "vxworks", 300 target_os = "watchos", 301 ))] 302 { 303 storage.ss_len = len as u8; 304 } 305 SockAddr { storage, len } 306 } 307 } 308 309 impl From<SocketAddrV6> for SockAddr { from(addr: SocketAddrV6) -> SockAddr310 fn from(addr: SocketAddrV6) -> SockAddr { 311 // SAFETY: a `sockaddr_storage` of all zeros is valid. 312 let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() }; 313 let len = { 314 let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::<sockaddr_in6>() }; 315 storage.sin6_family = AF_INET6 as sa_family_t; 316 storage.sin6_port = addr.port().to_be(); 317 storage.sin6_addr = crate::sys::to_in6_addr(addr.ip()); 318 storage.sin6_flowinfo = addr.flowinfo(); 319 #[cfg(unix)] 320 { 321 storage.sin6_scope_id = addr.scope_id(); 322 } 323 #[cfg(windows)] 324 { 325 storage.Anonymous = SOCKADDR_IN6_0 { 326 sin6_scope_id: addr.scope_id(), 327 }; 328 } 329 mem::size_of::<sockaddr_in6>() as socklen_t 330 }; 331 #[cfg(any( 332 target_os = "dragonfly", 333 target_os = "freebsd", 334 target_os = "haiku", 335 target_os = "hermit", 336 target_os = "ios", 337 target_os = "macos", 338 target_os = "netbsd", 339 target_os = "nto", 340 target_os = "openbsd", 341 target_os = "tvos", 342 target_os = "vxworks", 343 target_os = "watchos", 344 ))] 345 { 346 storage.ss_len = len as u8; 347 } 348 SockAddr { storage, len } 349 } 350 } 351 352 impl fmt::Debug for SockAddr { fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result353 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 354 let mut f = fmt.debug_struct("SockAddr"); 355 #[cfg(any( 356 target_os = "dragonfly", 357 target_os = "freebsd", 358 target_os = "haiku", 359 target_os = "hermit", 360 target_os = "ios", 361 target_os = "macos", 362 target_os = "netbsd", 363 target_os = "nto", 364 target_os = "openbsd", 365 target_os = "tvos", 366 target_os = "vxworks", 367 target_os = "watchos", 368 ))] 369 f.field("ss_len", &self.storage.ss_len); 370 f.field("ss_family", &self.storage.ss_family) 371 .field("len", &self.len) 372 .finish() 373 } 374 } 375 376 impl PartialEq for SockAddr { eq(&self, other: &Self) -> bool377 fn eq(&self, other: &Self) -> bool { 378 self.as_bytes() == other.as_bytes() 379 } 380 } 381 382 impl Eq for SockAddr {} 383 384 impl Hash for SockAddr { hash<H: std::hash::Hasher>(&self, state: &mut H)385 fn hash<H: std::hash::Hasher>(&self, state: &mut H) { 386 self.as_bytes().hash(state); 387 } 388 } 389 390 #[cfg(test)] 391 mod tests { 392 use super::*; 393 394 #[test] ipv4()395 fn ipv4() { 396 use std::net::Ipv4Addr; 397 let std = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876); 398 let addr = SockAddr::from(std); 399 assert!(addr.is_ipv4()); 400 assert!(!addr.is_ipv6()); 401 assert!(!addr.is_unix()); 402 assert_eq!(addr.family(), AF_INET as sa_family_t); 403 assert_eq!(addr.domain(), Domain::IPV4); 404 assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t); 405 assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std))); 406 assert_eq!(addr.as_socket_ipv4(), Some(std)); 407 assert!(addr.as_socket_ipv6().is_none()); 408 409 let addr = SockAddr::from(SocketAddr::from(std)); 410 assert_eq!(addr.family(), AF_INET as sa_family_t); 411 assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t); 412 assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std))); 413 assert_eq!(addr.as_socket_ipv4(), Some(std)); 414 assert!(addr.as_socket_ipv6().is_none()); 415 #[cfg(unix)] 416 { 417 assert!(addr.as_pathname().is_none()); 418 assert!(addr.as_abstract_namespace().is_none()); 419 } 420 } 421 422 #[test] ipv6()423 fn ipv6() { 424 use std::net::Ipv6Addr; 425 let std = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12); 426 let addr = SockAddr::from(std); 427 assert!(addr.is_ipv6()); 428 assert!(!addr.is_ipv4()); 429 assert!(!addr.is_unix()); 430 assert_eq!(addr.family(), AF_INET6 as sa_family_t); 431 assert_eq!(addr.domain(), Domain::IPV6); 432 assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t); 433 assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std))); 434 assert!(addr.as_socket_ipv4().is_none()); 435 assert_eq!(addr.as_socket_ipv6(), Some(std)); 436 437 let addr = SockAddr::from(SocketAddr::from(std)); 438 assert_eq!(addr.family(), AF_INET6 as sa_family_t); 439 assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t); 440 assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std))); 441 assert!(addr.as_socket_ipv4().is_none()); 442 assert_eq!(addr.as_socket_ipv6(), Some(std)); 443 #[cfg(unix)] 444 { 445 assert!(addr.as_pathname().is_none()); 446 assert!(addr.as_abstract_namespace().is_none()); 447 } 448 } 449 450 #[test] ipv4_eq()451 fn ipv4_eq() { 452 use std::net::Ipv4Addr; 453 454 let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876); 455 let std2 = SocketAddrV4::new(Ipv4Addr::new(5, 6, 7, 8), 8765); 456 457 test_eq( 458 SockAddr::from(std1), 459 SockAddr::from(std1), 460 SockAddr::from(std2), 461 ); 462 } 463 464 #[test] ipv4_hash()465 fn ipv4_hash() { 466 use std::net::Ipv4Addr; 467 468 let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876); 469 let std2 = SocketAddrV4::new(Ipv4Addr::new(5, 6, 7, 8), 8765); 470 471 test_hash( 472 SockAddr::from(std1), 473 SockAddr::from(std1), 474 SockAddr::from(std2), 475 ); 476 } 477 478 #[test] ipv6_eq()479 fn ipv6_eq() { 480 use std::net::Ipv6Addr; 481 482 let std1 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12); 483 let std2 = SocketAddrV6::new(Ipv6Addr::new(3, 4, 5, 6, 7, 8, 9, 0), 7654, 13, 14); 484 485 test_eq( 486 SockAddr::from(std1), 487 SockAddr::from(std1), 488 SockAddr::from(std2), 489 ); 490 } 491 492 #[test] ipv6_hash()493 fn ipv6_hash() { 494 use std::net::Ipv6Addr; 495 496 let std1 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12); 497 let std2 = SocketAddrV6::new(Ipv6Addr::new(3, 4, 5, 6, 7, 8, 9, 0), 7654, 13, 14); 498 499 test_hash( 500 SockAddr::from(std1), 501 SockAddr::from(std1), 502 SockAddr::from(std2), 503 ); 504 } 505 506 #[test] ipv4_ipv6_eq()507 fn ipv4_ipv6_eq() { 508 use std::net::Ipv4Addr; 509 use std::net::Ipv6Addr; 510 511 let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876); 512 let std2 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12); 513 514 test_eq( 515 SockAddr::from(std1), 516 SockAddr::from(std1), 517 SockAddr::from(std2), 518 ); 519 520 test_eq( 521 SockAddr::from(std2), 522 SockAddr::from(std2), 523 SockAddr::from(std1), 524 ); 525 } 526 527 #[test] ipv4_ipv6_hash()528 fn ipv4_ipv6_hash() { 529 use std::net::Ipv4Addr; 530 use std::net::Ipv6Addr; 531 532 let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876); 533 let std2 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12); 534 535 test_hash( 536 SockAddr::from(std1), 537 SockAddr::from(std1), 538 SockAddr::from(std2), 539 ); 540 541 test_hash( 542 SockAddr::from(std2), 543 SockAddr::from(std2), 544 SockAddr::from(std1), 545 ); 546 } 547 548 #[allow(clippy::eq_op)] // allow a0 == a0 check test_eq(a0: SockAddr, a1: SockAddr, b: SockAddr)549 fn test_eq(a0: SockAddr, a1: SockAddr, b: SockAddr) { 550 assert!(a0 == a0); 551 assert!(a0 == a1); 552 assert!(a1 == a0); 553 assert!(a0 != b); 554 assert!(b != a0); 555 } 556 test_hash(a0: SockAddr, a1: SockAddr, b: SockAddr)557 fn test_hash(a0: SockAddr, a1: SockAddr, b: SockAddr) { 558 assert!(calculate_hash(&a0) == calculate_hash(&a0)); 559 assert!(calculate_hash(&a0) == calculate_hash(&a1)); 560 // technically unequal values can have the same hash, in this case x != z and both have different hashes 561 assert!(calculate_hash(&a0) != calculate_hash(&b)); 562 } 563 calculate_hash(x: &SockAddr) -> u64564 fn calculate_hash(x: &SockAddr) -> u64 { 565 use std::collections::hash_map::DefaultHasher; 566 use std::hash::Hasher; 567 568 let mut hasher = DefaultHasher::new(); 569 x.hash(&mut hasher); 570 hasher.finish() 571 } 572 } 573