]> git.proxmox.com Git - proxmox-backup.git/blob - src/api2/node/dns.rs
tree-wide: use 'dyn' for all trait objects
[proxmox-backup.git] / src / api2 / node / dns.rs
1 use failure::*;
2
3
4 use crate::tools;
5 use crate::api2::*;
6 use crate::api_schema::*;
7 //use crate::api_schema::router::*;
8 use crate::api2::types::*;
9
10 use lazy_static::lazy_static;
11
12 use std::sync::{Arc, Mutex};
13 use openssl::sha;
14 use regex::Regex;
15
16 use serde_json::{json, Value};
17
18 static RESOLV_CONF_FN: &str = "/etc/resolv.conf";
19
20 fn read_etc_resolv_conf() -> Result<Value, Error> {
21
22 let mut result = json!({});
23
24 let mut nscount = 0;
25
26 let raw = tools::file_get_contents(RESOLV_CONF_FN)?;
27
28 result["digest"] = Value::from(tools::digest_to_hex(&sha::sha256(&raw)));
29
30 let data = String::from_utf8(raw)?;
31
32 lazy_static! {
33 static ref DOMAIN_REGEX: Regex = Regex::new(r"^\s*(?:search|domain)\s+(\S+)\s*").unwrap();
34 static ref SERVER_REGEX: Regex = Regex::new(
35 concat!(r"^\s*nameserver\s+(", IPRE!(), r")\s*")).unwrap();
36 }
37
38 for line in data.lines() {
39
40 if let Some(caps) = DOMAIN_REGEX.captures(&line) {
41 result["search"] = Value::from(&caps[1]);
42 } else if let Some(caps) = SERVER_REGEX.captures(&line) {
43 nscount += 1;
44 if nscount > 3 { continue };
45 let nameserver = &caps[1];
46 let id = format!("dns{}", nscount);
47 result[id] = Value::from(nameserver);
48 }
49 }
50
51 Ok(result)
52 }
53
54 fn update_dns(
55 param: Value,
56 _info: &ApiMethod,
57 _rpcenv: &mut dyn RpcEnvironment,
58 ) -> Result<Value, Error> {
59
60 lazy_static! {
61 static ref MUTEX: Arc<Mutex<usize>> = Arc::new(Mutex::new(0));
62 }
63
64 let _guard = MUTEX.lock();
65
66 let search = tools::required_string_param(&param, "search")?;
67
68 let raw = tools::file_get_contents(RESOLV_CONF_FN)?;
69 let old_digest = tools::digest_to_hex(&sha::sha256(&raw));
70
71 if let Some(digest) = param["digest"].as_str() {
72 tools::assert_if_modified(&old_digest, &digest)?;
73 }
74
75 let old_data = String::from_utf8(raw)?;
76
77 let mut data = format!("search {}\n", search);
78
79 for opt in &["dns1", "dns2", "dns3"] {
80 if let Some(server) = param[opt].as_str() {
81 data.push_str(&format!("nameserver {}\n", server));
82 }
83 }
84
85 // append other data
86 lazy_static! {
87 static ref SKIP_REGEX: Regex = Regex::new(r"^(search|domain|nameserver)\s+").unwrap();
88 }
89 for line in old_data.lines() {
90 if SKIP_REGEX.is_match(line) { continue; }
91 data.push_str(line);
92 data.push('\n');
93 }
94
95 tools::file_set_contents(RESOLV_CONF_FN, data.as_bytes(), None)?;
96
97 Ok(Value::Null)
98 }
99
100 fn get_dns(
101 _param: Value,
102 _info: &ApiMethod,
103 _rpcenv: &mut dyn RpcEnvironment,
104 ) -> Result<Value, Error> {
105
106 read_etc_resolv_conf()
107 }
108
109 pub fn router() -> Router {
110
111 let route = Router::new()
112 .get(
113 ApiMethod::new(
114 get_dns,
115 ObjectSchema::new("Read DNS settings.")
116 .required("node", NODE_SCHEMA.clone())
117 ).returns(
118 ObjectSchema::new("Returns DNS server IPs and sreach domain.")
119 .required("digest", PVE_CONFIG_DIGEST_SCHEMA.clone())
120 .optional("search", SEARCH_DOMAIN_SCHEMA.clone())
121 .optional("dns1", FIRST_DNS_SERVER_SCHEMA.clone())
122 .optional("dns2", SECOND_DNS_SERVER_SCHEMA.clone())
123 .optional("dns3", THIRD_DNS_SERVER_SCHEMA.clone())
124 )
125 )
126 .put(
127 ApiMethod::new(
128 update_dns,
129 ObjectSchema::new("Returns DNS server IPs and sreach domain.")
130 .required("node", NODE_SCHEMA.clone())
131 .required("search", SEARCH_DOMAIN_SCHEMA.clone())
132 .optional("dns1", FIRST_DNS_SERVER_SCHEMA.clone())
133 .optional("dns2", SECOND_DNS_SERVER_SCHEMA.clone())
134 .optional("dns3", THIRD_DNS_SERVER_SCHEMA.clone())
135 .optional("digest", PVE_CONFIG_DIGEST_SCHEMA.clone())
136 ).protected(true)
137 );
138
139 route
140 }