-
Notifications
You must be signed in to change notification settings - Fork 13.3k
std::net: adding new option todevice. #129172
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
r? @Noratrieb rustbot has assigned @Noratrieb. Use |
This comment has been minimized.
This comment has been minimized.
293b0a2
to
e6d0253
Compare
This comment has been minimized.
This comment has been minimized.
b7bb523
to
215ccf3
Compare
This comment has been minimized.
This comment has been minimized.
215ccf3
to
b0210c7
Compare
Thank you for the PR! This PR contains a public library API change, which should follow the process of creating an ACP first: https://std-dev-guide.rust-lang.org/development/feature-lifecycle.html |
Sorry for asking but is creating ACP a different process than tracking issue ? |
Yes, asking for an ACP, which is a relatively new process, asks the libs-api team whether this is worth adding in the first place. The tracking issue is there once it has been added, to track stabilization. |
library/std/src/sys/pal/unix/net.rs
Outdated
let buf: [libc::c_char; libc::IFNAMSIZ] = | ||
getsockopt(self, libc::SOL_SOCKET, libc::SO_BINDTODEVICE)?; | ||
let s: &[u8] = unsafe { core::slice::from_raw_parts(buf.as_ptr() as *const u8, buf.len()) }; | ||
let ifrname = CStr::from_bytes_with_nul(s).unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bytes with null will return an Interior null runtime error when device names are shorter then 16 characters.
for example eno1
would be represented as [101, 110, 111, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
.
let ifrname = CStr::from_bytes_with_nul(s).unwrap(); | |
let ifrname = CStr::from_bytes_until_nul(s).unwrap(); |
library/std/src/sys/pal/unix/net.rs
Outdated
#[cfg(any(target_os = "linux", target_os = "haiku", target_os = "vxworks"))] | ||
pub fn set_todevice(&self, ifrname: &CStr) -> io::Result<()> { | ||
let mut buf = [0; libc::IFNAMSIZ]; | ||
for (src, dst) in ifrname.to_bytes().iter().zip(&mut buf[..libc::IFNAMSIZ - 1]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should probably check if the input name is too long rather than silently truncating it because you used zip()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That value is already truncated to size specified by optlen when getsockopt
is called with optlen.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Plus length of interface is 16 on most unix systems, so no value is truncated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what I mean is, assuming IFNAMSIZ == 16
, if you have an interface named mylonginterface
(15 bytes), and you call this function with "mylonginterfacename"
then it will silently truncate that and use mylonginterface
instead of erroring like it should, because setsockopt
never has a chance to see the bad name and report an error.
Allows to bind a socket to an network interface, to exclusively listen from it. For packet sockets, regular bind is more appropriate.
b0210c7
to
dab4104
Compare
/// let socket = UnixDatagram::unbound()?; | ||
/// socket.set_todevice(c"eth0")?; | ||
/// let name = socket.todevice()?; | ||
/// assert_eq!(Ok("eth0"), name.to_str()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something seems odd here.
#![feature(unix_set_todevice)]
use std::os::unix::net::UnixDatagram;
///
fn main() -> std::io::Result<()> {
let socket = UnixDatagram::unbound()?;
socket.set_todevice(c"eno1")?;
let name = socket.todevice()?;
assert_eq!(Ok("eno1"), name.to_str());
Ok(())
}
The assertion fails.
thread 'main' panicked at test_case.rs:8:5:
assertion `left == right` failed
left: Ok("eno1")
right: Ok("�
�")
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
This comment has been minimized.
This comment has been minimized.
3057398
to
f7d3a1a
Compare
/// use std::os::unix::net::UnixStream; | ||
/// | ||
/// fn main() -> std::io::Result<()> { | ||
/// let socket = UnixStream::connect("/tmp/sock")?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this using UnixStream
? That...shouldn't work.
The examples should be things expected to work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait, it looks like these are being added to UNIX sockets? Shouldn't these be for TCP/UDP, not UNIX?
This comment has been minimized.
This comment has been minimized.
4308d3f
to
c97a6ea
Compare
This comment has been minimized.
This comment has been minimized.
c97a6ea
to
7537a8f
Compare
My understanding of the SO_BINDTODEVICE must be used before binding or connecting a socket. Currently std has no way to support this, So to support this std would first have to gain a way to create unbound sockets, configure them and then turn them into their final type. see rust-lang/libs-team#66 (comment) Additionally device-binding is a platform-specific API that's not fully portable. So it'd have to go into extension traits under the os module. So I have to reject this for now until we have a better story around unbound sockets. For now you can use the socket2 crate, which has device-binding methods |
Allows to bind a socket to an network interface, to exclusively listen from it. For packet sockets, regular bind is more appropriate.
tracking issue: #129182