Skip to content

Instantly share code, notes, and snippets.

@wych42
Last active February 5, 2024 05:39
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save wych42/2d38fbb86d47686b6ee757ebe70feb28 to your computer and use it in GitHub Desktop.
Save wych42/2d38fbb86d47686b6ee757ebe70feb28 to your computer and use it in GitHub Desktop.
Clash as transparent proxy(not totally transparent) on gateway box

My testing network topology

  • Mac as LAN device, connectted to network 10.13.1.0/24, gateway 10.13.1.1.
    • Run: sudo route add -host proxy-node-ip 10.13.1.1 to avoid routing loop.
  • Ubuntu VM runs in VMWare Fusion as gateway(running clash).
    • Bridge interface as default gateway for vm.
    • An NAT devices with subnet 192.168.107.0/24 to connect Host(Mac).Assign 192.168.107.128 to vm.

Clash

  • Install clash binary to /usr/local/bin/clash.
  • Run useradd -M clash
  • Run sudo setcap CAP_NET_ADMIN,CAP_NET_BIND_SERVICE+eip /usr/local/bin/clash.
  • Save config.yaml to /usr/local/etc/clash/config.yaml, change proxy nodes, rules to your own config.
    • allow-lan should be set to true.
    • redir-port, dns.listen port should be same as in iptables.
    • change log-level to info/warning after testing.
  • Save clash.service to /etc/systemd/system/clash.service.
  • Run systemctl daemon-reload systemctl start clash to start clash.
  • Run journalctl -u clash -f to view log.

Kernel

Assume enp0s1 is the network interface which the gateway ip address(e.g.: 192.168.107.128) for other devices is assigned to.

Run:

sysctl -w net.ipv4.conf.enp0s1.forwarding=1
sysctl -w net.ipv4.ip_forward=1

Iptables

  • In new terminal panel, save rules.v4 to /etc/iptables/rules.v4.
  • Change 192.168.107.0/24 to your subnet.
  • Change --uid-owner 1001 to --uid-owner {{ the actual uid of user clash }}
  • Run iptables-restore < /etc/iptables.v4.

Testing

On gateway box

Run dig www.baidu.com @114.114.114.114, should return 198.18.x.x due to fake-ip mode enabled. Run curl www.google.com -v > /dev/null, should return 200 ok.

On Lan devices

Set gateway to 192.168.107.128(as example above), and rerun the commands.

Cons

  • No UDP packets other than DNS queries to dst port 53 would be proxied.
  • No EDNS-Client-Subnet support.
[Unit]
Description=Clash service
After=network.target
[Service]
[Service]
Type=simple
StandardError=journal
User=clash
Group=clash
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
ExecStart=/usr/local/bin/clash -d /usr/local/etc/clash/
Restart=on-failure
RestartPreventExitStatus=23
[Install]
WantedBy=multi-user.target
port: 7890
socks-port: 7891
redir-port: 7892
allow-lan: true
mode: Rule
# info / warning / error / debug / silent
log-level: debug
dns:
enable: true # set true to enable dns (default is false)
ipv6: false # default is false
listen: 0.0.0.0:5353
enhanced-mode: fake-ip # redir-host or fake-ip; redir-host also works
nameserver:
- 117.50.10.10
- 223.5.5.5
fallback: # concurrent request with nameserver, fallback used when GEOIP country isn't CN
- https://dns.google/dns-query
- https://1.1.1.1/dns-query
# add your own proxies
proxies:
- name: "vmess-1"
type: vmess
server: {{ip-addr}}
port: 443
uuid: {{uuid}}
alterId: 64
cipher: none
udp: true
tls: true
skip-cert-verify: false
network: ws
ws-path: /path
ws-headers:
Host: {{hostname}}
- name: "vmess-2"
type: vmess
server: {{ip-addr}}
port: 443
uuid: {{uuid}}
alterId: 64
cipher: none
udp: true
tls: true
skip-cert-verify: false
network: ws
ws-path: /path
ws-headers:
Host: {{hostname}}
proxy-groups:
- name: "UrlTest"
type: url-test
proxies:
- "vmess-1"
- "vmess-2"
url: "http://www.gstatic.com/generate_204"
interval: 300
- name: "FallBack"
type: fallback
proxies:
- "vmess-1"
- "vmess-2"
url: "http://www.gstatic.com/generate_204"
interval: 300
- { name: "PROXY", type: select, proxies: ["FallBack"] }
- name: "Final"
type: select
proxies:
- "PROXY"
# all traffic go through "PROXY" group
# add your rules here
Rule:
- MATCH,Final
# Generated by iptables-save v1.6.1 on Wed May 6 07:36:19 2020
*mangle
:PREROUTING ACCEPT [383:34188]
:INPUT ACCEPT [383:34188]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [250:32880]
:POSTROUTING ACCEPT [250:32880]
COMMIT
# Completed on Wed May 6 07:36:19 2020
# Generated by iptables-save v1.6.1 on Wed May 6 07:36:19 2020
*filter
:INPUT ACCEPT [389:34500]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [256:33576]
COMMIT
# Completed on Wed May 6 07:36:19 2020
# Generated by iptables-save v1.6.1 on Wed May 6 07:36:19 2020
*nat
:PREROUTING ACCEPT [3:624]
:INPUT ACCEPT [3:624]
:OUTPUT ACCEPT [4:240]
:POSTROUTING ACCEPT [4:240]
-A POSTROUTING -s 192.168.107.0/24 -j MASQUERADE
:CLASH_DNS_EXTERNAL - [0:0]
:CLASH_DNS_LOCAL - [0:0]
:CLASH_EXTERNAL - [0:0]
:CLASH_LOCAL - [0:0]
-A PREROUTING -p udp -j CLASH_DNS_EXTERNAL
-A PREROUTING -p tcp -j CLASH_EXTERNAL
-A OUTPUT -p udp -j CLASH_DNS_LOCAL
-A OUTPUT -p tcp -j CLASH_LOCAL
-A CLASH_DNS_EXTERNAL -p udp -m udp ! --dport 53 -j RETURN
-A CLASH_DNS_EXTERNAL -p udp -j REDIRECT --to-ports 5353
-A CLASH_DNS_LOCAL -p udp -m udp ! --dport 53 -j RETURN
-A CLASH_DNS_LOCAL -m owner --uid-owner 1001 -j RETURN
-A CLASH_DNS_LOCAL -p udp -j REDIRECT --to-ports 5353
-A CLASH_EXTERNAL -d 0.0.0.0/8 -j RETURN
-A CLASH_EXTERNAL -d 127.0.0.0/8 -j RETURN
-A CLASH_EXTERNAL -d 224.0.0.0/4 -j RETURN
-A CLASH_EXTERNAL -d 172.16.0.0/12 -j RETURN
-A CLASH_EXTERNAL -d 127.0.0.0/8 -j RETURN
-A CLASH_EXTERNAL -d 169.254.0.0/16 -j RETURN
-A CLASH_EXTERNAL -d 240.0.0.0/4 -j RETURN
-A CLASH_EXTERNAL -d 192.168.0.0/16 -j RETURN
-A CLASH_EXTERNAL -d 10.0.0.0/8 -j RETURN
-A CLASH_EXTERNAL -p tcp -j REDIRECT --to-ports 7892
-A CLASH_LOCAL -m owner --uid-owner 1001 -j RETURN
-A CLASH_LOCAL -d 0.0.0.0/8 -j RETURN
-A CLASH_LOCAL -d 127.0.0.0/8 -j RETURN
-A CLASH_LOCAL -d 224.0.0.0/4 -j RETURN
-A CLASH_LOCAL -d 172.16.0.0/12 -j RETURN
-A CLASH_LOCAL -d 127.0.0.0/8 -j RETURN
-A CLASH_LOCAL -d 169.254.0.0/16 -j RETURN
-A CLASH_LOCAL -d 240.0.0.0/4 -j RETURN
-A CLASH_LOCAL -d 192.168.0.0/16 -j RETURN
-A CLASH_LOCAL -d 10.0.0.0/8 -j RETURN
-A CLASH_LOCAL -p tcp -j REDIRECT --to-ports 7892
COMMIT
# Completed on Wed May 6 07:36:19 2020
@oscar-c
Copy link

oscar-c commented Apr 11, 2022

In my experience, with clash 1.10, setcap CAP_NET_ADMIN,CAP_NET_BIND_SERVICE+eip will result in "All DNS requests failed" due to "operation not permitted".
Replace it with setcap CAP_NET_RAW,CAP_NET_BIND_SERVICE+ep fixed the problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment