linux_info/network/
network_manager.rs

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