Skip to content

Commit e460984

Browse files
Add name_to_index() & index_to_name() (#972)
* Add `name_to_index()` & `index_to_name()` * Update to libc 0.2.152.
1 parent 9095854 commit e460984

File tree

7 files changed

+214
-3
lines changed

7 files changed

+214
-3
lines changed

Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,15 @@ once_cell = { version = "1.5.2", optional = true }
3838
[target.'cfg(all(not(rustix_use_libc), not(miri), target_os = "linux", target_endian = "little", any(target_arch = "arm", all(target_arch = "aarch64", target_pointer_width = "64"), target_arch = "riscv64", all(rustix_use_experimental_asm, target_arch = "powerpc64"), all(rustix_use_experimental_asm, target_arch = "mips"), all(rustix_use_experimental_asm, target_arch = "mips32r6"), all(rustix_use_experimental_asm, target_arch = "mips64"), all(rustix_use_experimental_asm, target_arch = "mips64r6"), target_arch = "x86", all(target_arch = "x86_64", target_pointer_width = "64"))))'.dependencies]
3939
linux-raw-sys = { version = "0.4.11", default-features = false, features = ["general", "errno", "ioctl", "no_std", "elf"] }
4040
libc_errno = { package = "errno", version = "0.3.8", default-features = false, optional = true }
41-
libc = { version = "0.2.151", default-features = false, features = ["extra_traits"], optional = true }
41+
libc = { version = "0.2.152", default-features = false, features = ["extra_traits"], optional = true }
4242

4343
# Dependencies for platforms where only libc is supported:
4444
#
4545
# On all other Unix-family platforms, and under Miri, we always use the libc
4646
# backend, so enable its dependencies unconditionally.
4747
[target.'cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = "linux", target_endian = "little", any(target_arch = "arm", all(target_arch = "aarch64", target_pointer_width = "64"), target_arch = "riscv64", all(rustix_use_experimental_asm, target_arch = "powerpc64"), all(rustix_use_experimental_asm, target_arch = "mips"), all(rustix_use_experimental_asm, target_arch = "mips32r6"), all(rustix_use_experimental_asm, target_arch = "mips64"), all(rustix_use_experimental_asm, target_arch = "mips64r6"), target_arch = "x86", all(target_arch = "x86_64", target_pointer_width = "64")))))))'.dependencies]
4848
libc_errno = { package = "errno", version = "0.3.8", default-features = false }
49-
libc = { version = "0.2.150", default-features = false, features = ["extra_traits"] }
49+
libc = { version = "0.2.152", default-features = false, features = ["extra_traits"] }
5050

5151
# Additional dependencies for Linux with the libc backend:
5252
#
@@ -74,7 +74,7 @@ default-features = false
7474

7575
[dev-dependencies]
7676
tempfile = "3.5.0"
77-
libc = "0.2.150"
77+
libc = "0.2.152"
7878
libc_errno = { package = "errno", version = "0.3.8", default-features = false }
7979
serial_test = "2.0.0"
8080
memoffset = "0.9.0"

src/backend/libc/net/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ pub(crate) mod ext;
88
target_os = "wasi"
99
)))]
1010
pub(crate) mod msghdr;
11+
#[cfg(linux_kernel)]
12+
pub(crate) mod netdevice;
1113
pub(crate) mod read_sockaddr;
1214
pub(crate) mod send_recv;
1315
#[cfg(not(any(target_os = "redox", target_os = "wasi")))]

src/backend/libc/net/netdevice.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#![allow(unsafe_code)]
2+
3+
#[cfg(feature = "alloc")]
4+
use crate::alloc::string::String;
5+
use crate::backend::io::syscalls::ioctl;
6+
use crate::fd::AsFd;
7+
use crate::io;
8+
#[cfg(feature = "alloc")]
9+
use libc::SIOCGIFNAME;
10+
use libc::{__c_anonymous_ifr_ifru, c_char, ifreq, IFNAMSIZ, SIOCGIFINDEX};
11+
12+
pub(crate) fn name_to_index(fd: impl AsFd, if_name: &str) -> io::Result<u32> {
13+
let if_name_bytes = if_name.as_bytes();
14+
if if_name_bytes.len() >= IFNAMSIZ as usize {
15+
return Err(io::Errno::NODEV);
16+
}
17+
18+
let mut ifreq = ifreq {
19+
ifr_name: [0; 16],
20+
ifr_ifru: __c_anonymous_ifr_ifru { ifru_ifindex: 0 },
21+
};
22+
23+
let mut if_name_c_char_iter = if_name_bytes.iter().map(|byte| *byte as c_char);
24+
ifreq.ifr_name[..if_name_bytes.len()].fill_with(|| if_name_c_char_iter.next().unwrap());
25+
26+
unsafe { ioctl(fd.as_fd(), SIOCGIFINDEX as _, &mut ifreq as *mut ifreq as _) }?;
27+
let index = unsafe { ifreq.ifr_ifru.ifru_ifindex };
28+
Ok(index as u32)
29+
}
30+
31+
#[cfg(feature = "alloc")]
32+
pub(crate) fn index_to_name(fd: impl AsFd, index: u32) -> io::Result<String> {
33+
let mut ifreq = ifreq {
34+
ifr_name: [0; 16],
35+
ifr_ifru: __c_anonymous_ifr_ifru {
36+
ifru_ifindex: index as _,
37+
},
38+
};
39+
40+
unsafe { ioctl(fd.as_fd(), SIOCGIFNAME as _, &mut ifreq as *mut ifreq as _) }?;
41+
42+
if let Some(nul_byte) = ifreq.ifr_name.iter().position(|char| *char == 0) {
43+
let name: String = ifreq.ifr_name[..nul_byte]
44+
.iter()
45+
.map(|v| *v as u8 as char)
46+
.collect();
47+
48+
Ok(name)
49+
} else {
50+
Err(io::Errno::INVAL)
51+
}
52+
}

src/backend/linux_raw/net/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
pub(crate) mod addr;
22
pub(crate) mod msghdr;
3+
#[cfg(linux_kernel)]
4+
pub(crate) mod netdevice;
35
pub(crate) mod read_sockaddr;
46
pub(crate) mod send_recv;
57
pub(crate) mod sockopt;
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#![allow(unsafe_code)]
2+
3+
#[cfg(feature = "alloc")]
4+
use crate::alloc::string::String;
5+
use crate::backend::io::syscalls::ioctl;
6+
use crate::fd::AsFd;
7+
use crate::io;
8+
use linux_raw_sys::ioctl::SIOCGIFINDEX;
9+
#[cfg(feature = "alloc")]
10+
use linux_raw_sys::ioctl::SIOCGIFNAME;
11+
use linux_raw_sys::net::{ifreq, ifreq__bindgen_ty_1, ifreq__bindgen_ty_2, IFNAMSIZ};
12+
13+
pub(crate) fn name_to_index(fd: impl AsFd, if_name: &str) -> io::Result<u32> {
14+
let if_name_bytes = if_name.as_bytes();
15+
if if_name_bytes.len() >= IFNAMSIZ as usize {
16+
return Err(io::Errno::NODEV);
17+
}
18+
19+
let mut ifreq = ifreq {
20+
ifr_ifrn: ifreq__bindgen_ty_1 { ifrn_name: [0; 16] },
21+
ifr_ifru: ifreq__bindgen_ty_2 { ifru_ivalue: 0 },
22+
};
23+
unsafe { ifreq.ifr_ifrn.ifrn_name[..if_name_bytes.len()].copy_from_slice(if_name_bytes) };
24+
25+
unsafe { ioctl(fd.as_fd(), SIOCGIFINDEX, &mut ifreq as *mut ifreq as _) }?;
26+
let index = unsafe { ifreq.ifr_ifru.ifru_ivalue };
27+
Ok(index as u32)
28+
}
29+
30+
#[cfg(feature = "alloc")]
31+
pub(crate) fn index_to_name(fd: impl AsFd, index: u32) -> io::Result<String> {
32+
let mut ifreq = ifreq {
33+
ifr_ifrn: ifreq__bindgen_ty_1 { ifrn_name: [0; 16] },
34+
ifr_ifru: ifreq__bindgen_ty_2 {
35+
ifru_ivalue: index as _,
36+
},
37+
};
38+
39+
unsafe { ioctl(fd.as_fd(), SIOCGIFNAME, &mut ifreq as *mut ifreq as _) }?;
40+
41+
if let Some(nul_byte) = unsafe { ifreq.ifr_ifrn.ifrn_name }
42+
.iter()
43+
.position(|char| *char == 0)
44+
{
45+
let name = unsafe { ifreq.ifr_ifrn.ifrn_name }[..nul_byte]
46+
.iter()
47+
.map(|v| *v as char)
48+
.collect();
49+
50+
Ok(name)
51+
} else {
52+
Err(io::Errno::INVAL)
53+
}
54+
}

src/net/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ mod types;
1616
#[cfg(windows)]
1717
mod wsa;
1818

19+
#[cfg(linux_kernel)]
20+
pub mod netdevice;
1921
pub mod sockopt;
2022

2123
pub use crate::maybe_polyfill::net::{

src/net/netdevice.rs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
//! Low-level Linux network device access
2+
//!
3+
//! The methods in this module take a socket's file descriptor to communicate with
4+
//! the kernel in their ioctl call:
5+
//! - glibc uses an `AF_UNIX`, `AF_INET`, or `AF_INET6` socket.
6+
//! The address family itself does not matter and glibc tries the next address family if socket creation with one fails.
7+
//! - Android (bionic) uses an `AF_INET` socket.
8+
//! - Both create the socket with `SOCK_DGRAM|SOCK_CLOEXEC` type/flag.
9+
//! - The [man-pages] specify, that the ioctl calls "can be used on any socket's file descriptor regardless of the
10+
//! family or type".
11+
//!
12+
//! # References
13+
//! - [Linux]
14+
//!
15+
//! [man-pages]: https://man7.org/linux/man-pages/man7/netdevice.7.html
16+
//! [Linux]: https://man7.org/linux/man-pages/man7/netdevice.7.html
17+
18+
#[cfg(feature = "alloc")]
19+
use crate::alloc::string::String;
20+
use crate::fd::AsFd;
21+
use crate::io;
22+
23+
/// `ioctl(fd, SIOCGIFINDEX, ifreq)`—Returns the interface index for a given name.
24+
///
25+
/// See the [module-level documentation] for information about `fd` usage.
26+
///
27+
/// # References
28+
/// - [Linux]
29+
///
30+
/// [module-level documentation]: self
31+
/// [Linux]: https://man7.org/linux/man-pages/man7/netdevice.7.html
32+
#[inline]
33+
#[doc(alias = "SIOCGIFINDEX")]
34+
pub fn name_to_index(fd: impl AsFd, if_name: &str) -> io::Result<u32> {
35+
crate::backend::net::netdevice::name_to_index(fd, if_name)
36+
}
37+
38+
/// `ioctl(fd, SIOCGIFNAME, ifreq)`—Returns the interface name for a given index.
39+
///
40+
/// See the [module-level documentation] for information about `fd` usage.
41+
///
42+
/// # References
43+
/// - [Linux]
44+
///
45+
/// [module-level documentation]: self
46+
/// [Linux]: https://man7.org/linux/man-pages/man7/netdevice.7.html
47+
#[inline]
48+
#[doc(alias = "SIOCGIFNAME")]
49+
#[cfg(feature = "alloc")]
50+
pub fn index_to_name(fd: impl AsFd, index: u32) -> io::Result<String> {
51+
crate::backend::net::netdevice::index_to_name(fd, index)
52+
}
53+
54+
#[cfg(test)]
55+
mod tests {
56+
use crate::backend::net::netdevice::{index_to_name, name_to_index};
57+
use crate::net::{AddressFamily, SocketFlags, SocketType};
58+
59+
#[test]
60+
fn test_name_to_index() {
61+
let fd = crate::net::socket_with(
62+
AddressFamily::INET,
63+
SocketType::DGRAM,
64+
SocketFlags::CLOEXEC,
65+
None,
66+
)
67+
.unwrap();
68+
69+
let loopback_index = std::fs::read_to_string("/sys/class/net/lo/ifindex")
70+
.unwrap()
71+
.as_str()
72+
.split_at(1)
73+
.0
74+
.parse::<u32>()
75+
.unwrap();
76+
assert_eq!(Ok(loopback_index), name_to_index(fd, "lo"));
77+
}
78+
79+
#[test]
80+
#[cfg(feature = "alloc")]
81+
fn test_index_to_name() {
82+
let fd = crate::net::socket_with(
83+
AddressFamily::INET,
84+
SocketType::DGRAM,
85+
SocketFlags::CLOEXEC,
86+
None,
87+
)
88+
.unwrap();
89+
90+
let loopback_index = std::fs::read_to_string("/sys/class/net/lo/ifindex")
91+
.unwrap()
92+
.as_str()
93+
.split_at(1)
94+
.0
95+
.parse::<u32>()
96+
.unwrap();
97+
assert_eq!(Ok("lo".to_owned()), index_to_name(fd, loopback_index));
98+
}
99+
}

0 commit comments

Comments
 (0)