XTLS/Xray-core · error

invalid fakeDNS setting

Error message

invalid fakeDNS setting

What it means

The first chunk of a padding record must carry the varint length header (1-5 bytes), so writePaddingTurnWithBuffer requires chunks[0] >= header.Len(). With a generated (range-based) turn, defaultPaddingChunks sizes the first chunk at min(recordLength, writeChunkLength) which is always >= recordLength's own varint size, so this fires only with variant-based turns whose first post-prefix chunk is smaller than the encoded header.

Source

Thrown at app/dns/fakedns/fake.go:48

}

func (fkdns *Holder) GetFakeIPForDomain3(domain string, ipv4, ipv6 bool) []net.Address {
	isIPv6 := fkdns.ipRange.IP.To4() == nil
	if (isIPv6 && ipv6) || (!isIPv6 && ipv4) {
		return fkdns.GetFakeIPForDomain(domain)
	}
	return []net.Address{}
}

func (*Holder) Type() interface{} {
	return (*dns.FakeDNSEngine)(nil)
}

func (fkdns *Holder) Start() error {
	if fkdns.config != nil && fkdns.config.IpPool != "" && fkdns.config.LruSize != 0 {
		return fkdns.initializeFromConfig()
	}
	return errors.New("invalid fakeDNS setting")
}

func (fkdns *Holder) Close() error {
	// nothing to do for now, just wait GC
	return nil
}

func NewFakeDNSHolder() (*Holder, error) {
	var fkdns *Holder
	var err error

	if fkdns, err = NewFakeDNSHolderConfigOnly(nil); err != nil {
		return nil, errors.New("Unable to create Fake Dns Engine").Base(err).AtError()
	}
	err = fkdns.initialize(dns.FakeIPv4Pool, 65535)
	if err != nil {
		return nil, err
	}

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Enlarge the variant's first post-prefix chunk to at least 5 bytes (safe upper bound for any varint)
  2. Or reorder chunks so a chunk >= the encoded record length's varint size comes first
  3. Recompute after any prefix-length change, since trimming shifts which chunk is first

Example fix

// before: record ~300 bytes needs a 2-byte header, first chunk is 1
paddingVariant{chunks: []int{100, 1, 200}}
// after
paddingVariant{chunks: []int{100, 8, 193}}
Defensive patterns

Strategy: validation

Validate before calling

func firstChunkFitsHeader(v paddingVariant, prefix int) bool {
    chunks, _, err := trimPaddingPrefix(v, prefix)
    if err != nil || len(chunks) == 0 {
        return false
    }
    total := 0
    for _, c := range chunks {
        total += c
    }
    return chunks[0] >= len(Varint(total - 0).bytesIfAvailable()) // fallback: chunks[0] >= 5 is always safe
}

Prevention

When it happens

Trigger: A variant whose first chunk after prefix trimming is 1 byte while recordLength >= 128 (2-byte varint), or generally first chunk < varint length of the remaining record. Detected at write time, after validation has passed (validation checks chunk bounds but not header fit).

Common situations: Traffic-shaping variants crafted with a small leading chunk to mimic a specific protocol's first segment; prefix trimming that consumes large leading chunks and exposes a tiny next chunk.

Related errors


AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15). Data as JSON: /api/errors/789a9aa6589bf745. Report an issue: GitHub.