{"record":{"id":"33cb84fc169f9be1","repo":"XTLS/Xray-core","slug":"unable-to-create-fake-dns-engine","errorCode":null,"errorMessage":"Unable to create Fake Dns Engine","messagePattern":"Unable to create Fake Dns Engine","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"app/dns/fakedns/fake.go","lineNumber":61,"sourceCode":"\nfunc (fkdns *Holder) Start() error {\n\tif fkdns.config != nil && fkdns.config.IpPool != \"\" && fkdns.config.LruSize != 0 {\n\t\treturn fkdns.initializeFromConfig()\n\t}\n\treturn errors.New(\"invalid fakeDNS setting\")\n}\n\nfunc (fkdns *Holder) Close() error {\n\t// nothing to do for now, just wait GC\n\treturn nil\n}\n\nfunc NewFakeDNSHolder() (*Holder, error) {\n\tvar fkdns *Holder\n\tvar err error\n\n\tif fkdns, err = NewFakeDNSHolderConfigOnly(nil); err != nil {\n\t\treturn nil, errors.New(\"Unable to create Fake Dns Engine\").Base(err).AtError()\n\t}\n\terr = fkdns.initialize(dns.FakeIPv4Pool, 65535)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn fkdns, nil\n}\n\nfunc NewFakeDNSHolderConfigOnly(conf *FakeDnsPool) (*Holder, error) {\n\treturn &Holder{config: conf}, nil\n}\n\nfunc (fkdns *Holder) initializeFromConfig() error {\n\treturn fkdns.initialize(fkdns.config.IpPool, int(fkdns.config.LruSize))\n}\n\nfunc (fkdns *Holder) initialize(ipPoolCidr string, lruSize int) error {\n\tvar ipRange *net.IPNet","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/app/dns/fakedns/fake.go#L43-L79","documentation":"Every chunk written must satisfy 1 <= chunkLength <= maxPaddingChunkLength (48 KiB); writePaddingTurnWithBuffer enforces this at write time and sizes its buffer from the max chunk. Both the validation pass (paddingTurnBounds) and defaultPaddingChunks respect this bound, so in the shipped flow this is a defensive invariant against arithmetic bugs or direct calls to the write path with unvalidated variant chunks.","triggerScenarios":"Calling writePaddingTurn/writePaddingTurnWithBuffer directly with variant chunks containing a value <= 0 or > 48 KiB; or a fork changing maxPaddingChunkLength/chunk computation inconsistently.","commonSituations":"Bypassing runPaddingSchedule in custom transport code; generating variant chunk lists from user data without clamping; integer overflow in custom chunk-splitting helpers.","solutions":["Clamp every variant chunk to [1, 48*1024] before writing","Split oversized chunks into multiple <= 48 KiB chunks","Prefer runPaddingSchedule, whose validation reports the offending variant index up front"],"exampleFix":"// before\npaddingVariant{chunks: []int{100, 0, 50000}}\n// after\npaddingVariant{chunks: []int{100, 1, 47 * 1024}}","handlingStrategy":"validation","validationCode":"for _, c := range variant.chunks {\n    if c < 1 || c > 48*1024 {\n        return fmt.Errorf(\"chunk %d out of bounds\", c)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always run runPaddingSchedule validation before writing turns","Clamp or split generated chunk lists to the 48 KiB cap"],"tags":["padding","chunks","validation","xmc"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}