netconfig_rs/sys/linux/
handle.rs1use 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
17pub 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
25impl 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 message
147 .attributes
148 .push(AddressAttribute::Local(network.addr()));
149 message
151 .attributes
152 .push(AddressAttribute::Broadcast(network_v4.broadcast()));
153 }
154
155 message
156}