mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-10-24 23:05:01 +03:00
c3394fefed
Public Mihomo templates ship rules, rule-providers and proxy-groups together with a dns block those rules depend on (fake-ip ranges, nameserver policy). Pasting a template inline keeps its dns, but pointing the global routing rules at its URL dropped it, so URL users had to give up auto-refresh to keep it. A new switch, subClashRemoteDNS (off by default), also takes the remote dns and sniffer maps. It is opt-in because a remote dns block decides where clients send every lookup. A malformed dns or sniffer value is skipped, not the whole template. The component-test teardown now outlasts AntD Form's 10ms error debounce, which otherwise fired after jsdom was gone.
76 lines
2.5 KiB
Go
76 lines
2.5 KiB
Go
package sub
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
|
|
)
|
|
|
|
// Clash has no shadowsocks tcp/http header, so the inbound path drops the node
|
|
// (applyTransport returns false) and the external-link path must drop it too,
|
|
// instead of handing mihomo a proxy that connects with the wrong obfuscation.
|
|
func TestClashExternalShadowsocksMatchesInboundPath(t *testing.T) {
|
|
const settings = `{"method":"aes-256-gcm","password":"inboundpw","clients":[{"password":"clientpw","email":"user"}]}`
|
|
// base64("aes-256-gcm:clientpw") — the SIP002 userinfo of the links below.
|
|
const userinfo = "YWVzLTI1Ni1nY206Y2xpZW50cHc"
|
|
|
|
tests := []struct {
|
|
name string
|
|
stream string
|
|
link string
|
|
wantDropped bool
|
|
}{
|
|
{
|
|
name: "plain tcp",
|
|
stream: `{"network":"tcp","security":"none"}`,
|
|
link: "ss://" + userinfo + "@203.0.113.1:8443?type=tcp#ss",
|
|
},
|
|
{
|
|
name: "tcp http header",
|
|
stream: `{"network":"tcp","security":"none","tcpSettings":{"header":{"type":"http","request":{"path":["/"],"headers":{"Host":["test"]}}}}}`,
|
|
link: "ss://" + userinfo + "@203.0.113.1:8443?type=tcp&headerType=http&host=test#ss",
|
|
wantDropped: true,
|
|
},
|
|
{
|
|
name: "tls",
|
|
stream: `{"network":"tcp","security":"tls","tlsSettings":{"serverName":"ss.sni"}}`,
|
|
link: "ss://" + userinfo + "@203.0.113.1:8443?type=tcp&security=tls&sni=ss.sni#ss",
|
|
},
|
|
}
|
|
|
|
svc := NewSubClashService(false, "", false, &SubService{})
|
|
client := model.Client{Password: "clientpw", Email: "user"}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
inbound := &model.Inbound{
|
|
Listen: "203.0.113.1",
|
|
Port: 8443,
|
|
Protocol: model.Shadowsocks,
|
|
Remark: "ss",
|
|
Settings: settings,
|
|
StreamSettings: tc.stream,
|
|
}
|
|
|
|
fromInbound := svc.buildProxy(svc.SubService, inbound, client, svc.streamData(tc.stream), nil)
|
|
fromLink := svc.clashProxyFromExternal(tc.link, "external")
|
|
|
|
if tc.wantDropped {
|
|
if fromInbound != nil || fromLink != nil {
|
|
t.Fatalf("not representable in clash, want both dropped: inbound %#v, link %#v", fromInbound, fromLink)
|
|
}
|
|
return
|
|
}
|
|
if fromInbound == nil || fromLink == nil {
|
|
t.Fatalf("want a proxy from both paths: inbound %#v, link %#v", fromInbound, fromLink)
|
|
}
|
|
delete(fromInbound, "name")
|
|
delete(fromLink, "name")
|
|
if !reflect.DeepEqual(fromInbound, fromLink) {
|
|
t.Fatalf("inbound %#v != link %#v", fromInbound, fromLink)
|
|
}
|
|
})
|
|
}
|
|
}
|