From ccd0853b6cb87e5ae34818845536213ac507b572 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Mon, 1 Jun 2026 23:26:20 +0200 Subject: [PATCH] fix(inbounds): allow port 0 for UDS inbounds (#4783) Unix Domain Socket inbounds (listen path starting with /) use port 0, which xray-core ignores. Validation was hard-locked to a minimum of 1 in three places: the shared Zod PortSchema, the AntD InputNumber, and the Go Inbound model tag. Adds an InboundPortSchema (min 0) for the inbound form/API schemas, makes the port InputNumber min UDS-aware, and relaxes the Inbound model validate tag to gte=0. PortSchema and the Node model stay min 1. --- database/model/model.go | 2 +- frontend/src/generated/zod.ts | 2 +- frontend/src/pages/inbounds/form/InboundFormModal.tsx | 4 +++- frontend/src/schemas/api/inbound.ts | 4 ++-- frontend/src/schemas/forms/inbound-form.ts | 4 ++-- frontend/src/schemas/primitives/port.ts | 3 +++ 6 files changed, 12 insertions(+), 7 deletions(-) diff --git a/database/model/model.go b/database/model/model.go index baa9c3e9..dfde97d0 100644 --- a/database/model/model.go +++ b/database/model/model.go @@ -55,7 +55,7 @@ type Inbound struct { // Xray configuration fields Listen string `json:"listen" form:"listen"` - Port int `json:"port" form:"port" validate:"gte=1,lte=65535"` + Port int `json:"port" form:"port" validate:"gte=0,lte=65535"` Protocol Protocol `json:"protocol" form:"protocol" validate:"required,oneof=vmess vless trojan shadowsocks wireguard hysteria http mixed tunnel tun"` Settings string `json:"settings" form:"settings"` StreamSettings string `json:"streamSettings" form:"streamSettings"` diff --git a/frontend/src/generated/zod.ts b/frontend/src/generated/zod.ts index 29373964..abdc4414 100644 --- a/frontend/src/generated/zod.ts +++ b/frontend/src/generated/zod.ts @@ -291,7 +291,7 @@ export const InboundSchema = z.object({ lastTrafficResetTime: z.number().int(), listen: z.string(), nodeId: z.number().int().nullable().optional(), - port: z.number().int().min(1).max(65535), + port: z.number().int().min(0).max(65535), protocol: z.enum(['vmess', 'vless', 'trojan', 'shadowsocks', 'wireguard', 'hysteria', 'http', 'mixed', 'tunnel', 'tun']), remark: z.string(), settings: z.unknown(), diff --git a/frontend/src/pages/inbounds/form/InboundFormModal.tsx b/frontend/src/pages/inbounds/form/InboundFormModal.tsx index 8279f482..03da6749 100644 --- a/frontend/src/pages/inbounds/form/InboundFormModal.tsx +++ b/frontend/src/pages/inbounds/form/InboundFormModal.tsx @@ -161,6 +161,8 @@ export default function InboundFormModal({ const streamEnabled = canEnableStream({ protocol }); const wPort = Form.useWatch('port', form); + const wListen = (Form.useWatch('listen', form) ?? '') as string; + const isUdsListen = wListen.startsWith('/'); const wNodeId = Form.useWatch('nodeId', form) ?? null; const wTag = Form.useWatch('tag', form) ?? ''; const wSsNetwork = Form.useWatch(['settings', 'network'], form); @@ -488,7 +490,7 @@ export default function InboundFormModal({ label={t('pages.inbounds.port')} rules={[antdRule(InboundFormBaseSchema.shape.port, t)]} > - + ; export const InboundFormBaseSchema = z.object({ remark: z.string().default(''), enable: z.boolean().default(true), - port: PortSchema, + port: InboundPortSchema, listen: z.string().default(''), tag: z.string().default(''), expiryTime: z.number().int().default(0), diff --git a/frontend/src/schemas/primitives/port.ts b/frontend/src/schemas/primitives/port.ts index d73ed2c6..dbbf49a6 100644 --- a/frontend/src/schemas/primitives/port.ts +++ b/frontend/src/schemas/primitives/port.ts @@ -2,3 +2,6 @@ import { z } from 'zod'; export const PortSchema = z.number().int().min(1).max(65535); export type Port = z.infer; + +export const InboundPortSchema = z.number().int().min(0).max(65535); +export type InboundPort = z.infer;