netconfig_rs/sys/linux/
handle.rs

1use crate::sys::ifreq::ifreq;
2use crate::sys::{dummy_socket, ioctls, InterfaceHandle};
3use crate::{Error, Interface};
4use ipnet::IpNet;
5use libc::ARPHRD_ETHER;
6use netlink_packet_core::{
7    NetlinkHeader, NetlinkMessage, NetlinkPayload, NLM_F_DUMP, NLM_F_REQUEST,
8};
9use netlink_packet_route::address::{AddressAttribute, AddressMessage};
10use netlink_packet_route::{AddressFamily, RouteNetlinkMessage};
11use netlink_sys::constants::NETLINK_ROUTE;
12use netlink_sys::{Socket, SocketAddr};
13use nix::net::if_::InterfaceFlags;
14use std::net::IpAddr;
15use std::os::unix::io::AsRawFd;
16
17// Public interface (platform extension)
18pub trait InterfaceExt {
19    fn set_up(&self, v: bool) -> Result<(), Error>;
20    fn set_running(&self, v: bool) -> Result<(), Error>;
21    fn set_hwaddress(&self, hwaddress: [u8; 6]) -> Result<(), Error>;
22    fn set_packet_info(&self, v: bool) -> Result<(), Error>;
23}
24
25// Private interface
26impl InterfaceHandle {
27    pub fn add_address(&self, network: IpNet) -> Result<(), Error> {
28        let mut socket = Socket::new(NETLINK_ROUTE)?;
29        socket.bind_auto()?;
30        socket.connect(&SocketAddr::new(0, 0))?;
31
32        let message = make_address_message(self.index, network);
33        let mut nl_hdr = NetlinkHeader::default();
34        nl_hdr.flags = NLM_F_DUMP | NLM_F_REQUEST;
35        let mut req = NetlinkMessage::new(
36            nl_hdr,
37            NetlinkPayload::from(RouteNetlinkMessage::NewAddress(message)),
38        );
39
40        req.finalize();
41
42        let mut buf = vec![0; req.header.length as _];
43        req.serialize(&mut buf);
44
45        socket.send(&buf, 0)?;
46
47        Ok(())
48    }
49
50    pub fn remove_address(&self, network: IpNet) -> Result<(), Error> {
51        let mut socket = Socket::new(NETLINK_ROUTE)?;
52        socket.bind_auto()?;
53        socket.connect(&SocketAddr::new(0, 0))?;
54
55        let message = make_address_message(self.index, network);
56        let mut nl_hdr = NetlinkHeader::default();
57        nl_hdr.flags = NLM_F_REQUEST;
58        let mut req = NetlinkMessage::new(
59            nl_hdr,
60            NetlinkPayload::from(RouteNetlinkMessage::DelAddress(message)),
61        );
62
63        req.finalize();
64
65        let mut buf = vec![0; req.header.length as _];
66        req.serialize(&mut buf);
67
68        socket.send(&buf, 0)?;
69
70        Ok(())
71    }
72
73    pub fn hwaddress(&self) -> Result<[u8; 6], Error> {
74        let mut req = ifreq::new(self.name()?)?;
75        let socket = dummy_socket()?;
76
77        unsafe { ioctls::siocgifhwaddr(socket.as_raw_fd(), &mut req) }?;
78        let mut rs = [0; 6];
79        unsafe {
80            for (i, b) in req.ifr_ifru.ifru_hwaddr.sa_data.iter().take(6).enumerate() {
81                rs[i] = *b as _;
82            }
83        }
84        Ok(rs)
85    }
86}
87
88impl InterfaceExt for Interface {
89    fn set_up(&self, v: bool) -> Result<(), Error> {
90        self.0.set_up(v)
91    }
92    fn set_running(&self, v: bool) -> Result<(), Error> {
93        self.0.set_running(v)
94    }
95
96    fn set_hwaddress(&self, hwaddress: [u8; 6]) -> Result<(), Error> {
97        let mut req = ifreq::new(self.name()?)?;
98        req.ifr_ifru.ifru_hwaddr = libc::sockaddr {
99            sa_family: ARPHRD_ETHER,
100            sa_data: unsafe { std::mem::zeroed() },
101        };
102
103        unsafe {
104            req.ifr_ifru.ifru_hwaddr.sa_data[0..6]
105                .copy_from_slice(hwaddress.map(|c| c as _).as_slice());
106        }
107
108        let socket = dummy_socket()?;
109
110        unsafe { ioctls::siocsifhwaddr(socket.as_raw_fd(), &req) }?;
111        Ok(())
112    }
113
114    fn set_packet_info(&self, v: bool) -> Result<(), Error> {
115        let mut flags = self.0.flags()?;
116        flags.set(InterfaceFlags::IFF_NO_PI, !v);
117        self.0.set_flags(flags)?;
118        Ok(())
119    }
120}
121
122fn make_address_message(index: u32, network: IpNet) -> AddressMessage {
123    let mut message = AddressMessage::default();
124    message.header.prefix_len = network.prefix_len();
125    message.header.index = index;
126    let addr = network.addr();
127    message.header.family = if addr.is_ipv4() {
128        AddressFamily::Inet
129    } else {
130        AddressFamily::Inet6
131    };
132
133    if let IpAddr::V6(addr) = addr {
134        if addr.is_multicast() {
135            message.attributes.push(AddressAttribute::Multicast(addr));
136            return message;
137        }
138    }
139
140    message
141        .attributes
142        .push(AddressAttribute::Address(network.addr()));
143
144    if let IpNet::V4(network_v4) = network {
145        // for IPv4 the IFA_LOCAL address can be set to the same value as IFA_ADDRESS
146        message
147            .attributes
148            .push(AddressAttribute::Local(network.addr()));
149        // set the IFA_BROADCAST address as well (IPv6 does not support broadcast)
150        message
151            .attributes
152            .push(AddressAttribute::Broadcast(network_v4.broadcast()));
153    }
154
155    message
156}