From 46b79b9ee50ce1acb2a99a995a1a20abbc32d421 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Fri, 25 Jan 2019 10:15:32 +0100 Subject: [PATCH] api2/node/dns.rs: improve dns api --- src/api/schema.rs | 11 ++++-- src/api2.rs | 14 ++++++++ src/api2/node/dns.rs | 73 +++++++++++++++++++++++++++++++-------- src/api2/node/time.rs | 2 +- src/tools/common_regex.rs | 5 +++ 5 files changed, 86 insertions(+), 19 deletions(-) diff --git a/src/api/schema.rs b/src/api/schema.rs index ff360cb0..bf0629d9 100644 --- a/src/api/schema.rs +++ b/src/api/schema.rs @@ -2,6 +2,7 @@ use failure::*; use std::collections::HashMap; use serde_json::{json, Value}; use url::form_urlencoded; +use lazy_static::lazy_static; use regex::Regex; use std::fmt; use std::sync::Arc; @@ -358,7 +359,7 @@ impl From for Arc { pub enum ApiStringFormat { Enum(Vec), - Pattern(Box), + Pattern(&'static Regex), Complex(Arc), VerifyFn(fn(&str) -> Result<(), Error>), } @@ -695,11 +696,15 @@ fn test_query_string() { assert!(res.is_ok()); // TEST regex pattern + lazy_static! { + static ref TEST_REGEX: Regex = Regex::new("test").unwrap(); + static ref TEST2_REGEX: Regex = Regex::new("^test$").unwrap(); + } let schema = ObjectSchema::new("Parameters.") .required( "name", StringSchema::new("Name.") - .format(Arc::new(ApiStringFormat::Pattern(Box::new(Regex::new("test").unwrap())))) + .format(Arc::new(ApiStringFormat::Pattern(&TEST_REGEX))) ); let res = parse_query_string("name=abcd", &schema, true); @@ -711,7 +716,7 @@ fn test_query_string() { let schema = ObjectSchema::new("Parameters.") .required( "name", StringSchema::new("Name.") - .format(Arc::new(ApiStringFormat::Pattern(Box::new(Regex::new("^test$").unwrap())))) + .format(Arc::new(ApiStringFormat::Pattern(&TEST2_REGEX))) ); let res = parse_query_string("name=ateststring", &schema, true); diff --git a/src/api2.rs b/src/api2.rs index 80be53d7..36ee87de 100644 --- a/src/api2.rs +++ b/src/api2.rs @@ -3,6 +3,7 @@ use failure::*; use crate::api::schema::*; use crate::api::router::*; use serde_json::{json, Value}; +use std::sync::Arc; pub mod config; pub mod admin; @@ -10,6 +11,19 @@ pub mod node; mod version; mod subscription; +use lazy_static::lazy_static; +use crate::tools::common_regex; + +// common schema definitions + +lazy_static! { + pub static ref IP_FORMAT: Arc = ApiStringFormat::Pattern(&common_regex::IP_REGEX).into(); + + +} + + + fn test_sync_api_handler(param: Value, _info: &ApiMethod) -> Result { println!("This is a test {}", param); diff --git a/src/api2/node/dns.rs b/src/api2/node/dns.rs index 9b7c36c6..b57a6ae6 100644 --- a/src/api2/node/dns.rs +++ b/src/api2/node/dns.rs @@ -2,14 +2,14 @@ use failure::*; use crate::tools; -use crate::tools::common_regex; - -use crate::api::schema::*; -use crate::api::router::*; +use crate::api2::*; +//use crate::api::schema::*; +//use crate::api::router::*; use lazy_static::lazy_static; use std::io::{BufRead, BufReader}; +use std::sync::Arc; use serde_json::{json, Value}; @@ -22,7 +22,7 @@ fn read_etc_resolv_conf() -> Result { let mut nscount = 0; let file = std::fs::File::open(RESOLV_CONF_FN)?; - let mut reader = BufReader::new(file); + let reader = BufReader::new(file); let test = IPRE!(); @@ -35,26 +35,59 @@ fn read_etc_resolv_conf() -> Result { for line in reader.lines() { let line = line?; - if let Some(m) = DOMAIN_REGEX.find(&line) { - let domain = m.as_str(); - result["search"] = Value::from(domain); - } else if let Some(m) = SERVER_REGEX.find(&line) { + if let Some(caps) = DOMAIN_REGEX.captures(&line) { + result["search"] = Value::from(&caps[1]); + } else if let Some(caps) = SERVER_REGEX.captures(&line) { nscount += 1; if nscount > 3 { continue }; - let nameserver = m.as_str(); + let nameserver = &caps[1]; let id = format!("dns{}", nscount); - result[id] = Value::from(m.as_str()); + result[id] = Value::from(nameserver); } } Ok(result) } +fn update_dns(param: Value, _info: &ApiMethod) -> Result { + + let search = tools::required_string_param(¶m, "search")?; + + let mut data = format!("search {}\n", search); + + for opt in &["dns1", "dns2", "dns3"] { + if let Some(server) = param[opt].as_str() { + data.push_str(&format!("nameserver {}\n", server)); + } + } + + tools::file_set_contents(RESOLV_CONF_FN, data.as_bytes(), None)?; + + Ok(Value::Null) +} + fn get_dns(_param: Value, _info: &ApiMethod) -> Result { read_etc_resolv_conf() } +lazy_static! { + pub static ref SEARCH_DOMAIN_SCHEMA: Arc = + StringSchema::new("Search domain for host-name lookup.").into(); + + pub static ref FIRST_DNS_SERVER_SCHEMA: Arc = + StringSchema::new("First name server IP address.") + .format(IP_FORMAT.clone()).into(); + + pub static ref SECOND_DNS_SERVER_SCHEMA: Arc = + StringSchema::new("Second name server IP address.") + .format(IP_FORMAT.clone()).into(); + + pub static ref THIRD_DNS_SERVER_SCHEMA: Arc = + StringSchema::new("Third name server IP address.") + .format(IP_FORMAT.clone()).into(); +} + pub fn router() -> Router { let route = Router::new() @@ -64,11 +97,21 @@ pub fn router() -> Router { ObjectSchema::new("Read DNS settings.") ).returns( ObjectSchema::new("Returns DNS server IPs and sreach domain.") - .optional("search", StringSchema::new("Search domain for host-name lookup.")) - .optional("dns1", StringSchema::new("First name server IP address.")) - .optional("dns2", StringSchema::new("Second name server IP address.")) - .optional("dns3", StringSchema::new("Third name server IP address.")) + .optional("search", SEARCH_DOMAIN_SCHEMA.clone()) + .optional("dns1", FIRST_DNS_SERVER_SCHEMA.clone()) + .optional("dns2", SECOND_DNS_SERVER_SCHEMA.clone()) + .optional("dns3", THIRD_DNS_SERVER_SCHEMA.clone()) ) + ) + .put( + ApiMethod::new( + update_dns, + ObjectSchema::new("Returns DNS server IPs and sreach domain.") + .required("search", SEARCH_DOMAIN_SCHEMA.clone()) + .optional("dns1", FIRST_DNS_SERVER_SCHEMA.clone()) + .optional("dns2", SECOND_DNS_SERVER_SCHEMA.clone()) + .optional("dns3", THIRD_DNS_SERVER_SCHEMA.clone()) + ) ); route diff --git a/src/api2/node/time.rs b/src/api2/node/time.rs index 0d202e2b..7197e31a 100644 --- a/src/api2/node/time.rs +++ b/src/api2/node/time.rs @@ -42,7 +42,7 @@ fn set_timezone(param: Value, _info: &ApiMethod) -> Result { bail!("No such timezone."); } - tools::file_set_contents("/etc/timezone", timezone.as_bytes(), None); + tools::file_set_contents("/etc/timezone", timezone.as_bytes(), None)?; let _ = std::fs::remove_file("/etc/localtime"); diff --git a/src/tools/common_regex.rs b/src/tools/common_regex.rs index 591ca588..887e86be 100644 --- a/src/tools/common_regex.rs +++ b/src/tools/common_regex.rs @@ -3,6 +3,7 @@ //! This is a collection of useful regular expressions use lazy_static::lazy_static; +use regex::Regex; #[macro_export] macro_rules! IPV4OCTET { () => (r"(?:25[0-5]|(?:2[0-4]|1[0-9]|[1-9])?[0-9])") } @@ -30,3 +31,7 @@ macro_rules! IPV6RE { () => (concat!(r"(?:", #[macro_export] macro_rules! IPRE { () => (concat!(r"(?:", IPV4RE!(), "|", IPV6RE!(), ")")) } + +lazy_static! { + pub static ref IP_REGEX: Regex = Regex::new(IPRE!()).unwrap(); +}