Policy routing with Clash
I have had introduced Clash in the past and gave an introductory guide about how you can deploy it on your Linux gateway as a transparent proxy. This article will do pretty much the same, but more in-depth - and since Clash has evolved extensively with TUN, TPROXY and auto-redir support, this time we're going to do it much more simpler, and discover the massive potential you could get with Clash as your gateway.
Installation
First of all, we're going to deploy Clash Premium on the gateway. Different from Clash, it's proprietary at the moment and only compiled on Dreamacro's (author of Clash) personal computers. It has TUN support, script-based rules support, rule providers, profiling (like a built-in Prometheus exporter), eBPF and auto-redir support. We'll dive in to those later.
The latest release for linux-amd64 can be found at https://release.dreamacro.workers.dev/latest/clash-linux-amd64-latest.gz.
Download it to the gateway and unarchive:
$ wget -O clash.gz https://release.dreamacro.workers.dev/latest/clash-linux-amd64-latest.gz
--2022-08-26 15:21:38-- https://release.dreamacro.workers.dev/latest/clash-linux-amd64-latest.gz
Resolving release.dreamacro.workers.dev (release.dreamacro.workers.dev)... 104.21.37.61, 172.67.205.5, 2606:4700:3032::6815:253d, ...
Connecting to release.dreamacro.workers.dev (release.dreamacro.workers.dev)|104.21.37.61|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 6204563 (5.9M) [binary/octet-stream]
Saving to: 'clash.gz'
clash.gz 100%[==========================================================>] 5.92M 4.92MB/s in 1.2s
2022-08-26 15:21:48 (4.92 MB/s) - 'clash.gz' saved [6204563/6204563]
$ gzip -d clash.gz
$ file clash
clash: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped
$ chmod +x clash
$ ./clash -v
Clash 2022.08.26-1-g8720ef5 linux amd64 with go1.19 Fri 26 Aug 2022 02:52:04 PM UTC
Okay. Now we're going to give it a place to live and put the configuration files and IP database there.
mv ./clash /usr/local/bin
mkdir -p /etc/clash
clash -d /etc/clash # this creates default configuration and downloads IP database
Lastly let's set up its systemd service file:
[Unit]
Description=Clash daemon, A rule-based proxy in Go.
After=network.target
[Service]
Type=simple
Restart=always
ExecStart=/usr/local/bin/clash -d /etc/clash
[Install]
WantedBy=multi-user.target
... and make it start at boot:
systemctl daemon-reload
systemctl enable clash
systemctl start clash
You can refer to the official guide here: https://github.com/Dreamacro/clash/wiki/Running-Clash-as-a-service#systemd
Configuration
As a transparent proxy, here's an example config.yml to make it work.
General
# HTTP(S) and SOCKS4(A)/SOCKS5 server on the same port
mixed-port: 7890
mode: rule
routing-mark: 6666
auto-redir:
enable: true
auto-route: true
# This creates TUN device named utun on Linux
tun:
enable: true
stack: system
auto-route: true
auto-detect-interface: true
# This stores proxy group selection and fake-ip mappings
# in $HOME/.config/clash/.cache
profile:
store-selected: true
store-fake-ip: true
Look at the auto-redir
and tun
section. Enabling their auto-route
options, Clash automatically sets up the Linux routing table so any incoming/outgoing L2 traffic will be captured and forwarded by it. We no longer need to setup iptables manually now!
DNS, fake-ip and rules
# Required for domain-based policy routing.
dns:
enable: true
listen: 0.0.0.0:53
ipv6: false # when false, response to AAAA questions will be empty
# These nameservers are used to resolve the DNS nameserver hostnames below.
default-nameserver:
- 1.1.1.1
- 8.8.8.8
- 9.9.9.9
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
nameserver:
- 'https://1.1.1.1/dns-query'
- 8.8.8.8
This DNS server setup is particularly interesting if you haven't approached to the concept of fake-ip before. We will discuss later.
In the proxies
section you setup a variety of proxy servers and proxy groups. This is a brief example, check out the official documentation here for more.
# Some example outbound proxies you can have.
proxies:
- name: "ss3"
type: ss
server: server
port: 443
cipher: chacha20-ietf-poly1305
password: "password"
plugin: v2ray-plugin
plugin-opts:
mode: websocket
# socks5
- name: "socks"
type: socks5
server: server
port: 443
# username: username
# password: password
# tls: true
# skip-cert-verify: true
# udp: true
# You associate a rule with a single proxy or a proxy group.
# In a proxy group, Clash offers proxy relaying, failovering, load-balancing, benchmarking or simply you can select which proxy you want the group to use as the outbound.
# Read the official documentation at https://github.com/Dreamacro/clash/wiki/Configuration for more.
proxy-groups:
# If you have a VPN that exposes theirselves on a TUN device,
# Create a proxy group and use only DIRECT as outbound.
# Specify your outbound network device in `interface-name`.
- name: Cisco AnyConnect
type: select
interface-name: tun0
proxies:
- DIRECT
- name: Wireguard
type: select
interface-name: wg0
proxies:
- DIRECT
After setting up proxies and proxy groups, you set up your policy rules.
# Rule providers are a collection of rules.
# You can load them in a local file or load remotely from a URL.
rule-providers:
CloudflareIP:
type: file
behavior: ipcidr
path: ./RuleProviders/CloudflareIP.yaml
# Check this out for available rule types:
# https://github.com/Dreamacro/clash/wiki/Configuration#rules
rules:
- DOMAIN-SUFFIX,google.co.uk,Proxy
- DOMAIN,accounts.google.co.uk,DIRECT
- DOMAIN-SUFFIX,internal.company.com,Cisco AnyConnect
- DOMAIN-SUFFIX,doubleclick.net,REJECT
- RULE-SET,CloudflareIP,Wireguard
- GEOIP,US,Wireguard
- MATCH,DIRECT
Finally let me introduce you to fake-ip.
Simply put, Clash DNS will resolve every name as a fake-ip, which is an address in a particular IPv6 reserved address pool, by default 198.18.0.1/16
.
I'll give you an example. Let's say we want to curl -v http://icanhazip.com
. You would get
$ curl -v http://icanhazip.com
* Trying 198.18.3.18:80...
* Connected to icanhazip.com (198.18.3.18) port 80 (#0)
> GET / HTTP/1.1
> Host: icanhazip.com
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Fri, 26 Aug 2022 16:45:50 GMT
< (some http response headers redacted here)
<
123.123.123.123
The process is like this (simplified):
-
curl asks the Clash DNS for the IP address of
icanhazip.com
-
Clash finds an empty spot in
198.18.0.1/16
and answers the A question with198.18.3.18
. -
curl opens TCP socket to
198.18.3.18
and sends the HTTP request. -
The packet to
198.18.3.18
gets routed to Clash. -
Clash looks up in the fake-ip cache and see which hostname it is associated with:
icanhazip.com
in this case. -
Clash looks up the policy rules and see:
-
If there's an applying rule for
icanhazip.com
-
If there's any
GEOIP
,IP-CIDR
orIP-CIDR6
rule withoutno-resolve
property:-
Clash asks every nameservers set up in
dns.nameserver
, namely8.8.8.8
and1.1.1.1
(DoT) here in this example, what is the IP address oficanhazip.com
-
Clash then checks if the resolved IP address applies to any of the above rules.
-
-
If any of the rules apply, the outbound target is selected based on the rule.
-
Otherwise the outbound target specified in the
MATCH
rule is selected.
-
-
Clash forwards the packet to the target selected above, and will forward back if there is a reply.
You may ask: why fake-ip? Some proxy protocols connect to the remote host by their hostname. You give them the hostname that you want to connect to. This means if you're connecting to google.com
with a SOCKS5 proxy, the IP address of google.com
is actually resolved on the proxy server.
Imagine this scenario without fake-ip: You're in EU, you would locally resolve google.com
to their PoP in EU. Your proxy server is in AS. So connecting to the EU PoP of Google with an AS proxy is obviously a bad idea. Hence, fake-ip this offers significant speed boost on connections over proxies.
Beware that in the above example, without fake-ip, Clash would still need to resolve google.com
locally even we don't actually need it. So fake-ip saves one DNS lookup. Additionally, it offers protection against DNS pollution attack -- some ISP or national firewalls give you false DNS answers. This solves it by resolving remotely.
If you do read Chinese, here's an awesome in-depth article of fake-ip and recursive DNS.
Using Clash as the gateway
In your DHCP server options, set the advertised gateway and DNS server to the IP address of Clash.
Your devices will now have default route to the Clash host. They will resolve everything as a fake-ip. Every packet will be intercepted by Clash and forwarded conditionally.
Controlling Clash on the fly
There are two popular options available for a Clash web interface:
- https://clash.razord.top (https://github.com/Dreamacro/clash-dashboard)
- https://yacd.haishan.me (https://github.com/haishanh/yacd)
You can either use the public URL above or host them with Clash (see config option external-ui
).
The web interfaces connect to the external-controller port of Clash locally on your browser.