mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-11-02 19:25:05 +03:00
fix(sub): bound what a remote routing profile renders to
Remote routing sources are fetched documents the panel re-renders on every subscription request. A Clash YAML document stays small through aliases, which decode to one shared value but are written out in full, so it now has to fit a 4 MiB written-size budget and 16 levels of nesting when it is accepted (and when a persisted copy is loaded). A JSON routing profile could repeat route groups, each copy repeating every site list; a group now counts once, since a repeat can never match.
This commit is contained in:
@@ -3,6 +3,7 @@ package sub
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -748,3 +749,32 @@ rules:
|
||||
t.Fatalf("requests=%d, want 1", requests.Load())
|
||||
}
|
||||
}
|
||||
|
||||
// Aliases decode to one shared value but the encoder writes every copy out, on each Clash
|
||||
// request, so a small remote document must not be accepted if it marshals out of bounds.
|
||||
func TestNormalizeClashRoutingRefusesWhatMarshalsOutOfBounds(t *testing.T) {
|
||||
var laughs strings.Builder
|
||||
laughs.WriteString("a0: &a0 [\"" + strings.Repeat("x", 64) + "\"]\n")
|
||||
for i := 1; i <= 9; i++ {
|
||||
fmt.Fprintf(&laughs, "a%d: &a%d [", i, i)
|
||||
for j := range 10 {
|
||||
if j > 0 {
|
||||
laughs.WriteString(",")
|
||||
}
|
||||
fmt.Fprintf(&laughs, "*a%d", i-1)
|
||||
}
|
||||
laughs.WriteString("]\n")
|
||||
}
|
||||
bomb := laughs.String() + "rule-providers:\n p: {type: inline, behavior: domain, payload: *a9}\nrules:\n - RULE-SET,p,DIRECT\n - MATCH,DIRECT\n"
|
||||
if _, _, err := normalizeClashRouting([]byte(bomb)); err == nil || !strings.Contains(err.Error(), "too large") {
|
||||
t.Fatalf("alias bomb = %v, want it refused as too large", err)
|
||||
}
|
||||
deep := "rules:\n - MATCH,DIRECT\nrule-providers:\n p: {type: inline, behavior: domain, payload: " + strings.Repeat("[", 40) + strings.Repeat("]", 40) + "}\n"
|
||||
if _, _, err := normalizeClashRouting([]byte(deep)); err == nil {
|
||||
t.Fatal("a document nested 40 levels deep was accepted")
|
||||
}
|
||||
anchored := "x: &common {type: http, behavior: domain, interval: 86400}\nrule-providers:\n ads: {<<: *common, url: \"https://example.com/ads.yaml\"}\nrules:\n - RULE-SET,ads,REJECT\n - MATCH,DIRECT\n"
|
||||
if _, _, err := normalizeClashRouting([]byte(anchored)); err != nil {
|
||||
t.Fatalf("an ordinary anchored document was refused: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user