mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-08-17 08:40:59 +00:00
feat(mtproto): add domain-fronting and essential mtg options
Expose mtg's [domain-fronting] section (ip/port/proxy-protocol) plus proxy-protocol-listener, prefer-ip, and debug on MTProto inbounds. Each key is written to the generated mtg-<id>.toml only when set, so mtg's own defaults apply otherwise. The instance fingerprint now covers these fields, so editing an option restarts the sidecar. Since MTProto is mtg-served (not Xray), sniffing does not apply: hide the Sniffing tab and the Advanced sniffing sub-editor, drop it from the Advanced "All" JSON view, and emit empty sniffing in the wire payload, all gated by a new canEnableSniffing predicate.
This commit is contained in:
+72
-1
@@ -1,6 +1,7 @@
|
||||
package mtproto
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/database/model"
|
||||
@@ -37,7 +38,9 @@ func TestInstanceFromInbound(t *testing.T) {
|
||||
Listen: "0.0.0.0",
|
||||
Port: 8443,
|
||||
Protocol: model.MTProto,
|
||||
Settings: `{"fakeTlsDomain":"example.com","secret":""}`,
|
||||
Settings: `{"fakeTlsDomain":"example.com","secret":"",` +
|
||||
`"debug":true,"proxyProtocolListener":true,"preferIp":"prefer-ipv4",` +
|
||||
`"domainFronting":{"ip":"127.0.0.1","port":9443,"proxyProtocol":true}}`,
|
||||
}
|
||||
inst, ok := InstanceFromInbound(ib)
|
||||
if !ok {
|
||||
@@ -49,8 +52,76 @@ func TestInstanceFromInbound(t *testing.T) {
|
||||
if inst.Port != 8443 || inst.Id != 3 {
|
||||
t.Fatalf("bad instance %+v", inst)
|
||||
}
|
||||
if !inst.Debug || !inst.ProxyProtocolListener || inst.PreferIP != "prefer-ipv4" {
|
||||
t.Fatalf("scalar options not parsed: %+v", inst)
|
||||
}
|
||||
if inst.FrontingIP != "127.0.0.1" || inst.FrontingPort != 9443 || !inst.FrontingProxyProtocol {
|
||||
t.Fatalf("domain-fronting not parsed: %+v", inst)
|
||||
}
|
||||
|
||||
if _, ok := InstanceFromInbound(&model.Inbound{Protocol: model.VLESS}); ok {
|
||||
t.Fatal("non-mtproto inbound should not produce an instance")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRenderConfig(t *testing.T) {
|
||||
// A bare instance emits only the required keys and the prometheus block,
|
||||
// with no optional keys and no [domain-fronting] section.
|
||||
bare := renderConfig(Instance{Secret: "ee00", Listen: "0.0.0.0", Port: 8443}, 5000)
|
||||
for _, unwanted := range []string{"debug", "proxy-protocol-listener", "prefer-ip", "[domain-fronting]"} {
|
||||
if strings.Contains(bare, unwanted) {
|
||||
t.Fatalf("bare config should not contain %q:\n%s", unwanted, bare)
|
||||
}
|
||||
}
|
||||
if !strings.Contains(bare, `bind-to = "0.0.0.0:8443"`) {
|
||||
t.Fatalf("missing bind-to:\n%s", bare)
|
||||
}
|
||||
if !strings.Contains(bare, "[stats.prometheus]") || !strings.Contains(bare, "127.0.0.1:5000") {
|
||||
t.Fatalf("prometheus block must always be present:\n%s", bare)
|
||||
}
|
||||
|
||||
// A fully configured instance emits every option and the fronting section.
|
||||
full := renderConfig(Instance{
|
||||
Secret: "ee11", Listen: "0.0.0.0", Port: 443,
|
||||
Debug: true, ProxyProtocolListener: true, PreferIP: "only-ipv6",
|
||||
FrontingIP: "127.0.0.1", FrontingPort: 9443, FrontingProxyProtocol: true,
|
||||
}, 6000)
|
||||
for _, want := range []string{
|
||||
"debug = true\n",
|
||||
"proxy-protocol-listener = true\n",
|
||||
`prefer-ip = "only-ipv6"`,
|
||||
"[domain-fronting]",
|
||||
`ip = "127.0.0.1"`,
|
||||
"port = 9443",
|
||||
"proxy-protocol = true\n",
|
||||
} {
|
||||
if !strings.Contains(full, want) {
|
||||
t.Fatalf("full config missing %q:\n%s", want, full)
|
||||
}
|
||||
}
|
||||
// TOML requires top-level keys before any [section] header.
|
||||
if strings.Index(full, "prefer-ip") > strings.Index(full, "[domain-fronting]") {
|
||||
t.Fatalf("top-level keys must precede the [domain-fronting] section:\n%s", full)
|
||||
}
|
||||
if strings.LastIndex(full, "[domain-fronting]") > strings.Index(full, "[stats.prometheus]") {
|
||||
t.Fatalf("[domain-fronting] must precede [stats.prometheus]:\n%s", full)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFingerprintReactsToOptions(t *testing.T) {
|
||||
base := Instance{Secret: "ee", Listen: "0.0.0.0", Port: 443}
|
||||
for name, mutate := range map[string]func(*Instance){
|
||||
"debug": func(i *Instance) { i.Debug = true },
|
||||
"listener": func(i *Instance) { i.ProxyProtocolListener = true },
|
||||
"preferIp": func(i *Instance) { i.PreferIP = "only-ipv4" },
|
||||
"frontingIP": func(i *Instance) { i.FrontingIP = "127.0.0.1" },
|
||||
"frontingPort": func(i *Instance) { i.FrontingPort = 9443 },
|
||||
"frontingProxy": func(i *Instance) { i.FrontingProxyProtocol = true },
|
||||
} {
|
||||
changed := base
|
||||
mutate(&changed)
|
||||
if base.fingerprint() == changed.fingerprint() {
|
||||
t.Fatalf("fingerprint must change when %s changes", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user