Skip to content

Commit

Permalink
Support AF_ALG
Browse files Browse the repository at this point in the history
  • Loading branch information
Gleb Pomykalov committed Mar 12, 2019
1 parent 2d0d360 commit 6968cb4
Show file tree
Hide file tree
Showing 5 changed files with 381 additions and 11 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Added
- Add IP_RECVIF & IP_RECVDSTADDR. Enable IP_PKTINFO and IP6_PKTINFO on netbsd/openbsd.
([#1002](https://github.com/nix-rust/nix/pull/1002))

- Added `inotify_init1`, `inotify_add_watch` and `inotify_rm_watch` wrappers for
Android and Linux. ([#1016](https://github.com/nix-rust/nix/pull/1016))
- Add `ALG_SET_IV`, `ALG_SET_OP` and `ALG_SET_AEAD_ASSOCLEN` control messages and `AF_ALG`
socket types on Linux and Android ([#1031](https://github.com/nix-rust/nix/pull/1031))

### Changed
- `PollFd` event flags renamed to `PollFlags` ([#1024](https://github.com/nix-rust/nix/pull/1024/))
Expand Down
80 changes: 80 additions & 0 deletions src/sys/socket/addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use std::path::Path;
use std::os::unix::ffi::OsStrExt;
#[cfg(any(target_os = "android", target_os = "linux"))]
use ::sys::socket::addr::netlink::NetlinkAddr;
#[cfg(any(target_os = "android", target_os = "linux"))]
use ::sys::socket::addr::alg::AlgAddr;
#[cfg(any(target_os = "ios", target_os = "macos"))]
use std::os::unix::io::RawFd;
#[cfg(any(target_os = "ios", target_os = "macos"))]
Expand Down Expand Up @@ -740,6 +742,8 @@ pub enum SockAddr {
Unix(UnixAddr),
#[cfg(any(target_os = "android", target_os = "linux"))]
Netlink(NetlinkAddr),
#[cfg(any(target_os = "android", target_os = "linux"))]
Alg(AlgAddr),
#[cfg(any(target_os = "ios", target_os = "macos"))]
SysControl(SysControlAddr),
/// Datalink address (MAC)
Expand Down Expand Up @@ -768,6 +772,11 @@ impl SockAddr {
SockAddr::Netlink(NetlinkAddr::new(pid, groups))
}

#[cfg(any(target_os = "android", target_os = "linux"))]
pub fn new_alg(alg_type: &str, alg_name: &str) -> SockAddr {
SockAddr::Alg(AlgAddr::new(alg_type, alg_name))
}

#[cfg(any(target_os = "ios", target_os = "macos"))]
pub fn new_sys_control(sockfd: RawFd, name: &str, unit: u32) -> Result<SockAddr> {
SysControlAddr::from_name(sockfd, name, unit).map(|a| SockAddr::SysControl(a))
Expand All @@ -780,6 +789,8 @@ impl SockAddr {
SockAddr::Unix(..) => AddressFamily::Unix,
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Netlink(..) => AddressFamily::Netlink,
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Alg(..) => AddressFamily::Alg,
#[cfg(any(target_os = "ios", target_os = "macos"))]
SockAddr::SysControl(..) => AddressFamily::System,
#[cfg(any(target_os = "android", target_os = "linux"))]
Expand Down Expand Up @@ -856,6 +867,8 @@ impl SockAddr {
SockAddr::Unix(UnixAddr(ref addr, len)) => (mem::transmute(addr), (len + offset_of!(libc::sockaddr_un, sun_path)) as libc::socklen_t),
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Netlink(NetlinkAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t),
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Alg(AlgAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_alg>() as libc::socklen_t),
#[cfg(any(target_os = "ios", target_os = "macos"))]
SockAddr::SysControl(SysControlAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_ctl>() as libc::socklen_t),
#[cfg(any(target_os = "android", target_os = "linux"))]
Expand Down Expand Up @@ -910,6 +923,8 @@ impl hash::Hash for SockAddr {
SockAddr::Unix(ref a) => a.hash(s),
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Netlink(ref a) => a.hash(s),
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Alg(ref a) => a.hash(s),
#[cfg(any(target_os = "ios", target_os = "macos"))]
SockAddr::SysControl(ref a) => a.hash(s),
#[cfg(any(target_os = "android",
Expand Down Expand Up @@ -938,6 +953,8 @@ impl fmt::Display for SockAddr {
SockAddr::Unix(ref unix) => unix.fmt(f),
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Netlink(ref nl) => nl.fmt(f),
#[cfg(any(target_os = "android", target_os = "linux"))]
SockAddr::Alg(ref nl) => nl.fmt(f),
#[cfg(any(target_os = "ios", target_os = "macos"))]
SockAddr::SysControl(ref sc) => sc.fmt(f),
#[cfg(any(target_os = "android",
Expand Down Expand Up @@ -1014,6 +1031,69 @@ pub mod netlink {
}
}

#[cfg(any(target_os = "android", target_os = "linux"))]
pub mod alg {
use libc::{AF_ALG, sockaddr_alg, c_char};
use std::{fmt, mem, str};
use std::hash::{Hash, Hasher};
use std::ffi::CStr;

#[derive(Copy, Clone)]
pub struct AlgAddr(pub sockaddr_alg);

// , PartialEq, Eq, Debug, Hash
impl PartialEq for AlgAddr {
fn eq(&self, other: &Self) -> bool {
let (inner, other) = (self.0, other.0);
(inner.salg_family, &inner.salg_type[..], inner.salg_feat, inner.salg_mask, &inner.salg_name[..]) ==
(other.salg_family, &other.salg_type[..], other.salg_feat, other.salg_mask, &other.salg_name[..])
}
}

impl Eq for AlgAddr {}

impl Hash for AlgAddr {
fn hash<H: Hasher>(&self, s: &mut H) {
let inner = self.0;
(inner.salg_family, &inner.salg_type[..], inner.salg_feat, inner.salg_mask, &inner.salg_name[..]).hash(s);
}
}

impl AlgAddr {
pub fn new(alg_type: &str, alg_name: &str) -> AlgAddr {
let mut addr: sockaddr_alg = unsafe { mem::zeroed() };
addr.salg_family = AF_ALG as u16;
addr.salg_type[..alg_type.len()].copy_from_slice(alg_type.to_string().as_bytes());
addr.salg_name[..alg_name.len()].copy_from_slice(alg_name.to_string().as_bytes());

AlgAddr(addr)
}


pub fn alg_type(&self) -> &CStr {
unsafe { CStr::from_ptr(self.0.salg_type.as_ptr() as *const c_char) }
}

pub fn alg_name(&self) -> &CStr {
unsafe { CStr::from_ptr(self.0.salg_name.as_ptr() as *const c_char) }
}
}

impl fmt::Display for AlgAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "type: {} alg: {}",
self.alg_name().to_string_lossy(),
self.alg_type().to_string_lossy())
}
}

impl fmt::Debug for AlgAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
}

#[cfg(any(target_os = "ios", target_os = "macos"))]
pub mod sys_control {
use ::sys::socket::addr::AddressFamily;
Expand Down
111 changes: 101 additions & 10 deletions src/sys/socket/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ pub use self::addr::{
};
#[cfg(any(target_os = "android", target_os = "linux"))]
pub use ::sys::socket::addr::netlink::NetlinkAddr;
#[cfg(any(target_os = "android", target_os = "linux"))]
pub use sys::socket::addr::alg::AlgAddr;

pub use libc::{
cmsghdr,
Expand Down Expand Up @@ -700,6 +702,37 @@ pub enum ControlMessage<'a> {
// and put that in here instead of a raw ucred.
#[cfg(any(target_os = "android", target_os = "linux"))]
ScmCredentials(&'a libc::ucred),

/// Set IV for `AF_ALG` crypto API.
///
/// For further information, please refer to the
/// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
#[cfg(any(
target_os = "android",
target_os = "linux",
))]
AlgSetIv(&'a [u8]),
/// Set crypto operation for `AF_ALG` crypto API. It may be one of
/// `ALG_OP_ENCRYPT` or `ALG_OP_DECRYPT`
///
/// For further information, please refer to the
/// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
#[cfg(any(
target_os = "android",
target_os = "linux",
))]
AlgSetOp(&'a libc::c_int),
/// Set the length of associated authentication data (AAD) (applicable only to AEAD algorithms)
/// for `AF_ALG` crypto API.
///
/// For further information, please refer to the
/// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
#[cfg(any(
target_os = "android",
target_os = "linux",
))]
AlgSetAeadAssoclen(&'a u32),

}

// An opaque structure used to prevent cmsghdr from being a public type
Expand Down Expand Up @@ -729,16 +762,44 @@ impl<'a> ControlMessage<'a> {
}

/// Return a reference to the payload data as a byte pointer
fn data(&self) -> *const u8 {
match self {
fn copy_to_cmsg_data(&self, cmsg_data: *mut u8) {
let data_ptr = match self {
&ControlMessage::ScmRights(fds) => {
fds as *const _ as *const u8
},
#[cfg(any(target_os = "android", target_os = "linux"))]
&ControlMessage::ScmCredentials(creds) => {
creds as *const libc::ucred as *const u8
}
}
#[cfg(any(target_os = "android", target_os = "linux"))]
&ControlMessage::AlgSetIv(iv) => {
unsafe {
let alg_iv = cmsg_data as *mut libc::af_alg_iv;
(*alg_iv).ivlen = iv.len() as u32;
ptr::copy_nonoverlapping(
iv.as_ptr(),
(*alg_iv).iv.as_mut_ptr(),
iv.len()
);
};
return
},
#[cfg(any(target_os = "android", target_os = "linux"))]
&ControlMessage::AlgSetOp(op) => {
op as *const _ as *const u8
},
#[cfg(any(target_os = "android", target_os = "linux"))]
&ControlMessage::AlgSetAeadAssoclen(len) => {
len as *const _ as *const u8
},
};
unsafe {
ptr::copy_nonoverlapping(
data_ptr,
cmsg_data,
self.len()
)
};
}

/// The size of the payload, excluding its cmsghdr
Expand All @@ -751,6 +812,18 @@ impl<'a> ControlMessage<'a> {
&ControlMessage::ScmCredentials(creds) => {
mem::size_of_val(creds)
}
#[cfg(any(target_os = "android", target_os = "linux"))]
&ControlMessage::AlgSetIv(iv) => {
mem::size_of::<libc::af_alg_iv>() + iv.len()
},
#[cfg(any(target_os = "android", target_os = "linux"))]
&ControlMessage::AlgSetOp(op) => {
mem::size_of_val(op)
},
#[cfg(any(target_os = "android", target_os = "linux"))]
&ControlMessage::AlgSetAeadAssoclen(len) => {
mem::size_of_val(len)
},
}
}

Expand All @@ -760,6 +833,10 @@ impl<'a> ControlMessage<'a> {
&ControlMessage::ScmRights(_) => libc::SOL_SOCKET,
#[cfg(any(target_os = "android", target_os = "linux"))]
&ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET,
#[cfg(any(target_os = "android", target_os = "linux"))]
&ControlMessage::AlgSetIv(_) | &ControlMessage::AlgSetOp(_) | &ControlMessage::AlgSetAeadAssoclen(_) => {
libc::SOL_ALG
},
}
}

Expand All @@ -769,6 +846,18 @@ impl<'a> ControlMessage<'a> {
&ControlMessage::ScmRights(_) => libc::SCM_RIGHTS,
#[cfg(any(target_os = "android", target_os = "linux"))]
&ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS,
#[cfg(any(target_os = "android", target_os = "linux"))]
&ControlMessage::AlgSetIv(_) => {
libc::ALG_SET_IV
},
#[cfg(any(target_os = "android", target_os = "linux"))]
&ControlMessage::AlgSetOp(_) => {
libc::ALG_SET_OP
},
#[cfg(any(target_os = "android", target_os = "linux"))]
&ControlMessage::AlgSetAeadAssoclen(_) => {
libc::ALG_SET_AEAD_ASSOCLEN
},
}
}

Expand All @@ -778,12 +867,7 @@ impl<'a> ControlMessage<'a> {
(*cmsg).cmsg_level = self.cmsg_level();
(*cmsg).cmsg_type = self.cmsg_type();
(*cmsg).cmsg_len = self.cmsg_len();
let data = self.data();
ptr::copy_nonoverlapping(
data,
CMSG_DATA(cmsg),
self.len()
);
self.copy_to_cmsg_data(CMSG_DATA(cmsg));
}
}

Expand Down Expand Up @@ -1098,6 +1182,8 @@ pub enum SockLevel {
Udp = libc::IPPROTO_UDP,
#[cfg(any(target_os = "android", target_os = "linux"))]
Netlink = libc::SOL_NETLINK,
#[cfg(any(target_os = "android", target_os = "linux"))]
Alg = libc::SOL_ALG,
}

/// Represents a socket option that can be accessed or set. Used as an argument
Expand All @@ -1111,7 +1197,7 @@ pub trait GetSockOpt : Copy {

/// Represents a socket option that can be accessed or set. Used as an argument
/// to `setsockopt`
pub trait SetSockOpt : Copy {
pub trait SetSockOpt : Clone {
type Val;

#[doc(hidden)]
Expand Down Expand Up @@ -1212,6 +1298,11 @@ pub unsafe fn sockaddr_storage_to_addr(
use libc::sockaddr_nl;
Ok(SockAddr::Netlink(NetlinkAddr(*(addr as *const _ as *const sockaddr_nl))))
}
#[cfg(any(target_os = "android", target_os = "linux"))]
libc::AF_ALG => {
use libc::sockaddr_alg;
Ok(SockAddr::Alg(AlgAddr(*(addr as *const _ as *const sockaddr_alg))))
}
af => panic!("unexpected address family {}", af),
}
}
Expand Down
49 changes: 49 additions & 0 deletions src/sys/socket/sockopt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,55 @@ sockopt_impl!(Both, Ipv4RecvIf, libc::IPPROTO_IP, libc::IP_RECVIF, bool);
sockopt_impl!(Both, Ipv4RecvDstAddr, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, bool);


#[cfg(any(target_os = "android", target_os = "linux"))]
#[derive(Copy, Clone, Debug)]
pub struct AlgSetAeadAuthSize;

// ALG_SET_AEAD_AUTH_SIZE read the length from passed `option_len`
// See https://elixir.bootlin.com/linux/v4.4/source/crypto/af_alg.c#L222
#[cfg(any(target_os = "android", target_os = "linux"))]
impl SetSockOpt for AlgSetAeadAuthSize {
type Val = usize;

fn set(&self, fd: RawFd, val: &usize) -> Result<()> {
unsafe {
let res = libc::setsockopt(fd,
libc::SOL_ALG,
libc::ALG_SET_AEAD_AUTHSIZE,
::std::ptr::null(),
*val as libc::socklen_t);
Errno::result(res).map(drop)
}
}
}

#[cfg(any(target_os = "android", target_os = "linux"))]
#[derive(Clone, Debug)]
pub struct AlgSetKey<T>(::std::marker::PhantomData<T>);

#[cfg(any(target_os = "android", target_os = "linux"))]
impl<T> Default for AlgSetKey<T> {
fn default() -> Self {
AlgSetKey(Default::default())
}
}

#[cfg(any(target_os = "android", target_os = "linux"))]
impl<T> SetSockOpt for AlgSetKey<T> where T: AsRef<[u8]> + Clone {
type Val = T;

fn set(&self, fd: RawFd, val: &T) -> Result<()> {
unsafe {
let res = libc::setsockopt(fd,
libc::SOL_ALG,
libc::ALG_SET_KEY,
val.as_ref().as_ptr() as *const _,
val.as_ref().len() as libc::socklen_t);
Errno::result(res).map(drop)
}
}
}

/*
*
* ===== Accessor helpers =====
Expand Down
Loading

0 comments on commit 6968cb4

Please sign in to comment.