# How FakeDNS Works in Xray-core: Complete Configuration Guide

> Learn how FakeDNS in Xray-core works to enable domain-based routing, even with DNS issues. Get a complete guide to configuring FakeDNS for seamless connectivity.

- Repository: [Project X Community, Not Porn-jet X Hub/Xray-core](https://github.com/XTLS/Xray-core)
- Tags: how-to-guide
- Published: 2026-04-21

---

**FakeDNS is a built-in DNS engine in Xray-core that synthesizes deterministic IP addresses for domain names, enabling domain-based routing even when actual DNS resolution is blocked or poisoned, and requires both `address: fakedns` in DNS servers and `destOverride: [fakedns]` in inbound sniffing to operate correctly.**

FakeDNS serves as a bridge between DNS resolution and traffic routing in the Xray-core proxy framework. By mapping domains to synthetic IP addresses from reserved ranges (`198.18.0.0/15` for IPv4 and `fc00::/18` for IPv6), it allows the proxy to handle connections based on domain names after the client has already resolved a fake IP. This implementation leverages an LRU cache for mapping management and integrates with the core's dispatcher for reverse lookups.

## Architecture and Implementation

The FakeDNS engine is implemented as a **Feature** interface (`dns.FakeDNSEngine`) that components can require for DNS resolution. The architecture follows a clear pipeline from configuration detection to packet sniffing.

### Configuration Detection and Loading

When the DNS server list contains an entry with `address: fakedns`, the core automatically loads the Fake DNS feature via `core.OptionalFeatures` in [`proxy/dns/dns.go`](https://github.com/XTLS/Xray-core/blob/main/proxy/dns/dns.go). The configuration parsing happens in [`infra/conf/fakedns.go`](https://github.com/XTLS/Xray-core/blob/main/infra/conf/fakedns.go), where the `FakeDNSConfig` struct handles either a single `pool` or multiple `pools`. The `FakeDNSPostProcessingStage` in the same file validates that at least one inbound has `sniffing.destOverride` set to `fakedns` (or `fakedns+others`), and creates default IPv4 and IPv6 pools if none are explicitly defined.

### The FakeDNSEngine Interface

The feature interface is defined in [`features/dns/fakedns.go`](https://github.com/XTLS/Xray-core/blob/main/features/dns/fakedns.go) as:

```go
type FakeDNSEngine interface {
    features.Feature
    GetFakeIPForDomain(domain string) []net.Address
    GetDomainFromFakeDNS(ip net.Address) string
}

```

This interface exposes the two core operations: generating fake IPs for domains and reverse-mapping fake IPs back to their original domains.

### IP Generation and Pool Management

The concrete implementation resides in [`app/dns/fakedns/fake.go`](https://github.com/XTLS/Xray-core/blob/main/app/dns/fakedns/fake.go) within the `Holder` struct. This struct maintains an **LRU cache** for domain-to-IP mappings and manages CIDR pools for address allocation.

During `Start()`, the holder initializes with either user-supplied pools or defaults to the standard reserved ranges. The `GetFakeIPForDomain` method generates IPs by adding a timestamp-derived offset to the pool's base address, checks the LRU for collisions to ensure uniqueness, and stores the mapping in [`app/dns/fakedns/fake.go`](https://github.com/XTLS/Xray-core/blob/main/app/dns/fakedns/fake.go) lines 99-130. The reverse lookup via `GetDomainFromFakeDNS` queries this cache and returns an empty string if the IP is not in the managed pool.

### DNS Server Integration

The [`app/dns/nameserver_fakedns.go`](https://github.com/XTLS/Xray-core/blob/main/app/dns/nameserver_fakedns.go) file implements a DNS server wrapper that forwards incoming DNS queries to the Fake DNS engine. When a query arrives, it calls `GetFakeIPForDomain` (or `GetFakeIPForDomain3` for IPv4/IPv6-specific responses) and returns the generated IP with a TTL of 1, minimizing DNS caching on the client side.

### Sniffer Integration and Reverse Lookup

The dispatcher creates a "fake DNS sniffer" implemented in [`app/dispatcher/fakednssniffer.go`](https://github.com/XTLS/Xray-core/blob/main/app/dispatcher/fakednssniffer.go). When it detects traffic destined for a fake IP address, it queries the engine via `GetDomainFromFakeDNS` to retrieve the original domain. This allows routing rules that depend on domain names (such as site-based routing) to function correctly even after the connection has been NAT-ed to a synthetic IP address.

## Configuration Examples

### Minimal Configuration

To enable FakeDNS, you must configure both the DNS servers and the inbound sniffing override:

```yaml
dns:
  servers:
    - address: fakedns

inbounds:
  - port: 1080
    protocol: vmess
    sniffing:
      enabled: true
      destOverride: [fakedns]

```

If the `fakeDns` section is omitted, `FakeDNSPostProcessingStage` automatically creates default pools using `198.18.0.0/15` for IPv4 and `fc00::/18` for IPv6 according to the logic in [`infra/conf/fakedns.go`](https://github.com/XTLS/Xray-core/blob/main/infra/conf/fakedns.go) lines 92-118.

### Custom Pool Configuration

For explicit control over IP ranges and pool sizes:

```yaml
dns:
  servers:
    - address: fakedns
  queryStrategy: UseIPv4

fakeDns:
  pools:
    - ipPool: 198.18.0.0/15
      poolSize: 32768
    - ipPool: fc00::/18
      poolSize: 32768

inbounds:
  - port: 1080
    protocol: vmess
    sniffing:
      enabled: true
      destOverride: [fakedns]

```

### Protocol-Specific FakeDNS

To force FakeDNS to use only IPv4 or IPv6 pools, set the `queryStrategy` in the DNS configuration. This setting propagates through `FakeDNSPostProcessingStage` which sets `isIPv4Enable` and `isIPv6Enable` flags based on the strategy, and the server calls `GetFakeIPForDomain3` respecting these flags as implemented in [`app/dns/nameserver_fakedns.go`](https://github.com/XTLS/Xray-core/blob/main/app/dns/nameserver_fakedns.go) lines 34-36.

```yaml
dns:
  servers:
    - address: fakedns
  queryStrategy: UseIPv6  # Forces IPv6 fake pool only

```

## Programmatic Usage

You can interact with the FakeDNS engine directly in Go applications:

```go
import (
    "github.com/xtls/xray-core/app/dns/fakedns"
    "github.com/xtls/xray-core/features/dns"
    "github.com/xtls/xray-core/common/net"
)

// Initialize with default IPv4 pool
holder, _ := fakedns.NewFakeDNSHolder()
holder.Start()

// Generate fake IP for domain
ips := holder.GetFakeIPForDomain("example.com")
fakeIP := ips[0].IP()

// Reverse lookup
domain := holder.GetDomainFromFakeDNS(ips[0])

// The holder implements dns.FakeDNSEngine
var engine dns.FakeDNSEngine = holder

```

This code mirrors the production implementation in [`app/dns/fakedns/fake.go`](https://github.com/XTLS/Xray-core/blob/main/app/dns/fakedns/fake.go), utilizing the same `Holder` struct that manages the LRU cache and CIDR-based allocation.

## Summary

- **FakeDNS** in Xray-core generates synthetic IPs from reserved ranges (`198.18.0.0/15` and `fc00::/18`) to enable domain-based routing.
- **Configuration** requires `address: fakedns` in DNS servers and `destOverride: [fakedns]` in inbound sniffing settings.
- **Implementation** centers on the `dns.FakeDNSEngine` interface in [`features/dns/fakedns.go`](https://github.com/XTLS/Xray-core/blob/main/features/dns/fakedns.go), with concrete logic in [`app/dns/fakedns/fake.go`](https://github.com/XTLS/Xray-core/blob/main/app/dns/fakedns/fake.go).
- **Key components** include the `Holder` struct for LRU cache management, [`nameserver_fakedns.go`](https://github.com/XTLS/Xray-core/blob/main/nameserver_fakedns.go) for query handling, and [`fakednssniffer.go`](https://github.com/XTLS/Xray-core/blob/main/fakednssniffer.go) for reverse IP-to-domain mapping.
- **IP generation** uses timestamp-derived offsets to prevent collisions, while reverse lookup enables routing rules to function post-resolution.

## Frequently Asked Questions

### What are the default IP ranges used by FakeDNS?

By default, Xray-core allocates fake IPs from `198.18.0.0/15` for IPv4 and `fc00::/18` for IPv6. These ranges are defined as constants `FakeIPv4Pool` and `FakeIPv6Pool` in [`features/dns/fakedns.go`](https://github.com/XTLS/Xray-core/blob/main/features/dns/fakedns.go) and are automatically used when no explicit pool configuration is provided.

### Why is my FakeDNS configuration not working?

The most common issue is missing the `destOverride: [fakedns]` setting in your inbound configuration. The `FakeDNSPostProcessingStage` in [`infra/conf/fakedns.go`](https://github.com/XTLS/Xray-core/blob/main/infra/conf/fakedns.go) explicitly validates that at least one inbound has sniffing enabled with `fakedns` in the destination override list. Without this, the sniffer cannot map fake IPs back to domains, breaking domain-based routing.

### How does FakeDNS handle domain collisions?

The `Holder` implementation in [`app/dns/fakedns/fake.go`](https://github.com/XTLS/Xray-core/blob/main/app/dns/fakedns/fake.go) uses an LRU (Least Recently Used) cache to store domain-to-IP mappings. When `GetFakeIPForDomain` generates a new IP using a timestamp-derived offset, it first checks the cache for existing mappings. If a collision occurs (the generated IP is already assigned), the system handles it within the cache logic to maintain deterministic one-to-one mappings between domains and fake IPs.

### Can I use FakeDNS with IPv6-only networks?

Yes. Set `queryStrategy: UseIPv6` in your DNS configuration to force the FakeDNS engine to only allocate addresses from the IPv6 pool (`fc00::/18`). The `GetFakeIPForDomain3` method in the nameserver implementation respects the IPv4/IPv6 enable flags set during the post-processing stage, allowing single-stack operation.