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. Furthermore, 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 = "visionos", 295 target_os = "macos", 296 target_os = "netbsd", 297 target_os = "nto", 298 target_os = "openbsd", 299 target_os = "tvos", 300 target_os = "vxworks", 301 target_os = "watchos", 302 ))] 303 { 304 storage.ss_len = len as u8; 305 } 306 SockAddr { storage, len } 307 } 308 } 309 310 impl From<SocketAddrV6> for SockAddr { from(addr: SocketAddrV6) -> SockAddr311 fn from(addr: SocketAddrV6) -> SockAddr { 312 // SAFETY: a `sockaddr_storage` of all zeros is valid. 313 let mut storage = unsafe { mem::zeroed::<sockaddr_storage>() }; 314 let len = { 315 let storage = unsafe { &mut *ptr::addr_of_mut!(storage).cast::<sockaddr_in6>() }; 316 storage.sin6_family = AF_INET6 as sa_family_t; 317 storage.sin6_port = addr.port().to_be(); 318 storage.sin6_addr = crate::sys::to_in6_addr(addr.ip()); 319 storage.sin6_flowinfo = addr.flowinfo(); 320 #[cfg(unix)] 321 { 322 storage.sin6_scope_id = addr.scope_id(); 323 } 324 #[cfg(windows)] 325 { 326 storage.Anonymous = SOCKADDR_IN6_0 { 327 sin6_scope_id: addr.scope_id(), 328 }; 329 } 330 mem::size_of::<sockaddr_in6>() as socklen_t 331 }; 332 #[cfg(any( 333 target_os = "dragonfly", 334 target_os = "freebsd", 335 target_os = "haiku", 336 target_os = "hermit", 337 target_os = "ios", 338 target_os = "visionos", 339 target_os = "macos", 340 target_os = "netbsd", 341 target_os = "nto", 342 target_os = "openbsd", 343 target_os = "tvos", 344 target_os = "vxworks", 345 target_os = "watchos", 346 ))] 347 { 348 storage.ss_len = len as u8; 349 } 350 SockAddr { storage, len } 351 } 352 } 353 354 impl fmt::Debug for SockAddr { fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result355 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 356 let mut f = fmt.debug_struct("SockAddr"); 357 #[cfg(any( 358 target_os = "dragonfly", 359 target_os = "freebsd", 360 target_os = "haiku", 361 target_os = "hermit", 362 target_os = "ios", 363 target_os = "visionos", 364 target_os = "macos", 365 target_os = "netbsd", 366 target_os = "nto", 367 target_os = "openbsd", 368 target_os = "tvos", 369 target_os = "vxworks", 370 target_os = "watchos", 371 ))] 372 f.field("ss_len", &self.storage.ss_len); 373 f.field("ss_family", &self.storage.ss_family) 374 .field("len", &self.len) 375 .finish() 376 } 377 } 378 379 impl PartialEq for SockAddr { eq(&self, other: &Self) -> bool380 fn eq(&self, other: &Self) -> bool { 381 self.as_bytes() == other.as_bytes() 382 } 383 } 384 385 impl Eq for SockAddr {} 386 387 impl Hash for SockAddr { hash<H: std::hash::Hasher>(&self, state: &mut H)388 fn hash<H: std::hash::Hasher>(&self, state: &mut H) { 389 self.as_bytes().hash(state); 390 } 391 } 392 393 #[cfg(test)] 394 mod tests { 395 use super::*; 396 397 #[test] ipv4()398 fn ipv4() { 399 use std::net::Ipv4Addr; 400 let std = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876); 401 let addr = SockAddr::from(std); 402 assert!(addr.is_ipv4()); 403 assert!(!addr.is_ipv6()); 404 assert!(!addr.is_unix()); 405 assert_eq!(addr.family(), AF_INET as sa_family_t); 406 assert_eq!(addr.domain(), Domain::IPV4); 407 assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t); 408 assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std))); 409 assert_eq!(addr.as_socket_ipv4(), Some(std)); 410 assert!(addr.as_socket_ipv6().is_none()); 411 412 let addr = SockAddr::from(SocketAddr::from(std)); 413 assert_eq!(addr.family(), AF_INET as sa_family_t); 414 assert_eq!(addr.len(), size_of::<sockaddr_in>() as socklen_t); 415 assert_eq!(addr.as_socket(), Some(SocketAddr::V4(std))); 416 assert_eq!(addr.as_socket_ipv4(), Some(std)); 417 assert!(addr.as_socket_ipv6().is_none()); 418 #[cfg(unix)] 419 { 420 assert!(addr.as_pathname().is_none()); 421 assert!(addr.as_abstract_namespace().is_none()); 422 } 423 } 424 425 #[test] ipv6()426 fn ipv6() { 427 use std::net::Ipv6Addr; 428 let std = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12); 429 let addr = SockAddr::from(std); 430 assert!(addr.is_ipv6()); 431 assert!(!addr.is_ipv4()); 432 assert!(!addr.is_unix()); 433 assert_eq!(addr.family(), AF_INET6 as sa_family_t); 434 assert_eq!(addr.domain(), Domain::IPV6); 435 assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t); 436 assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std))); 437 assert!(addr.as_socket_ipv4().is_none()); 438 assert_eq!(addr.as_socket_ipv6(), Some(std)); 439 440 let addr = SockAddr::from(SocketAddr::from(std)); 441 assert_eq!(addr.family(), AF_INET6 as sa_family_t); 442 assert_eq!(addr.len(), size_of::<sockaddr_in6>() as socklen_t); 443 assert_eq!(addr.as_socket(), Some(SocketAddr::V6(std))); 444 assert!(addr.as_socket_ipv4().is_none()); 445 assert_eq!(addr.as_socket_ipv6(), Some(std)); 446 #[cfg(unix)] 447 { 448 assert!(addr.as_pathname().is_none()); 449 assert!(addr.as_abstract_namespace().is_none()); 450 } 451 } 452 453 #[test] ipv4_eq()454 fn ipv4_eq() { 455 use std::net::Ipv4Addr; 456 457 let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876); 458 let std2 = SocketAddrV4::new(Ipv4Addr::new(5, 6, 7, 8), 8765); 459 460 test_eq( 461 SockAddr::from(std1), 462 SockAddr::from(std1), 463 SockAddr::from(std2), 464 ); 465 } 466 467 #[test] ipv4_hash()468 fn ipv4_hash() { 469 use std::net::Ipv4Addr; 470 471 let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876); 472 let std2 = SocketAddrV4::new(Ipv4Addr::new(5, 6, 7, 8), 8765); 473 474 test_hash( 475 SockAddr::from(std1), 476 SockAddr::from(std1), 477 SockAddr::from(std2), 478 ); 479 } 480 481 #[test] ipv6_eq()482 fn ipv6_eq() { 483 use std::net::Ipv6Addr; 484 485 let std1 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12); 486 let std2 = SocketAddrV6::new(Ipv6Addr::new(3, 4, 5, 6, 7, 8, 9, 0), 7654, 13, 14); 487 488 test_eq( 489 SockAddr::from(std1), 490 SockAddr::from(std1), 491 SockAddr::from(std2), 492 ); 493 } 494 495 #[test] ipv6_hash()496 fn ipv6_hash() { 497 use std::net::Ipv6Addr; 498 499 let std1 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12); 500 let std2 = SocketAddrV6::new(Ipv6Addr::new(3, 4, 5, 6, 7, 8, 9, 0), 7654, 13, 14); 501 502 test_hash( 503 SockAddr::from(std1), 504 SockAddr::from(std1), 505 SockAddr::from(std2), 506 ); 507 } 508 509 #[test] ipv4_ipv6_eq()510 fn ipv4_ipv6_eq() { 511 use std::net::Ipv4Addr; 512 use std::net::Ipv6Addr; 513 514 let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876); 515 let std2 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12); 516 517 test_eq( 518 SockAddr::from(std1), 519 SockAddr::from(std1), 520 SockAddr::from(std2), 521 ); 522 523 test_eq( 524 SockAddr::from(std2), 525 SockAddr::from(std2), 526 SockAddr::from(std1), 527 ); 528 } 529 530 #[test] ipv4_ipv6_hash()531 fn ipv4_ipv6_hash() { 532 use std::net::Ipv4Addr; 533 use std::net::Ipv6Addr; 534 535 let std1 = SocketAddrV4::new(Ipv4Addr::new(1, 2, 3, 4), 9876); 536 let std2 = SocketAddrV6::new(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), 9876, 11, 12); 537 538 test_hash( 539 SockAddr::from(std1), 540 SockAddr::from(std1), 541 SockAddr::from(std2), 542 ); 543 544 test_hash( 545 SockAddr::from(std2), 546 SockAddr::from(std2), 547 SockAddr::from(std1), 548 ); 549 } 550 551 #[allow(clippy::eq_op)] // allow a0 == a0 check test_eq(a0: SockAddr, a1: SockAddr, b: SockAddr)552 fn test_eq(a0: SockAddr, a1: SockAddr, b: SockAddr) { 553 assert!(a0 == a0); 554 assert!(a0 == a1); 555 assert!(a1 == a0); 556 assert!(a0 != b); 557 assert!(b != a0); 558 } 559 test_hash(a0: SockAddr, a1: SockAddr, b: SockAddr)560 fn test_hash(a0: SockAddr, a1: SockAddr, b: SockAddr) { 561 assert!(calculate_hash(&a0) == calculate_hash(&a0)); 562 assert!(calculate_hash(&a0) == calculate_hash(&a1)); 563 // technically unequal values can have the same hash, in this case x != z and both have different hashes 564 assert!(calculate_hash(&a0) != calculate_hash(&b)); 565 } 566 calculate_hash(x: &SockAddr) -> u64567 fn calculate_hash(x: &SockAddr) -> u64 { 568 use std::collections::hash_map::DefaultHasher; 569 use std::hash::Hasher; 570 571 let mut hasher = DefaultHasher::new(); 572 x.hash(&mut hasher); 573 hasher.finish() 574 } 575 } 576