Skip to content

Commit 954232c

Browse files
author
Conrad Kramer
committed
Add support for system control sockets for XNU
1 parent bfb9150 commit 954232c

File tree

4 files changed

+147
-1
lines changed

4 files changed

+147
-1
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
66
## [Unreleased]
77

88
### Added
9+
- Added support for XNU system control sockets
10+
([#478](https://github.com/nix-rust/nix/pull/478))
911
- Added support for `ioctl` calls on BSD platforms
1012
([#478](https://github.com/nix-rust/nix/pull/478))
1113
- Added struct `TimeSpec`

src/sys/socket/addr.rs

Lines changed: 121 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ use std::path::Path;
77
use std::os::unix::ffi::OsStrExt;
88
#[cfg(any(target_os = "linux", target_os = "android"))]
99
use ::sys::socket::addr::netlink::NetlinkAddr;
10+
#[cfg(any(target_os = "macos", target_os = "ios"))]
11+
use std::os::unix::io::RawFd;
12+
#[cfg(any(target_os = "macos", target_os = "ios"))]
13+
use ::sys::socket::addr::sys_control::SysControlAddr;
1014

1115
// TODO: uncomment out IpAddr functions: rust-lang/rfcs#988
1216

@@ -26,6 +30,8 @@ pub enum AddressFamily {
2630
Netlink = consts::AF_NETLINK,
2731
#[cfg(any(target_os = "linux", target_os = "android"))]
2832
Packet = consts::AF_PACKET,
33+
#[cfg(any(target_os = "macos", target_os = "ios"))]
34+
System = consts::AF_SYSTEM,
2935
}
3036

3137
#[derive(Copy)]
@@ -475,7 +481,9 @@ pub enum SockAddr {
475481
Inet(InetAddr),
476482
Unix(UnixAddr),
477483
#[cfg(any(target_os = "linux", target_os = "android"))]
478-
Netlink(NetlinkAddr)
484+
Netlink(NetlinkAddr),
485+
#[cfg(any(target_os = "macos", target_os = "ios"))]
486+
SysControl(SysControlAddr),
479487
}
480488

481489
impl SockAddr {
@@ -492,13 +500,20 @@ impl SockAddr {
492500
SockAddr::Netlink(NetlinkAddr::new(pid, groups))
493501
}
494502

503+
#[cfg(any(target_os = "macos", target_os = "ios"))]
504+
pub fn new_sys_control(sockfd: RawFd, name: &str, unit: u32) -> Result<SockAddr> {
505+
SysControlAddr::from_name(sockfd, name, unit).map(|a| SockAddr::SysControl(a))
506+
}
507+
495508
pub fn family(&self) -> AddressFamily {
496509
match *self {
497510
SockAddr::Inet(InetAddr::V4(..)) => AddressFamily::Inet,
498511
SockAddr::Inet(InetAddr::V6(..)) => AddressFamily::Inet6,
499512
SockAddr::Unix(..) => AddressFamily::Unix,
500513
#[cfg(any(target_os = "linux", target_os = "android"))]
501514
SockAddr::Netlink(..) => AddressFamily::Netlink,
515+
#[cfg(any(target_os = "macos", target_os = "ios"))]
516+
SockAddr::SysControl(..) => AddressFamily::System,
502517
}
503518
}
504519

@@ -513,6 +528,8 @@ impl SockAddr {
513528
SockAddr::Unix(UnixAddr(ref addr, len)) => (mem::transmute(addr), (len + offset_of!(libc::sockaddr_un, sun_path)) as libc::socklen_t),
514529
#[cfg(any(target_os = "linux", target_os = "android"))]
515530
SockAddr::Netlink(NetlinkAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t),
531+
#[cfg(any(target_os = "macos", target_os = "ios"))]
532+
SockAddr::SysControl(SysControlAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<sys_control::sockaddr_ctl>() as libc::socklen_t),
516533
}
517534
}
518535
}
@@ -545,6 +562,8 @@ impl hash::Hash for SockAddr {
545562
SockAddr::Unix(ref a) => a.hash(s),
546563
#[cfg(any(target_os = "linux", target_os = "android"))]
547564
SockAddr::Netlink(ref a) => a.hash(s),
565+
#[cfg(any(target_os = "macos", target_os = "ios"))]
566+
SockAddr::SysControl(ref a) => a.hash(s),
548567
}
549568
}
550569
}
@@ -562,6 +581,8 @@ impl fmt::Display for SockAddr {
562581
SockAddr::Unix(ref unix) => unix.fmt(f),
563582
#[cfg(any(target_os = "linux", target_os = "android"))]
564583
SockAddr::Netlink(ref nl) => nl.fmt(f),
584+
#[cfg(any(target_os = "macos", target_os = "ios"))]
585+
SockAddr::SysControl(ref sc) => sc.fmt(f),
565586
}
566587
}
567588
}
@@ -620,3 +641,102 @@ pub mod netlink {
620641
}
621642
}
622643
}
644+
645+
#[cfg(any(target_os = "macos", target_os = "ios"))]
646+
pub mod sys_control {
647+
use ::sys::socket::consts;
648+
use ::sys::socket::addr::{AddressFamily};
649+
use libc::{c_uchar, uint16_t, uint32_t};
650+
use std::{fmt, mem};
651+
use std::hash::{Hash, Hasher};
652+
use std::os::unix::io::RawFd;
653+
use {Errno, Error, Result};
654+
655+
#[repr(C)]
656+
pub struct ctl_ioc_info {
657+
pub ctl_id: uint32_t,
658+
pub ctl_name: [c_uchar; MAX_KCTL_NAME],
659+
}
660+
661+
const CTL_IOC_MAGIC: u8 = 'N' as u8;
662+
const CTL_IOC_INFO: u8 = 3;
663+
const MAX_KCTL_NAME: usize = 96;
664+
665+
ioctl!(readwrite ctl_info with CTL_IOC_MAGIC, CTL_IOC_INFO; ctl_ioc_info);
666+
667+
#[repr(C)]
668+
#[derive(Copy, Clone)]
669+
pub struct sockaddr_ctl {
670+
pub sc_len: c_uchar,
671+
pub sc_family: c_uchar,
672+
pub ss_sysaddr: uint16_t,
673+
pub sc_id: uint32_t,
674+
pub sc_unit: uint32_t,
675+
pub sc_reserved: [uint32_t; 5],
676+
}
677+
678+
#[derive(Copy, Clone)]
679+
pub struct SysControlAddr(pub sockaddr_ctl);
680+
681+
// , PartialEq, Eq, Debug, Hash
682+
impl PartialEq for SysControlAddr {
683+
fn eq(&self, other: &Self) -> bool {
684+
let (inner, other) = (self.0, other.0);
685+
(inner.sc_id, inner.sc_unit) ==
686+
(other.sc_id, other.sc_unit)
687+
}
688+
}
689+
690+
impl Eq for SysControlAddr {}
691+
692+
impl Hash for SysControlAddr {
693+
fn hash<H: Hasher>(&self, s: &mut H) {
694+
let inner = self.0;
695+
(inner.sc_id, inner.sc_unit).hash(s);
696+
}
697+
}
698+
699+
700+
impl SysControlAddr {
701+
pub fn new(id: u32, unit: u32) -> SysControlAddr {
702+
let addr = sockaddr_ctl {
703+
sc_len: mem::size_of::<sockaddr_ctl>() as c_uchar,
704+
sc_family: AddressFamily::System as c_uchar,
705+
ss_sysaddr: consts::AF_SYS_CONTROL as uint16_t,
706+
sc_id: id,
707+
sc_unit: unit,
708+
sc_reserved: [0; 5]
709+
};
710+
711+
SysControlAddr(addr)
712+
}
713+
714+
pub fn from_name(sockfd: RawFd, name: &str, unit: u32) -> Result<SysControlAddr> {
715+
if name.len() > MAX_KCTL_NAME {
716+
return Err(Error::Sys(Errno::ENAMETOOLONG));
717+
}
718+
719+
let mut ctl_name = [0; MAX_KCTL_NAME];
720+
ctl_name[..name.len()].clone_from_slice(name.as_bytes());
721+
let mut info = ctl_ioc_info { ctl_id: 0, ctl_name: ctl_name };
722+
723+
unsafe { try!(ctl_info(sockfd, &mut info)); }
724+
725+
Ok(SysControlAddr::new(info.ctl_id, unit))
726+
}
727+
728+
pub fn id(&self) -> u32 {
729+
self.0.sc_id
730+
}
731+
732+
pub fn unit(&self) -> u32 {
733+
self.0.sc_unit
734+
}
735+
}
736+
737+
impl fmt::Display for SysControlAddr {
738+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
739+
write!(f, "id: {} unit: {}", self.id(), self.unit())
740+
}
741+
}
742+
}

src/sys/socket/consts.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,11 @@ mod os {
132132
pub const AF_INET6: c_int = 28;
133133
#[cfg(any(target_os = "macos", target_os = "ios"))]
134134
pub const AF_INET6: c_int = 30;
135+
#[cfg(any(target_os = "macos", target_os = "ios"))]
136+
pub const AF_SYSTEM: c_int = 32;
137+
138+
#[cfg(any(target_os = "macos", target_os = "ios"))]
139+
pub const AF_SYS_CONTROL: c_int = 2;
135140

136141
pub const SOCK_STREAM: c_int = 1;
137142
pub const SOCK_DGRAM: c_int = 2;
@@ -144,6 +149,8 @@ mod os {
144149
pub const IPPROTO_IPV6: c_int = 41;
145150
pub const IPPROTO_TCP: c_int = 6;
146151
pub const IPPROTO_UDP: c_int = 17;
152+
#[cfg(any(target_os = "macos", target_os = "ios"))]
153+
pub const SYSPROTO_CONTROL: c_int = 2;
147154

148155
pub const SO_ACCEPTCONN: c_int = 0x0002;
149156
pub const SO_BROADCAST: c_int = 0x0020;

test/sys/test_socket.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,20 @@ pub fn test_unixdomain() {
180180

181181
assert_eq!(&buf[..], b"hello");
182182
}
183+
184+
// Test creating and using named system control sockets
185+
#[cfg(any(target_os = "macos", target_os = "ios"))]
186+
#[test]
187+
pub fn test_syscontrol() {
188+
use nix::{Errno, Error};
189+
use nix::sys::socket::{AddressFamily, SockType, SockFlag};
190+
use nix::sys::socket::{socket, SockAddr};
191+
use nix::sys::socket::SYSPROTO_CONTROL;
192+
193+
let fd = socket(AddressFamily::System, SockType::Datagram, SockFlag::empty(), SYSPROTO_CONTROL).expect("socket failed");
194+
let _sockaddr = SockAddr::new_sys_control(fd, "com.apple.net.utun_control", 0).expect("resolving sys_control name failed");
195+
assert_eq!(SockAddr::new_sys_control(fd, "foo.bar.lol", 0).err(), Some(Error::Sys(Errno::ENOENT)));
196+
197+
// requires root privileges
198+
// connect(fd, &sockaddr).expect("connect failed");
199+
}

0 commit comments

Comments
 (0)