clash.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. use crate::utils::{dirs, help};
  2. use anyhow::Result;
  3. use serde::{Deserialize, Serialize};
  4. use serde_yaml::{Mapping, Value};
  5. use std::{
  6. net::{IpAddr, Ipv4Addr, SocketAddr},
  7. str::FromStr,
  8. };
  9. #[derive(Default, Debug, Clone)]
  10. pub struct IClashTemp(pub Mapping);
  11. impl IClashTemp {
  12. pub fn new() -> Self {
  13. let template = Self::template();
  14. match dirs::clash_path().and_then(|path| help::read_merge_mapping(&path)) {
  15. Ok(mut map) => {
  16. template.0.keys().for_each(|key| {
  17. if !map.contains_key(key) {
  18. map.insert(key.clone(), template.0.get(key).unwrap().clone());
  19. }
  20. });
  21. Self(Self::guard(map))
  22. }
  23. Err(err) => {
  24. log::error!(target: "app", "{err}");
  25. template
  26. }
  27. }
  28. }
  29. pub fn template() -> Self {
  30. let mut map = Mapping::new();
  31. let mut tun = Mapping::new();
  32. tun.insert("stack".into(), "gvisor".into());
  33. tun.insert("device".into(), "Mihomo".into());
  34. tun.insert("auto-route".into(), true.into());
  35. tun.insert("strict-route".into(), false.into());
  36. tun.insert("auto-detect-interface".into(), true.into());
  37. tun.insert("dns-hijack".into(), vec!["any:53"].into());
  38. tun.insert("mtu".into(), 1500.into());
  39. #[cfg(not(target_os = "windows"))]
  40. map.insert("redir-port".into(), 7895.into());
  41. #[cfg(target_os = "linux")]
  42. map.insert("tproxy-port".into(), 7896.into());
  43. map.insert("mixed-port".into(), 7897.into());
  44. map.insert("socks-port".into(), 7898.into());
  45. map.insert("port".into(), 7899.into());
  46. map.insert("log-level".into(), "info".into());
  47. map.insert("allow-lan".into(), false.into());
  48. map.insert("mode".into(), "rule".into());
  49. map.insert("external-controller".into(), "127.0.0.1:9097".into());
  50. map.insert("secret".into(), "".into());
  51. map.insert("tun".into(), tun.into());
  52. Self(map)
  53. }
  54. fn guard(mut config: Mapping) -> Mapping {
  55. #[cfg(not(target_os = "windows"))]
  56. let redir_port = Self::guard_redir_port(&config);
  57. #[cfg(target_os = "linux")]
  58. let tproxy_port = Self::guard_tproxy_port(&config);
  59. let mixed_port = Self::guard_mixed_port(&config);
  60. let socks_port = Self::guard_socks_port(&config);
  61. let port = Self::guard_port(&config);
  62. let ctrl = Self::guard_server_ctrl(&config);
  63. #[cfg(not(target_os = "windows"))]
  64. config.insert("redir-port".into(), redir_port.into());
  65. #[cfg(target_os = "linux")]
  66. config.insert("tproxy-port".into(), tproxy_port.into());
  67. config.insert("mixed-port".into(), mixed_port.into());
  68. config.insert("socks-port".into(), socks_port.into());
  69. config.insert("port".into(), port.into());
  70. config.insert("external-controller".into(), ctrl.into());
  71. config
  72. }
  73. pub fn patch_config(&mut self, patch: Mapping) {
  74. for (key, value) in patch.into_iter() {
  75. self.0.insert(key, value);
  76. }
  77. }
  78. pub fn save_config(&self) -> Result<()> {
  79. help::save_yaml(
  80. &dirs::clash_path()?,
  81. &self.0,
  82. Some("# Generated by Clash Verge"),
  83. )
  84. }
  85. pub fn get_mixed_port(&self) -> u16 {
  86. Self::guard_mixed_port(&self.0)
  87. }
  88. #[allow(unused)]
  89. pub fn get_socks_port(&self) -> u16 {
  90. Self::guard_socks_port(&self.0)
  91. }
  92. #[allow(unused)]
  93. pub fn get_port(&self) -> u16 {
  94. Self::guard_port(&self.0)
  95. }
  96. pub fn get_client_info(&self) -> ClashInfo {
  97. let config = &self.0;
  98. ClashInfo {
  99. mixed_port: Self::guard_mixed_port(config),
  100. socks_port: Self::guard_socks_port(config),
  101. port: Self::guard_port(config),
  102. server: Self::guard_client_ctrl(config),
  103. secret: config.get("secret").and_then(|value| match value {
  104. Value::String(val_str) => Some(val_str.clone()),
  105. Value::Bool(val_bool) => Some(val_bool.to_string()),
  106. Value::Number(val_num) => Some(val_num.to_string()),
  107. _ => None,
  108. }),
  109. }
  110. }
  111. #[cfg(not(target_os = "windows"))]
  112. pub fn guard_redir_port(config: &Mapping) -> u16 {
  113. let mut port = config
  114. .get("redir-port")
  115. .and_then(|value| match value {
  116. Value::String(val_str) => val_str.parse().ok(),
  117. Value::Number(val_num) => val_num.as_u64().map(|u| u as u16),
  118. _ => None,
  119. })
  120. .unwrap_or(7895);
  121. if port == 0 {
  122. port = 7895;
  123. }
  124. port
  125. }
  126. #[cfg(target_os = "linux")]
  127. pub fn guard_tproxy_port(config: &Mapping) -> u16 {
  128. let mut port = config
  129. .get("tproxy-port")
  130. .and_then(|value| match value {
  131. Value::String(val_str) => val_str.parse().ok(),
  132. Value::Number(val_num) => val_num.as_u64().map(|u| u as u16),
  133. _ => None,
  134. })
  135. .unwrap_or(7896);
  136. if port == 0 {
  137. port = 7896;
  138. }
  139. port
  140. }
  141. pub fn guard_mixed_port(config: &Mapping) -> u16 {
  142. let mut port = config
  143. .get("mixed-port")
  144. .and_then(|value| match value {
  145. Value::String(val_str) => val_str.parse().ok(),
  146. Value::Number(val_num) => val_num.as_u64().map(|u| u as u16),
  147. _ => None,
  148. })
  149. .unwrap_or(7897);
  150. if port == 0 {
  151. port = 7897;
  152. }
  153. port
  154. }
  155. pub fn guard_socks_port(config: &Mapping) -> u16 {
  156. let mut port = config
  157. .get("socks-port")
  158. .and_then(|value| match value {
  159. Value::String(val_str) => val_str.parse().ok(),
  160. Value::Number(val_num) => val_num.as_u64().map(|u| u as u16),
  161. _ => None,
  162. })
  163. .unwrap_or(7898);
  164. if port == 0 {
  165. port = 7898;
  166. }
  167. port
  168. }
  169. pub fn guard_port(config: &Mapping) -> u16 {
  170. let mut port = config
  171. .get("port")
  172. .and_then(|value| match value {
  173. Value::String(val_str) => val_str.parse().ok(),
  174. Value::Number(val_num) => val_num.as_u64().map(|u| u as u16),
  175. _ => None,
  176. })
  177. .unwrap_or(7899);
  178. if port == 0 {
  179. port = 7899;
  180. }
  181. port
  182. }
  183. pub fn guard_server_ctrl(config: &Mapping) -> String {
  184. config
  185. .get("external-controller")
  186. .and_then(|value| match value.as_str() {
  187. Some(val_str) => {
  188. let val_str = val_str.trim();
  189. let val = match val_str.starts_with(':') {
  190. true => format!("127.0.0.1{val_str}"),
  191. false => val_str.to_owned(),
  192. };
  193. SocketAddr::from_str(val.as_str())
  194. .ok()
  195. .map(|s| s.to_string())
  196. }
  197. None => None,
  198. })
  199. .unwrap_or("127.0.0.1:9097".into())
  200. }
  201. pub fn guard_client_ctrl(config: &Mapping) -> String {
  202. let value = Self::guard_server_ctrl(config);
  203. match SocketAddr::from_str(value.as_str()) {
  204. Ok(mut socket) => {
  205. if socket.ip().is_unspecified() {
  206. socket.set_ip(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
  207. }
  208. socket.to_string()
  209. }
  210. Err(_) => "127.0.0.1:9097".into(),
  211. }
  212. }
  213. }
  214. #[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
  215. pub struct ClashInfo {
  216. /// clash core port
  217. pub mixed_port: u16,
  218. pub socks_port: u16,
  219. pub port: u16,
  220. /// same as `external-controller`
  221. pub server: String,
  222. /// clash secret
  223. pub secret: Option<String>,
  224. }
  225. #[test]
  226. fn test_clash_info() {
  227. fn get_case<T: Into<Value>, D: Into<Value>>(mp: T, ec: D) -> ClashInfo {
  228. let mut map = Mapping::new();
  229. map.insert("mixed-port".into(), mp.into());
  230. map.insert("external-controller".into(), ec.into());
  231. IClashTemp(IClashTemp::guard(map)).get_client_info()
  232. }
  233. fn get_result<S: Into<String>>(port: u16, server: S) -> ClashInfo {
  234. ClashInfo {
  235. mixed_port: port,
  236. socks_port: 7898,
  237. port: 7899,
  238. server: server.into(),
  239. secret: None,
  240. }
  241. }
  242. assert_eq!(
  243. IClashTemp(IClashTemp::guard(Mapping::new())).get_client_info(),
  244. get_result(7897, "127.0.0.1:9097")
  245. );
  246. assert_eq!(get_case("", ""), get_result(7897, "127.0.0.1:9097"));
  247. assert_eq!(get_case(65537, ""), get_result(1, "127.0.0.1:9097"));
  248. assert_eq!(
  249. get_case(8888, "127.0.0.1:8888"),
  250. get_result(8888, "127.0.0.1:8888")
  251. );
  252. assert_eq!(
  253. get_case(8888, " :98888 "),
  254. get_result(8888, "127.0.0.1:9097")
  255. );
  256. assert_eq!(
  257. get_case(8888, "0.0.0.0:8080 "),
  258. get_result(8888, "127.0.0.1:8080")
  259. );
  260. assert_eq!(
  261. get_case(8888, "0.0.0.0:8080"),
  262. get_result(8888, "127.0.0.1:8080")
  263. );
  264. assert_eq!(
  265. get_case(8888, "[::]:8080"),
  266. get_result(8888, "127.0.0.1:8080")
  267. );
  268. assert_eq!(
  269. get_case(8888, "192.168.1.1:8080"),
  270. get_result(8888, "192.168.1.1:8080")
  271. );
  272. assert_eq!(
  273. get_case(8888, "192.168.1.1:80800"),
  274. get_result(8888, "127.0.0.1:9097")
  275. );
  276. }
  277. #[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
  278. #[serde(rename_all = "kebab-case")]
  279. pub struct IClash {
  280. pub mixed_port: Option<u16>,
  281. pub allow_lan: Option<bool>,
  282. pub log_level: Option<String>,
  283. pub ipv6: Option<bool>,
  284. pub mode: Option<String>,
  285. pub external_controller: Option<String>,
  286. pub secret: Option<String>,
  287. pub dns: Option<IClashDNS>,
  288. pub tun: Option<IClashTUN>,
  289. pub interface_name: Option<String>,
  290. }
  291. #[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
  292. #[serde(rename_all = "kebab-case")]
  293. pub struct IClashTUN {
  294. pub enable: Option<bool>,
  295. pub stack: Option<String>,
  296. pub auto_route: Option<bool>,
  297. pub auto_detect_interface: Option<bool>,
  298. pub dns_hijack: Option<Vec<String>>,
  299. }
  300. #[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
  301. #[serde(rename_all = "kebab-case")]
  302. pub struct IClashDNS {
  303. pub enable: Option<bool>,
  304. pub listen: Option<String>,
  305. pub default_nameserver: Option<Vec<String>>,
  306. pub enhanced_mode: Option<String>,
  307. pub fake_ip_range: Option<String>,
  308. pub use_hosts: Option<bool>,
  309. pub fake_ip_filter: Option<Vec<String>>,
  310. pub nameserver: Option<Vec<String>>,
  311. pub fallback: Option<Vec<String>>,
  312. pub fallback_filter: Option<IClashFallbackFilter>,
  313. pub nameserver_policy: Option<Vec<String>>,
  314. }
  315. #[derive(Default, Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
  316. #[serde(rename_all = "kebab-case")]
  317. pub struct IClashFallbackFilter {
  318. pub geoip: Option<bool>,
  319. pub geoip_code: Option<String>,
  320. pub ipcidr: Option<Vec<String>>,
  321. pub domain: Option<Vec<String>>,
  322. }