Quellcode durchsuchen

feat: Support config redir port and tproxy port

MystiPanda vor 1 Jahr
Ursprung
Commit
2d925c62f5

+ 43 - 2
src-tauri/src/config/clash.rs

@@ -39,7 +39,10 @@ impl IClashTemp {
         tun.insert("auto-detect-interface".into(), true.into());
         tun.insert("dns-hijack".into(), vec!["any:53"].into());
         tun.insert("mtu".into(), 9000.into());
-
+        #[cfg(not(target_os = "windows"))]
+        map.insert("redir-port".into(), 7895.into());
+        #[cfg(target_os = "linux")]
+        map.insert("tproxy-port".into(), 7896.into());
         map.insert("mixed-port".into(), 7897.into());
         map.insert("socks-port".into(), 7898.into());
         map.insert("port".into(), 7899.into());
@@ -54,11 +57,18 @@ impl IClashTemp {
     }
 
     fn guard(mut config: Mapping) -> Mapping {
+        #[cfg(not(target_os = "windows"))]
+        let redir_port = Self::guard_redir_port(&config);
+        #[cfg(target_os = "linux")]
+        let tproxy_port = Self::guard_tproxy_port(&config);
         let mixed_port = Self::guard_mixed_port(&config);
         let socks_port = Self::guard_socks_port(&config);
         let port = Self::guard_port(&config);
         let ctrl = Self::guard_server_ctrl(&config);
-
+        #[cfg(not(target_os = "windows"))]
+        config.insert("redir-port".into(), redir_port.into());
+        #[cfg(target_os = "linux")]
+        config.insert("tproxy-port".into(), tproxy_port.into());
         config.insert("mixed-port".into(), mixed_port.into());
         config.insert("socks-port".into(), socks_port.into());
         config.insert("port".into(), port.into());
@@ -110,6 +120,37 @@ impl IClashTemp {
             }),
         }
     }
+    #[cfg(not(target_os = "windows"))]
+    pub fn guard_redir_port(config: &Mapping) -> u16 {
+        let mut port = config
+            .get("redir-port")
+            .and_then(|value| match value {
+                Value::String(val_str) => val_str.parse().ok(),
+                Value::Number(val_num) => val_num.as_u64().map(|u| u as u16),
+                _ => None,
+            })
+            .unwrap_or(7895);
+        if port == 0 {
+            port = 7895;
+        }
+        port
+    }
+
+    #[cfg(target_os = "linux")]
+    pub fn guard_tproxy_port(config: &Mapping) -> u16 {
+        let mut port = config
+            .get("tproxy-port")
+            .and_then(|value| match value {
+                Value::String(val_str) => val_str.parse().ok(),
+                Value::Number(val_num) => val_num.as_u64().map(|u| u as u16),
+                _ => None,
+            })
+            .unwrap_or(7896);
+        if port == 0 {
+            port = 7896;
+        }
+        port
+    }
 
     pub fn guard_mixed_port(config: &Mapping) -> u16 {
         let mut port = config

+ 15 - 1
src-tauri/src/config/verge.rs

@@ -126,7 +126,13 @@ pub struct IVerge {
     /// 是否启用随机端口
     pub enable_random_port: Option<bool>,
 
-    /// verge mixed port 用于覆盖 clash 的 mixed port
+    /// verge 的各种 port 用于覆盖 clash 的各种 port
+    #[cfg(not(target_os = "windows"))]
+    pub verge_redir_port: Option<u16>,
+
+    #[cfg(target_os = "linux")]
+    pub verge_tproxy_port: Option<u16>,
+
     pub verge_mixed_port: Option<u16>,
 
     pub verge_socks_port: Option<u16>,
@@ -190,6 +196,10 @@ impl IVerge {
             enable_silent_start: Some(false),
             enable_system_proxy: Some(false),
             enable_random_port: Some(false),
+            #[cfg(not(target_os = "windows"))]
+            verge_redir_port: Some(7895),
+            #[cfg(target_os = "linux")]
+            verge_tproxy_port: Some(7896),
             verge_mixed_port: Some(7897),
             verge_socks_port: Some(7898),
             verge_port: Some(7899),
@@ -239,6 +249,10 @@ impl IVerge {
         patch!(enable_auto_launch);
         patch!(enable_silent_start);
         patch!(enable_random_port);
+        #[cfg(not(target_os = "windows"))]
+        patch!(verge_redir_port);
+        #[cfg(target_os = "linux")]
+        patch!(verge_tproxy_port);
         patch!(verge_mixed_port);
         patch!(verge_socks_port);
         patch!(verge_port);

+ 3 - 1
src-tauri/src/enhance/field.rs

@@ -1,8 +1,10 @@
 use serde_yaml::{Mapping, Value};
 use std::collections::HashSet;
 
-pub const HANDLE_FIELDS: [&str; 9] = [
+pub const HANDLE_FIELDS: [&str; 11] = [
     "mode",
+    "redir-port",
+    "tproxy-port",
     "mixed-port",
     "socks-port",
     "port",

+ 5 - 1
src-tauri/src/feat.rs

@@ -107,6 +107,8 @@ pub async fn patch_clash(patch: Mapping) -> Result<()> {
     Config::clash().draft().patch_config(patch.clone());
 
     match {
+        let redir_port = patch.get("redir-port");
+        let tproxy_port = patch.get("tproxy-port");
         let mixed_port = patch.get("mixed-port");
         let socks_port = patch.get("socks-port");
         let port = patch.get("port");
@@ -129,7 +131,9 @@ pub async fn patch_clash(patch: Mapping) -> Result<()> {
         };
 
         // 激活订阅
-        if mixed_port.is_some()
+        if redir_port.is_some()
+            || tproxy_port.is_some()
+            || mixed_port.is_some()
             || socks_port.is_some()
             || port.is_some()
             || patch.get("secret").is_some()

+ 53 - 1
src/components/setting/mods/clash-port-viewer.tsx

@@ -5,6 +5,8 @@ import { List, ListItem, ListItemText, TextField } from "@mui/material";
 import { useClashInfo } from "@/hooks/use-clash";
 import { BaseDialog, DialogRef, Notice } from "@/components/base";
 import { useVerge } from "@/hooks/use-verge";
+import getSystem from "@/utils/get-system";
+const OS = getSystem();
 
 export const ClashPortViewer = forwardRef<DialogRef>((props, ref) => {
   const { t } = useTranslation();
@@ -13,6 +15,12 @@ export const ClashPortViewer = forwardRef<DialogRef>((props, ref) => {
   const { verge, patchVerge } = useVerge();
 
   const [open, setOpen] = useState(false);
+  const [redirPort, setRedirPort] = useState(
+    verge?.verge_redir_port ?? clashInfo?.redir_port ?? 7895
+  );
+  const [tproxyPort, setTproxyPort] = useState(
+    verge?.verge_tproxy_port ?? clashInfo?.tproxy_port ?? 7896
+  );
   const [mixedPort, setMixedPort] = useState(
     verge?.verge_mixed_port ?? clashInfo?.mixed_port ?? 7897
   );
@@ -25,6 +33,8 @@ export const ClashPortViewer = forwardRef<DialogRef>((props, ref) => {
 
   useImperativeHandle(ref, () => ({
     open: () => {
+      if (verge?.verge_redir_port) setRedirPort(verge?.verge_redir_port);
+      if (verge?.verge_tproxy_port) setTproxyPort(verge?.verge_tproxy_port);
       if (verge?.verge_mixed_port) setMixedPort(verge?.verge_mixed_port);
       if (verge?.verge_socks_port) setSocksPort(verge?.verge_socks_port);
       if (verge?.verge_port) setPort(verge?.verge_port);
@@ -35,6 +45,8 @@ export const ClashPortViewer = forwardRef<DialogRef>((props, ref) => {
 
   const onSave = useLockFn(async () => {
     if (
+      redirPort === verge?.verge_redir_port &&
+      tproxyPort === verge?.verge_tproxy_port &&
       mixedPort === verge?.verge_mixed_port &&
       socksPort === verge?.verge_socks_port &&
       port === verge?.verge_port
@@ -42,11 +54,22 @@ export const ClashPortViewer = forwardRef<DialogRef>((props, ref) => {
       setOpen(false);
       return;
     }
-    if (mixedPort === socksPort || mixedPort === port || socksPort === port) {
+
+    if (
+      new Set([redirPort, tproxyPort, mixedPort, socksPort, port]).size !== 5
+    ) {
       Notice.error("Port conflict!", 4000);
       return;
     }
     try {
+      if (OS !== "windows") {
+        await patchInfo({ "redir-port": redirPort });
+        await patchVerge({ verge_redir_port: redirPort });
+      }
+      if (OS === "linux") {
+        await patchInfo({ "tproxy-port": tproxyPort });
+        await patchVerge({ verge_tproxy_port: tproxyPort });
+      }
       await patchInfo({ "mixed-port": mixedPort });
       await patchInfo({ "socks-port": socksPort });
       await patchInfo({ port });
@@ -72,6 +95,35 @@ export const ClashPortViewer = forwardRef<DialogRef>((props, ref) => {
       onOk={onSave}
     >
       <List>
+        {OS !== "windows" && (
+          <ListItem sx={{ padding: "5px 2px" }}>
+            <ListItemText primary="Redir Port" />
+            <TextField
+              size="small"
+              autoComplete="off"
+              sx={{ width: 135 }}
+              value={redirPort}
+              onChange={(e) =>
+                setRedirPort(+e.target.value?.replace(/\D+/, "").slice(0, 5))
+              }
+            />
+          </ListItem>
+        )}
+        {OS === "linux" && (
+          <ListItem sx={{ padding: "5px 2px" }}>
+            <ListItemText primary="Tproxy Port" />
+            <TextField
+              size="small"
+              autoComplete="off"
+              sx={{ width: 135 }}
+              value={tproxyPort}
+              onChange={(e) =>
+                setTproxyPort(+e.target.value?.replace(/\D+/, "").slice(0, 5))
+              }
+            />
+          </ListItem>
+        )}
+
         <ListItem sx={{ padding: "5px 2px" }}>
           <ListItemText primary="Mixed Port" />
           <TextField

+ 29 - 1
src/hooks/use-clash.ts

@@ -49,11 +49,19 @@ export const useClashInfo = () => {
     patch: Partial<
       Pick<
         IConfigData,
-        "port" | "socks-port" | "mixed-port" | "external-controller" | "secret"
+        | "port"
+        | "socks-port"
+        | "mixed-port"
+        | "redir-port"
+        | "tproxy-port"
+        | "external-controller"
+        | "secret"
       >
     >
   ) => {
     const hasInfo =
+      patch["redir-port"] != null ||
+      patch["tproxy-port"] != null ||
       patch["mixed-port"] != null ||
       patch["socks-port"] != null ||
       patch["port"] != null ||
@@ -62,6 +70,26 @@ export const useClashInfo = () => {
 
     if (!hasInfo) return;
 
+    if (patch["redir-port"]) {
+      const port = patch["redir-port"];
+      if (port < 1000) {
+        throw new Error("The port should not < 1000");
+      }
+      if (port > 65536) {
+        throw new Error("The port should not > 65536");
+      }
+    }
+
+    if (patch["tproxy-port"]) {
+      const port = patch["tproxy-port"];
+      if (port < 1000) {
+        throw new Error("The port should not < 1000");
+      }
+      if (port > 65536) {
+        throw new Error("The port should not > 65536");
+      }
+    }
+
     if (patch["mixed-port"]) {
       const port = patch["mixed-port"];
       if (port < 1000) {

+ 4 - 0
src/services/types.d.ts

@@ -142,6 +142,8 @@ interface IClashInfo {
   // status: string;
   mixed_port?: number; // clash mixed port
   socks_port?: number; // clash socks port
+  redir_port?: number; // clash redir port
+  tproxy_port?: number; // clash tproxy port
   port?: number; // clash http port
   server?: string; // external-controller
   secret?: string;
@@ -214,6 +216,8 @@ interface IVergeConfig {
   enable_random_port?: boolean;
   verge_mixed_port?: number;
   verge_socks_port?: number;
+  verge_redir_port?: number;
+  verge_tproxy_port?: number;
   verge_port?: number;
   enable_proxy_guard?: boolean;
   proxy_guard_duration?: number;