clash.rs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. use crate::utils::{config, dirs};
  2. use anyhow::Result;
  3. use serde::{Deserialize, Serialize};
  4. use serde_yaml::{Mapping, Value};
  5. #[derive(Default, Debug, Clone, Deserialize, Serialize)]
  6. pub struct ClashInfo {
  7. /// clash sidecar status
  8. pub status: String,
  9. /// clash core port
  10. pub port: Option<String>,
  11. /// same as `external-controller`
  12. pub server: Option<String>,
  13. /// clash secret
  14. pub secret: Option<String>,
  15. }
  16. impl ClashInfo {
  17. /// parse the clash's config.yaml
  18. /// get some information
  19. pub fn from(config: &Mapping) -> ClashInfo {
  20. let key_port_1 = Value::from("port");
  21. let key_port_2 = Value::from("mixed-port");
  22. let key_server = Value::from("external-controller");
  23. let key_secret = Value::from("secret");
  24. let port = match config.get(&key_port_1) {
  25. Some(value) => match value {
  26. Value::String(val_str) => Some(val_str.clone()),
  27. Value::Number(val_num) => Some(val_num.to_string()),
  28. _ => None,
  29. },
  30. _ => None,
  31. };
  32. let port = match port {
  33. Some(_) => port,
  34. None => match config.get(&key_port_2) {
  35. Some(value) => match value {
  36. Value::String(val_str) => Some(val_str.clone()),
  37. Value::Number(val_num) => Some(val_num.to_string()),
  38. _ => None,
  39. },
  40. _ => None,
  41. },
  42. };
  43. // `external-controller` could be
  44. // "127.0.0.1:9090" or ":9090"
  45. let server = match config.get(&key_server) {
  46. Some(value) => {
  47. let val_str = value.as_str().unwrap_or("");
  48. if val_str.starts_with(":") {
  49. Some(format!("127.0.0.1{val_str}"))
  50. } else {
  51. Some(val_str.into())
  52. }
  53. }
  54. _ => None,
  55. };
  56. let secret = match config.get(&key_secret) {
  57. Some(value) => match value {
  58. Value::String(val_str) => Some(val_str.clone()),
  59. Value::Bool(val_bool) => Some(val_bool.to_string()),
  60. Value::Number(val_num) => Some(val_num.to_string()),
  61. _ => None,
  62. },
  63. _ => None,
  64. };
  65. ClashInfo {
  66. status: "init".into(),
  67. port,
  68. server,
  69. secret,
  70. }
  71. }
  72. }
  73. pub struct Clash {
  74. /// maintain the clash config
  75. pub config: Mapping,
  76. /// some info
  77. pub info: ClashInfo,
  78. }
  79. impl Clash {
  80. pub fn new() -> Clash {
  81. let config = Clash::read_config();
  82. let info = ClashInfo::from(&config);
  83. Clash { config, info }
  84. }
  85. /// get clash config
  86. pub fn read_config() -> Mapping {
  87. config::read_yaml::<Mapping>(dirs::clash_path())
  88. }
  89. /// save the clash config
  90. pub fn save_config(&self) -> Result<()> {
  91. config::save_yaml(
  92. dirs::clash_path(),
  93. &self.config,
  94. Some("# Default Config For Clash Core\n\n"),
  95. )
  96. }
  97. /// patch update the clash config
  98. /// if the port is changed then return true
  99. pub fn patch_config(&mut self, patch: Mapping) -> Result<bool> {
  100. let port_key = Value::from("mixed-port");
  101. let server_key = Value::from("external-controller");
  102. let secret_key = Value::from("secret");
  103. let mut change_port = false;
  104. let mut change_info = false;
  105. for (key, value) in patch.into_iter() {
  106. if key == port_key {
  107. change_port = true;
  108. }
  109. if key == port_key || key == server_key || key == secret_key {
  110. change_info = true;
  111. }
  112. self.config.insert(key, value);
  113. }
  114. if change_info {
  115. self.info = ClashInfo::from(&self.config);
  116. }
  117. self.save_config()?;
  118. Ok(change_port)
  119. }
  120. /// revise the `tun` and `dns` config
  121. pub fn _tun_mode(mut config: Mapping, enable: bool) -> Mapping {
  122. macro_rules! revise {
  123. ($map: expr, $key: expr, $val: expr) => {
  124. let ret_key = Value::String($key.into());
  125. $map.insert(ret_key, Value::from($val));
  126. };
  127. }
  128. // if key not exists then append value
  129. macro_rules! append {
  130. ($map: expr, $key: expr, $val: expr) => {
  131. let ret_key = Value::String($key.into());
  132. if !$map.contains_key(&ret_key) {
  133. $map.insert(ret_key, Value::from($val));
  134. }
  135. };
  136. }
  137. // tun config
  138. let tun_val = config.get(&Value::from("tun"));
  139. let mut new_tun = Mapping::new();
  140. if tun_val.is_some() && tun_val.as_ref().unwrap().is_mapping() {
  141. new_tun = tun_val.as_ref().unwrap().as_mapping().unwrap().clone();
  142. }
  143. revise!(new_tun, "enable", enable);
  144. if enable {
  145. append!(new_tun, "stack", "gvisor");
  146. append!(new_tun, "dns-hijack", vec!["198.18.0.2:53"]);
  147. append!(new_tun, "auto-route", true);
  148. append!(new_tun, "auto-detect-interface", true);
  149. }
  150. revise!(config, "tun", new_tun);
  151. if enable {
  152. // dns config
  153. let dns_val = config.get(&Value::from("dns"));
  154. let mut new_dns = Mapping::new();
  155. if dns_val.is_some() && dns_val.as_ref().unwrap().is_mapping() {
  156. new_dns = dns_val.as_ref().unwrap().as_mapping().unwrap().clone();
  157. }
  158. revise!(new_dns, "enable", enable);
  159. // 借鉴cfw的默认配置
  160. append!(new_dns, "enhanced-mode", "fake-ip");
  161. append!(
  162. new_dns,
  163. "nameserver",
  164. vec!["114.114.114.114", "223.5.5.5", "8.8.8.8"]
  165. );
  166. append!(new_dns, "fallback", vec![] as Vec<&str>);
  167. #[cfg(target_os = "windows")]
  168. append!(
  169. new_dns,
  170. "fake-ip-filter",
  171. vec![
  172. "dns.msftncsi.com",
  173. "www.msftncsi.com",
  174. "www.msftconnecttest.com"
  175. ]
  176. );
  177. revise!(config, "dns", new_dns);
  178. }
  179. config
  180. }
  181. /// only 5 default fields available (clash config fields)
  182. /// convert to lowercase
  183. pub fn strict_filter(config: Mapping) -> Mapping {
  184. // Only the following fields are allowed:
  185. // proxies/proxy-providers/proxy-groups/rule-providers/rules
  186. let valid_keys = vec![
  187. "proxies",
  188. "proxy-providers",
  189. "proxy-groups",
  190. "rules",
  191. "rule-providers",
  192. ];
  193. let mut new_config = Mapping::new();
  194. for (key, value) in config.into_iter() {
  195. key.as_str().map(|key_str| {
  196. // change to lowercase
  197. let mut key_str = String::from(key_str);
  198. key_str.make_ascii_lowercase();
  199. // filter
  200. if valid_keys.contains(&&*key_str) {
  201. new_config.insert(Value::String(key_str), value);
  202. }
  203. });
  204. }
  205. new_config
  206. }
  207. /// more clash config fields available
  208. /// convert to lowercase
  209. pub fn loose_filter(config: Mapping) -> Mapping {
  210. // all of these can not be revised by script or merge
  211. // http/https/socks port should be under control
  212. let not_allow = vec![
  213. "port",
  214. "socks-port",
  215. "mixed-port",
  216. "allow-lan",
  217. "mode",
  218. "external-controller",
  219. "secret",
  220. "log-level",
  221. ];
  222. let mut new_config = Mapping::new();
  223. for (key, value) in config.into_iter() {
  224. key.as_str().map(|key_str| {
  225. // change to lowercase
  226. let mut key_str = String::from(key_str);
  227. key_str.make_ascii_lowercase();
  228. // filter
  229. if !not_allow.contains(&&*key_str) {
  230. new_config.insert(Value::String(key_str), value);
  231. }
  232. });
  233. }
  234. new_config
  235. }
  236. }
  237. impl Default for Clash {
  238. fn default() -> Self {
  239. Clash::new()
  240. }
  241. }