DEV Community

Wang Ziting
Wang Ziting

Posted on • Updated on

Setup Clash transparent proxy on a Linux router

I bought a very small fanless PC in April 2019, intended to install a Linux then replace my main router in my home, and set up a transparent proxy on it, Finally, I finished it in November 2019.

Hardware and OS

The router using J1900 CPU, installed 2G memory and 128G SSD, and I install an Ubuntu on it. Because Ubuntu is my most used Linux distributions.

Many people believe router that using specially designed hardware may have higher performance. But I think that a Linux on a universal PC hardware will have almost the same performance with special hardware.

Overview

I installed or use the following software on my router:

  • dnsmasq for providing DHCP service and DNS cache.
  • Clash for providing redir proxy and DNS service.
  • iptables for providing NAT and firewall, redirects TCP connections.

I install them by Ansible — a configuration management tool, the source code is available on my GitHub. You can’t use it directly, but you can learn more details about my setup, or modify your own version based on it.

Turn into a router

My router has four RJ45 ports, Let’s assume that the first port (enp1s0) connected to the Internet — we call it WAN, and the rest ports connect to used by my devices — we call it LAN.

Edit /etc/sysctl.conf, set the following instructions to enable forwarding for IPv4:

net.ipv4.ip_forward=1
Enter fullscreen mode Exit fullscreen mode

Create /etc/netplan/bridges.yaml, use NetPlan — Ubuntu’s new network configuration utility to make a bridge interface(called brlan) between our LAN interfaces, includes enp2s0, enp3s0 and enp4s0, then assign 10.0.0.1/24 to it:

network:
  version: 2
  renderer: networkd
  ethernets:
    enp1s0:
      dhcp4: true
    enp2s0:
      optional: true
    enp3s0:
      optional: true
    enp4s0:
      optional: true
bridges:
    brlan:
      addresses:
        - 10.0.0.1/24
      interfaces:
        - enp2s0
        - enp3s0
        - enp4s0
Enter fullscreen mode Exit fullscreen mode

You will need a reboot to make sysctl.conf and NetPlan take effects.

Run the following commands in shell to setup iptables NAT rules:

iptables -t nat -A POSTROUTING -o enp1s0 -j MASQUERADE
Enter fullscreen mode Exit fullscreen mode

We need to set some of basic firewall rules, we deny all income connections by default unless explicitly permit.

iptables -A INPUT -i enp1s0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -i enp1s0 -p icmp -j ACCEPT
iptables -A INPUT -i enp1s0 -j REJECT --reject-with icmp-port-unreachable
Enter fullscreen mode Exit fullscreen mode

Then install netfilter-persistent to persistent the rules after reboot:

apt-get install netfilter-persistent
netfilter-persistent save
Enter fullscreen mode Exit fullscreen mode

Now your Linux has become a NAT router.

DHCP

To be a real router, we also need DHCP service, we use dnsmasq to do that:

apt install dnsmasq
Enter fullscreen mode Exit fullscreen mode

Modify the following lines in /etc/dnsmasq.conf:

interface=brlan
dhcp-range=brlan,10.0.0.1,10.0.0.255,12h
dhcp-option=6,10.0.0.1
Enter fullscreen mode Exit fullscreen mode

Clash

Download release from GitHub, unarchive and move to /usr/bin/clash, add executable permissions:

curl -o clash.gz https://github.com/Dreamacro/clash/releases/download/v1.1.0/clash-linux-amd64-v1.1.0.gz
gzip -dk clash.gz
mv clash /usr/bin/clash
chmod +x /usr/bin/clash
Enter fullscreen mode Exit fullscreen mode

Create /etc/systemd/system/clash.service:

[Unit]
Description=clash daemon
[Service]
Type=simple
LimitNOFILE=49152
ExecStart=/usr/bin/clash -d /etc/clash
[Install]
WantedBy=multi-user.target
Enter fullscreen mode Exit fullscreen mode

Prepare a clash config in /etc/clash/config.yml, the following just showing some key instructions, not the complete configuration, you need to modify by yourself:

redir-port: 7892
mode: rule

proxies:
    - { name: 'My Upstream Proxy', type: 'http', server: 'example.com', port: 443}

proxy-groups:
    - { name: "Proxy", type: select, proxies: ['My Upstream Proxy']}

rules:

# Domains don't want to be proxy
- DOMAIN-SUFFIX,alipay.com,DIRECT
- DOMAIN-SUFFIX,baidu.com,DIRECT
- DOMAIN-SUFFIX,bilibili.com,DIRECT
- DOMAIN-SUFFIX,douban.com,DIRECT
- DOMAIN-SUFFIX,iqiyi.com,DIRECT
- DOMAIN-SUFFIX,jd.com,DIRECT
- DOMAIN-SUFFIX,qq.com,DIRECT
- DOMAIN-SUFFIX,taobao.com,DIRECT
- DOMAIN-SUFFIX,tmall.com,DIRECT
- DOMAIN-SUFFIX,weibo.com,DIRECT
- DOMAIN-SUFFIX,zhihu.com,DIRECT

# Domain keywords to be proxy
- DOMAIN-KEYWORD,amazon,Proxy
- DOMAIN-KEYWORD,google,Proxy
- DOMAIN-KEYWORD,gmail,Proxy
- DOMAIN-KEYWORD,youtube,Proxy
- DOMAIN-KEYWORD,facebook,Proxy
- DOMAIN-KEYWORD,twitter,Proxy
- DOMAIN-KEYWORD,instagram,Proxy
- DOMAIN-KEYWORD,dropbox,Proxy

# Local address
- IP-CIDR,127.0.0.0/8,DIRECT
- IP-CIDR,172.16.0.0/12,DIRECT
- IP-CIDR,192.168.0.0/16,DIRECT
- IP-CIDR,10.0.0.0/8,DIRECT
- IP-CIDR,17.0.0.0/8,DIRECT
- IP-CIDR,100.64.0.0/10,DIRECT

# Finally rules
- GEOIP,CN,DIRECT
- MATCH,Proxy
Enter fullscreen mode Exit fullscreen mode

Redir proxy

We will use iptables to redirect TCP connections to our clash redir port.

First, create a chain for Clash:

iptables -t nat -N CLASH
Enter fullscreen mode Exit fullscreen mode

Ignore connections to local private address:

iptables -t nat -A CLASH -p tcp -d 0.0.0.0/8 -j RETURN
iptables -t nat -A CLASH -p tcp -d 10.0.0.0/8 -j RETURN
iptables -t nat -A CLASH -p tcp -d 127.0.0.0/8 -j RETURN
iptables -t nat -A CLASH -p tcp -d 172.16.0.0/12 -j RETURN
iptables -t nat -A CLASH -p tcp -d 192.168.0.0/16 -j RETURN
Enter fullscreen mode Exit fullscreen mode

Ignore connections to redir port to avoid cyclic redirect:

iptables -t nat -A CLASH -p tcp -m tcp --dport 7892 -j RETURN
Enter fullscreen mode Exit fullscreen mode

We also need ignore connections to your upstream proxy to avoid cyclic redirect:

# if you upstream proxy has a stable address
iptables -t nat -A CLASH -p tcp -d <your upstream proxy address> -j RETURN
# if you upstream proxy has a stable proxy
iptables -t nat -A CLASH -p tcp -m tcp --dport <your upstream proxy port> -j RETURN
Enter fullscreen mode Exit fullscreen mode

Then, redirect to clash:

iptables -t nat -A CLASH -p tcp -j REDIRECT --to-ports 7892
Enter fullscreen mode Exit fullscreen mode

Send traffics from LAN to the CLASH chain:

iptables -t nat -A PREROUTING -s 10.0.0.0/24 -p tcp -j CLASH
Enter fullscreen mode Exit fullscreen mode

Now, all of your outgoing connections will be redirect to Clash.

Troubles about DNS

Unlike a system proxy, iptables redirect traffic on the IP layer, it uses IP instead of a domain. So the domain-related rules in Clash don’t work.

The DNS query is sent by UDP, which can’t redirect by the previous rules, and may produce an incorrect result. We are going to use Clash’s DNS to replace systemd-resolved — the default DNS resolver of Ubuntu.

Disable systemd-resolved:

systemctl disable systemd-resolved
systemctl stop systemd-resolved
Enter fullscreen mode Exit fullscreen mode

Modify Clash config:

dns:
  enable: true
  ipv6: false
  listen: 127.0.0.53:53
  enhanced-mode: redir-host
  nameserver:
    - 119.29.29.29
    - 223.5.5.5
  fallback:
    - 'tls://1.1.1.1:853'
    - 'tls://8.8.8.8:853'
    - 'tls://9.9.9.9:853'
Enter fullscreen mode Exit fullscreen mode

Clash will resolve domains by servers in nameserver section and fallback section in the same time.

Servers in nameserver section are fast but unreliable, if it returns an address which GEOIP country is CN, we use that; otherwise, we wait for the result form servers in fallback section.

In this process, Clash will remember the mapping from domain to IP, so Clash will know the domain of a redirected connection, and apply domain-related rules.
Now, Clash will provide correct DNS resolve on 127.0.0.53:53. Then we need set dnsmasq as a DNS cache server, Modify the following lines in /etc/dnsmasq.conf:

port=53
no-resolv
server=127.0.0.53
cache-size=1000
Enter fullscreen mode Exit fullscreen mode

Modify /etc/resolv.conf to use dnsmasq as local resolver:

nameserver 127.0.0.1
Enter fullscreen mode Exit fullscreen mode

Other components in my case

  • pppd for providing PPPoE connection.
  • netdata for monitoring dashboard.

Discussion (0)