Skip to main content

linux_info/network/
network_manager.rs

1//! Connect to the NetworkManager
2
3use std::net::Ipv4Addr;
4use std::sync::Arc;
5use std::time::Duration;
6
7use dbus::arg::RefArg;
8use dbus::blocking::{Connection, Proxy};
9use dbus::{Error, Path};
10
11use nmdbus::device::Device as DeviceTrait;
12use nmdbus::device_modem::DeviceModem;
13use nmdbus::ip4config::IP4Config;
14use nmdbus::NetworkManager as DbusNetworkManager;
15
16const DBUS_NAME: &str = "org.freedesktop.NetworkManager";
17const DBUS_PATH: &str = "/org/freedesktop/NetworkManager";
18const TIMEOUT: Duration = Duration::from_secs(2);
19
20#[derive(Clone)]
21struct Dbus {
22	conn: Arc<Connection>,
23}
24
25impl Dbus {
26	fn connect() -> Result<Self, Error> {
27		Connection::new_system()
28			.map(Arc::new)
29			.map(|conn| Self { conn })
30	}
31
32	fn proxy<'a, 'b>(
33		&'b self,
34		path: impl Into<Path<'a>>,
35	) -> Proxy<'a, &'b Connection> {
36		self.conn.with_proxy(DBUS_NAME, path, TIMEOUT)
37	}
38}
39
40#[derive(Clone)]
41pub struct NetworkManager {
42	dbus: Dbus,
43}
44
45impl NetworkManager {
46	pub fn connect() -> Result<Self, Error> {
47		Dbus::connect().map(|dbus| Self { dbus })
48	}
49
50	pub fn devices(&self) -> Result<Vec<Device>, Error> {
51		let paths = self.dbus.proxy(DBUS_PATH).get_devices()?;
52		let devices = paths
53			.into_iter()
54			.map(|path| Device {
55				dbus: self.dbus.clone(),
56				path,
57			})
58			.collect();
59
60		Ok(devices)
61	}
62}
63
64pub struct Device {
65	dbus: Dbus,
66	path: Path<'static>,
67}
68
69impl Device {
70	/// The path of the device as exposed by the udev property ID_PATH.  
71	/// Note that non-UTF-8 characters are backslash escaped.
72	/// Use g_strcompress() to obtain the true (non-UTF-8) string.
73	pub fn path(&self) -> Result<String, Error> {
74		self.dbus.proxy(&self.path).path()
75	}
76
77	/// The name of the device's control (and often data) interface. Note that
78	/// non UTF-8 characters are backslash escaped, so the resulting name may
79	/// be longer then 15 characters. Use g_strcompress() to revert the
80	/// escaping.
81	pub fn interface(&self) -> Result<String, Error> {
82		self.dbus.proxy(&self.path).interface()
83	}
84
85	/// The driver handling the device. Non-UTF-8 sequences are backslash
86	/// escaped. Use g_strcompress() to revert.
87	pub fn driver(&self) -> Result<String, Error> {
88		self.dbus.proxy(&self.path).driver()
89	}
90
91	/// The current state of the device.
92	pub fn state(&self) -> Result<DeviceState, Error> {
93		DeviceTrait::state(&self.dbus.proxy(&self.path)).map(Into::into)
94	}
95
96	/// The general type of the network device; ie Ethernet, Wi-Fi, etc.
97	pub fn kind(&self) -> Result<DeviceKind, Error> {
98		self.dbus.proxy(&self.path).device_type().map(Into::into)
99	}
100
101	/// Ipv4 Configuration of the device. Only valid when the device is in
102	/// DeviceState::Activated
103	pub fn ipv4_config(&self) -> Result<Ipv4Config, Error> {
104		self.dbus
105			.proxy(&self.path)
106			.ip4_config()
107			.map(|path| Ipv4Config {
108				dbus: self.dbus.clone(),
109				path,
110			})
111	}
112
113	/// The access point name the modem is connected to. Blank if disconnected.
114	pub fn modem_apn(&self) -> Result<String, Error> {
115		self.dbus.proxy(&self.path).apn()
116	}
117}
118
119pub struct Ipv4Config {
120	dbus: Dbus,
121	path: Path<'static>,
122}
123
124impl Ipv4Config {
125	pub fn addresses(&self) -> Result<Vec<Ipv4Addr>, Error> {
126		let data = self.dbus.proxy(&self.path).address_data()?;
127		let addrs = data
128			.into_iter()
129			.filter_map(|mut d| d.remove("address"))
130			.filter_map(|addr| addr.as_str()?.parse().ok())
131			.collect();
132
133		Ok(addrs)
134	}
135}
136
137#[repr(u32)]
138#[derive(Debug, Clone, Copy, PartialEq, Eq)]
139#[cfg_attr(
140	feature = "serde",
141	derive(serde1::Serialize, serde1::Deserialize),
142	serde(crate = "serde1")
143)]
144pub enum DeviceKind {
145	/// unknown device
146	Unknown = 0,
147	/// generic support for unrecognized device types
148	Generic = 14,
149	/// a wired ethernet device
150	Ethernet = 1,
151	/// an 802.11 Wi-Fi device
152	Wifi = 2,
153	/// not used
154	Unused1 = 3,
155	/// not used
156	Unused2 = 4,
157	/// a Bluetooth device supporting PAN or DUN access protocols
158	Bt = 5,
159	/// an OLPC XO mesh networking device
160	OlpcMesh = 6,
161	/// an 802.16e Mobile WiMAX broadband device
162	Wimax = 7,
163	/// a modem supporting analog telephone, CDMA/EVDO, GSM/UMTS,
164	/// or LTE network access protocols
165	Modem = 8,
166	/// an IP-over-InfiniBand device
167	Infiniband = 9,
168	/// a bond master interface
169	Bond = 10,
170	/// an 802.1Q VLAN interface
171	Vlan = 11,
172	/// ADSL modem
173	Adsl = 12,
174	/// a bridge master interface
175	Bridge = 13,
176	/// a team master interface
177	Team = 15,
178	/// a TUN or TAP interface
179	Tun = 16,
180	/// a IP tunnel interface
181	IpTunnel = 17,
182	/// a MACVLAN interface
183	Macvlan = 18,
184	/// a VXLAN interface
185	Vxlan = 19,
186	/// a VETH interface
187	Veth = 20,
188	/// a MACsec interface
189	Macsec = 21,
190	/// a dummy interface
191	Dummy = 22,
192	/// a PPP interface
193	Ppp = 23,
194	/// a Open vSwitch interface
195	OvsInterface = 24,
196	/// a Open vSwitch port
197	OvsPort = 25,
198	/// a Open vSwitch bridge
199	OvsBridge = 26,
200	/// a IEEE 802.15.4 (WPAN) MAC Layer Device
201	Wpan = 27,
202	/// 6LoWPAN interface
203	SixLowPan = 28,
204	/// a WireGuard interface
205	Wireguard = 29,
206	/// an 802.11 Wi-Fi P2P device. Since: 1.16.
207	WifiP2p = 30,
208	/// A VRF (Virtual Routing and Forwarding) interface. Since: 1.24.
209	Vrf = 31,
210}
211
212impl From<u32> for DeviceKind {
213	fn from(num: u32) -> Self {
214		if num > 31 {
215			Self::Unknown
216		} else {
217			unsafe { *(&num as *const u32 as *const Self) }
218		}
219	}
220}
221
222#[repr(u32)]
223#[derive(Debug, Clone, Copy, PartialEq, Eq)]
224#[cfg_attr(
225	feature = "serde",
226	derive(serde1::Serialize, serde1::Deserialize),
227	serde(crate = "serde1")
228)]
229pub enum DeviceState {
230	/// the device's state is unknown
231	Unknown = 0,
232	/// the device is recognized, but not managed by NetworkManager
233	Unmanaged = 10,
234	/// the device is managed by NetworkManager, but is not available for use.
235	/// Reasons may include the wireless switched off, missing firmware, no
236	/// ethernet carrier, missing supplicant or modem manager, etc.
237	Unavailable = 20,
238	/// the device can be activated, but is currently idle and not connected
239	/// to a network.
240	Disconnected = 30,
241	/// the device is preparing the connection to the network. This may include
242	/// operations like changing the MAC address, setting physical link
243	/// properties, and anything else required to connect to the requested
244	/// network.
245	Prepare = 40,
246	/// the device is connecting to the requested network. This may include
247	/// operations like associating with the Wi-Fi AP, dialing the modem,
248	/// connecting to the remote Bluetooth device, etc.
249	Config = 50,
250	/// the device requires more information to continue connecting to the
251	/// requested network. This includes secrets like WiFi passphrases, login
252	/// passwords, PIN codes, etc.
253	NeedAuth = 60,
254	/// the device is requesting IPv4 and/or IPv6 addresses and routing
255	/// information from the network.
256	IpConfig = 70,
257	/// the device is checking whether further action is required for the
258	/// requested network connection. This may include checking whether only
259	/// local network access is available, whether a captive portal is
260	/// blocking access to the Internet, etc.
261	IpCheck = 80,
262	/// the device is waiting for a secondary connection (like a VPN) which
263	/// must activated before the device can be activated
264	Secondaries = 90,
265	/// the device has a network connection, either local or global.
266	Activated = 100,
267	/// a disconnection from the current network connection was requested, and
268	/// the device is cleaning up resources used for that connection. The
269	/// network connection may still be valid.
270	Deactivating = 110,
271	/// the device failed to connect to the requested network and is cleaning
272	/// up the connection request
273	Failed = 120,
274}
275
276impl From<u32> for DeviceState {
277	fn from(num: u32) -> Self {
278		if num > 120 || num % 10 != 0 {
279			Self::Unknown
280		} else {
281			unsafe { *(&num as *const u32 as *const Self) }
282		}
283	}
284}