From f97981b146c2ad26a05605f946aeef33df99afa4 Mon Sep 17 00:00:00 2001 From: im0o <0ojixueseno0@gmail.com> Date: Mon, 10 Aug 2026 12:37:33 +0800 Subject: [PATCH] =?UTF-8?q?=E9=BB=98=E8=AE=A4=E5=85=A5=E7=AB=99=EF=BC=9A?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E5=8F=AF=E9=80=89=E5=87=BA=E7=AB=99=EF=BC=8C?= =?UTF-8?q?=E5=B9=B6=E7=BB=99=E4=B8=80=E6=9D=A1=E8=BD=AC=E6=88=90=E5=91=BD?= =?UTF-8?q?=E5=90=8D=E5=85=A5=E7=AB=99=E7=9A=84=E8=B7=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 上一版把默认入站的整个出站块都藏了,结果策略组也看不见。改成只藏 RULE/DIRECT/GLOBAL 那三张卡(它固定是 RULE),策略组和线路照常列出来当上下文,只是不可点。 顺带修一个显示错误:老式顶层端口没有 listen 字段,实际地址是内核从 allow-lan 和 bind-address 推出来的(listener/listener.go:709-718)——allow-lan 关着时绑的是 127.0.0.1,而界面一律显示 0.0.0.0,会让人以为局域网连得上。 转换时会把老式端口字段删掉并把推导出的地址显式写进 listen:不删会导致同一个端口被声明 两次内核起不来,不写 listen 则以后改 allow-lan 会连带影响这个端口。 --- shared/inbounds.test.ts | 22 +++++++++++++ shared/inbounds.ts | 19 ++++++++++- web/views/InboundDetail.vue | 66 ++++++++++++++++++++++++++++++------- web/views/RouterPage.vue | 33 ++++++++++++++++++- 4 files changed, 126 insertions(+), 14 deletions(-) diff --git a/shared/inbounds.test.ts b/shared/inbounds.test.ts index 15e6165..f90a1f9 100644 --- a/shared/inbounds.test.ts +++ b/shared/inbounds.test.ts @@ -39,6 +39,28 @@ describe('合并两套写法的入站', () => { }) }) +describe('老式端口实际绑在哪', () => { + // 内核源码 listener/listener.go:709-718。界面上一律显示 0.0.0.0 会骗人。 + it('allow-lan 没开时只绑本机', () => { + expect(collectInbounds({ 'mixed-port': 7777 })[0]!.listen).toBe('127.0.0.1') + expect(collectInbounds({ 'mixed-port': 7777, 'allow-lan': false })[0]!.listen).toBe('127.0.0.1') + }) + + it('allow-lan 开了但没指定地址时绑所有网卡', () => { + expect(collectInbounds({ 'mixed-port': 7777, 'allow-lan': true })[0]!.listen).toBe('0.0.0.0') + expect( + collectInbounds({ 'mixed-port': 7777, 'allow-lan': true, 'bind-address': '*' })[0]!.listen, + ).toBe('0.0.0.0') + }) + + it('指定了地址就用那个地址', () => { + expect( + collectInbounds({ 'mixed-port': 7777, 'allow-lan': true, 'bind-address': '192.168.1.5' })[0]! + .listen, + ).toBe('192.168.1.5') + }) +}) + describe('出站去向的四种形态', () => { const of = (proxy?: string) => { // 用扩展而不是直接写 proxy: undefined —— 配置里「没有这个键」和「这个键是空」 diff --git a/shared/inbounds.ts b/shared/inbounds.ts index 03f09ee..e47122a 100644 --- a/shared/inbounds.ts +++ b/shared/inbounds.ts @@ -74,8 +74,25 @@ export function outboundToProxyField(mode: OutboundMode): string | undefined { return mode.name } +/** + * 老式顶层端口实际绑在哪个地址上。 + * + * 它没有自己的 listen 字段,地址是内核从两个全局开关推出来的 + * (内核源码 `listener/listener.go:709-718`): + * allow-lan 关 → 127.0.0.1,只有本机连得上 + * allow-lan 开 → bind-address 指定的地址,写 * 或没写就是所有网卡 + * 界面上不能一律显示 0.0.0.0,那会让人以为局域网连得上而实际连不上。 + */ +export function legacyListenAddress(data: ConfigObject): string { + if (data['allow-lan'] !== true) return '127.0.0.1' + const bind = data['bind-address'] + if (typeof bind !== 'string' || bind === '' || bind === '*') return '0.0.0.0' + return bind +} + export function collectInbounds(data: ConfigObject): Inbound[] { const result: Inbound[] = [] + const legacyListen = legacyListenAddress(data) for (const { key, type } of LEGACY_PORTS) { const raw = data[key] @@ -89,7 +106,7 @@ export function collectInbounds(data: ConfigObject): Inbound[] { name: key, type, port: String(port), - listen: null, + listen: legacyListen, outbound: { kind: 'rules' }, ruleSet: null, isDefault: true, diff --git a/web/views/InboundDetail.vue b/web/views/InboundDetail.vue index a7044e5..5a65e1e 100644 --- a/web/views/InboundDetail.vue +++ b/web/views/InboundDetail.vue @@ -6,6 +6,7 @@ import type { ProxyInfo } from '../api' import IconOffline from '~icons/ri/cloud-off-line' import IconEdit from '~icons/ri/edit-line' import IconDelete from '~icons/ri/delete-bin-line' +import IconConvert from '~icons/ri/swap-line' const props = defineProps<{ inbound: Inbound @@ -18,7 +19,7 @@ const props = defineProps<{ saving: boolean }>() -const emit = defineEmits<{ pick: [mode: OutboundMode]; edit: []; remove: [] }>() +const emit = defineEmits<{ pick: [mode: OutboundMode]; edit: []; remove: []; convert: [] }>() interface Option { key: string @@ -129,14 +130,20 @@ function delayClass(ms: number | null): string { -
- 由 {{ inbound.legacyKey }} 声明,这种写法没有 proxy 字段,出站固定是 RULE
-
+ 由 {{ inbound.legacyKey }} 声明,这种写法没有 proxy 字段,出站固定是
+ RULE,下面这些都不能选。
+