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,下面这些都不能选。
+