netconfig-rs 0.1.6

Crate for managing network interfaces and IP addresses in a cross-platform way
Documentation
use crate::sys::scinterface::SCNetworkInterface;
use crate::sys::{dummy_socket, ioctls, InterfaceHandle};
use crate::sys::{ifreq, InterfaceName};
use crate::{Error, Interface};
use ipnet::IpNet;
use nix::sys::socket::{SockaddrIn, SockaddrIn6};
use std::net;
use std::os::unix::io::AsRawFd;

pub trait InterfaceExt {
    fn set_up(&self, v: bool) -> Result<(), Error>;
    fn set_running(&self, v: bool) -> Result<(), Error>;
    fn alias(&self) -> Result<String, Error>;
}

impl InterfaceHandle {
    pub fn add_address(&self, network: IpNet) -> Result<(), Error> {
        let socket = dummy_socket()?;
        let name = self.name()?;
        match network {
            IpNet::V4(network) => {
                let ifra_addr = SockaddrIn::from(net::SocketAddrV4::new(network.addr(), 0));
                let ifra_dest_addr = SockaddrIn::from(net::SocketAddrV4::new(network.network(), 0));
                let ifra_dest_mask = SockaddrIn::from(net::SocketAddrV4::new(network.netmask(), 0));

                let req = ifreq::ifaliasreq4 {
                    ifra_name: name
                        .parse::<InterfaceName>()
                        .map_err(|e| std::io::Error::other(e.to_string()))?,
                    ifra_addr: *ifra_addr.as_ref(),
                    ifra_broadaddr: *ifra_dest_addr.as_ref(),
                    ifra_mask: *ifra_dest_mask.as_ref(),
                };

                unsafe {
                    ioctls::siocaifaddr4(socket.as_raw_fd(), &req)?;
                }
                Ok(())
            }
            IpNet::V6(network) => {
                let ifra_addr = SockaddrIn6::from(net::SocketAddrV6::new(network.addr(), 0, 0, 0));
                let ifra_dest_addr =
                    SockaddrIn6::from(net::SocketAddrV6::new(network.network(), 0, 0, 0));
                let ifra_dest_mask =
                    SockaddrIn6::from(net::SocketAddrV6::new(network.netmask(), 0, 0, 0));

                let req = ifreq::ifaliasreq6 {
                    ifra_name: name
                        .parse::<InterfaceName>()
                        .map_err(|e| std::io::Error::other(e.to_string()))?,
                    ifra_addr: *ifra_addr.as_ref(),
                    ifra_broadaddr: *ifra_dest_addr.as_ref(),
                    ifra_mask: *ifra_dest_mask.as_ref(),
                };

                unsafe {
                    ioctls::siocaifaddr6(socket.as_raw_fd(), &req)?;
                }
                Ok(())
            }
        }
    }

    pub fn remove_address(&self, _network: IpNet) -> Result<(), Error> {
        todo!()
    }

    pub fn hwaddress(&self) -> Result<[u8; 6], Error> {
        todo!()
    }
}

impl InterfaceExt for Interface {
    fn alias(&self) -> Result<String, Error> {
        match SCNetworkInterface::get_displayname(&self.name()?) {
            Some(alias) => Ok(alias),
            None => Ok(self.name()?),
        }
    }
    fn set_up(&self, v: bool) -> Result<(), Error> {
        self.0.set_up(v)
    }
    fn set_running(&self, v: bool) -> Result<(), Error> {
        self.0.set_running(v)
    }
}