mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-06 20:39:35 +00:00
fix(external-proxy): relabel "Host" as "Address", add per-entry ECH (#4935)
The external proxy "Host" field was bound to dest (the connection address that becomes the link host) but labeled "Host", misleading users into thinking it set a transport host header. Relabel it to "Address" to match what it actually controls. Add per-entry ECH (echConfigList) to the external proxy schema, form (shown under Force TLS = TLS), the TS link generator, and the Go sub services: ech is emitted on share links and vmess objects, and written into the stream so the JSON subscription picks it up via the existing tlsData reader.
This commit is contained in:
@@ -137,6 +137,7 @@ function applyExternalProxyTLSObj(
|
||||
if (alpn.length > 0) obj.alpn = alpn;
|
||||
const pins = externalProxyPins(externalProxy.pinnedPeerCertSha256);
|
||||
if (pins.length > 0) obj.pcs = pins;
|
||||
if (externalProxy.echConfigList && externalProxy.echConfigList.length > 0) obj.ech = externalProxy.echConfigList;
|
||||
}
|
||||
|
||||
export interface GenVmessLinkInput {
|
||||
@@ -280,6 +281,7 @@ function applyExternalProxyTLSParams(
|
||||
if (alpn.length > 0) params.set('alpn', alpn);
|
||||
const pins = externalProxyPins(externalProxy.pinnedPeerCertSha256);
|
||||
if (pins.length > 0) params.set('pcs', pins);
|
||||
if (externalProxy.echConfigList && externalProxy.echConfigList.length > 0) params.set('ech', externalProxy.echConfigList);
|
||||
}
|
||||
|
||||
export interface GenVlessLinkInput {
|
||||
|
||||
@@ -16,6 +16,7 @@ const newEntry = () => ({
|
||||
fingerprint: '',
|
||||
alpn: [],
|
||||
pinnedPeerCertSha256: [],
|
||||
echConfigList: '',
|
||||
});
|
||||
|
||||
function Field({ label, children }: { label: ReactNode; children: ReactNode }) {
|
||||
@@ -92,9 +93,9 @@ export default function ExternalProxyForm({
|
||||
/>
|
||||
</Form.Item>
|
||||
</Field>
|
||||
<Field label={t('host')}>
|
||||
<Field label={t('pages.inbounds.address')}>
|
||||
<Form.Item name={[field.name, 'dest']} noStyle>
|
||||
<Input placeholder={t('host')} />
|
||||
<Input placeholder={t('pages.inbounds.address')} />
|
||||
</Form.Item>
|
||||
</Field>
|
||||
<Field label={t('pages.inbounds.port')}>
|
||||
@@ -125,7 +126,7 @@ export default function ExternalProxyForm({
|
||||
<div className="ext-proxy-grid ext-proxy-grid--tls">
|
||||
<Field label="SNI">
|
||||
<Form.Item name={[field.name, 'sni']} noStyle>
|
||||
<Input placeholder={t('pages.inbounds.form.sniPlaceholder')} />
|
||||
<Input placeholder={t('pages.inbounds.form.serverNameIndication')} />
|
||||
</Form.Item>
|
||||
</Field>
|
||||
<Field label={t('pages.inbounds.form.fingerprint')}>
|
||||
@@ -157,6 +158,11 @@ export default function ExternalProxyForm({
|
||||
</Form.Item>
|
||||
</Field>
|
||||
</div>
|
||||
<Field label={t('pages.inbounds.form.echConfig')}>
|
||||
<Form.Item name={[field.name, 'echConfigList']} noStyle>
|
||||
<Input placeholder={t('pages.inbounds.form.echConfig')} />
|
||||
</Form.Item>
|
||||
</Field>
|
||||
<Field label={t('pages.inbounds.form.pinnedPeerCertSha256')}>
|
||||
<Space.Compact block>
|
||||
<Form.Item name={[field.name, 'pinnedPeerCertSha256']} noStyle>
|
||||
|
||||
@@ -23,5 +23,6 @@ export const ExternalProxyEntrySchema = z.object({
|
||||
),
|
||||
alpn: z.array(AlpnSchema).optional(),
|
||||
pinnedPeerCertSha256: z.array(z.string()).optional(),
|
||||
echConfigList: z.string().optional(),
|
||||
});
|
||||
export type ExternalProxyEntry = z.infer<typeof ExternalProxyEntrySchema>;
|
||||
|
||||
Reference in New Issue
Block a user