Просмотр исходного кода

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.
MHSanaei 9 часов назад
Родитель
Сommit
e62ad84bb7
2 измененных файлов с 111 добавлено и 1 удалено
  1. 67 1
      frontend/src/pages/inbounds/InboundFormModal.tsx
  2. 44 0
      frontend/src/pages/xray/OutboundFormModal.tsx

+ 67 - 1
frontend/src/pages/inbounds/InboundFormModal.tsx

@@ -1157,7 +1157,17 @@ export default function InboundFormModal({
                     onChange={(v) => {
                     onChange={(v) => {
                       setFieldValue(
                       setFieldValue(
                         ['streamSettings', 'tcpSettings', 'header'],
                         ['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>
           </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>
         </>
         </>
       )}
       )}
 
 

+ 44 - 0
frontend/src/pages/xray/OutboundFormModal.tsx

@@ -38,6 +38,7 @@ import {
   OutboundDomainStrategies,
   OutboundDomainStrategies,
   OutboundProtocols as Protocols,
   OutboundProtocols as Protocols,
   SNIFFING_OPTION,
   SNIFFING_OPTION,
+  TCP_CONGESTION_OPTION,
   TLS_FLOW_CONTROL,
   TLS_FLOW_CONTROL,
   USERS_SECURITY,
   USERS_SECURITY,
   UTLS_FINGERPRINT,
   UTLS_FINGERPRINT,
@@ -1516,6 +1517,49 @@ export default function OutboundFormModal({
                                   >
                                   >
                                     <Input />
                                     <Input />
                                   </Form.Item>
                                   </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>
                                 </>
                                 </>
                               )}
                               )}
                             </>
                             </>