{"record":{"id":"2ea38312a2dd1525","repo":"XTLS/Xray-core","slug":"fakednsengine-is-not-initialized-but-such-a-sniff","errorCode":null,"errorMessage":"FakeDNSEngine is not initialized, but such a sniffer is used","messagePattern":"FakeDNSEngine is not initialized, but such a sniffer is used","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/dispatcher/fakednssniffer.go","lineNumber":26,"sourceCode":"\t\"github.com/xtls/xray-core/common/errors\"\n\t\"github.com/xtls/xray-core/common/net\"\n\t\"github.com/xtls/xray-core/common/session\"\n\t\"github.com/xtls/xray-core/core\"\n\t\"github.com/xtls/xray-core/features/dns\"\n)\n\n// newFakeDNSSniffer Creates a Fake DNS metadata sniffer\nfunc newFakeDNSSniffer(ctx context.Context) (protocolSnifferWithMetadata, error) {\n\tvar fakeDNSEngine dns.FakeDNSEngine\n\t{\n\t\tfakeDNSEngineFeat := core.MustFromContext(ctx).GetFeature((*dns.FakeDNSEngine)(nil))\n\t\tif fakeDNSEngineFeat != nil {\n\t\t\tfakeDNSEngine = fakeDNSEngineFeat.(dns.FakeDNSEngine)\n\t\t}\n\t}\n\n\tif fakeDNSEngine == nil {\n\t\terrNotInit := errors.New(\"FakeDNSEngine is not initialized, but such a sniffer is used\").AtError()\n\t\treturn protocolSnifferWithMetadata{}, errNotInit\n\t}\n\treturn protocolSnifferWithMetadata{protocolSniffer: func(ctx context.Context, bytes []byte) (SniffResult, error) {\n\t\toutbounds := session.OutboundsFromContext(ctx)\n\t\tob := outbounds[len(outbounds)-1]\n\t\tif ob.Target.Network == net.Network_TCP || ob.Target.Network == net.Network_UDP {\n\t\t\tdomainFromFakeDNS := fakeDNSEngine.GetDomainFromFakeDNS(ob.Target.Address)\n\t\t\tif domainFromFakeDNS != \"\" {\n\t\t\t\terrors.LogInfo(ctx, \"fake dns got domain: \", domainFromFakeDNS, \" for ip: \", ob.Target.Address.String())\n\t\t\t\treturn &fakeDNSSniffResult{domainName: domainFromFakeDNS}, nil\n\t\t\t}\n\t\t}\n\n\t\tif ipAddressInRangeValueI := ctx.Value(ipAddressInRange); ipAddressInRangeValueI != nil {\n\t\t\tipAddressInRangeValue := ipAddressInRangeValueI.(*ipAddressInRangeOpt)\n\t\t\tif fkr0, ok := fakeDNSEngine.(dns.FakeDNSEngineRev0); ok {\n\t\t\t\tinPool := fkr0.IsIPInIPPool(ob.Target.Address)\n\t\t\t\tipAddressInRangeValue.addressInRange = &inPool","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/app/dispatcher/fakednssniffer.go#L8-L44","documentation":"The first padding turn must carry the protocol prefix (e.g. an early data / auth tag) followed by at least one byte of real padding record, so validatePaddingSchedule requires schedule[0]'s minimum total length to exceed firstTurnPrefixLength. If minLength - firstTurnPrefixLength < 1, the smallest possible turn cannot hold even one record byte and the schedule is rejected.","triggerScenarios":"firstTurnPrefixLength >= minLength of turn 0 (e.g. prefix 100 with minLength 100 or 99). Triggered by runPaddingSchedule with a non-zero prefix and a short first turn; fails during up-front validation.","commonSituations":"Enabling 0-RTT / early data (which raises the prefix length) without enlarging the first turn's minLength; hand-tuning minLength down for smaller overhead; a server profile with a large prefix paired with a client's short-turn schedule.","solutions":["Increase turn 0 minLength so it is at least firstTurnPrefixLength + 1","Or reduce firstTurnPrefixLength (e.g. smaller/no early data) if the prefix is under your control","Verify both peers use matching prefix expectations for the first turn"],"exampleFix":"// before\nrunPaddingSchedule(r, w, true, 64, []paddingTurn{{\n  direction: paddingClientToServer, minLength: 64, maxLength: 128,\n}})\n// after\nrunPaddingSchedule(r, w, true, 64, []paddingTurn{{\n  direction: paddingClientToServer, minLength: 65, maxLength: 128,\n}})","handlingStrategy":"validation","validationCode":"if len(schedule) > 0 && schedule[0].minLength-firstTurnPrefixLength < 1 {\n    return fmt.Errorf(\"first turn must exceed prefix %d\", firstTurnPrefixLength)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep firstTurnPrefixLength and schedule[0] bounds in the same config block so they change together","When enabling early data, re-check turn 0 minLength >= prefix + 1"],"tags":["padding","config","validation","prefix","early-data","xmc"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}