mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-01-29 17:15:38 +08:00
feat: Support Tun Config (#416)
This commit is contained in:
192
src/components/setting/mods/tun-viewer.tsx
Normal file
192
src/components/setting/mods/tun-viewer.tsx
Normal file
@@ -0,0 +1,192 @@
|
||||
import { forwardRef, useImperativeHandle, useState } from "react";
|
||||
import { useLockFn } from "ahooks";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
List,
|
||||
ListItem,
|
||||
ListItemText,
|
||||
MenuItem,
|
||||
Select,
|
||||
Switch,
|
||||
TextField,
|
||||
} from "@mui/material";
|
||||
import { useClash } from "@/hooks/use-clash";
|
||||
import { BaseDialog, DialogRef, Notice } from "@/components/base";
|
||||
|
||||
export const TunViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { clash, mutateClash, patchClash } = useClash();
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [values, setValues] = useState({
|
||||
stack: "gVisor",
|
||||
device: "Mihomo",
|
||||
autoRoute: true,
|
||||
autoDetectInterface: true,
|
||||
dnsHijack: ["any:53", "tcp://any:53"],
|
||||
strictRoute: true,
|
||||
mtu: 9000,
|
||||
});
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
open: () => {
|
||||
setOpen(true);
|
||||
setValues({
|
||||
stack: clash?.tun.stack ?? "gVisor",
|
||||
device: clash?.tun.device ?? "Mihomo",
|
||||
autoRoute: clash?.tun["auto-route"] ?? true,
|
||||
autoDetectInterface: clash?.tun["auto-detect-interface"] ?? true,
|
||||
dnsHijack: clash?.tun["dns-hijack"] ?? ["any:53", "tcp://any:53"],
|
||||
strictRoute: clash?.tun["strict-route"] ?? true,
|
||||
mtu: clash?.tun.mtu ?? 9000,
|
||||
});
|
||||
},
|
||||
close: () => setOpen(false),
|
||||
}));
|
||||
|
||||
const onSave = useLockFn(async () => {
|
||||
try {
|
||||
let tun = {
|
||||
stack: values.stack,
|
||||
device: values.device,
|
||||
"auto-route": values.autoRoute,
|
||||
"auto-detect-interface": values.autoDetectInterface,
|
||||
"dns-hijack": values.dnsHijack,
|
||||
"strict-route": values.strictRoute,
|
||||
mtu: values.mtu,
|
||||
};
|
||||
await patchClash({ tun });
|
||||
await mutateClash(
|
||||
(old) => ({
|
||||
...(old! || {}),
|
||||
tun,
|
||||
}),
|
||||
false
|
||||
);
|
||||
setOpen(false);
|
||||
} catch (err: any) {
|
||||
Notice.error(err.message || err.toString());
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<BaseDialog
|
||||
open={open}
|
||||
title={t("Tun Mode")}
|
||||
contentSx={{ width: 450 }}
|
||||
okBtn={t("Save")}
|
||||
cancelBtn={t("Cancel")}
|
||||
onClose={() => setOpen(false)}
|
||||
onCancel={() => setOpen(false)}
|
||||
onOk={onSave}
|
||||
>
|
||||
<List>
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Stack")} />
|
||||
<Select
|
||||
size="small"
|
||||
sx={{ width: 100, "> div": { py: "7.5px" } }}
|
||||
value={values.stack}
|
||||
onChange={(e) => {
|
||||
setValues((v) => ({
|
||||
...v,
|
||||
stack: e.target.value as string,
|
||||
}));
|
||||
}}
|
||||
>
|
||||
{["System", "gVisor", "Mixed"].map((i) => (
|
||||
<MenuItem value={i} key={i}>
|
||||
{i}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Device")} />
|
||||
<TextField
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
spellCheck="false"
|
||||
sx={{ width: 250 }}
|
||||
value={values.device}
|
||||
placeholder="Mihomo"
|
||||
onChange={(e) =>
|
||||
setValues((v) => ({ ...v, device: e.target.value }))
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Auto Route")} />
|
||||
<Switch
|
||||
edge="end"
|
||||
checked={values.autoRoute}
|
||||
onChange={(_, c) => setValues((v) => ({ ...v, autoRoute: c }))}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Strict Route")} />
|
||||
<Switch
|
||||
edge="end"
|
||||
checked={values.strictRoute}
|
||||
onChange={(_, c) => setValues((v) => ({ ...v, strictRoute: c }))}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Auto Detect Interface")} />
|
||||
<Switch
|
||||
edge="end"
|
||||
checked={values.autoDetectInterface}
|
||||
onChange={(_, c) =>
|
||||
setValues((v) => ({ ...v, autoDetectInterface: c }))
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("DNS Hijack")} />
|
||||
<TextField
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
spellCheck="false"
|
||||
sx={{ width: 250 }}
|
||||
value={values.dnsHijack.join(",")}
|
||||
placeholder="Please use , to separate multiple DNS servers"
|
||||
onChange={(e) =>
|
||||
setValues((v) => ({ ...v, dnsHijack: e.target.value.split(",") }))
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("MTU")} />
|
||||
<TextField
|
||||
size="small"
|
||||
type="number"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
spellCheck="false"
|
||||
sx={{ width: 250 }}
|
||||
value={values.mtu}
|
||||
placeholder="9000"
|
||||
onChange={(e) =>
|
||||
setValues((v) => ({
|
||||
...v,
|
||||
mtu: parseInt(e.target.value),
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
</List>
|
||||
</BaseDialog>
|
||||
);
|
||||
});
|
||||
@@ -41,7 +41,6 @@ const SettingClash = ({ onError }: Props) => {
|
||||
const { enable_random_port = false, verge_mixed_port } = verge ?? {};
|
||||
|
||||
const webRef = useRef<DialogRef>(null);
|
||||
const fieldRef = useRef<DialogRef>(null);
|
||||
const portRef = useRef<DialogRef>(null);
|
||||
const ctrlRef = useRef<DialogRef>(null);
|
||||
const coreRef = useRef<DialogRef>(null);
|
||||
|
||||
@@ -10,6 +10,7 @@ import { SettingList, SettingItem } from "./mods/setting-comp";
|
||||
import { GuardState } from "./mods/guard-state";
|
||||
import { ServiceViewer } from "./mods/service-viewer";
|
||||
import { SysproxyViewer } from "./mods/sysproxy-viewer";
|
||||
import { TunViewer } from "./mods/tun-viewer";
|
||||
import getSystem from "@/utils/get-system";
|
||||
|
||||
interface Props {
|
||||
@@ -36,6 +37,7 @@ const SettingSystem = ({ onError }: Props) => {
|
||||
|
||||
const serviceRef = useRef<DialogRef>(null);
|
||||
const sysproxyRef = useRef<DialogRef>(null);
|
||||
const tunRef = useRef<DialogRef>(null);
|
||||
|
||||
const {
|
||||
enable_tun_mode,
|
||||
@@ -53,6 +55,7 @@ const SettingSystem = ({ onError }: Props) => {
|
||||
return (
|
||||
<SettingList title={t("System Setting")}>
|
||||
<SysproxyViewer ref={sysproxyRef} />
|
||||
<TunViewer ref={tunRef} />
|
||||
{isWIN && (
|
||||
<ServiceViewer ref={serviceRef} enable={!!enable_service_mode} />
|
||||
)}
|
||||
@@ -60,17 +63,31 @@ const SettingSystem = ({ onError }: Props) => {
|
||||
<SettingItem
|
||||
label={t("Tun Mode")}
|
||||
extra={
|
||||
<Tooltip
|
||||
title={isWIN ? t("Tun Mode Info Windows") : t("Tun Mode Info Unix")}
|
||||
placement="top"
|
||||
>
|
||||
<IconButton color="inherit" size="small">
|
||||
<InfoRounded
|
||||
<>
|
||||
<Tooltip
|
||||
title={
|
||||
isWIN ? t("Tun Mode Info Windows") : t("Tun Mode Info Unix")
|
||||
}
|
||||
placement="top"
|
||||
>
|
||||
<IconButton color="inherit" size="small">
|
||||
<InfoRounded
|
||||
fontSize="inherit"
|
||||
style={{ cursor: "pointer", opacity: 0.75 }}
|
||||
/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
size="small"
|
||||
onClick={() => tunRef.current?.open()}
|
||||
>
|
||||
<Settings
|
||||
fontSize="inherit"
|
||||
style={{ cursor: "pointer", opacity: 0.75 }}
|
||||
/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<GuardState
|
||||
|
||||
9
src/services/types.d.ts
vendored
9
src/services/types.d.ts
vendored
@@ -32,6 +32,15 @@ interface IConfigData {
|
||||
"tproxy-port": number;
|
||||
"external-controller": string;
|
||||
secret: string;
|
||||
tun: {
|
||||
stack: string;
|
||||
device: string;
|
||||
"auto-route": boolean;
|
||||
"auto-detect-interface": boolean;
|
||||
"dns-hijack": string[];
|
||||
"strict-route": boolean;
|
||||
mtu: number;
|
||||
};
|
||||
}
|
||||
|
||||
interface IRuleItem {
|
||||
|
||||
Reference in New Issue
Block a user