diff --git a/system-configuration/examples/network_configuration.rs b/system-configuration/examples/network_configuration.rs index a60a9f7..3614c85 100644 --- a/system-configuration/examples/network_configuration.rs +++ b/system-configuration/examples/network_configuration.rs @@ -10,11 +10,11 @@ use system_configuration::network_configuration::{global_router, SCNetworkInterf fn main() { let store = SCDynamicStoreBuilder::new("session_name").build(); - - println!("Global Service:\n{:?}\n", SCNetworkService::global(&store)); + let service = SCNetworkService::global(&store).unwrap(); + println!("Global Service:\n{:?}\n", service); println!( "Global Interface:\n{:?}\n", - SCNetworkInterface::global(&store) + service.interface() ); println!("Global Service Router:\n{:?}\n", global_router(&store)); diff --git a/system-configuration/examples/set_dns.rs b/system-configuration/examples/set_dns.rs index f79797a..15f60ef 100644 --- a/system-configuration/examples/set_dns.rs +++ b/system-configuration/examples/set_dns.rs @@ -1,6 +1,7 @@ extern crate system_configuration; -use system_configuration::network_configuration::{SCNetworkGlobal, SCNetworkServiceDns}; +use system_configuration::dynamic_store::SCDynamicStoreBuilder; +use system_configuration::network_configuration::{SCNetworkService}; use std::net::{IpAddr, Ipv4Addr}; @@ -18,16 +19,16 @@ fn main() { IpAddr::V4(Ipv4Addr::new(8, 8, 4, 4)), ]; - let global_service = SCNetworkGlobal.service().expect("No PrimaryService active"); - let global_interface = global_service - .interface() - .expect("No PrimaryInterface active"); + let store = SCDynamicStoreBuilder::new("session_name").build(); + + let global_service = SCNetworkService::global(&store).expect("No PrimaryService active"); + let global_interface = global_service.interface().expect("No PrimaryInterface active"); println!("Global Service:"); println!("\tid: {:?}", global_service.id()); println!("\tname: {:?}", global_service.name()); println!("\tenabled: {:?}", global_service.enabled()); - println!("\tdns: {:?}", global_service.dns()); + println!("\tdns: {:?}", global_service.dns(&store)); println!("\tinterface: {:?}", global_interface.name().unwrap()); println!( @@ -36,15 +37,15 @@ fn main() { global_service.name() ); - let dns = SCNetworkServiceDns::new((None, None), (None, Some(addrs))); + // let dns = SCNetworkServiceDns::new((None, None), (None, Some(addrs))); - println!("Success: {:?}", global_service.set_dns(dns)); + println!("Success: {:?}", global_service.set_dns_server_addresses(&store, Some(addrs) )); // Check // networksetup -getdnsservers "Wi-Fi" // scutil --dns // dig - println!("{:?}", global_service.dns()); + println!("{:?}", global_service.dns(&store)); println!( "\n\nUse Command `networksetup -setdnsservers \"{}\" \"Empty\"` to restore DNS setting. ", diff --git a/system-configuration/src/network_configuration.rs b/system-configuration/src/network_configuration.rs index 70d08da..cf14edb 100644 --- a/system-configuration/src/network_configuration.rs +++ b/system-configuration/src/network_configuration.rs @@ -16,9 +16,9 @@ use core_foundation::array::CFArray; use core_foundation::base::{CFType, TCFType}; use core_foundation::base::kCFAllocatorDefault; use core_foundation::dictionary::CFDictionary; -use core_foundation::string::{CFString, CFStringRef}; +use core_foundation::string::{CFString}; -use dynamic_store::{SCDynamicStore, SCDynamicStoreBuilder}; +use dynamic_store::{SCDynamicStore}; pub use system_configuration_sys::network_configuration::*; use system_configuration_sys::preferences::SCPreferencesCreate; @@ -41,43 +41,22 @@ pub struct SCNetworkInterfaceMtu { /// DNS #[derive(Debug)] pub struct SCNetworkServiceDns { - state_domain_name: Option, - setup_domain_name: Option, - state_server_addresses: Option>, - setup_server_addresses: Option>, + /// State DNS setting + pub state: DnsSetting, + /// Setup DNS setting + pub setup: DnsSetting, } -impl SCNetworkServiceDns { - /// DNS Constructor - pub fn new( - domain_name: (Option, Option), - server_addresses: (Option>, Option>), - ) -> SCNetworkServiceDns { - SCNetworkServiceDns { - state_domain_name: domain_name.0, - setup_domain_name: domain_name.1, - state_server_addresses: server_addresses.0, - setup_server_addresses: server_addresses.1, - } - } - - /// Returns DomainName (state and setup) - pub fn domain_name(&self) -> (Option, Option) { - ( - self.state_domain_name.clone(), - self.setup_domain_name.clone(), - ) - } - - /// Returns ServerAddresses (state and setup) - pub fn server_addresses(&self) -> (Option>, Option>) { - ( - self.state_server_addresses.clone(), - self.setup_server_addresses.clone(), - ) - } +/// DNS Setting +#[derive(Debug)] +pub struct DnsSetting { + /// Domain Name + pub domain_name: Option, + /// DNS Server Addresses + pub server_addresses: Option>, } + fn global_query(store: &SCDynamicStore, key: &str) -> Option { let path = CFString::from_static_string("State:/Network/Global/IPv4"); @@ -146,14 +125,12 @@ impl SCNetworkService { ) }; - let array: CFArray = + let array: CFArray = unsafe { CFArray::wrap_under_get_rule(SCNetworkServiceCopyAll(prefs)) }; - array - .get_all_values() - .iter() - .map(|service_ptr| unsafe { SCNetworkService::wrap_under_get_rule(*service_ptr as _) }) - .collect::>() + array.iter() + .map(|item| item.downcast::().unwrap()) + .collect::>() } /// Returns the user-specified ordering of network services within the specified set. @@ -168,15 +145,18 @@ impl SCNetworkService { let netset = unsafe { SCNetworkSetCopyCurrent(prefs) }; - let array: CFArray = + let array: CFArray = unsafe { CFArray::wrap_under_get_rule(SCNetworkSetGetServiceOrder(netset)) }; let mut services = Vec::new(); - for id_ptr in array.get_all_values().iter() { - let service_ptr: SCNetworkServiceRef = - unsafe { SCNetworkServiceCopy(prefs, *id_ptr as _) }; - services.push(unsafe { SCNetworkService::wrap_under_get_rule(service_ptr) }); + for item in array.iter() { + if let Some(id) = item.downcast::() { + let service_ref = unsafe { CFType::wrap_under_get_rule(SCNetworkServiceCopy(prefs, id.as_concrete_TypeRef() )) }; + if let Some(serv) = service_ref.downcast::() { + services.push(serv); + } + } } services @@ -199,12 +179,11 @@ impl SCNetworkService { } /// Returns the DNS infomation on this network service - pub fn dns(&self) -> SCNetworkServiceDns { - let store = SCDynamicStoreBuilder::new("ns_dns").build(); + pub fn dns(&self, store: &SCDynamicStore) -> SCNetworkServiceDns { - let query = |path: String| -> (Option, Option>) { - let mut _domain_name: Option = None; - let mut _server_addresses: Option> = None; + let query = |path: String| -> DnsSetting { + let mut dns_domain_name: Option = None; + let mut dns_server_addresses: Option> = None; if let Some(value) = store.get(CFString::new(&path)) { if let Some(dict) = value.downcast_into::() { @@ -213,7 +192,7 @@ impl SCNetworkService { { let domain_name = unsafe { CFType::wrap_under_get_rule(domain_name) }; if let Some(domain_name) = domain_name.downcast::() { - _domain_name = Some(domain_name.to_string()); + dns_domain_name = Some(domain_name.to_string()); } } @@ -221,83 +200,71 @@ impl SCNetworkService { dict.find2(&CFString::from_static_string("ServerAddresses")) { let addrs = unsafe { CFType::wrap_under_get_rule(addrs) }; - if let Some(addrs) = addrs.downcast::>() { + if let Some(addrs) = addrs.downcast::>() { let mut temp = Vec::new(); for addr in addrs.iter() { - if let Ok(ip_addr) = addr.to_string().parse::() { - temp.push(ip_addr); + if let Some(addr) = addr.downcast::() { + if let Ok(ip_addr) = addr.to_string().parse::() { + temp.push(ip_addr); + } } } if temp.len() > 0 { - _server_addresses = Some(temp); + dns_server_addresses = Some(temp); } } } } } - return (_domain_name, _server_addresses); + DnsSetting { + domain_name: dns_domain_name, + server_addresses: dns_server_addresses, + } }; - let (state_domain_name, state_server_addresses) = + let state_dns_setting = query(format!("State:/Network/Service/{}/DNS", self.id())); - let (setup_domain_name, setup_server_addresses) = + let setup_dns_setting = query(format!("Setup:/Network/Service/{}/DNS", self.id())); SCNetworkServiceDns { - state_domain_name: state_domain_name, - state_server_addresses: state_server_addresses, - setup_domain_name: setup_domain_name, - setup_server_addresses: setup_server_addresses, + state: state_dns_setting, + setup: setup_dns_setting } } + + /// Setting DNS Domain Name on this network service + pub fn set_dns_domain_name(&self, store: &SCDynamicStore, domain_name: Option) -> bool { + let key = CFString::from_static_string("DomainName"); + let value = CFString::new(domain_name.unwrap_or("Empty".to_string()).as_str()); + let dictionary = CFDictionary::from_CFType_pairs(&[(key, value)]); - /// Setting DNS on this network service - pub fn set_dns(&self, dns: SCNetworkServiceDns) -> bool { - let store = SCDynamicStoreBuilder::new("ns_dns_set").build(); - - if dns.setup_server_addresses.is_some() { - let key = CFString::from_static_string("ServerAddresses"); - let addrs: Vec = dns.setup_server_addresses - .unwrap() - .iter() - .map(|s| CFString::new(&format!("{}", s))) - .collect(); - let value = CFArray::from_CFTypes(&addrs); - let dictionary = CFDictionary::from_CFType_pairs(&[(key, value)]); - - let path = CFString::new(&format!("Setup:/Network/Service/{}/DNS", self.id())); - - if !store.set(path, dictionary) { - return false; - } - } + let path = CFString::new(&format!("Setup:/Network/Service/{}/DNS", self.id())); - if dns.setup_domain_name.is_some() { - let key = CFString::from_static_string("DomainName"); - let value = CFString::new(dns.setup_domain_name.unwrap().as_str()); - let dictionary = CFDictionary::from_CFType_pairs(&[(key, value)]); + store.set(path, dictionary) + } - let path = CFString::new(&format!("Setup:/Network/Service/{}/DNS", self.id())); + /// Setting DNS Server Addresses on this network service + pub fn set_dns_server_addresses(&self, store: &SCDynamicStore, server_addrs: Option>) -> bool { + let key = CFString::from_static_string("ServerAddresses"); + let addrs: Vec = match server_addrs { + Some(addrs) => addrs.iter().map(|s| CFString::new(&format!("{}", s))).collect(), + None => vec![ CFString::new("Empty") ] + }; + let value = CFArray::from_CFTypes(&addrs); + let dictionary = CFDictionary::from_CFType_pairs(&[(key, value)]); - if !store.set(path, dictionary) { - // FIXME: should rollback ? - return false; - } - } + let path = CFString::new(&format!("Setup:/Network/Service/{}/DNS", self.id())); - return true; + store.set(path, dictionary) } /// Returns the network interface associated with this network service. pub fn interface(&self) -> Option { - let interface_ptr = unsafe { SCNetworkServiceGetInterface(self.0) }; - if interface_ptr.is_null() { - None - } else { - Some(unsafe { SCNetworkInterface::wrap_under_get_rule(interface_ptr) }) - } + let interface_ref = unsafe { CFType::wrap_under_get_rule(SCNetworkServiceGetInterface(self.0)) }; + interface_ref.downcast::() } } @@ -311,12 +278,11 @@ impl fmt::Debug for SCNetworkService { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, - "SCNetworkService{{ id: {:?}, name: {:?}, enabled: {}, interface: {:?}, dns: {:?} }}", + "SCNetworkService{{ id: {:?}, name: {:?}, enabled: {}, interface: {:?} }}", self.id(), self.name(), self.enabled(), self.interface(), - self.dns() ) } } @@ -335,33 +301,14 @@ impl_TCFType!( impl SCNetworkInterface { - /// Returns primary network interface - pub fn global(store: &SCDynamicStore) -> Option { - if let Some(ifname) = global_query(store, "PrimaryInterface") { - for iface in SCNetworkInterface::list() { - if let Some(bsd_name) = iface.bsd_name() { - if bsd_name == ifname { - return Some(iface); - } - } - } - } - - return None; - } - /// Returns all network-capable interfaces on the system. pub fn list() -> Vec { - let array: CFArray = + let array: CFArray = unsafe { CFArray::wrap_under_get_rule(SCNetworkInterfaceCopyAll()) }; - array - .get_all_values() - .iter() - .map(|interface_ptr| unsafe { - SCNetworkInterface::wrap_under_get_rule(*interface_ptr as _) - }) - .collect::>() + array.iter() + .map(|item| item.downcast::().unwrap() ) + .collect::>() } /// Returns the current MTU setting and the range of allowable values @@ -384,7 +331,7 @@ impl SCNetworkInterface { } /// Returns the BSD interface or device name - pub fn bsd_name(&self) -> Option { + pub fn name(&self) -> Option { unsafe { let str_ptr = SCNetworkInterfaceGetBSDName(self.0); if str_ptr.is_null() { @@ -395,20 +342,10 @@ impl SCNetworkInterface { } } - /// Returns the BSD interface or device name - pub fn name(&self) -> Option { - self.bsd_name() - } - /// Returns the network interface type - pub fn type_(&self) -> Option { + pub fn interface_type(&self) -> String { unsafe { - let str_ptr = SCNetworkInterfaceGetInterfaceType(self.0); - if str_ptr.is_null() { - None - } else { - Some(CFString::wrap_under_get_rule(str_ptr).to_string()) - } + CFString::wrap_under_get_rule(SCNetworkInterfaceGetInterfaceType(self.0)).to_string() } } @@ -458,10 +395,10 @@ impl fmt::Debug for SCNetworkInterface { write!( f, - "SCNetworkInterface{{ mtu: {}, bsd_name: {:?}, type: {:?}, hwaddr: {:?} }}", + "SCNetworkInterface{{ mtu: {}, name: {:?}, type: {:?}, hwaddr: {:?} }}", mtu_fmt, - self.bsd_name(), - self.type_(), + self.name(), + self.interface_type(), self.hwaddr() ) }