server.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. /*************************************************************************
  2. *
  3. * Copyright (C) 2018-2025 Ruilin Peng (Nick) <[email protected]>.
  4. *
  5. * smartdns is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * smartdns is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. use smartdns_ui::data_server::DataServer;
  19. use smartdns_ui::db::*;
  20. use smartdns_ui::dns_log;
  21. use smartdns_ui::plugin::*;
  22. use smartdns_ui::smartdns::*;
  23. use std::io::Write;
  24. use std::sync::Arc;
  25. use tempfile::TempDir;
  26. static INSTANCE_LOCK: std::sync::RwLock<()> = std::sync::RwLock::new(());
  27. pub struct InstanceLockGuard<'a> {
  28. _read_guard: Option<std::sync::RwLockReadGuard<'a, ()>>,
  29. _write_guard: Option<std::sync::RwLockWriteGuard<'a, ()>>,
  30. }
  31. impl<'a> InstanceLockGuard<'a> {
  32. pub fn new_read_guard() -> Self {
  33. Self {
  34. _read_guard: Some(INSTANCE_LOCK.read().unwrap()),
  35. _write_guard: None,
  36. }
  37. }
  38. pub fn new_write_guard() -> Self {
  39. Self {
  40. _read_guard: None,
  41. _write_guard: Some(INSTANCE_LOCK.write().unwrap()),
  42. }
  43. }
  44. }
  45. pub struct TestDnsRequest {
  46. pub domain: String,
  47. pub group_name: String,
  48. pub qtype: u32,
  49. pub qclass: i32,
  50. pub id: u16,
  51. pub rcode: u16,
  52. pub query_time: i32,
  53. pub query_timestamp: u64,
  54. pub ping_time: f64,
  55. pub is_blocked: bool,
  56. pub is_cached: bool,
  57. pub remote_mac: [u8; 6],
  58. pub remote_addr: String,
  59. pub local_addr: String,
  60. pub prefetch_request: bool,
  61. pub dualstack_request: bool,
  62. pub drop_callback: Option<Box<dyn Fn() + Send + Sync>>,
  63. }
  64. #[allow(dead_code)]
  65. impl TestDnsRequest {
  66. pub fn new() -> Self {
  67. TestDnsRequest {
  68. domain: "".to_string(),
  69. group_name: "default".to_string(),
  70. qtype: 1,
  71. qclass: 1,
  72. id: 0,
  73. rcode: 2,
  74. query_time: 0,
  75. query_timestamp: get_utc_time_ms(),
  76. ping_time: -0.1 as f64,
  77. is_blocked: false,
  78. is_cached: false,
  79. remote_mac: [0; 6],
  80. remote_addr: "127.0.0.1".to_string(),
  81. local_addr: "127.0.0.1".to_string(),
  82. prefetch_request: false,
  83. dualstack_request: false,
  84. drop_callback: None,
  85. }
  86. }
  87. }
  88. #[allow(dead_code)]
  89. impl DnsRequest for TestDnsRequest {
  90. fn get_group_name(&self) -> String {
  91. self.group_name.clone()
  92. }
  93. fn get_domain(&self) -> String {
  94. self.domain.clone()
  95. }
  96. fn get_qtype(&self) -> u32 {
  97. self.qtype
  98. }
  99. fn get_qclass(&self) -> i32 {
  100. self.qclass
  101. }
  102. fn get_id(&self) -> u16 {
  103. self.id
  104. }
  105. fn get_rcode(&self) -> u16 {
  106. self.rcode
  107. }
  108. fn get_query_time(&self) -> i32 {
  109. self.query_time
  110. }
  111. fn get_query_timestamp(&self) -> u64 {
  112. self.query_timestamp
  113. }
  114. fn get_ping_time(&self) -> f64 {
  115. self.ping_time
  116. }
  117. fn get_is_blocked(&self) -> bool {
  118. self.is_blocked
  119. }
  120. fn get_is_cached(&self) -> bool {
  121. self.is_cached
  122. }
  123. fn get_remote_mac(&self) -> [u8; 6] {
  124. self.remote_mac
  125. }
  126. fn get_remote_addr(&self) -> String {
  127. self.remote_addr.clone()
  128. }
  129. fn get_local_addr(&self) -> String {
  130. self.local_addr.clone()
  131. }
  132. fn is_prefetch_request(&self) -> bool {
  133. self.prefetch_request
  134. }
  135. fn is_dualstack_request(&self) -> bool {
  136. self.dualstack_request
  137. }
  138. }
  139. impl Drop for TestDnsRequest {
  140. fn drop(&mut self) {
  141. if let Some(f) = &self.drop_callback {
  142. f();
  143. }
  144. }
  145. }
  146. unsafe impl Send for TestDnsRequest {}
  147. unsafe impl Sync for TestDnsRequest {}
  148. #[allow(dead_code)]
  149. struct TestSmartDnsConfigItem {
  150. pub key: String,
  151. pub value: String,
  152. }
  153. pub struct TestSmartDnsServer {
  154. confs: Vec<TestSmartDnsConfigItem>,
  155. is_started: bool,
  156. workdir: String,
  157. thread: Option<std::thread::JoinHandle<()>>,
  158. }
  159. impl TestSmartDnsServer {
  160. pub fn new() -> Self {
  161. let mut server = TestSmartDnsServer {
  162. confs: Vec::new(),
  163. is_started: false,
  164. workdir: "/tmp/smartdns-test.conf".to_string(),
  165. thread: None,
  166. };
  167. server.add_conf("bind", ":66603");
  168. server.add_conf("log-level", "debug");
  169. server.add_conf("log-num", "0");
  170. server.add_conf("cache-persist", "no");
  171. server
  172. }
  173. pub fn set_workdir(&mut self, workdir: &str) {
  174. self.workdir = workdir.to_string();
  175. }
  176. pub fn add_conf(&mut self, key: &str, value: &str) {
  177. self.confs.push(TestSmartDnsConfigItem {
  178. key: key.to_string(),
  179. value: value.to_string(),
  180. });
  181. }
  182. fn gen_conf_file(&self) -> std::io::Result<String> {
  183. let file = self.workdir.clone() + "/smartdns.conf";
  184. let mut f = std::fs::File::create(&file)?;
  185. for conf in self.confs.iter() {
  186. f.write_all(format!("{} {}\n", conf.key, conf.value).as_bytes())?;
  187. }
  188. Ok(file)
  189. }
  190. pub fn start(&mut self) -> Result<(), Box<dyn std::error::Error>> {
  191. let conf_file = self.gen_conf_file()?;
  192. let t = std::thread::spawn(move || {
  193. dns_log!(LogLevel::ERROR, "smartdns server run start...");
  194. smartdns_ui::smartdns::smartdns_server_run(&conf_file).unwrap();
  195. dns_log!(LogLevel::ERROR, "smartdns server run exit...");
  196. });
  197. self.thread = Some(t);
  198. self.is_started = true;
  199. dns_log!(LogLevel::ERROR, "smartdns_server_run");
  200. Ok(())
  201. }
  202. pub fn stop(&mut self) {
  203. if !self.is_started {
  204. return;
  205. }
  206. self.is_started = false;
  207. smartdns_ui::smartdns::smartdns_server_stop();
  208. if self.thread.is_none() {
  209. return;
  210. }
  211. let _ = self.thread.take().unwrap().join();
  212. }
  213. }
  214. impl Drop for TestSmartDnsServer {
  215. fn drop(&mut self) {
  216. self.stop();
  217. }
  218. }
  219. pub struct TestServer {
  220. dns_server: TestSmartDnsServer,
  221. dns_server_enable: bool,
  222. plugin: Arc<SmartdnsPlugin>,
  223. args: Vec<String>,
  224. workdir: String,
  225. temp_dir: TempDir,
  226. www_root: String,
  227. is_started: bool,
  228. ip: String,
  229. is_https: bool,
  230. log_level: LogLevel,
  231. old_log_level: LogLevel,
  232. one_instance: bool,
  233. instance_lock_guard: Option<InstanceLockGuard<'static>>,
  234. }
  235. impl TestServer {
  236. pub fn new() -> Self {
  237. let mut server = TestServer {
  238. dns_server: TestSmartDnsServer::new(),
  239. dns_server_enable: false,
  240. plugin: SmartdnsPlugin::new(),
  241. args: Vec::new(),
  242. workdir: String::new(),
  243. temp_dir: TempDir::with_prefix("smartdns-ui-").unwrap(),
  244. www_root: String::new(),
  245. is_started: false,
  246. ip: "http://127.0.0.1:0".to_string(),
  247. is_https: false,
  248. log_level: LogLevel::INFO,
  249. old_log_level: LogLevel::INFO,
  250. one_instance: false,
  251. instance_lock_guard: None,
  252. };
  253. server.workdir = server.temp_dir.path().to_str().unwrap().to_string();
  254. server.dns_server.set_workdir(&server.workdir);
  255. server.get_data_server().set_recv_in_batch(false);
  256. server
  257. }
  258. fn setup_default_args(&mut self) {
  259. self.args.insert(0, "--ip".to_string());
  260. self.args.insert(1, self.ip.clone());
  261. self.args.insert(0, "--data-dir".to_string());
  262. self.args.insert(1, self.workdir.clone() + "/data.db");
  263. self.args.insert(0, "--www-root".to_string());
  264. self.www_root = self.workdir.clone() + "/www";
  265. self.args.insert(1, self.www_root.clone());
  266. self.args.insert(0, "smartdns-ui".to_string());
  267. dns_log!(LogLevel::INFO, "workdir: {}", self.workdir);
  268. }
  269. #[allow(dead_code)]
  270. pub fn get_url(&self, path: &str) -> String {
  271. self.ip.clone() + path
  272. }
  273. pub fn get_host(&self) -> String {
  274. self.ip.clone()
  275. }
  276. #[allow(dead_code)]
  277. pub fn get_www_root(&self) -> &String {
  278. &self.www_root
  279. }
  280. fn create_workdir(&self) -> std::io::Result<()> {
  281. std::fs::create_dir_all(&self.workdir)?;
  282. std::fs::create_dir_all(&self.www_root)?;
  283. Ok(())
  284. }
  285. fn remove_workdir(&self) -> std::io::Result<()> {
  286. let r = std::fs::remove_dir_all(&self.workdir);
  287. return r;
  288. }
  289. #[allow(dead_code)]
  290. pub fn add_mock_server_conf(&mut self, key: &str, value: &str) {
  291. self.dns_server.add_conf(key, value);
  292. }
  293. #[allow(dead_code)]
  294. pub fn enable_mock_server(&mut self) {
  295. self.dns_server_enable = true;
  296. self.set_one_instance(true);
  297. }
  298. #[allow(dead_code)]
  299. pub fn add_args(&mut self, args: Vec<String>) {
  300. for arg in args.iter() {
  301. self.args.push(arg.clone());
  302. }
  303. }
  304. #[allow(dead_code)]
  305. pub fn send_test_dnsrequest(
  306. &mut self,
  307. mut request: TestDnsRequest,
  308. ) -> Result<(), Box<dyn std::error::Error>> {
  309. let batch_mode = self.get_data_server().get_recv_in_batch();
  310. let (tx, rx) = std::sync::mpsc::channel();
  311. let request_drop_callback = move || {
  312. tx.send(()).unwrap();
  313. };
  314. if batch_mode == false {
  315. request.drop_callback = Some(Box::new(request_drop_callback));
  316. }
  317. let ret = self.plugin.query_complete(Box::new(request));
  318. if let Err(e) = ret {
  319. dns_log!(LogLevel::ERROR, "send_test_dnsrequest error: {:?}", e);
  320. return Err(e);
  321. }
  322. if batch_mode == false {
  323. rx.recv().unwrap();
  324. }
  325. Ok(())
  326. }
  327. #[allow(dead_code)]
  328. pub fn new_mock_domain_record(&self) -> DomainData {
  329. DomainData {
  330. id: 0,
  331. timestamp: smartdns_ui::smartdns::get_utc_time_ms(),
  332. domain: "example.com".to_string(),
  333. domain_type: 1,
  334. client: "127.0.0.1".to_string(),
  335. domain_group: "default".to_string(),
  336. reply_code: 0,
  337. query_time: 0,
  338. ping_time: -0.1 as f64,
  339. is_blocked: false,
  340. is_cached: false,
  341. }
  342. }
  343. #[allow(dead_code)]
  344. pub fn get_data_server(&self) -> Arc<DataServer> {
  345. self.plugin.get_data_server()
  346. }
  347. #[allow(dead_code)]
  348. pub fn add_domain_record(
  349. &mut self,
  350. record: &DomainData,
  351. ) -> Result<(), Box<dyn std::error::Error>> {
  352. self.plugin.get_data_server().insert_domain(record)
  353. }
  354. pub fn set_log_level(&mut self, level: LogLevel) {
  355. self.log_level = level;
  356. }
  357. fn init_server(&mut self) -> Result<(), Box<dyn std::error::Error>> {
  358. self.create_workdir()?;
  359. self.old_log_level = smartdns_ui::smartdns::dns_log_get_level();
  360. smartdns_ui::smartdns::dns_log_set_level(self.log_level);
  361. Ok(())
  362. }
  363. #[allow(dead_code)]
  364. pub fn set_https(&mut self, enable: bool) {
  365. self.is_https = enable;
  366. if enable {
  367. self.ip = "https://127.0.0.1:0".to_string();
  368. } else {
  369. self.ip = "http://127.0.0.1:0".to_string();
  370. }
  371. }
  372. pub fn set_one_instance(&mut self, one_instance: bool) {
  373. self.one_instance = one_instance;
  374. }
  375. pub fn start(&mut self) -> Result<(), Box<dyn std::error::Error>> {
  376. if self.one_instance {
  377. self.instance_lock_guard = Some(InstanceLockGuard::new_write_guard());
  378. if self.dns_server_enable {
  379. let ret = self.dns_server.start();
  380. if let Err(e) = ret {
  381. dns_log!(LogLevel::ERROR, "start dns server failed: {:?}", e);
  382. return Err(e);
  383. }
  384. }
  385. } else {
  386. self.instance_lock_guard = Some(InstanceLockGuard::new_read_guard());
  387. }
  388. self.setup_default_args();
  389. dns_log!(LogLevel::INFO, "TestServer start");
  390. let ret = self.init_server();
  391. if let Err(e) = ret {
  392. dns_log!(LogLevel::ERROR, "init server failed: {:?}", e);
  393. return Err(e);
  394. }
  395. let result = self.plugin.start(&self.args);
  396. if let Err(e) = result {
  397. dns_log!(LogLevel::ERROR, "start error: {:?}", e);
  398. return Err(e);
  399. }
  400. let addr = self.plugin.get_http_server().get_local_addr();
  401. if addr.is_none() {
  402. return Err(Box::new(std::io::Error::new(
  403. std::io::ErrorKind::Other,
  404. "get local addr failed",
  405. )));
  406. }
  407. let addr = addr.unwrap();
  408. if self.is_https {
  409. self.ip = format!("https://{}:{}", addr.ip(), addr.port());
  410. } else {
  411. self.ip = format!("http://{}:{}", addr.ip(), addr.port());
  412. }
  413. self.is_started = true;
  414. Ok(())
  415. }
  416. pub fn stop(&mut self) {
  417. if !self.is_started {
  418. return;
  419. }
  420. dns_log!(LogLevel::INFO, "TestServer stop");
  421. self.plugin.stop();
  422. self.is_started = false;
  423. self.one_instance = false;
  424. smartdns_ui::smartdns::dns_log_set_level(self.old_log_level);
  425. self.dns_server.stop();
  426. self.instance_lock_guard = None;
  427. }
  428. }
  429. impl Drop for TestServer {
  430. fn drop(&mut self) {
  431. self.stop();
  432. let _ = self.remove_workdir();
  433. }
  434. }