clash.rs 9.3 KB

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