Code Monkey home page Code Monkey logo

uds's Introduction

uds

A unix domain sockets Rust library that supports abstract addresses, fd-passing, SOCK_SEQPACKET sockets and more.

crates.io page License: Apache v2 / MIT Documentation cirrus-ci build status sourcehut build status

When possible, features are implemented via extension traits for std::os::unix::net types (and optionally mio's uds types) instead of exposing new structs. The only new socket structs this crate exposes are those for seqpacket sockets.

Ancillary credentials and timestamps are not yet supported.

Example

(only runs sucessfully on Linux)

extern crate uds;

let addr = uds::UnixSocketAddr::from_abstract(b"not a file!")
    .expect("create abstract socket address");
let listener = uds::UnixSeqpacketListener::bind_unix_addr(&addr)
    .expect("create seqpacket listener");

let client = uds::UnixSeqpacketConn::connect_unix_addr(&addr)
    .expect("connect to listener");
client.send_fds(b"Here I come", &[0, 1, 2])
    .expect("send stdin, stdout and stderr");

let (server_side, _) = listener.accept_unix_addr()
    .expect("accept connection");
let creds: uds::ConnCredentials = server_side.initial_peer_credentials()
    .expect("get peer credentials");
if creds.euid() == 0 {
    let mut fd_buf = [-1; 3];
    let (_, _, fds) = server_side.recv_fds(&mut[0u8; 1], &mut fd_buf
        ).expect("receive with fd capacity");
    if fds == 3 {
        /* do something with the file descriptors */
    }
    /* remember to close the file descripts */
} else {
    server_side.send(b"go away!\n").expect("send response");
}

Portability

macOS doesn't support SOCK_SEQPACKET sockets, and abstract socket addresses is Linux-only, so if you don't want to bother with supporting non-portable features you are probably better off only using what std or mio provides. If you're writing a datagram server though, using std or mio means you can't respond to abstract adresses, forcing clients to use path addresses and deal with cleaning up the socket file after themselves.

Even when all operating systems you care about supports something, they might behave differently:
On Linux file descriptors are cloned when they are sent, but macOS and the BSDs first clones them when they are received. This means that if a FD is closed before the peer receives it you have a problem.
Also, some OSes might return the original file descriptor without cloning it if it's received within the same process as it was sent from. (DragonFly BSD, possibly macOS and maybe FreeBSD).

Linux macOS FreeBSD OpenBSD DragonFly BSD NetBSD Illumos
Seqpacket Yes N/A Yes Yes Yes Yes N/A
fd-passing Yes Yes Yes Yes Yes Yes No
abstract addresses Yes N/A N/A N/A N/A N/A N/A
mio 0.8 Yes Yes Yes Yes Yes Yes Yes
tokio 1.0 Yes Yes Yes Yes Yes Yes No
Tested? Locally + CI CI CI CI Manually* Manually* Manually*

*: Not tested since v0.2.6. (but (cross)checked on CI.)

Other OSes

  • Android: I haven't tested on it, but I assume there are no differences from regular Linux.
  • Windows 10: While it added some unix socket features, Windows support is not a priority. (PRs are welcome though).
  • Solaris: Treated identically as Illumos. mio 0.8 doesn't support it.

mio integration

The mio_08 feature makes the seqpacket types usable with mio version 0.8 (by implementing its Source trait for them), and implements this crates extension traits for the unix socket types in mio::net.

To enable it, add this to Cargo.toml:

[dependencies]
uds = {version="0.4.0", features=["mio_08"]}

tokio integration

The tokio feature adds async-based seqpacket types for use with tokio version 1.*:

To enable it, add this to Cargo.toml:

[dependencies]
uds = {version="0.4.2", features=["tokio"]}

Minimum Rust version

The minimum Rust version is 1.63.
Older versions might work, but might break in a minor release.

unsafe usage

This crate calls many C functions, which are all unsafe (even ones as simple as socket()). The public interface is safe (except for FromRawFd), so if you find something unsound (even internal functions that aren't marked unsafe) please open an issue.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

uds's People

Contributors

devnexen avatar domenukk avatar jake-shadle avatar jmagnuson avatar manishearth avatar tormol avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

uds's Issues

Tokio latest version possibility.

Hello,

Is it possible to update tokio dependency, so your able to use the latest version in a project, and not having and old outdated version also pulled - in only for uds ?.

Potentially incorrect normalization code in new_from_ffi

Caught during unsafe review

uds/src/addr.rs

Lines 647 to 654 in a596894

// normalize addr.len to include terminating NUL byte if possible
// and not be greater than capacity
if addr.len >= capacity {
addr.len = capacity;
} else if addr.addr.sun_path[(addr.len-1-path_offset()) as usize] != 0 {
addr.len += 1;
addr.addr.sun_path[(addr.len-1-path_offset()) as usize] = 0;
}

Some platforms, including FreeBSD, require a null terminator here, which we are sometimes stripping

e.g. FreeBSD:

The sun_path field must be terminated by a NUL character to be used with SUN_LEN(), but the terminating NUL is not part of the address.

We do have some code on OpenBSD that talks about this but it isn't involved here, and it's only OpenBSD, not FreeBSD as well.

uds/src/addr.rs

Lines 252 to 257 in a596894

/// Is the size of the underlying `sun_path` field,
/// minus 1 if the OS is known to require a trailing NUL (`'\0'`) byte.
pub fn max_path_len() -> usize {
mem::size_of_val(&Self::new_unspecified().addr.sun_path)
- if cfg!(target_os="openbsd") {1} else {0}
}

I'd recommend we'd cautiously not strip the NUL except for specific platforms where we know that that's okay.

In general the NUL invariant is also hard to follow in this follow, would be worth documenting it more.

Tokio support

Thanks for the useful crate. Has there been any consideration given for building optional tokio functionality? Something like:

pub struct UnixSeqpacketConn {
    io: PollEvented<crate::nonblocking::UnixSeqpacketConn>,
}

and then impls various tokio-related traits for async support. I got a POC working for AsyncRead/AsyncWrite, but it's far from comprehensive and I'm not sure how it would fit within this crate. Curious to hear what the thoughts are.

Undefined behavior: CMSG_DATA and CMSG_NXTHDR may return null

*(CMSG_DATA(header) as *mut c_void as *mut _) = creds;

let dst = CMSG_DATA(header) as *mut c_void;

let first_fd = CMSG_DATA(self.next_message) as *const c_void;

let creds_ptr = CMSG_DATA(self.next_message) as *const c_void;

header = &mut*CMSG_NXTHDR(&mut msg, header);

The docs say that these functions may return null, but they're not null-checked in the locations above (the usage of CMSG_NXTHDR for initializing next_message is, however). The code is dereferencing the results here and dereferencing a null pointer is UB: it should null-check these.

Read/write timeout

Hi, trying to use your library, can't understand how to add read/write timeout, because in blocking mode it blocks infinitely

Unsoundness: Incorrect safety invariant checks in UnixSocketAddr::from_raw()

We perform a bunch of invariant checks in UnixSocketAddr::from_raw()

uds/src/addr.rs

Lines 670 to 686 in a596894

if addr.is_null() && len == 0 {
Ok(Self::new_unspecified())
} else if addr.is_null() {
Err(io::Error::new(ErrorKind::InvalidInput, "addr is NULL"))
} else if len < path_offset() {
Err(io::Error::new(ErrorKind::InvalidInput, "address length is too low"))
} else if len > path_offset() + mem::size_of_val(&copy.addr.sun_path) as socklen_t {
Err(io::Error::new(ErrorKind::InvalidInput, TOO_LONG_DESC))
} else if (&*addr).sa_family != AF_UNIX as sa_family_t {
Err(io::Error::new(ErrorKind::InvalidData, "not an unix socket address"))
} else {
let addr = addr as *const sockaddr_un;
let sun_path_ptr = (&*addr).sun_path.as_ptr();
let sun_path = slice::from_raw_parts(sun_path_ptr, len as usize);
copy.addr.sun_path.copy_from_slice(sun_path);
copy.len = len;
Ok(copy)

Specificlaly, we check that path_offset() < len < path_offset() + sizeof(sun_path)

We then call slice::from_raw_parts(sun_path_ptr, len as usize);

This seems incorrect. path_offset is the offset of sun_path in sockaddr_un. The bounds check we need is 0 < len < sizeof(sun_path), since we are indexing directly into sun_path_ptr, not sockaddr_un.

Compile error for android target

I get compilation errors when uds is compiled for android (arm, NDK 22).

error[E0308]: mismatched types
  --> /Users/test/.cargo/registry/src/github.com-1ecc6299db9ec823/uds-0.2.1/src/ancillary.rs:90:30
   |
90 |         msg.msg_controllen = needed_capacity as ControlLen;
   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `i32`

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.