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