Routing and DNS: fake-IP, policy, rule providers, and leak prevention
This tutorial combines, in one complete profile:
- fake-IP DNS.
nameserver-policy.domain,ipcidr, andclassicalrule providers.- Rules from precise exceptions down to a final
MATCH. - Controller DNS queries, rule hit counters, and provider status.
- Common DNS, IPv6, UDP, and TUN leak checks.
Finish Your first proxy profile first and confirm a single proxy works before adding complex routing. Otherwise “the node is broken” and “the rules / DNS are wrong” are hard to tell apart.
Goal
Traffic should end up like this:
| Kind | Result |
|---|---|
| Ad / tracker test domains | REJECT |
| LAN / internal domains and RFC 1918 addresses | DIRECT |
example.com | DIRECT, as a reproducible rule test |
ipify.org | PROXY, as a reproducible proxy test |
| Everything else | PROXY |
| Ordinary DNS names | Return a fake-IP, then Aster restores the domain |
| Private, mDNS, and time-sync names | Do not use fake-IP |
Prerequisites
You need:
- Aster Core that can start normally.
- One already-working proxy. The complete YAML on this page uses AnyTLS + REALITY; every
<...>must be replaced with your values. 127.0.0.1:7890,:1053, and:9090not taken by another program.- Optional:
dig,jq, andtcpdumpto inspect results.
Test on loopback first
This page keeps DNS, the mixed proxy, and the Controller listening on 127.0.0.1 only. Do not change them to 0.0.0.0 just so the LAN can connect. DNS recursion, an unauthenticated proxy, and the Controller each need their own firewall, ACL, and authentication design.
1. Understand the fake-IP data path first
Ordinary DNS mode hands the real IP from upstream back to the application. Fake-IP mode is:
- The application queries Aster DNS for
www.example.org. - Aster returns a reserved address in
198.18.0.0/16. - Traffic enters Aster through the mixed / TUN / transparent-proxy inbound.
- Aster restores
www.example.orgfrom the fake-IP mapping. - Domain rules match the original domain, then choose
DIRECT,PROXY, orREJECT.
The benefit is that domain rules do not depend on a possibly poisoned local lookup. The important requirement is that DNS and the later traffic both go through the same Aster runtime. If an app gets 198.18.x.x and then connects out the physical NIC, that host does not exist on the network and the connection fails.
fake-ip-filter is for names that should not use fake-IP, for example:
.lan,.local, and mDNS.- Printers, NAS boxes, game consoles, or captive portals that need a real IP.
- NTP, connectivity checks, or some P2P / VoIP services.
2. Write the complete cookbook profile
Create or review config.yaml under the Aster home. The profile below is a complete structure; replace every <...> first:
mixed-port: 7890
allow-lan: false
mode: rule
# Use debug during the tutorial, then change it back to info.
log-level: debug
ipv6: false
external-controller: 127.0.0.1:9090
secret: "<CONTROLLER_SECRET>"
profile:
store-selected: true
store-fake-ip: true
dns:
enable: true
listen: 127.0.0.1:1053
ipv6: false
cache-algorithm: arc
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
# Bootstrap resolvers may only be raw IPs or system.
default-nameserver:
- 1.1.1.1
- 8.8.8.8
# Ordinary queries use encrypted DNS. IP literals avoid an extra hostname bootstrap.
nameserver:
- https://1.1.1.1/dns-query
- https://8.8.8.8/dns-query
# Resolve proxy node hostnames so you do not create a “need a proxy to resolve the proxy” loop.
proxy-server-nameserver:
- https://1.1.1.1/dns-query
- https://8.8.8.8/dns-query
# Default false: nameserver / fallback connections do not go through rules again.
respect-rules: false
# In blacklist mode, hits use a real IP; non-hits use fake-IP.
fake-ip-filter-mode: blacklist
fake-ip-filter:
- "*.lan"
- "*.local"
- "time.*.com"
- "rule-set:private-domains"
# Ordinary domain matchers, GEOSITE, or domain/classical rule sets are all valid.
nameserver-policy:
"rule-set:private-domains":
- system
"+.example.com":
- https://1.1.1.1/dns-query
proxies:
- name: Edge-AnyTLS-REALITY
type: anytls
server: <ASTER_SERVER_HOST_OR_IP>
port: 443
password: "<ANYTLS_PASSWORD>"
sni: <REALITY_SNI_FROM_SERVER>
client-fingerprint: chrome
reality-opts:
public-key: <REALITY_PUBLIC_KEY>
short-id: <REALITY_SHORT_ID>
udp: true
proxy-groups:
- name: PROXY
type: select
proxies:
- Edge-AnyTLS-REALITY
- DIRECT
rule-providers:
# domain behavior payloads contain only domain matchers.
private-domains:
type: inline
behavior: domain
payload:
- "+.lan"
- "+.local"
- "+.internal.example"
# ipcidr behavior payloads contain only IP prefixes.
private-cidrs:
type: inline
behavior: ipcidr
payload:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
- 127.0.0.0/8
- 169.254.0.0/16
# classical behavior holds full rules, but without a final target.
tutorial-ads:
type: inline
behavior: classical
payload:
- DOMAIN-SUFFIX,ads.example
- DOMAIN-KEYWORD,tracker
rules:
# Start with the most specific traffic that must not leave the machine.
- RULE-SET,tutorial-ads,REJECT
- RULE-SET,private-domains,DIRECT
- RULE-SET,private-cidrs,DIRECT,no-resolve
# Reproducible direct and proxy tests.
- DOMAIN-SUFFIX,example.com,DIRECT
- DOMAIN-SUFFIX,ipify.org,PROXY
# The final rule always comes last.
- MATCH,PROXYIf you are not using AnyTLS, replace the proxies block using Outbounds and groups. Keep the name Edge-AnyTLS-REALITY, or update the PROXY.proxies references to match.
3. Understand nameserver-policy
nameserver-policy picks a different resolver from the queried name. The example has two entries:
nameserver-policy:
"rule-set:private-domains":
- system
"+.example.com":
- https://1.1.1.1/dns-query- Names that hit
private-domainsgo to the system resolver, which is a good fit for internal DNS from DHCP / VPN. example.comand its subdomains always go to Cloudflare DoH.- Names that miss the policy use
nameserver.
Valid key forms include:
nameserver-policy:
"www.example.com": 1.1.1.1
"+.corp.example": 10.0.0.53
"geosite:private": system
"rule-set:internal-domains":
- 10.0.0.53
- 10.0.0.54default-nameserver is not an ordinary domain policy. It bootstraps DoH / DoT upstreams that contain a hostname, so the program requires a raw-IP resolver or system. Do not put a value such as https://dns.example/dns-query there; that still needs a hostname lookup first.
A rule-set: policy may only reference:
behavior: domain.behavior: classical, but only the domain-class rules take part in DNS policy.
behavior: ipcidr has no domain to match, so it cannot be used in nameserver-policy or fake-ip-filter.
How to see which upstream was chosen
The tutorial YAML uses log-level: debug. During a query you can find:
[DNS] resolve <domain> A from <upstream><upstream> shows the selected DNS address. After you have confirmed it, change log-level back to info so production does not generate a flood of logs.
4. Design rule order
rules match from top to bottom; the first hit decides the target. A practical order is usually:
- Safety blocks and very precise exceptions.
- LAN / internal domains.
- Private IPs and IP rules that should not resolve.
- Explicit direct or proxied services.
- Larger GEOIP / GEOSITE / rule sets.
- The final
MATCH.
The cookbook below can be inserted before MATCH in the complete YAML as needed:
rules:
# Single host and suffix.
- DOMAIN,api.example.com,PROXY
- DOMAIN-SUFFIX,example.net,DIRECT
# Keywords and regular expressions should stay specific to avoid collateral hits.
- DOMAIN-KEYWORD,tracker,REJECT
- DOMAIN-REGEX,^ads[0-9]*\.,REJECT
# When an IP rule already has a destination IP, add no-resolve so matching does not trigger a lookup.
- IP-CIDR,203.0.113.0/24,REJECT,no-resolve
- IP-CIDR6,2001:db8::/32,REJECT,no-resolve
# Port / network conditions.
- DST-PORT,22,DIRECT
- NETWORK,UDP,PROXY
- MATCH,PROXY203.0.113.0/24 and 2001:db8::/32 are documentation reserved ranges. They are not something you should block in a production profile just because they appear here.
Put domain rules ahead of IP rules that trigger resolution
When metadata still has a hostname, domain rules can match it directly. Putting a large set of resolve-required IP / GEOIP rules first can add DNS latency. Rules that can use no-resolve should say so explicitly.
5. Choose a rule-provider behavior
domain
Contains only domain matchers. Good for domain blocks, direct lists, and DNS policy:
rule-providers:
streaming-domains:
type: inline
behavior: domain
payload:
- "+.video.example"
- "api.media.example"Reference:
rules:
- RULE-SET,streaming-domains,PROXYipcidr
Contains only IPv4 / IPv6 CIDRs. Good for private networks or an already-curated IP list:
rule-providers:
office-networks:
type: inline
behavior: ipcidr
payload:
- 10.20.0.0/16
- 2001:db8:20::/48
rules:
- RULE-SET,office-networks,DIRECT,no-resolveclassical
Each item is full rule syntax, but the provider itself has no target. The outer RULE-SET supplies the target:
rule-providers:
mixed-blocklist:
type: inline
behavior: classical
payload:
- DOMAIN-SUFFIX,ads.example
- DOMAIN-KEYWORD,telemetry
- IP-CIDR,203.0.113.0/24,no-resolve
rules:
- RULE-SET,mixed-blocklist,REJECTClassical is the most flexible, but large lists usually cost more CPU and memory than dedicated domain / ipcidr sets.
6. Switch to a local or remote provider
type: inline is best for a self-contained tutorial. Production can use file or http.
Local YAML provider
Configuration:
rule-providers:
local-direct:
type: file
behavior: domain
format: yaml
path: ./rules/local-direct.yaml./rules/local-direct.yaml:
payload:
- "+.example.com"
- "updates.example.net"A relative path is resolved from the Aster home. By default only safe paths inside the home directory are allowed. If you need another root, set SAFE_PATHS explicitly instead of disabling the safe-path check.
Remote MRS provider
rule-providers:
remote-ads:
type: http
behavior: domain
format: mrs
url: https://<TRUSTED_PROVIDER_HOST>/rules/ads.mrs
path: ./rules/remote-ads.mrs
interval: 86400
proxy: DIRECT
size-limit: 5242880Notes:
<TRUSTED_PROVIDER_HOST>must be an HTTPS origin you trust.pathshould be a dedicated file under home so providers do not overwrite each other.intervalis in seconds.proxycontrols which outbound / group downloads the provider. If you setPROXY, the proxy must already be usable at startup.size-limitcaps an untrusted or abnormal response.- MRS only supports
domainandipcidr, notclassical.
A YAML provider needs a top-level payload: (or rules:). A text provider is one item per line. MRS is a binary format; convert with Aster:
aster-core convert-ruleset domain yaml source.yaml target.mrs
aster-core convert-ruleset ipcidr text source.txt target.mrsDo not treat arbitrary subscription content as trusted configuration. A provider can redirect a large amount of traffic. Before you go live, pin the source, use HTTPS, limit size, and keep the previous version for rollback.
7. Validate and start
Linux / macOS:
./aster-core -d ./config -f ./config/config.yaml -t
./aster-core -d ./config -f ./config/config.yamlPowerShell:
.\aster-core.exe -d .\config -f .\config\config.yaml -t
.\aster-core.exe -d .\config -f .\config\config.yamlValidation checks:
- Rule targets that exist as a proxy / group.
RULE-SETnames that exist.- Nameserver policy that references a usable domain/classical provider.
- Fake-IP range, filter, and DNS upstream format.
- Provider behavior / format / path.
-t does not prove a remote provider URL, internal DNS, or the proxy node can be reached. You still need runtime tests.
8. Verify DNS and fake-IP
Query the DNS listener directly
dig @127.0.0.1 -p 1053 example.org A +shortOrdinary domains should return a fake-IP in 198.18.0.0/16.
Query a time-sync name from the filter:
dig @127.0.0.1 -p 1053 time.apple.com A +shortIf the upstream can resolve it, this should return a real IP, not 198.18.x.x.
Without dig, use the Controller:
curl -fsS \
-H 'Authorization: Bearer <CONTROLLER_SECRET>' \
'http://127.0.0.1:9090/dns/query?name=example.org&type=A'Flush DNS and fake-IP cache
After you change policy, filters, or providers, old cache can make results look unchanged:
curl -fsS -X POST \
-H 'Authorization: Bearer <CONTROLLER_SECRET>' \
http://127.0.0.1:9090/cache/dns/flush
curl -fsS -X POST \
-H 'Authorization: Bearer <CONTROLLER_SECRET>' \
http://127.0.0.1:9090/cache/fakeip/flushBoth endpoints return HTTP 204 No Content on success. The OS, browser, and application may still have their own DNS caches; flush or restart those separately.
9. Verify rule hits
Generate three kinds of traffic first:
# Explicit DIRECT.
curl -I --proxy http://127.0.0.1:7890 https://example.com/
# Explicit PROXY.
curl -fsS --proxy http://127.0.0.1:7890 https://api.ipify.org
# Hitting tutorial-ads should be REJECT quickly.
curl --max-time 3 --proxy http://127.0.0.1:7890 http://ads.example/The terminal log should show match ... using DIRECT, using PROXY[...], or using REJECT.
Aster keeps hit / miss counters for top-level rules. Read them from the Controller:
curl -fsS \
-H 'Authorization: Bearer <CONTROLLER_SECRET>' \
http://127.0.0.1:9090/rulesWith jq:
curl -fsS \
-H 'Authorization: Bearer <CONTROLLER_SECRET>' \
http://127.0.0.1:9090/rules |
jq '.rules[] | {
index,
type,
payload,
proxy,
hitCount: .extra.hitCount,
missCount: .extra.missCount
}'If traffic succeeds but the expected rule’s hitCount does not increase:
- An earlier rule already matched.
- The application is not using the Aster proxy / TUN.
- The SOCKS client resolved locally, so metadata is only an IP and domain rules cannot match.
- The browser reused an existing connection and did not open a new one.
Check provider load status
curl -fsS \
-H 'Authorization: Bearer <CONTROLLER_SECRET>' \
http://127.0.0.1:9090/providers/rulesAsk an HTTP / file provider to update:
curl -fsS -X PUT \
-H 'Authorization: Bearer <CONTROLLER_SECRET>' \
http://127.0.0.1:9090/providers/rules/remote-adsInline providers do not download; an update only refreshes their timestamps.
10. DNS leak-prevention strategy
“No DNS leak” only makes sense after you define the threat model. Two common layers:
- Do not send plaintext UDP/TCP 53: DoH / DoT / DoQ can do that.
- The DNS upstream itself must also go through the proxy: using DoH alone does not mean it is proxied. The example’s
respect-rules: falseis deliberate so DNS connections go direct and bootstrap stays simple.
Send ordinary DNS upstreams through the proxy
First confirm the proxy hostname can be resolved directly by proxy-server-nameserver, then consider:
dns:
respect-rules: true
proxy-server-nameserver:
- https://1.1.1.1/dns-query
nameserver:
- https://1.1.1.1/dns-queryWhen respect-rules: true, proxy-server-nameserver cannot be empty. Ordinary nameserver / fallback / policy upstream connections follow rules; the proxy node itself is bootstrapped by the dedicated resolver so you do not recurse.
You can also pin a single DNS upstream to a group:
dns:
nameserver:
- "https://1.1.1.1/dns-query#PROXY"Validate the simple respect-rules: false mode first, then switch step by step. If “resolving the proxy requires the proxy,” you have a deadlock.
Applications that bypass system DNS
Browsers, Android Private DNS, VPN clients, and some apps use their own DoH / DoT. Options:
- Turn off the app’s custom DNS and use system / Aster DNS.
- Or manage that DoH host with explicit rules.
- On a network you control, block unauthorized UDP/TCP 53 and 853. DoH uses 443, so port matching alone cannot identify it completely.
- Do not assume setting
dns.listenintercepts every program.
SOCKS5 local resolution
This form may resolve the hostname on the host that runs curl first:
curl --proxy socks5://127.0.0.1:7890 https://example.org/Use remote hostname resolution instead:
curl --proxy socks5h://127.0.0.1:7890 https://example.org/SOCKS clients name this option differently. Confirm whether they send a domain or an IP.
11. Whole-machine takeover and TUN DNS hijack
Setting only an HTTP/SOCKS proxy does not take over programs that ignore the system proxy. For whole-machine takeover, add at the top level:
tun:
enable: true
stack: mixed
auto-route: true
auto-detect-interface: true
strict-route: true
dns-hijack:
- any:53Before enabling it, understand:
- Linux usually needs
CAP_NET_ADMIN/ root and/dev/net/tun. - Windows needs matching privileges and a usable TUN driver.
strict-routereduces bypass routes, but can also block LAN or another VPN. Keep an out-of-band management path first.- DNS hijack only handles matching DNS traffic. An app’s own DoH is still ordinary HTTPS.
- Aster’s own upstreams must not be hijacked back into itself, or you get a loop.
- With fake-IP, TUN must stay up so later connections to
198.18.0.0/16are intercepted. - Docker Desktop, WSL, routers, and native Linux do not route the same way.
The first time you enable TUN, keep allow-lan: false, do not add a complex firewall rewrite at the same time, and verify DNS, TCP, UDP, and LAN step by step.
12. Hunt leaks with packet capture
On Linux you can watch classic DNS / DoT during a test:
sudo tcpdump -ni any '(udp port 53 or tcp port 53 or tcp port 853)'Generate test traffic in another terminal, then check:
- Whether an application is querying the router, ISP, or an unknown resolver directly.
- Whether the packet’s source process / network namespace is actually not Aster.
- Whether
proxy-server-nameserverbootstrap queries look as expected. - Whether IPv6 shows DNS or direct traffic that was never designed in.
DoH uses TCP/UDP 443, so port alone cannot tell you. Cross-check destination IPs, Aster debug logs, browser policy, and firewall logs. On Windows use Wireshark / pktmon; on macOS use tcpdump.
Troubleshooting
DNS listener failed to start
127.0.0.1:1053is already taken by another Aster instance or DNS program.- You changed it to 53 and lack permission to bind a low port.
- Docker did not publish both UDP and TCP.
dns.enableis not on in the YAML.
Queries only time out
- The DoH / DoT upstream is blocked on the network.
default-nameservercannot bootstrap the upstream hostname.respect-rulessent DNS through a proxy that is not ready yet.- The firewall allows only UDP but missed TCP DNS, or only TCP 443 while you are using DoQ.
- The
systemresolver points back at127.0.0.1:1053and loops.
nameserver-policy has no effect
- The key’s domain matcher is misspelled.
rule-set:points at a provider that does not exist.- The provider is
behavior: ipcidrand cannot match a DNS domain. - Old DNS cache has not been flushed.
- The real query left through the browser’s built-in DoH and never entered Aster DNS.
Domain rules miss; only IP / MATCH hits
- The SOCKS client resolved locally; switch to remote DNS mode.
- The application connected by IP, so Aster has no hostname metadata.
- fake-IP DNS and the traffic inbound are not the same Aster instance / profile.
- Rule order is wrong; something earlier already matched.
- A long-lived connection was not rebuilt.
fake-IP queries look fine, but every connection fails
This usually means DNS already uses Aster, but later traffic does not enter Aster. Confirm:
- The application is set to an HTTP/SOCKS proxy; or
- TUN is enabled and the routes include
198.18.0.0/16; and - Another VPN / route table is not stealing the fake-IP traffic.
HTTP works, but QUIC / games / voice still go direct
HTTP CONNECT mainly handles TCP. UDP apps need:
- SOCKS5 UDP / a client that supports UDP, or
- TUN / TProxy takeover; and
- A proxy outbound that itself supports UDP. This page’s AnyTLS profile uses
udp: trueand carries UDP over UoT, but the client-to-Aster inbound still has to take over that traffic correctly.
IPv6 leaks or IPv6 sites behave differently
This page sets both top-level ipv6: false and dns.ipv6: false, which is a controllable IPv4 baseline. To enable IPv6:
- Confirm the proxy and DNS upstreams support IPv6.
- Add IPv6 rules and routes.
- Handle
::/0and AAAA in TUN / the firewall as well. - Test direct and proxied IPv6 egress separately.
Turning off Aster’s AAAA answers cannot stop an app that bypasses Aster entirely and connects over IPv6 itself. Real whole-machine leak prevention still depends on routes / firewall.
Rules did not change after a provider update
- Check
/providers/rulesforupdatedAt,ruleCount, and format. - The HTTP response may not be the expected YAML/text/MRS.
- The YAML is missing
payload:/rules:. behaviordoes not match the data.pathis outside the allowed safe path.- Flush DNS cache and make a new request for existing connections.
Pre-production checklist
- Change
log-level: debugback toinfo. - Keep Controller, DNS, and the mixed proxy on loopback, or configure the required ACL / authentication.
PROXYis not stuck onDIRECTbecause ofstore-selected.- The fake-IP filter covers real LAN, mDNS, NTP, games, and captive-portal needs.
- Providers use HTTPS, a trusted source, a reasonable
size-limit, and a recoverable cache. - DNS bootstrap does not depend on a proxy that is not up yet.
- Packet capture shows no unexpected UDP/TCP 53, 853, IPv6, or bypass traffic.
- TUN environments have been tested separately for TCP, UDP, DNS, LAN, sleep/wake, and network switches.
