]> git.proxmox.com Git - proxmox-backup.git/blame - src/api2/node/dns.rs
replace Userid with Authid
[proxmox-backup.git] / src / api2 / node / dns.rs
CommitLineData
a2479cfa
WB
1use std::sync::{Arc, Mutex};
2
f7d4e4b5 3use anyhow::{Error};
a2479cfa
WB
4use lazy_static::lazy_static;
5use openssl::sha;
6use regex::Regex;
7use serde_json::{json, Value};
14627d67 8use ::serde::{Deserialize, Serialize};
b2b3485d 9
4b40148c 10use proxmox::api::{api, ApiMethod, Router, RpcEnvironment, Permission};
feaa1ad3 11use proxmox::tools::fs::{file_get_contents, replace_file, CreateOptions};
9ea4bce4 12use proxmox::{IPRE, IPV4RE, IPV6RE, IPV4OCTET, IPV6H16, IPV6LS32};
7f66c29e 13
4ebf0eab 14use crate::api2::types::*;
4b40148c 15use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
8f973f81 16
8f973f81
DM
17static RESOLV_CONF_FN: &str = "/etc/resolv.conf";
18
14627d67
DM
19#[api()]
20#[derive(Serialize, Deserialize)]
21#[allow(non_camel_case_types)]
22/// Deletable property name
23pub enum DeletableProperty {
24 /// Delete first nameserver entry
25 dns1,
26 /// Delete second nameserver entry
27 dns2,
28 /// Delete third nameserver entry
29 dns3,
30}
31
550e0d88 32pub fn read_etc_resolv_conf() -> Result<Value, Error> {
8f973f81
DM
33
34 let mut result = json!({});
35
36 let mut nscount = 0;
37
e18a6c9e 38 let raw = file_get_contents(RESOLV_CONF_FN)?;
8f973f81 39
bffd40d6 40 result["digest"] = Value::from(proxmox::tools::digest_to_hex(&sha::sha256(&raw)));
de6b0721
DM
41
42 let data = String::from_utf8(raw)?;
8f973f81
DM
43
44 lazy_static! {
af2fddea
DM
45 static ref DOMAIN_REGEX: Regex = Regex::new(r"^\s*(?:search|domain)\s+(\S+)\s*").unwrap();
46 static ref SERVER_REGEX: Regex = Regex::new(
8f973f81
DM
47 concat!(r"^\s*nameserver\s+(", IPRE!(), r")\s*")).unwrap();
48 }
49
14627d67
DM
50 let mut options = String::new();
51
de6b0721 52 for line in data.lines() {
8f973f81 53
46b79b9e
DM
54 if let Some(caps) = DOMAIN_REGEX.captures(&line) {
55 result["search"] = Value::from(&caps[1]);
56 } else if let Some(caps) = SERVER_REGEX.captures(&line) {
8f973f81
DM
57 nscount += 1;
58 if nscount > 3 { continue };
46b79b9e 59 let nameserver = &caps[1];
8f973f81 60 let id = format!("dns{}", nscount);
46b79b9e 61 result[id] = Value::from(nameserver);
14627d67
DM
62 } else {
63 if !options.is_empty() { options.push('\n'); }
64 options.push_str(line);
8f973f81
DM
65 }
66 }
67
14627d67
DM
68 if !options.is_empty() {
69 result["options"] = options.into();
70 }
71
8f973f81
DM
72 Ok(result)
73}
b2b3485d 74
bd098a7f
DM
75#[api(
76 protected: true,
77 input: {
78 description: "Update DNS settings.",
79 properties: {
80 node: {
81 schema: NODE_SCHEMA,
82 },
83 search: {
84 schema: SEARCH_DOMAIN_SCHEMA,
14627d67 85 optional: true,
bd098a7f
DM
86 },
87 dns1: {
88 optional: true,
89 schema: FIRST_DNS_SERVER_SCHEMA,
90 },
91 dns2: {
92 optional: true,
93 schema: SECOND_DNS_SERVER_SCHEMA,
94 },
95 dns3: {
96 optional: true,
97 schema: THIRD_DNS_SERVER_SCHEMA,
98 },
14627d67
DM
99 delete: {
100 description: "List of properties to delete.",
101 type: Array,
102 optional: true,
103 items: {
104 type: DeletableProperty,
105 }
106 },
bd098a7f
DM
107 digest: {
108 optional: true,
109 schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
110 },
111 },
112 },
4b40148c 113 access: {
74c08a57 114 permission: &Permission::Privilege(&["system", "network", "dns"], PRIV_SYS_MODIFY, false),
4b40148c 115 }
bd098a7f
DM
116)]
117/// Update DNS settings
14627d67
DM
118pub fn update_dns(
119 search: Option<String>,
120 dns1: Option<String>,
121 dns2: Option<String>,
122 dns3: Option<String>,
123 delete: Option<Vec<DeletableProperty>>,
124 digest: Option<String>,
6049b71f 125) -> Result<Value, Error> {
46b79b9e 126
af2fddea
DM
127 lazy_static! {
128 static ref MUTEX: Arc<Mutex<usize>> = Arc::new(Mutex::new(0));
129 }
130
9f49fe1d 131 let _guard = MUTEX.lock();
af2fddea 132
14627d67
DM
133 let mut config = read_etc_resolv_conf()?;
134 let old_digest = config["digest"].as_str().unwrap();
46b79b9e 135
14627d67
DM
136 if let Some(digest) = digest {
137 crate::tools::assert_if_modified(old_digest, &digest)?;
138 }
af2fddea 139
14627d67
DM
140 if let Some(delete) = delete {
141 for delete_prop in delete {
142 let config = config.as_object_mut().unwrap();
143 match delete_prop {
144 DeletableProperty::dns1 => { config.remove("dns1"); },
145 DeletableProperty::dns2 => { config.remove("dns2"); },
146 DeletableProperty::dns3 => { config.remove("dns3"); },
147 }
148 }
af2fddea
DM
149 }
150
14627d67
DM
151 if let Some(search) = search { config["search"] = search.into(); }
152 if let Some(dns1) = dns1 { config["dns1"] = dns1.into(); }
153 if let Some(dns2) = dns2 { config["dns2"] = dns2.into(); }
154 if let Some(dns3) = dns3 { config["dns3"] = dns3.into(); }
af2fddea 155
14627d67 156 let mut data = String::new();
46b79b9e 157
14627d67
DM
158 if let Some(search) = config["search"].as_str() {
159 data.push_str(&format!("search {}\n", search));
160 }
46b79b9e 161 for opt in &["dns1", "dns2", "dns3"] {
14627d67 162 if let Some(server) = config[opt].as_str() {
46b79b9e
DM
163 data.push_str(&format!("nameserver {}\n", server));
164 }
165 }
14627d67
DM
166 if let Some(options) = config["options"].as_str() {
167 data.push_str(options);
af2fddea
DM
168 }
169
feaa1ad3 170 replace_file(RESOLV_CONF_FN, data.as_bytes(), CreateOptions::new())?;
46b79b9e
DM
171
172 Ok(Value::Null)
173}
174
bd098a7f
DM
175#[api(
176 input: {
177 properties: {
178 node: {
179 schema: NODE_SCHEMA,
180 },
181 },
182 },
183 returns: {
184 description: "Returns DNS server IPs and sreach domain.",
185 type: Object,
186 properties: {
187 digest: {
188 schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
189 },
190 search: {
191 optional: true,
192 schema: SEARCH_DOMAIN_SCHEMA,
193 },
194 dns1: {
195 optional: true,
196 schema: FIRST_DNS_SERVER_SCHEMA,
197 },
198 dns2: {
199 optional: true,
200 schema: SECOND_DNS_SERVER_SCHEMA,
201 },
202 dns3: {
203 optional: true,
204 schema: THIRD_DNS_SERVER_SCHEMA,
205 },
206 },
207 },
4b40148c 208 access: {
74c08a57 209 permission: &Permission::Privilege(&["system", "network", "dns"], PRIV_SYS_AUDIT, false),
4b40148c 210 }
bd098a7f
DM
211)]
212/// Read DNS settings.
14627d67 213pub fn get_dns(
6049b71f
DM
214 _param: Value,
215 _info: &ApiMethod,
dd5495d6 216 _rpcenv: &mut dyn RpcEnvironment,
6049b71f 217) -> Result<Value, Error> {
b2b3485d 218
8f973f81 219 read_etc_resolv_conf()
b2b3485d
DM
220}
221
255f378a 222pub const ROUTER: Router = Router::new()
bd098a7f
DM
223 .get(&API_METHOD_GET_DNS)
224 .put(&API_METHOD_UPDATE_DNS);