├── .gitignore ├── README.md ├── bypass-proxy ├── bypass-proxy-pid.cc ├── clash-cgroups.service ├── clash-tun.service ├── clash-tun@.service ├── clean-clash-tun.sh ├── env ├── setup-clash-cgroup.sh └── setup-clash-tun.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .ccls-cache/ 2 | bypass-proxy-pid 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Clash-tun Scripts 2 | 3 | Some scripts to use with [comzyh/clash](https://github.com/comzyh/clash) and cgroup v2. 4 | 5 | **~~Only for Linux with cgroup v2 support.~~ Support both cgroup v1 and v2.** 6 | 7 | Archlinux users can use the package `clash-tun` in AUR. 8 | 9 | `bypass-proxy ` to run command and make it bypass the clash proxy. 10 | 11 | `bypass-proxy-pid ` to make a process bypass the clash proxy. 12 | 13 | #### Manual Setup 14 | 15 | Install `*.sh` scripts to `/opt/script/`, `bypass-proxy` and `bypass-proxy-pid` (need to be compiled, you can use `g++ -O2 -static bypass-proxy-pid.cc -o bypass-proxy-pid`) to `/usr/bin/`, env to `/etc/clash-tun/`, and then use the systemd services; 16 | -------------------------------------------------------------------------------- /bypass-proxy: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "`id -u`" = "0" ];then 4 | /opt/script/setup-clash-cgroup.sh 5 | fi 6 | 7 | bypass-proxy-pid $$ 8 | 9 | exec "$@" 10 | -------------------------------------------------------------------------------- /bypass-proxy-pid.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) { 6 | if (argc != 2) { 7 | std::cerr << "Wrong number of arguments: 1, " << argc - 1 << std::endl; 8 | return -1; 9 | } else { 10 | std::ofstream fout; 11 | struct stat sb; 12 | if(stat("/sys/fs/cgroup/system.slice/", &sb), S_ISDIR(sb.st_mode)) 13 | fout.open("/sys/fs/cgroup/bypass_proxy/cgroup.procs"); 14 | else 15 | fout.open("/sys/fs/cgroup/net_cls/bypass_proxy/tasks"); 16 | fout << argv[1] << std::endl; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /clash-cgroups.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Set up the cgroup earlier. 3 | Before=clash-tun.service 4 | Before=clash-tun@.service 5 | 6 | [Service] 7 | User=root 8 | Type=oneshot 9 | RemainAfterExit=yes 10 | EnvironmentFile=/etc/clash-tun/env 11 | ExecStart=/usr/bin/bash /opt/script/setup-clash-cgroup.sh 12 | 13 | [Install] 14 | WantedBy=sysinit.target 15 | -------------------------------------------------------------------------------- /clash-tun.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=A rule based proxy tunnel 3 | After=network-online.target 4 | After=iptables.service 5 | After=ip6tables.service 6 | After=nftables.service 7 | After=clash-cgroups.service 8 | 9 | [Service] 10 | Type=simple 11 | User=nobody 12 | Group=nobody 13 | EnvironmentFile=/etc/clash-tun/env 14 | Environment="PROXY_TUN_USER=nobody" 15 | ExecStartPre=/usr/bin/sleep 2 16 | ExecStartPre=+/opt/script/setup-clash-tun.sh 17 | ExecStopPost=+/opt/script/clean-clash-tun.sh 18 | ExecStart=/usr/bin/bypass-proxy /usr/bin/clash -d /srv/clash 19 | 20 | [Install] 21 | WantedBy=multi-user.target 22 | -------------------------------------------------------------------------------- /clash-tun@.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=A rule based proxy tunnel 3 | After=network-online.target 4 | After=iptables.service 5 | After=ip6tables.service 6 | After=nftables.service 7 | After=clash-cgroups.service 8 | 9 | [Service] 10 | Type=simple 11 | User=%i 12 | EnvironmentFile=/etc/clash-tun/env 13 | Environment="PROXY_TUN_USER=%i" 14 | ExecStartPre=/usr/bin/sleep 2 15 | ExecStartPre=+/opt/script/setup-clash-tun.sh 16 | ExecStopPost=+/opt/script/clean-clash-tun.sh 17 | ExecStart=/usr/bin/bypass-proxy /usr/bin/clash 18 | 19 | [Install] 20 | WantedBy=multi-user.target 21 | -------------------------------------------------------------------------------- /clean-clash-tun.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | exec 1> /dev/null 4 | exec 2> /dev/null 5 | 6 | ip link set dev "$PROXY_TUN_DEVICE_NAME" down 7 | ip tuntap del "$PROXY_TUN_DEVICE_NAME" mode tun 8 | 9 | ip route del default dev "$PROXY_TUN_DEVICE_NAME" table "$PROXY_ROUTE_TABLE" 10 | ip rule del fwmark "$PROXY_FWMARK" lookup "$PROXY_ROUTE_TABLE" 11 | 12 | iptables -t mangle -D OUTPUT -j CLASH 13 | iptables -t nat -D OUTPUT -p udp --dport 53 -j CLASH_DNS 14 | 15 | if [ $ENABLE_PREROUTING = 1 ];then 16 | iptables -t mangle -D PREROUTING -m set ! --match-set localnetwork dst -j MARK --set-mark "$PROXY_FWMARK" 17 | iptables -t nat -D PREROUTING -p udp --dport 53 -j REDIRECT --to-ports "$PROXY_DNS_PORT" 18 | fi 19 | 20 | iptables -t mangle -F CLASH 21 | iptables -t mangle -X CLASH 22 | 23 | iptables -t nat -F CLASH_DNS 24 | iptables -t nat -X CLASH_DNS 25 | 26 | ipset destroy localnetwork 27 | 28 | if [ $ENABLE_IPv6 = 1 ];then 29 | ip -6 route del default dev "$PROXY_TUN_DEVICE_NAME" table "$PROXY_ROUTE_TABLE" 30 | ip -6 rule del fwmark "$PROXY_FWMARK" lookup "$PROXY_ROUTE_TABLE" 31 | 32 | ip6tables -t mangle -D OUTPUT -j CLASH6 33 | ip6tables -t nat -D OUTPUT -p udp --dport 53 -j CLASH_DNS6 34 | 35 | if [ $ENABLE_PREROUTING = 1 ];then 36 | ip6tables -t mangle -D PREROUTING -m set ! --match-set localnetwork6 dst -j MARK --set-mark "$PROXY_FWMARK" 37 | ip6tables -t nat -D PREROUTING -p udp --dport 53 -j REDIRECT --to-ports "$PROXY_DNS_PORT" 38 | fi 39 | 40 | ip6tables -t mangle -F CLASH6 41 | ip6tables -t mangle -X CLASH6 42 | 43 | ip6tables -t nat -F CLASH_DNS6 44 | ip6tables -t nat -X CLASH_DNS6 45 | 46 | ipset destroy localnetwork6 47 | fi 48 | 49 | exit 0 50 | -------------------------------------------------------------------------------- /env: -------------------------------------------------------------------------------- 1 | PROXY_BYPASS_USER= 2 | PROXY_BYPASS_CGROUP="0x16200000" 3 | PROXY_FWMARK="0x162" 4 | PROXY_ROUTE_TABLE="0x162" 5 | PROXY_DNS_PORT="1053" 6 | PROXY_FORCE_NETADDR="198.18.0.0/16" 7 | PROXY_TUN_DEVICE_NAME="clash0" 8 | PROXY_TUN_ADDRESS="172.31.255.253/30" 9 | PROXY_DNS_SERVER="127.0.0.1:1053" 10 | ENABLE_IPv6=1 11 | ENABLE_PREROUTING=1 12 | -------------------------------------------------------------------------------- /setup-clash-cgroup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ -d "/sys/fs/cgroup/bypass_proxy" ] || [ -d "/sys/fs/cgroup/net_cls/bypass_proxy" ];then 3 | exit 0 4 | fi 5 | if [ -d /sys/fs/cgroup/system.slice/ ]; then 6 | mkdir -p /sys/fs/cgroup/bypass_proxy 7 | else 8 | mkdir -p /sys/fs/cgroup/net_cls/bypass_proxy 9 | sleep 1 10 | echo "$PROXY_BYPASS_CGROUP" > /sys/fs/cgroup/net_cls/bypass_proxy/net_cls.classid 11 | fi 12 | 13 | exit 0 14 | -------------------------------------------------------------------------------- /setup-clash-tun.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | /opt/script/clean-clash-tun.sh 4 | 5 | /opt/script/setup-clash-cgroup.sh 6 | 7 | ipset create localnetwork hash:net 8 | ipset add localnetwork 127.0.0.0/8 9 | ipset add localnetwork 10.0.0.0/8 10 | ipset add localnetwork 192.168.0.0/16 11 | ipset add localnetwork 224.0.0.0/4 12 | ipset add localnetwork 172.16.0.0/12 13 | 14 | 15 | ip tuntap add "$PROXY_TUN_DEVICE_NAME" mode tun user $PROXY_TUN_USER 16 | ip link set "$PROXY_TUN_DEVICE_NAME" up 17 | 18 | ip address replace "$PROXY_TUN_ADDRESS" dev "$PROXY_TUN_DEVICE_NAME" 19 | 20 | ip route replace default dev "$PROXY_TUN_DEVICE_NAME" table "$PROXY_ROUTE_TABLE" 21 | 22 | ip rule add fwmark "$PROXY_FWMARK" lookup "$PROXY_ROUTE_TABLE" 23 | 24 | iptables -t mangle -N CLASH 25 | iptables -t mangle -F CLASH 26 | if [ $PROXY_BYPASS_USER ];then 27 | iptables -t mangle -A CLASH -m owner --uid-owner "$PROXY_BYPASS_USER" -j RETURN 28 | fi 29 | iptables -t mangle -A CLASH -d "$PROXY_FORCE_NETADDR" -j MARK --set-mark "$PROXY_FWMARK" 30 | if [ -d /sys/fs/cgroup/system.slice/ ]; then 31 | iptables -t mangle -A CLASH -m cgroup --path bypass_proxy -j RETURN 32 | else 33 | iptables -t mangle -A CLASH -m cgroup --cgroup "$PROXY_BYPASS_CGROUP" -j RETURN 34 | fi 35 | iptables -t mangle -A CLASH -m addrtype --dst-type BROADCAST -j RETURN 36 | iptables -t mangle -A CLASH -m set --match-set localnetwork dst -j RETURN 37 | iptables -t mangle -A CLASH -p udp --sport 6771 -j RETURN 38 | iptables -t mangle -A CLASH -j MARK --set-mark "$PROXY_FWMARK" 39 | 40 | iptables -t nat -N CLASH_DNS 41 | iptables -t nat -F CLASH_DNS 42 | if [ $PROXY_BYPASS_USER ];then 43 | iptables -t nat -A CLASH_DNS -m owner --uid-owner "$PROXY_BYPASS_USER" -j RETURN 44 | fi 45 | if [ -d /sys/fs/cgroup/system.slice/ ]; then 46 | iptables -t nat -A CLASH_DNS -m cgroup --path bypass_proxy -j RETURN 47 | else 48 | iptables -t nat -A CLASH_DNS -m cgroup --cgroup "$PROXY_BYPASS_CGROUP" -j RETURN 49 | fi 50 | iptables -t nat -A CLASH_DNS -p udp -j REDIRECT --to-ports "$PROXY_DNS_PORT" 51 | 52 | iptables -t mangle -I OUTPUT -j CLASH 53 | iptables -t nat -I OUTPUT -p udp --dport 53 -j CLASH_DNS 54 | 55 | if [ $ENABLE_PREROUTING = 1 ];then 56 | iptables -t mangle -I PREROUTING -m set ! --match-set localnetwork dst -j MARK --set-mark "$PROXY_FWMARK" 57 | iptables -t nat -I PREROUTING -p udp --dport 53 -j REDIRECT --to "$PROXY_DNS_PORT" 58 | fi 59 | 60 | if [ $ENABLE_IPv6 = 1 ];then 61 | ipset create localnetwork6 hash:net -6 62 | ipset add localnetwork6 fe80::/10 63 | ipset add localnetwork6 ::1/128 64 | ipset add localnetwork6 ff00::/8 65 | ipset add localnetwork6 ::/128 66 | 67 | ip -6 route replace default dev "$PROXY_TUN_DEVICE_NAME" table "$PROXY_ROUTE_TABLE" 68 | 69 | ip -6 rule add fwmark "$PROXY_FWMARK" lookup "$PROXY_ROUTE_TABLE" 70 | 71 | ip6tables -t mangle -N CLASH6 72 | ip6tables -t mangle -F CLASH6 73 | if [ $PROXY_BYPASS_USER ];then 74 | ip6tables -t mangle -A CLASH6 -m owner --uid-owner "$PROXY_BYPASS_USER" -j RETURN 75 | fi 76 | if [ -d /sys/fs/cgroup/system.slice/ ]; then 77 | ip6tables -t mangle -A CLASH6 -m cgroup --path bypass_proxy -j RETURN 78 | else 79 | ip6tables -t mangle -A CLASH6 -m cgroup --cgroup "$PROXY_BYPASS_CGROUP" -j RETURN 80 | fi 81 | ip6tables -t mangle -A CLASH6 -m set --match-set localnetwork6 dst -j RETURN 82 | ip6tables -t mangle -A CLASH6 -p udp --sport 6771 -j RETURN 83 | ip6tables -t mangle -A CLASH6 -j MARK --set-mark "$PROXY_FWMARK" 84 | 85 | ip6tables -t nat -N CLASH_DNS6 86 | ip6tables -t nat -F CLASH_DNS6 87 | if [ $PROXY_BYPASS_USER ];then 88 | ip6tables -t nat -A CLASH_DNS6 -m owner --uid-owner "$PROXY_BYPASS_USER" -j RETURN 89 | fi 90 | if [ -d /sys/fs/cgroup/system.slice/ ]; then 91 | ip6tables -t nat -A CLASH_DNS6 -m cgroup --path bypass_proxy -j RETURN 92 | else 93 | ip6tables -t nat -A CLASH_DNS6 -m cgroup --cgroup "$PROXY_BYPASS_CGROUP" -j RETURN 94 | fi 95 | ip6tables -t nat -A CLASH_DNS6 -p udp -j REDIRECT --to-ports "$PROXY_DNS_PORT" 96 | 97 | ip6tables -t mangle -I OUTPUT -j CLASH6 98 | ip6tables -t nat -I OUTPUT -p udp --dport 53 -j CLASH_DNS6 99 | if [ $ENABLE_PREROUTING = 1 ];then 100 | ip6tables -t mangle -I PREROUTING -m set ! --match-set localnetwork6 dst -j MARK --set-mark "$PROXY_FWMARK" 101 | ip6tables -t nat -I PREROUTING -p udp --dport 53 -j REDIRECT --to "$PROXY_DNS_PORT" 102 | fi 103 | 104 | fi 105 | --------------------------------------------------------------------------------