mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-05-28 16:09:36 +00:00
feat(frontend): symmetric TCP HTTP host/path + extra sockopt knobs
OutboundFormModal: - Sockopt section gains 5 common-but-rarely-tweaked knobs: acceptProxyProtocol, tproxy (off/redirect/tproxy), tcpcongestion (bbr/cubic/reno), V6Only, tcpUserTimeout. The remaining sockopt fields (tcpKeepAliveIdle, tcpMaxSeg, tcpWindowClamp, trustedXForwardedFor) are still edit-via-JSON; they are deeply tunable and not commonly touched. InboundFormModal: - TCP HTTP camouflage gains host + path inputs symmetric to the outbound side. Switch ON seeds request with sensible defaults (version 1.1, method GET, path ['/'], empty headers). The two inputs use the same normalize/getValueProps comma-string ↔ string[] dance the outbound side uses, so the wire shape stays identical to what xray-core expects.
This commit is contained in:
@@ -1157,7 +1157,17 @@ export default function InboundFormModal({
|
||||
onChange={(v) => {
|
||||
setFieldValue(
|
||||
['streamSettings', 'tcpSettings', 'header'],
|
||||
v ? { type: 'http' } : { type: 'none' },
|
||||
v
|
||||
? {
|
||||
type: 'http',
|
||||
request: {
|
||||
version: '1.1',
|
||||
method: 'GET',
|
||||
path: ['/'],
|
||||
headers: {},
|
||||
},
|
||||
}
|
||||
: { type: 'none' },
|
||||
);
|
||||
}}
|
||||
/>
|
||||
@@ -1165,6 +1175,62 @@ export default function InboundFormModal({
|
||||
}}
|
||||
</Form.Item>
|
||||
</Form.Item>
|
||||
{/* Host + path camouflage inputs only render when the Switch
|
||||
above is on. Both are string[] on the wire; normalize +
|
||||
getValueProps translate to/from comma-joined input. Mirrors
|
||||
the symmetric outbound side. */}
|
||||
<Form.Item
|
||||
noStyle
|
||||
shouldUpdate={(prev, curr) =>
|
||||
prev.streamSettings?.tcpSettings?.header?.type
|
||||
!== curr.streamSettings?.tcpSettings?.header?.type
|
||||
}
|
||||
>
|
||||
{({ getFieldValue }) => {
|
||||
const headerType = getFieldValue(
|
||||
['streamSettings', 'tcpSettings', 'header', 'type'],
|
||||
) as string | undefined;
|
||||
if (headerType !== 'http') return null;
|
||||
return (
|
||||
<>
|
||||
<Form.Item
|
||||
label={t('host')}
|
||||
name={[
|
||||
'streamSettings', 'tcpSettings', 'header',
|
||||
'request', 'headers', 'Host',
|
||||
]}
|
||||
normalize={(v: unknown) =>
|
||||
typeof v === 'string'
|
||||
? v.split(',').map((s) => s.trim()).filter(Boolean)
|
||||
: Array.isArray(v) ? v : []
|
||||
}
|
||||
getValueProps={(v: unknown) => ({
|
||||
value: Array.isArray(v) ? v.join(',') : '',
|
||||
})}
|
||||
>
|
||||
<Input placeholder="example.com,cdn.example.com" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t('path')}
|
||||
name={[
|
||||
'streamSettings', 'tcpSettings', 'header',
|
||||
'request', 'path',
|
||||
]}
|
||||
normalize={(v: unknown) =>
|
||||
typeof v === 'string'
|
||||
? v.split(',').map((s) => s.trim()).filter(Boolean)
|
||||
: Array.isArray(v) ? v : ['/']
|
||||
}
|
||||
getValueProps={(v: unknown) => ({
|
||||
value: Array.isArray(v) ? v.join(',') : '/',
|
||||
})}
|
||||
>
|
||||
<Input placeholder="/,/api,/static" />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ import {
|
||||
OutboundDomainStrategies,
|
||||
OutboundProtocols as Protocols,
|
||||
SNIFFING_OPTION,
|
||||
TCP_CONGESTION_OPTION,
|
||||
TLS_FLOW_CONTROL,
|
||||
USERS_SECURITY,
|
||||
UTLS_FINGERPRINT,
|
||||
@@ -1516,6 +1517,49 @@ export default function OutboundFormModal({
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="TProxy"
|
||||
name={['streamSettings', 'sockopt', 'tproxy']}
|
||||
>
|
||||
<Select
|
||||
options={[
|
||||
{ value: 'off', label: 'off' },
|
||||
{ value: 'redirect', label: 'redirect' },
|
||||
{ value: 'tproxy', label: 'tproxy' },
|
||||
]}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="TCP congestion"
|
||||
name={['streamSettings', 'sockopt', 'tcpcongestion']}
|
||||
>
|
||||
<Select
|
||||
options={Object.values(TCP_CONGESTION_OPTION).map((v) => ({
|
||||
value: v,
|
||||
label: v,
|
||||
}))}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="IPv6 only"
|
||||
name={['streamSettings', 'sockopt', 'V6Only']}
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="Accept proxy protocol"
|
||||
name={['streamSettings', 'sockopt', 'acceptProxyProtocol']}
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="TCP user timeout (ms)"
|
||||
name={['streamSettings', 'sockopt', 'tcpUserTimeout']}
|
||||
>
|
||||
<InputNumber min={0} style={{ width: '100%' }} />
|
||||
</Form.Item>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user