Skip to content
This repository has been archived by the owner on Oct 29, 2024. It is now read-only.

Commit

Permalink
ipv6 support
Browse files Browse the repository at this point in the history
  • Loading branch information
ChisBread committed May 9, 2022
1 parent 34bc84b commit b09e942
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 90 deletions.
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ ENV CLASH_MIXED_PORT=7893
ENV DASH_PORT=8080
ENV IP_ROUTE=1
ENV UDP_PROXY=1
ENV IPV6_PROXY=1
ENV PROXY_FWMARK=0x162
ENV PROXY_ROUTE_TABLE=0x162
ENV LOG_LEVEL="info"
ENV SECRET=""
EXPOSE $CLASH_HTTP_PORT $CLASH_SOCKS_PORT $CLASH_TPROXY_PORT $CLASH_MIXED_PORT $DASH_PORT
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ services:
- DASH_PORT=8080 # optional (default:8080) RESTful API端口(同时也是Web UI端口 e.g. http://IP:8080/ui)
- IP_ROUTE=1 # optional (default:1) 开启透明代理
- UDP_PROXY=1 # optional (default:1) 开启透明代理-UDP转发(当代理节点不支持UDP时,可关闭)
- IPV6_PROXY=0 # optional (default:1) 开启IPv6透明代理
- LOG_LEVEL=info # optional (default:info) 日志等级
- MUST_CONFIG=<path(in container!!) to must.yaml> # optional 不能被覆盖的设置项 (e.g. /etc/clash/must.yaml)
volumes:
Expand Down
6 changes: 6 additions & 0 deletions start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@
set -ex
setroute() {
/transparent_proxy/tproxy.start
if [ "$IPV6_PROXY" == "1" ]; then
/transparent_proxy/tproxy.start ipv6
fi
}
unsetroute() {
/transparent_proxy/tproxy.stop
if [ "$IPV6_PROXY" == "1" ]; then
/transparent_proxy/tproxy.stop ipv6
fi
}
#清理
_term() {
Expand Down
143 changes: 77 additions & 66 deletions transparent_proxy/tproxy.start
Original file line number Diff line number Diff line change
@@ -1,92 +1,103 @@
#!/usr/bin/env bash

set -ex

# ENABLE ipv4 forward
sysctl -w net.ipv4.ip_forward=1
IP_CMD='ip'
IPTABLES_CMD='iptables'
IP_STACK='ipv4'
NO_PROXY_IP=("0.0.0.0/8" "127.0.0.0/8" "172.16.0.0/12" "192.168.0.0/16" "169.254.0.0/16" "224.0.0.0/4" "240.0.0.0/4")
# 第一个参数决定IPv4/IPv6
if [ "$1" == "ipv6" ]; then
IP_CMD='ip -6'
IPTABLES_CMD='ip6tables'
IP_STACK='ipv6'
NO_PROXY_IP=("::/128" "::1/128" "::ffff:0:0/96" "::ffff:0:0:0/96" "64:ff9b::/96" "100::/64" "2001::/32" "2001:20::/28" "2001:db8::/32" "2002::/16" "fc00::/7" "fe80::/10" "ff00::/8")
fi

# ENABLE ip forward
if [ "$IP_STACK" == "ipv4" ]; then
sysctl -w net.ipv4.ip_forward=1
fi
if [ "$IP_STACK" == "ipv6" ]; then
sysctl -w net.ipv6.conf.all.forwarding=1
fi
# ROUTE RULES
ip rule add fwmark 666 lookup 666
ip route add local 0.0.0.0/0 dev lo table 666

$IP_CMD rule add fwmark $PROXY_FWMARK lookup $PROXY_ROUTE_TABLE
if [ "$IP_STACK" == "ipv4" ]; then
$IP_CMD route add local 0.0.0.0/0 dev lo table $PROXY_ROUTE_TABLE
fi
if [ "$IP_STACK" == "ipv6" ]; then
$IP_CMD route add local ::/0 dev lo table $PROXY_ROUTE_TABLE
fi
# CLASH 链负责处理转发流量
iptables -t mangle -N CLASH
iptables -t mangle -F CLASH
$IPTABLES_CMD -t mangle -N CLASH || true
$IPTABLES_CMD -t mangle -F CLASH || true
# 目标地址为局域网或保留地址的流量跳过处理
# 保留地址参考: https://zh.wikipedia.org/wiki/%E5%B7%B2%E5%88%86%E9%85%8D%E7%9A%84/8_IPv4%E5%9C%B0%E5%9D%80%E5%9D%97%E5%88%97%E8%A1%A8
iptables -t mangle -A CLASH -d 0.0.0.0/8 -j RETURN
iptables -t mangle -A CLASH -d 127.0.0.0/8 -j RETURN
iptables -t mangle -A CLASH -d 10.0.0.0/8 -j RETURN
iptables -t mangle -A CLASH -d 172.16.0.0/12 -j RETURN
iptables -t mangle -A CLASH -d 192.168.0.0/16 -j RETURN
iptables -t mangle -A CLASH -d 169.254.0.0/16 -j RETURN

iptables -t mangle -A CLASH -d 224.0.0.0/4 -j RETURN
iptables -t mangle -A CLASH -d 240.0.0.0/4 -j RETURN
for element in ${NO_PROXY_IP[@]}
do
$IPTABLES_CMD -t mangle -A CLASH -d $element -j RETURN
done

# 其他所有流量转向到 $CLASH_TPROXY_PORT 端口,并打上 mark
iptables -t mangle -A CLASH -p tcp -j TPROXY --on-port $CLASH_TPROXY_PORT --tproxy-mark 666
$IPTABLES_CMD -t mangle -A CLASH -p tcp -j TPROXY --on-port $CLASH_TPROXY_PORT --tproxy-mark $PROXY_FWMARK
if [ "$UDP_PROXY" == "1" ]; then
iptables -t mangle -A CLASH -p udp -j TPROXY --on-port $CLASH_TPROXY_PORT --tproxy-mark 666
$IPTABLES_CMD -t mangle -A CLASH -p udp -j TPROXY --on-port $CLASH_TPROXY_PORT --tproxy-mark $PROXY_FWMARK
fi
# 转发所有 DNS 查询到 1053 端口
# 此操作会导致所有 DNS 请求全部返回虚假 IP(fake ip 198.18.0.1/16)
# iptables -t nat -I PREROUTING -p udp --dport 53 -j REDIRECT --to 1053

# 如果想要 dig 等命令可用, 可以只处理 DNS SERVER 设置为当前内网的 DNS 请求
# iptables -t nat -I PREROUTING -p udp --dport 53 -d 192.168.0.0/16 -j REDIRECT --to 1053
iptables -t nat -N CLASH_DNS_LOCAL
iptables -t nat -N CLASH_DNS_EXTERNAL
iptables -t nat -F CLASH_DNS_LOCAL
iptables -t nat -F CLASH_DNS_EXTERNAL

iptables -t nat -A CLASH_DNS_LOCAL -p udp --dport 53 -j REDIRECT --to-ports 1053
iptables -t nat -A CLASH_DNS_LOCAL -p tcp --dport 53 -j REDIRECT --to-ports 1053
iptables -t nat -A CLASH_DNS_LOCAL -m owner --uid-owner clash -j RETURN

iptables -t nat -A CLASH_DNS_EXTERNAL -p udp --dport 53 -j REDIRECT --to-ports 1053
iptables -t nat -A CLASH_DNS_EXTERNAL -p tcp --dport 53 -j REDIRECT --to-ports 1053

iptables -t nat -I OUTPUT -p udp -j CLASH_DNS_LOCAL
iptables -t nat -I PREROUTING -p udp -j CLASH_DNS_EXTERNAL

# 最后让所有流量通过 CLASH 链进行处理
iptables -t mangle -A PREROUTING -j CLASH

# CLASH_LOCAL 链负责处理网关本身发出的流量
iptables -t mangle -N CLASH_LOCAL
iptables -t mangle -F CLASH_LOCAL
# nerdctl 容器流量重新路由
#iptables -t mangle -A CLASH_LOCAL -i nerdctl2 -p udp -j MARK --set-mark 666
#iptables -t mangle -A CLASH_LOCAL -i nerdctl2 -p tcp -j MARK --set-mark 666

$IPTABLES_CMD -t mangle -N CLASH_LOCAL || true
$IPTABLES_CMD -t mangle -F CLASH_LOCAL || true
# 跳过内网流量
iptables -t mangle -A CLASH_LOCAL -d 0.0.0.0/8 -j RETURN
iptables -t mangle -A CLASH_LOCAL -d 127.0.0.0/8 -j RETURN
iptables -t mangle -A CLASH_LOCAL -d 10.0.0.0/8 -j RETURN
iptables -t mangle -A CLASH_LOCAL -d 172.16.0.0/12 -j RETURN
iptables -t mangle -A CLASH_LOCAL -d 192.168.0.0/16 -j RETURN
iptables -t mangle -A CLASH_LOCAL -d 169.254.0.0/16 -j RETURN
for element in ${NO_PROXY_IP[@]}
do
$IPTABLES_CMD -t mangle -A CLASH_LOCAL -d $element -j RETURN
done

iptables -t mangle -A CLASH_LOCAL -d 224.0.0.0/4 -j RETURN
iptables -t mangle -A CLASH_LOCAL -d 240.0.0.0/4 -j RETURN

# 为本机发出的流量打 mark
iptables -t mangle -A CLASH_LOCAL -p tcp -j MARK --set-mark 666
# 跳过 CLASH 程序本身发出的流量, 防止死循环(CLASH 程序需要使用 "CLASH" 用户启动)
$IPTABLES_CMD -t mangle -A OUTPUT -p tcp -m owner --uid-owner clash -j RETURN
if [ "$UDP_PROXY" == "1" ]; then
iptables -t mangle -A CLASH_LOCAL -p udp -j MARK --set-mark 666
$IPTABLES_CMD -t mangle -A OUTPUT -p udp -m owner --uid-owner clash -j RETURN
fi
# 跳过 CLASH 程序本身发出的流量, 防止死循环(CLASH 程序需要使用 "CLASH" 用户启动)
iptables -t mangle -A OUTPUT -p tcp -m owner --uid-owner clash -j RETURN
# 为本机发出的流量打 mark
$IPTABLES_CMD -t mangle -A CLASH_LOCAL -p tcp -j MARK --set-mark $PROXY_FWMARK
if [ "$UDP_PROXY" == "1" ]; then
iptables -t mangle -A OUTPUT -p udp -m owner --uid-owner clash -j RETURN
$IPTABLES_CMD -t mangle -A CLASH_LOCAL -p udp -j MARK --set-mark $PROXY_FWMARK
fi

# 让本机发出的流量跳转到 CLASH_LOCAL
# CLASH_LOCAL 链会为本机流量打 mark, 打过 mark 的流量会重新回到 PREROUTING 上
iptables -t mangle -A OUTPUT -j CLASH_LOCAL
$IPTABLES_CMD -t mangle -A OUTPUT -j CLASH_LOCAL

# 修复 ICMP(ping)
# 这并不能保证 ping 结果有效(CLASH 等不支持转发 ICMP), 只是让它有返回结果而已
# --to-destination 设置为一个可达的地址即可
sysctl -w net.ipv4.conf.all.route_localnet=1
iptables -t nat -A PREROUTING -p icmp -d 198.18.0.0/16 -j DNAT --to-destination 127.0.0.1
if [ "$IP_STACK" == "ipv4" ]; then
sysctl -w net.$IP_STACK.conf.all.route_localnet=1
$IPTABLES_CMD -t nat -A PREROUTING -p icmp -d 198.18.0.0/16 -j DNAT --to-destination 127.0.0.1
fi

#################### DNS #########################

# 转发所有 DNS 查询到 1053 端口
# 此操作会导致所有 DNS 请求全部返回虚假 IP(fake ip 198.18.0.1/16)
# $IPTABLES_CMD -t nat -I PREROUTING -p udp --dport 53 -j REDIRECT --to 1053

# 如果想要 dig 等命令可用, 可以只处理 DNS SERVER 设置为当前内网的 DNS 请求
# $IPTABLES_CMD -t nat -I PREROUTING -p udp --dport 53 -d 192.168.0.0/16 -j REDIRECT --to 1053
$IPTABLES_CMD -t nat -N CLASH_DNS_LOCAL
$IPTABLES_CMD -t nat -N CLASH_DNS_EXTERNAL
$IPTABLES_CMD -t nat -F CLASH_DNS_LOCAL
$IPTABLES_CMD -t nat -F CLASH_DNS_EXTERNAL

$IPTABLES_CMD -t nat -A CLASH_DNS_LOCAL -p udp --dport 53 -j REDIRECT --to-ports 1053
$IPTABLES_CMD -t nat -A CLASH_DNS_LOCAL -p tcp --dport 53 -j REDIRECT --to-ports 1053
$IPTABLES_CMD -t nat -A CLASH_DNS_LOCAL -m owner --uid-owner clash -j RETURN

$IPTABLES_CMD -t nat -A CLASH_DNS_EXTERNAL -p udp --dport 53 -j REDIRECT --to-ports 1053
$IPTABLES_CMD -t nat -A CLASH_DNS_EXTERNAL -p tcp --dport 53 -j REDIRECT --to-ports 1053

$IPTABLES_CMD -t nat -I OUTPUT -p udp -j CLASH_DNS_LOCAL
$IPTABLES_CMD -t nat -I PREROUTING -p udp -j CLASH_DNS_EXTERNAL

# 最后让所有流量通过 CLASH 链进行处理
$IPTABLES_CMD -t mangle -A PREROUTING -j CLASH
64 changes: 40 additions & 24 deletions transparent_proxy/tproxy.stop
Original file line number Diff line number Diff line change
@@ -1,50 +1,66 @@
#!/usr/bin/env bash
set -x

# set -ex
IP_CMD='ip'
IPTABLES_CMD='iptables'
IP_STACK='ipv4'
# 第一个参数决定IPv4/IPv6
if [ "$1" == "ipv6" ]; then
IP_CMD='ip -6'
IPTABLES_CMD='ip6tables'
IP_STACK='ipv6'
fi

ip rule del fwmark 666 table 666 || true
ip route del local 0.0.0.0/0 dev lo table 666 || true
$IP_CMD rule del fwmark $PROXY_FWMARK table $PROXY_ROUTE_TABLE || true
if [ "$IP_STACK" == "ipv4" ]; then
$IP_CMD route del local 0.0.0.0/0 dev lo table $PROXY_ROUTE_TABLE || true
fi
if [ "$IP_STACK" == "ipv6" ]; then
$IP_CMD route del local ::/0 dev lo table $PROXY_ROUTE_TABLE
fi

################ 清理DNS规则 ##################
while :
do
iptables -t nat -D PREROUTING -p udp -j CLASH_DNS_EXTERNAL
$IPTABLES_CMD -t nat -D PREROUTING -p udp -j CLASH_DNS_EXTERNAL
if [ "$?" == "0" ]; then continue; fi
iptables -t nat -D OUTPUT -p udp -j CLASH_DNS_LOCAL
$IPTABLES_CMD -t nat -D OUTPUT -p udp -j CLASH_DNS_LOCAL
if [ "$?" == "0" ]; then continue; fi
iptables -t nat -D CLASH_DNS_EXTERNAL -p tcp --dport 53 -j REDIRECT --to-ports 1053
$IPTABLES_CMD -t nat -D CLASH_DNS_EXTERNAL -p tcp --dport 53 -j REDIRECT --to-ports 1053
if [ "$?" == "0" ]; then continue; fi
iptables -t nat -D CLASH_DNS_EXTERNAL -p udp --dport 53 -j REDIRECT --to-ports 1053
$IPTABLES_CMD -t nat -D CLASH_DNS_EXTERNAL -p udp --dport 53 -j REDIRECT --to-ports 1053
if [ "$?" == "0" ]; then continue; fi
iptables -t nat -D CLASH_DNS_LOCAL -m owner --uid-owner clash -j RETURN
$IPTABLES_CMD -t nat -D CLASH_DNS_LOCAL -m owner --uid-owner clash -j RETURN
if [ "$?" == "0" ]; then continue; fi
iptables -t nat -D CLASH_DNS_LOCAL -p tcp --dport 53 -j REDIRECT --to-ports 1053
$IPTABLES_CMD -t nat -D CLASH_DNS_LOCAL -p tcp --dport 53 -j REDIRECT --to-ports 1053
if [ "$?" == "0" ]; then continue; fi
iptables -t nat -D CLASH_DNS_LOCAL -p udp --dport 53 -j REDIRECT --to-ports 1053
$IPTABLES_CMD -t nat -D CLASH_DNS_LOCAL -p udp --dport 53 -j REDIRECT --to-ports 1053
if [ "$?" == "0" ]; then continue; fi
break;
done
iptables -t nat -F CLASH_DNS_EXTERNAL
iptables -t nat -F CLASH_DNS_LOCAL
iptables -t nat -X CLASH_DNS_EXTERNAL || true
iptables -t nat -X CLASH_DNS_LOCAL || true
$IPTABLES_CMD -t nat -F CLASH_DNS_EXTERNAL
$IPTABLES_CMD -t nat -F CLASH_DNS_LOCAL
$IPTABLES_CMD -t nat -X CLASH_DNS_EXTERNAL || true
$IPTABLES_CMD -t nat -X CLASH_DNS_LOCAL || true

################ 清理TPROXY规则 ##################
while :
do
iptables -t nat -D PREROUTING -p icmp -d 198.18.0.0/16 -j DNAT --to-destination 127.0.0.1
if [ "$IP_STACK" == "ipv4" ]; then
$IPTABLES_CMD -t nat -D PREROUTING -p icmp -d 198.18.0.0/16 -j DNAT --to-destination 127.0.0.1
if [ "$?" == "0" ]; then continue; fi
fi
$IPTABLES_CMD -t mangle -D OUTPUT -j CLASH_LOCAL
if [ "$?" == "0" ]; then continue; fi
iptables -t mangle -D OUTPUT -j CLASH_LOCAL
$IPTABLES_CMD -t mangle -D OUTPUT -p tcp -m owner --uid-owner clash -j RETURN
if [ "$?" == "0" ]; then continue; fi
iptables -t mangle -D OUTPUT -p tcp -m owner --uid-owner clash -j RETURN
$IPTABLES_CMD -t mangle -D OUTPUT -p udp -m owner --uid-owner clash -j RETURN
if [ "$?" == "0" ]; then continue; fi
iptables -t mangle -D OUTPUT -p udp -m owner --uid-owner clash -j RETURN
if [ "$?" == "0" ]; then continue; fi
iptables -t mangle -D PREROUTING -j CLASH
$IPTABLES_CMD -t mangle -D PREROUTING -j CLASH
if [ "$?" == "0" ]; then continue; fi
break;
done
iptables -t mangle -F CLASH
iptables -t mangle -F CLASH_LOCAL
iptables -t mangle -X CLASH || true
iptables -t mangle -X CLASH_LOCAL || true
$IPTABLES_CMD -t mangle -F CLASH
$IPTABLES_CMD -t mangle -F CLASH_LOCAL
$IPTABLES_CMD -t mangle -X CLASH || true
$IPTABLES_CMD -t mangle -X CLASH_LOCAL || true

0 comments on commit b09e942

Please sign in to comment.