# Routing (Routing)

### Adding profiles

Routing profiles can be added via:

* Clipboard
* Deeplink links
* QR codes
* HTTP headers (`routing`)
* Subscription body (body)

### Link types

| Link format                     | Description                                                          |
| ------------------------------- | -------------------------------------------------------------------- |
| `incy://routing/add/{base64}`   | Adds a profile; activated after geofiles are successfully downloaded |
| `incy://routing/onadd/{base64}` | Adds and immediately activates the profile                           |

> `{base64}` — a JSON profile encoded in base64.

> Backward compatibility: links `://routing/add/` and `://routing/onadd/` are also supported.

### Error handling

The geofile download manager runs in the background:

* Downloads longer than 3 minutes are interrupted
* Error messages are displayed on the main screen
* Problematic profiles are marked with a red exclamation mark in the list
* Issues disappear after files are successfully downloaded or the profile is deleted

### HTTP header

The profile is passed in the header `routing` in base64 format. Two formats are supported:

**Format 1 — base64 directly:**

```
HTTP/2 200
routing: ewogICJOYW1lIjogIlJvc2NvbVZQTiIs...
```

**Format 2 — full link (any scheme):**

```
HTTP/2 200
routing: ://routing/onadd/ewogICJOYW1lIjogIlJvc2NvbVZQTiIs...
```

### Subscription body

The routing string is placed in the subscription body along with server configurations:

```
vless://uuid@server1:443?security=tls#Server1
vmess://eyJhZGQiOiAic2VydmVyMi...
incy://routing/onadd/ewogICJOYW1lIjogIlJvc2NvbVZQTiIs...
```

### Updating existing profiles

* Profiles with the same field `Name` are updated, not duplicated
* Field `LastUpdated` with Unix timestamp controls freshness — an update occurs when the value is greater than that of the saved profile

***

### Profile structure

#### Profile example

```json
{
    "Name": "RoscomVPN",
    "GlobalProxy": "true",
    "RemoteDNSType": "DoH",
    "RemoteDNSDomain": "https://cloudflare-dns.com/dns-query",
    "RemoteDNSIP": "1.1.1.1",
    "DomesticDNSType": "DoH",
    "DomesticDNSDomain": "https://dns.google/dns-query",
    "DomesticDNSIP": "8.8.8.8",
    "Geoipurl": "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat",
    "Geositeurl": "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat",
    "DnsHosts": {
        "cloudflare-dns.com": "1.1.1.1",
        "dns.google": "8.8.8.8"
    },
    "DirectSites": ["geosite:ru"],
    "DirectIp": ["geoip:ru", "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "169.254.0.0/16", "224.0.0.0/4", "255.255.255.255"],
    "ProxySites": [],
    "ProxyIp": [],
    "BlockSites": ["geosite:category-ads-all"],
    "BlockIp": [],
    "DomainStrategy": "IPIfNonMatch",
    "FakeDNS": "false"
}
```

#### Field description

**Main settings**

| Field         | Type   | Default     | Description                                                                                                                             |
| ------------- | ------ | ----------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `Name`        | string | `"Default"` | Profile name                                                                                                                            |
| `GlobalProxy` | string | `"true"`    | `"true"` — all traffic through the proxy; `"false"` — direct connection. Determines behavior when there are no matches in routing rules |
| `LastUpdated` | string |             | Unix timestamp. Controls forced geofile updates on first save or when updating a profile with a newer timestamp                         |

**DNS settings**

The system splits DNS queries into remote (Remote, through proxy) and local (Domestic, direct connection).

**Remote DNS** (for proxy resources):

| Field             | Type   | Default                                  | Description                                                  |
| ----------------- | ------ | ---------------------------------------- | ------------------------------------------------------------ |
| `RemoteDNSType`   | string | `"DoH"`                                  | Protocol: `DoH`, `DoU`                                       |
| `RemoteDNSDomain` | string | `"https://cloudflare-dns.com/dns-query"` | DNS server address (required for DoH)                        |
| `RemoteDNSIP`     | string | `"1.1.1.1"`                              | DNS server IP                                                |
| `RemoteDns`       | string |                                          | Alternative field for `RemoteDNSIP` (backward compatibility) |

**Local DNS** (for direct resources):

| Field               | Type   | Default                          | Description                                                    |
| ------------------- | ------ | -------------------------------- | -------------------------------------------------------------- |
| `DomesticDNSType`   | string | `"DoH"`                          | Protocol: `DoH`, `DoU`                                         |
| `DomesticDNSDomain` | string | `"https://dns.google/dns-query"` | DNS server address                                             |
| `DomesticDNSIP`     | string | `"8.8.8.8"`                      | DNS server IP                                                  |
| `DomesticDns`       | string |                                  | Alternative field for `DomesticDNSIP` (backward compatibility) |

**Additional DNS settings:**

| Field      | Type   | Description                                                                                                                |
| ---------- | ------ | -------------------------------------------------------------------------------------------------------------------------- |
| `DnsHosts` | object | Manual DNS records (analogous to a hosts file). Format: `{"domain": "ip"}`                                                 |
| `FakeDNS`  | string | `"true"` — substitutes virtual IPs instead of real ones so that Xray processes all requests according to the configuration |

**Routing rules**

Traffic is distributed into three categories:

| Field         | Type      | Description                                          |
| ------------- | --------- | ---------------------------------------------------- |
| `DirectSites` | string\[] | Domains/categories for direct access (without proxy) |
| `DirectIp`    | string\[] | IP addresses and subnets for direct access           |
| `ProxySites`  | string\[] | Domains/categories routed through the proxy          |
| `ProxyIp`     | string\[] | IP addresses and subnets through the proxy           |
| `BlockSites`  | string\[] | Blocked domains/categories (ads, trackers)           |
| `BlockIp`     | string\[] | Blocked IP addresses and subnets                     |

The rules support geo-categories (`geosite:ru`, `geoip:ru`), specific domains and IP/CIDR subnets.

**Geofiles**

| Field        | Type   | Description                       |
| ------------ | ------ | --------------------------------- |
| `Geoipurl`   | string | URL for downloading `geoip.dat`   |
| `Geositeurl` | string | URL for downloading `geosite.dat` |

**Routing strategy**

Field `DomainStrategy` defines the order of rule checks:

| Value          | Description                                                                    |
| -------------- | ------------------------------------------------------------------------------ |
| `AsIs`         | Domains are passed as is, without DNS resolution                               |
| `IPIfNonMatch` | First check by domain; if there is no match, resolve DNS and check by IP rules |
| `IPOnDemand`   | Always resolves domains to IP before checking rules                            |

***

### Geofiles: optimized downloading

Geofiles (`geoip.dat`, `geosite.dat`) are downloaded from the URLs specified in the profile. A hash check is used to save traffic.

#### Algorithm

1. Downloaded `{filename}.sha256` (a few bytes) from the same URL
2. If the hash matches the saved one **and** the file exists locally → download is skipped (even during manual update)
3. If the file `.sha256` is unavailable → fallback to timestamp comparison `LastUpdated`
4. The full file is downloaded → SHA-256 is computed → the file is replaced
5. The new hash is saved in the profile

#### Recommendation for providers

Place the file `geoip.dat.sha256` and `geosite.dat.sha256` next to the geofiles. The file should contain only the hex string of the SHA-256 hash (64 characters). This will allow clients to skip downloading unchanged files and save traffic.

Example content `geoip.dat.sha256`:

```
38c25fea171323e0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4
```

***

### Trimming geofiles (chunk files)

Full geoip/geosite files are tens of megabytes. If a profile uses only a limited subset of `geoip:`/`geosite:` tags, the client can trim the downloaded files down to the entries actually needed.

#### Profile field

| Field           | Type    | Description                                                                                                               |
| --------------- | ------- | ------------------------------------------------------------------------------------------------------------------------- |
| `useChunkFiles` | boolean | If `true` — the client calls the internal `CutGeoData()` after downloading and keeps only the tags mentioned in the rules |

* **Default** `false` on all platforms — backward compatibility with old profiles.
* **Android / iOS** implement trimming via the built-in Go module `incycore.CutGeoData()` (protobuf parsing of geoip/geosite and removal of unnecessary entries).
* **Desktop (Linux / Windows)** currently uses full files — `useChunkFiles` ignored; the xray process works with untrimmed `.dat`.
* After trimming, the hash is recalculated locally and saved in the profile — re-downloading will not start until the source `.sha256` on the server changes.

#### When to use

Enable it if:

* In `proxy` / `direct` / `block` few geotags are used (for example, only `geoip:ru`, `geoip:cn`, `geosite:google`).
* Users complain about memory usage when loading heavy lists.

Do not enable if:

* The profile uses many tags — trimming will not provide any benefit.
* There are custom geosite files with a non-standard layout — the client may not recognize the structure.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://incy.gitbook.io/docs/docs-en/developer-documentation/routing-routing.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
