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