Skip to content

Commit 8835561

Browse files
committed
socket api
1 parent a96a31e commit 8835561

File tree

7 files changed

+5445
-2921
lines changed

7 files changed

+5445
-2921
lines changed

src/ifaddrs.rs

+98-77
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,32 @@
22
//!
33
//! Uses the Linux and/or BSD specific function `getifaddrs` to query the list
44
//! of interfaces and their associated addresses.
5-
65
use cfg_if::cfg_if;
7-
#[cfg(apple_targets)]
8-
use std::convert::TryFrom;
96
use std::ffi;
107
use std::iter::Iterator;
8+
use std::marker::PhantomData;
119
use std::mem;
1210
use std::option::Option;
1311

1412
use crate::net::if_::*;
15-
use crate::sys::socket::{SockaddrLike, SockaddrStorage};
13+
use crate::sys::socket::RawAddr;
1614
use crate::{Errno, Result};
1715

1816
/// Describes a single address for an interface as returned by `getifaddrs`.
19-
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
20-
pub struct InterfaceAddress {
17+
#[derive(Clone, Debug, Eq, PartialEq)]
18+
pub struct InterfaceAddress<'a> {
2119
/// Name of the network interface
2220
pub interface_name: String,
2321
/// Flags as from `SIOCGIFFLAGS` ioctl
2422
pub flags: InterfaceFlags,
2523
/// Network address of this interface
26-
pub address: Option<SockaddrStorage>,
24+
pub address: Option<RawAddr<'a>>,
2725
/// Netmask of this interface
28-
pub netmask: Option<SockaddrStorage>,
26+
pub netmask: Option<RawAddr<'a>>,
2927
/// Broadcast address of this interface, if applicable
30-
pub broadcast: Option<SockaddrStorage>,
28+
pub broadcast: Option<RawAddr<'a>>,
3129
/// Point-to-point destination address
32-
pub destination: Option<SockaddrStorage>,
30+
pub destination: Option<RawAddr<'a>>,
3331
}
3432

3533
cfg_if! {
@@ -44,54 +42,12 @@ cfg_if! {
4442
}
4543
}
4644

47-
/// Workaround a bug in XNU where netmasks will always have the wrong size in
48-
/// the sa_len field due to the kernel ignoring trailing zeroes in the structure
49-
/// when setting the field. See https://github.com/nix-rust/nix/issues/1709#issuecomment-1199304470
50-
///
51-
/// To fix this, we stack-allocate a new sockaddr_storage, zero it out, and
52-
/// memcpy sa_len of the netmask to that new storage. Finally, we reset the
53-
/// ss_len field to sizeof(sockaddr_storage). This is supposedly valid as all
54-
/// members of the sockaddr_storage are "ok" with being zeroed out (there are
55-
/// no pointers).
56-
#[cfg(apple_targets)]
57-
unsafe fn workaround_xnu_bug(info: &libc::ifaddrs) -> Option<SockaddrStorage> {
58-
let src_sock = info.ifa_netmask;
59-
if src_sock.is_null() {
60-
return None;
61-
}
62-
63-
let mut dst_sock = mem::MaybeUninit::<libc::sockaddr_storage>::zeroed();
64-
65-
let dst_sock = unsafe {
66-
// memcpy only sa_len bytes, assume the rest is zero
67-
std::ptr::copy_nonoverlapping(
68-
src_sock as *const u8,
69-
dst_sock.as_mut_ptr().cast(),
70-
(*src_sock).sa_len.into(),
71-
);
72-
73-
// Initialize ss_len to sizeof(libc::sockaddr_storage).
74-
(*dst_sock.as_mut_ptr()).ss_len =
75-
u8::try_from(mem::size_of::<libc::sockaddr_storage>()).unwrap();
76-
dst_sock.assume_init()
77-
};
78-
79-
let dst_sock_ptr =
80-
&dst_sock as *const libc::sockaddr_storage as *const libc::sockaddr;
81-
82-
unsafe { SockaddrStorage::from_raw(dst_sock_ptr, None) }
83-
}
84-
85-
impl InterfaceAddress {
45+
impl<'a> InterfaceAddress<'a> {
8646
/// Create an `InterfaceAddress` from the libc struct.
8747
fn from_libc_ifaddrs(info: &libc::ifaddrs) -> InterfaceAddress {
8848
let ifname = unsafe { ffi::CStr::from_ptr(info.ifa_name) };
89-
let address = unsafe { SockaddrStorage::from_raw(info.ifa_addr, None) };
90-
#[cfg(apple_targets)]
91-
let netmask = unsafe { workaround_xnu_bug(info) };
92-
#[cfg(not(apple_targets))]
93-
let netmask =
94-
unsafe { SockaddrStorage::from_raw(info.ifa_netmask, None) };
49+
let address = unsafe { RawAddr::new(&*info.ifa_addr) };
50+
let netmask = unsafe { RawAddr::new(&*info.ifa_netmask) };
9551
let mut addr = InterfaceAddress {
9652
interface_name: ifname.to_string_lossy().to_string(),
9753
flags: InterfaceFlags::from_bits_truncate(info.ifa_flags as i32),
@@ -103,9 +59,9 @@ impl InterfaceAddress {
10359

10460
let ifu = get_ifu_from_sockaddr(info);
10561
if addr.flags.contains(InterfaceFlags::IFF_POINTOPOINT) {
106-
addr.destination = unsafe { SockaddrStorage::from_raw(ifu, None) };
62+
addr.destination = unsafe { RawAddr::new(&*ifu) };
10763
} else if addr.flags.contains(InterfaceFlags::IFF_BROADCAST) {
108-
addr.broadcast = unsafe { SockaddrStorage::from_raw(ifu, None) };
64+
addr.broadcast = unsafe { RawAddr::new(&*ifu) };
10965
}
11066

11167
addr
@@ -114,23 +70,43 @@ impl InterfaceAddress {
11470

11571
/// Holds the results of `getifaddrs`.
11672
///
117-
/// Use the function `getifaddrs` to create this Iterator. Note that the
118-
/// actual list of interfaces can be iterated once and will be freed as
119-
/// soon as the Iterator goes out of scope.
120-
#[derive(Debug, Eq, Hash, PartialEq)]
121-
pub struct InterfaceAddressIterator {
73+
/// Use the function `getifaddrs` to create this struct and [`Self::iter`]
74+
/// to create the iterator. Note that the actual list of interfaces can be
75+
/// iterated once and will be freed as soon as the Iterator goes out of scope.
76+
#[derive(Debug)]
77+
pub struct InterfaceAddresses {
12278
base: *mut libc::ifaddrs,
123-
next: *mut libc::ifaddrs,
12479
}
12580

126-
impl Drop for InterfaceAddressIterator {
81+
impl InterfaceAddresses {
82+
/// Create an iterator over the list of interfaces.
83+
pub fn iter(&self) -> InterfaceAddressIterator<'_> {
84+
InterfaceAddressIterator {
85+
next: self.base,
86+
_a: PhantomData,
87+
}
88+
}
89+
}
90+
91+
impl Drop for InterfaceAddresses {
12792
fn drop(&mut self) {
12893
unsafe { libc::freeifaddrs(self.base) };
12994
}
13095
}
13196

132-
impl Iterator for InterfaceAddressIterator {
133-
type Item = InterfaceAddress;
97+
/// Holds the results of `getifaddrs`.
98+
///
99+
/// Use the function `getifaddrs` to create this Iterator. Note that the
100+
/// actual list of interfaces can be iterated once and will be freed as
101+
/// soon as the Iterator goes out of scope.
102+
#[derive(Debug, Eq, Hash, PartialEq)]
103+
pub struct InterfaceAddressIterator<'a> {
104+
next: *mut libc::ifaddrs,
105+
_a: PhantomData<&'a ()>,
106+
}
107+
108+
impl<'a> Iterator for InterfaceAddressIterator<'a> {
109+
type Item = InterfaceAddress<'a>;
134110
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
135111
match unsafe { self.next.as_ref() } {
136112
Some(ifaddr) => {
@@ -154,7 +130,7 @@ impl Iterator for InterfaceAddressIterator {
154130
/// # Example
155131
/// ```
156132
/// let addrs = nix::ifaddrs::getifaddrs().unwrap();
157-
/// for ifaddr in addrs {
133+
/// for ifaddr in addrs.iter() {
158134
/// match ifaddr.address {
159135
/// Some(address) => {
160136
/// println!("interface {} address {}",
@@ -167,21 +143,23 @@ impl Iterator for InterfaceAddressIterator {
167143
/// }
168144
/// }
169145
/// ```
170-
pub fn getifaddrs() -> Result<InterfaceAddressIterator> {
146+
pub fn getifaddrs() -> Result<InterfaceAddresses> {
171147
let mut addrs = mem::MaybeUninit::<*mut libc::ifaddrs>::uninit();
172148
unsafe {
173149
Errno::result(libc::getifaddrs(addrs.as_mut_ptr())).map(|_| {
174-
InterfaceAddressIterator {
150+
InterfaceAddresses {
175151
base: addrs.assume_init(),
176-
next: addrs.assume_init(),
177152
}
178153
})
179154
}
180155
}
181156

182157
#[cfg(test)]
183158
mod tests {
159+
use std::collections::HashMap;
160+
184161
use super::*;
162+
use crate::sys::socket::{AddressFamily, Ipv4Address};
185163

186164
// Only checks if `getifaddrs` can be invoked without panicking.
187165
#[test]
@@ -194,22 +172,65 @@ mod tests {
194172
#[test]
195173
fn test_getifaddrs_netmask_correct() {
196174
let addrs = getifaddrs().unwrap();
197-
for iface in addrs {
175+
for iface in addrs.iter() {
198176
let sock = if let Some(sock) = iface.netmask {
199177
sock
200178
} else {
201179
continue;
202180
};
203-
if sock.family() == Some(crate::sys::socket::AddressFamily::Inet) {
204-
let _ = sock.as_sockaddr_in().unwrap();
181+
if sock.family() == AddressFamily::INET {
182+
let _ = sock.to_ipv4().unwrap();
205183
return;
206-
} else if sock.family()
207-
== Some(crate::sys::socket::AddressFamily::Inet6)
208-
{
209-
let _ = sock.as_sockaddr_in6().unwrap();
184+
} else if sock.family() == AddressFamily::INET6 {
185+
let _ = sock.to_ipv6().unwrap();
210186
return;
211187
}
212188
}
213189
panic!("No address?");
214190
}
191+
192+
#[test]
193+
fn test_get_ifaddrs_netmasks_eq() {
194+
let mut netmasks = HashMap::new();
195+
196+
let ifs = getifaddrs().unwrap();
197+
198+
for ifa in ifs.iter() {
199+
let Some(netmask) =
200+
ifa.netmask.filter(|n| n.family() == AddressFamily::INET)
201+
else {
202+
continue;
203+
};
204+
205+
let ipv4 = *netmask.to_ipv4().unwrap();
206+
207+
let [a, b, c, d] = ipv4.ip().to_be_bytes();
208+
209+
let x = Ipv4Address::new(a, b, c, d, ipv4.port());
210+
211+
assert_eq!(ipv4, x);
212+
213+
netmasks.insert(
214+
ifa.interface_name.clone(),
215+
*netmask.to_ipv4().unwrap(),
216+
);
217+
}
218+
219+
drop(ifs);
220+
221+
let ifs = getifaddrs().unwrap();
222+
223+
for ifa in ifs.iter() {
224+
let Some(netmask) =
225+
ifa.netmask.filter(|n| n.family() == AddressFamily::INET)
226+
else {
227+
continue;
228+
};
229+
230+
assert_eq!(
231+
netmasks.get(&ifa.interface_name).unwrap(),
232+
netmask.to_ipv4().unwrap(),
233+
);
234+
}
235+
}
215236
}

src/sys/ptrace/bsd.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ unsafe fn ptrace_other(
6868
addr,
6969
data,
7070
))
71-
.map(|_| 0)
71+
.map(|_| 0)
7272
}
7373
}
7474

0 commit comments

Comments
 (0)