ssr-rules 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051
  1. #!/bin/sh
  2. #
  3. # Copyright (C) 2017 openwrt-ssr
  4. # Copyright (C) 2017 yushi studio <[email protected]>
  5. #
  6. # This is free software, licensed under the GNU General Public License v3.
  7. # See /LICENSE for more information.
  8. #
  9. # Detect firewall version and set appropriate tools
  10. detect_firewall() {
  11. if command -v nft >/dev/null 2>&1 && \
  12. { [ -n "$(uci get firewall.@defaults[0].syn_flood 2>/dev/null)" ] || \
  13. [ -n "$(uci get firewall.@defaults[0].synflood_protect 2>/dev/null)" ]; } && \
  14. ! grep -q "fw3" /etc/init.d/firewall 2>/dev/null; then
  15. USE_NFT=1
  16. NFT="nft"
  17. FWI=$(uci get firewall.shadowsocksr.path 2>/dev/null) # firewall include file
  18. else
  19. USE_NFT=0
  20. IPT="iptables -t nat" # alias of iptables
  21. FWI=$(uci get firewall.shadowsocksr.path 2>/dev/null) # firewall include file
  22. fi
  23. }
  24. # Initialize firewall detection
  25. detect_firewall
  26. TAG="_SS_SPEC_RULE_" # comment tag
  27. usage() {
  28. cat <<-EOF
  29. Usage: ssr-rules [options]
  30. Valid options are:
  31. -s <server_ip> ip address of shadowsocksr remote server
  32. -l <local_port> port number of shadowsocksr local server
  33. -S <server_ip> ip address of shadowsocksr remote UDP server
  34. -L <local_port> port number of shadowsocksr local UDP server
  35. -i <ip_list_file> a file content is bypassed ip list
  36. -a <lan_ips> lan ip of access control, need a prefix to
  37. define access control mode
  38. -b <wan_ips> wan ip of will be bypassed
  39. -w <wan_ips> wan ip of will be forwarded
  40. -B <bp_lan_ips> lan ip of will be bypassed proxy
  41. -p <fp_lan_ips> lan ip of will be global proxy
  42. -G <gm_lan_ips> lan ip of will be game mode proxy
  43. -D <proxy_ports> proxy ports
  44. -F shunt mode
  45. -N shunt server IP
  46. -M shunt proxy mode
  47. -m <Interface> Interface name
  48. -I <ip_list_file> a file content is bypassed shunt ip list
  49. -e <extra_options> extra options for iptables
  50. -o apply the rules to the OUTPUT chain
  51. -O apply the global rules to the OUTPUT chain
  52. -u enable udprelay mode, TPROXY is required
  53. -U enable udprelay mode, using different IP
  54. and ports for TCP and UDP
  55. -f flush the rules
  56. -g gfwlist mode
  57. -r router mode
  58. -c oversea mode
  59. -z all mode
  60. -h show this help message and exit
  61. EOF
  62. exit $1
  63. }
  64. loger() {
  65. # 1.alert 2.crit 3.err 4.warn 5.notice 6.info 7.debug
  66. logger -st ssr-rules[$$] -p$1 $2
  67. }
  68. flush_r() {
  69. if [ "$USE_NFT" = "1" ]; then
  70. flush_nftables
  71. else
  72. flush_iptables_legacy
  73. fi
  74. return 0
  75. }
  76. flush_nftables() {
  77. # 删除 inet ss_spec 表
  78. if $NFT list table inet ss_spec >/dev/null 2>&1; then
  79. # 删除所有链
  80. local CHAINS=$($NFT list table inet ss_spec | awk '/chain [a-zA-Z0-9_-]+/ {print $2}' | sort -u)
  81. for chain in $CHAINS; do
  82. $NFT flush chain inet ss_spec $chain 2>/dev/null
  83. $NFT delete chain inet ss_spec $chain 2>/dev/null
  84. done
  85. # 删除所有集合(set)
  86. local SETS=$($NFT list table inet ss_spec | awk '/set [a-zA-Z0-9_-]+/ {print $2}' | sort -u)
  87. for setname in $SETS; do
  88. $NFT flush set inet ss_spec $setname 2>/dev/null
  89. $NFT delete set inet ss_spec $setname 2>/dev/null
  90. done
  91. # 删除整个表
  92. $NFT delete table inet ss_spec 2>/dev/null
  93. fi
  94. # 删除 ip ss_spec_mangle 表(如果存在)
  95. if $NFT list table ip ss_spec_mangle >/dev/null 2>&1; then
  96. # 删除所有链
  97. local CHAINS=$($NFT list table ip ss_spec_mangle | awk '/chain [a-zA-Z0-9_-]+/ {print $2}' | sort -u)
  98. for chain in $CHAINS; do
  99. $NFT flush chain ip ss_spec_mangle $chain 2>/dev/null
  100. $NFT delete chain ip ss_spec_mangle $chain 2>/dev/null
  101. done
  102. # 删除所有集合(set)
  103. local SETS=$($NFT list table ip ss_spec_mangle | awk '/set [a-zA-Z0-9_-]+/ {print $2}' | sort -u)
  104. for setname in $SETS; do
  105. $NFT flush set ip ss_spec_mangle $setname 2>/dev/null
  106. $NFT delete set ip ss_spec_mangle $setname 2>/dev/null
  107. done
  108. # 删除整个表
  109. $NFT delete table ip ss_spec_mangle 2>/dev/null
  110. fi
  111. # 删除策略路由标记规则
  112. ip rule del fwmark 0x01/0x01 table 100 2>/dev/null
  113. ip route del local 0.0.0.0/0 dev lo table 100 2>/dev/null
  114. # 可选:强制删除所有 ss_spec 相关的集合(即使表被误删)
  115. for setname in ss_spec_lan_ac ss_spec_wan_ac ssr_gen_router fplan bplan gmlan oversea whitelist blacklist netflix gfwlist china music; do
  116. $NFT delete set inet ss_spec $setname 2>/dev/null
  117. $NFT delete set ip ss_spec_mangle $setname 2>/dev/null
  118. done
  119. # 重置防火墙 include 文件
  120. [ -n "$FWI" ] && echo '#!/bin/sh' >"$FWI"
  121. return 0
  122. }
  123. flush_iptables_legacy() {
  124. flush_iptables() {
  125. local ipt="iptables -t $1"
  126. local DAT=$(iptables-save -t $1)
  127. eval $(echo "$DAT" | grep "$TAG" | sed -e 's/^-A/$ipt -D/' -e 's/$/;/')
  128. for chain in $(echo "$DAT" | awk '/^:SS_SPEC/{print $1}'); do
  129. $ipt -F ${chain:1} 2>/dev/null && $ipt -X ${chain:1}
  130. done
  131. }
  132. flush_iptables nat
  133. flush_iptables mangle
  134. ip rule del fwmark 0x01/0x01 table 100 2>/dev/null
  135. ip route del local 0.0.0.0/0 dev lo table 100 2>/dev/null
  136. ipset -X ss_spec_lan_ac 2>/dev/null
  137. ipset -X ss_spec_wan_ac 2>/dev/null
  138. ipset -X ssr_gen_router 2>/dev/null
  139. ipset -X fplan 2>/dev/null
  140. ipset -X bplan 2>/dev/null
  141. ipset -X gmlan 2>/dev/null
  142. ipset -X oversea 2>/dev/null
  143. ipset -X whitelist 2>/dev/null
  144. ipset -X blacklist 2>/dev/null
  145. ipset -X netflix 2>/dev/null
  146. [ -n "$FWI" ] && echo '#!/bin/sh' >$FWI
  147. return 0
  148. }
  149. ipset_r() {
  150. if [ "$USE_NFT" = "1" ]; then
  151. ipset_nft
  152. else
  153. ipset_iptables
  154. fi
  155. return $?
  156. }
  157. ipset_nft() {
  158. # Create nftables table and sets
  159. if ! $NFT list table inet ss_spec >/dev/null 2>&1; then
  160. $NFT add table inet ss_spec 2>/dev/null
  161. fi
  162. # Create necessary collections
  163. for setname in china gmlan fplan bplan whitelist blacklist netflix; do
  164. if ! $NFT list set inet ss_spec $setname >/dev/null 2>&1; then
  165. $NFT add set inet ss_spec $setname '{ type ipv4_addr; flags interval; auto-merge; }' 2>/dev/null
  166. else
  167. $NFT flush set inet ss_spec $setname 2>/dev/null
  168. fi
  169. done
  170. # 批量导入中国IP列表
  171. if [ -f "${china_ip:=/etc/ssrplus/china_ssr.txt}" ]; then
  172. $NFT add element inet ss_spec china "{ $(tr '\n' ',' < "${china_ip}" | sed 's/,$//') }" 2>/dev/null
  173. fi
  174. # Add IP addresses to sets
  175. for ip in $LAN_GM_IP; do
  176. [ -n "$ip" ] && $NFT add element inet ss_spec gmlan "{ $ip }" 2>/dev/null
  177. done
  178. for ip in $LAN_FP_IP; do
  179. [ -n "$ip" ] && $NFT add element inet ss_spec fplan "{ $ip }" 2>/dev/null
  180. done
  181. for ip in $LAN_BP_IP; do
  182. [ -n "$ip" ] && $NFT add element inet ss_spec bplan "{ $ip }" 2>/dev/null
  183. done
  184. for ip in $WAN_BP_IP; do
  185. [ -n "$ip" ] && $NFT add element inet ss_spec whitelist "{ $ip }" 2>/dev/null
  186. done
  187. for ip in $WAN_FW_IP; do
  188. [ -n "$ip" ] && $NFT add element inet ss_spec blacklist "{ $ip }" 2>/dev/null
  189. done
  190. # Create main chain for WAN access control
  191. if ! $NFT list chain inet ss_spec ss_spec_wan_ac >/dev/null 2>&1; then
  192. $NFT add chain inet ss_spec ss_spec_wan_ac 2>/dev/null
  193. fi
  194. $NFT flush chain inet ss_spec ss_spec_wan_ac 2>/dev/null
  195. # Create forward chain with better error handling
  196. if ! $NFT list chain inet ss_spec ss_spec_wan_fw >/dev/null 2>&1; then
  197. $NFT add chain inet ss_spec ss_spec_wan_fw 2>/dev/null || {
  198. loger 3 "Failed to create forward chain"
  199. return 1
  200. }
  201. fi
  202. # Clear existing rules
  203. $NFT flush chain inet ss_spec ss_spec_wan_fw 2>/dev/null
  204. EXT_ARGS=""
  205. if [ -n "$PROXY_PORTS" ]; then
  206. PORTS_ARGS=$(echo "$PROXY_PORTS" | sed 's/-m multiport --dports //')
  207. if [ -n "$PORTS_ARGS" ]; then
  208. EXT_ARGS="th dport { $PORTS_ARGS }"
  209. fi
  210. fi
  211. # Add basic rules
  212. # ========== 按照正确顺序添加规则 ==========
  213. # 1. 基础例外规则(最高优先级)
  214. $NFT add rule inet ss_spec ss_spec_wan_ac tcp dport 53 ip daddr 127.0.0.0/8 return
  215. [ -n "$server" ] && $NFT add rule inet ss_spec ss_spec_wan_ac tcp dport != 53 ip daddr "$server" return
  216. # 2. 强制访问控制
  217. $NFT add rule inet ss_spec ss_spec_wan_ac ip daddr @blacklist jump ss_spec_wan_fw
  218. $NFT add rule inet ss_spec ss_spec_wan_ac ip daddr @whitelist return
  219. $NFT add rule inet ss_spec ss_spec_wan_ac ip saddr @fplan jump ss_spec_wan_fw
  220. $NFT add rule inet ss_spec ss_spec_wan_ac ip saddr @bplan return
  221. # 3. 特殊功能规则
  222. # Music unlocking support
  223. if $NFT list set inet ss_spec music >/dev/null 2>&1; then
  224. $NFT add rule inet ss_spec ss_spec_wan_ac ip daddr @music return
  225. fi
  226. # Shunt/Netflix rules
  227. if [ "$SHUNT_PORT" != "0" ] && [ -f "$SHUNT_LIST" ]; then
  228. for ip in $(cat "$SHUNT_LIST" 2>/dev/null); do
  229. [ -n "$ip" ] && $NFT add element inet ss_spec netflix "{ $ip }" 2>/dev/null
  230. done
  231. case "$SHUNT_PORT" in
  232. 1)
  233. $NFT add rule inet ss_spec ss_spec_wan_ac meta l4proto tcp $EXT_ARGS ip daddr @netflix counter redirect to :$local_port
  234. ;;
  235. *)
  236. $NFT add rule inet ss_spec ss_spec_wan_ac meta l4proto tcp $EXT_ARGS ip daddr @netflix counter redirect to :$SHUNT_PORT
  237. if [ "$SHUNT_PROXY" = "1" ]; then
  238. $NFT add rule inet ss_spec ss_spec_wan_ac meta l4proto tcp $EXT_ARGS ip daddr $SHUNT_IP counter redirect to :$local_port
  239. else
  240. [ -n "$SHUNT_IP" ] && $NFT add element inet ss_spec whitelist "{ $SHUNT_IP }" 2>/dev/null
  241. fi
  242. ;;
  243. esac
  244. fi
  245. # 4. 模式特定规则
  246. # Set up mode-specific rules
  247. case "$RUNMODE" in
  248. router)
  249. if ! $NFT list set inet ss_spec ss_spec_wan_ac >/dev/null 2>&1; then
  250. $NFT add set inet ss_spec ss_spec_wan_ac '{ type ipv4_addr; flags interval; auto-merge; }'
  251. else
  252. $NFT flush set inet ss_spec ss_spec_wan_ac 2>/dev/null
  253. fi
  254. # Add special IP ranges to WAN AC set
  255. for ip in $(gen_spec_iplist); do
  256. [ -n "$ip" ] && $NFT add element inet ss_spec ss_spec_wan_ac "{ $ip }" 2>/dev/null
  257. done
  258. $NFT add rule inet ss_spec ss_spec_wan_ac ip daddr @ss_spec_wan_ac return
  259. $NFT add rule inet ss_spec ss_spec_wan_ac ip daddr @china return
  260. if $NFT list chain inet ss_spec ss_spec_wan_fw >/dev/null 2>&1; then
  261. $NFT add rule inet ss_spec ss_spec_wan_ac ip saddr @gmlan ip daddr != @china jump ss_spec_wan_fw
  262. $NFT add rule inet ss_spec ss_spec_wan_ac jump ss_spec_wan_fw
  263. fi
  264. ;;
  265. gfw)
  266. if ! $NFT list set inet ss_spec gfwlist >/dev/null 2>&1; then
  267. $NFT add set inet ss_spec gfwlist '{ type ipv4_addr; flags interval; auto-merge; }' 2>/dev/null
  268. fi
  269. $NFT add rule inet ss_spec ss_spec_wan_ac ip daddr @china return
  270. $NFT add rule inet ss_spec ss_spec_wan_ac ip daddr @gfwlist jump ss_spec_wan_fw
  271. $NFT add rule inet ss_spec ss_spec_wan_ac ip saddr @gmlan ip daddr != @china jump ss_spec_wan_fw
  272. ;;
  273. oversea)
  274. if ! $NFT list set inet ss_spec oversea >/dev/null 2>&1; then
  275. $NFT add set inet ss_spec oversea '{ type ipv4_addr; flags interval; auto-merge; }' 2>/dev/null
  276. fi
  277. $NFT add rule inet ss_spec ss_spec_wan_ac ip daddr @oversea jump ss_spec_wan_fw
  278. $NFT add rule inet ss_spec ss_spec_wan_ac ip saddr @gmlan jump ss_spec_wan_fw
  279. $NFT add rule inet ss_spec ss_spec_wan_ac ip daddr @china jump ss_spec_wan_fw
  280. ;;
  281. all)
  282. if $NFT list chain inet ss_spec ss_spec_wan_fw >/dev/null 2>&1; then
  283. $NFT add rule inet ss_spec ss_spec_wan_ac jump ss_spec_wan_fw
  284. fi
  285. ;;
  286. esac
  287. return $?
  288. }
  289. ipset_iptables() {
  290. [ -f "$IGNORE_LIST" ] && /usr/share/shadowsocksr/chinaipset.sh "$IGNORE_LIST"
  291. $IPT -N SS_SPEC_WAN_AC 2>/dev/null
  292. $IPT -I SS_SPEC_WAN_AC -p tcp --dport 53 -d 127.0.0.0/8 -j RETURN
  293. $IPT -I SS_SPEC_WAN_AC -p tcp ! --dport 53 -d "$server" -j RETURN
  294. ipset -N gmlan hash:net 2>/dev/null
  295. for ip in $LAN_GM_IP; do ipset -! add gmlan "$ip"; done
  296. case "$RUNMODE" in
  297. router)
  298. ipset -! -R <<-EOF || return 1
  299. create ss_spec_wan_ac hash:net
  300. $(gen_spec_iplist | sed -e "s/^/add ss_spec_wan_ac /")
  301. EOF
  302. $IPT -A SS_SPEC_WAN_AC -m set --match-set ss_spec_wan_ac dst -j RETURN
  303. $IPT -A SS_SPEC_WAN_AC -m set --match-set china dst -j RETURN
  304. $IPT -A SS_SPEC_WAN_AC -m set --match-set gmlan src -m set ! --match-set china dst -j SS_SPEC_WAN_FW
  305. $IPT -A SS_SPEC_WAN_AC -j SS_SPEC_WAN_FW
  306. ;;
  307. gfw)
  308. ipset -N gfwlist hash:net 2>/dev/null
  309. $IPT -A SS_SPEC_WAN_AC -m set --match-set china dst -j RETURN
  310. $IPT -A SS_SPEC_WAN_AC -m set --match-set gfwlist dst -j SS_SPEC_WAN_FW
  311. $IPT -A SS_SPEC_WAN_AC -m set --match-set gmlan src -m set ! --match-set china dst -j SS_SPEC_WAN_FW
  312. ;;
  313. oversea)
  314. ipset -N oversea hash:net 2>/dev/null
  315. $IPT -I SS_SPEC_WAN_AC -m set --match-set oversea dst -j SS_SPEC_WAN_FW
  316. $IPT -A SS_SPEC_WAN_AC -m set --match-set gmlan src -j SS_SPEC_WAN_FW
  317. $IPT -A SS_SPEC_WAN_AC -m set --match-set china dst -j SS_SPEC_WAN_FW
  318. ;;
  319. all)
  320. $IPT -A SS_SPEC_WAN_AC -j SS_SPEC_WAN_FW
  321. ;;
  322. esac
  323. ipset -N fplan hash:net 2>/dev/null
  324. for ip in $LAN_FP_IP; do ipset -! add fplan "$ip"; done
  325. $IPT -I SS_SPEC_WAN_AC -m set --match-set fplan src -j SS_SPEC_WAN_FW
  326. ipset -N bplan hash:net 2>/dev/null
  327. for ip in $LAN_BP_IP; do ipset -! add bplan "$ip"; done
  328. $IPT -I SS_SPEC_WAN_AC -m set --match-set bplan src -j RETURN
  329. ipset -N whitelist hash:net 2>/dev/null
  330. ipset -N blacklist hash:net 2>/dev/null
  331. $IPT -I SS_SPEC_WAN_AC -m set --match-set blacklist dst -j SS_SPEC_WAN_FW
  332. $IPT -I SS_SPEC_WAN_AC -m set --match-set whitelist dst -j RETURN
  333. if [ $(ipset list music -name -quiet | grep music) ]; then
  334. $IPT -I SS_SPEC_WAN_AC -m set --match-set music dst -j RETURN 2>/dev/null
  335. fi
  336. for ip in $WAN_BP_IP; do ipset -! add whitelist "$ip"; done
  337. for ip in $WAN_FW_IP; do ipset -! add blacklist "$ip"; done
  338. if [ "$SHUNT_PORT" != "0" ]; then
  339. ipset -N netflix hash:net 2>/dev/null
  340. for ip in $(cat "${SHUNT_LIST:=/dev/null}" 2>/dev/null); do ipset -! add netflix "$ip"; done
  341. case "$SHUNT_PORT" in
  342. 0) ;;
  343. 1)
  344. $IPT -I SS_SPEC_WAN_AC -p tcp -m set --match-set netflix dst -j REDIRECT --to-ports "$local_port"
  345. ;;
  346. *)
  347. $IPT -I SS_SPEC_WAN_AC -p tcp -m set --match-set netflix dst -j REDIRECT --to-ports "$SHUNT_PORT"
  348. if [ "$SHUNT_PROXY" = "1" ]; then
  349. $IPT -I SS_SPEC_WAN_AC -p tcp -d "$SHUNT_IP" -j REDIRECT --to-ports "$local_port"
  350. else
  351. ipset -! add whitelist "$SHUNT_IP"
  352. fi
  353. ;;
  354. esac
  355. fi
  356. return $?
  357. }
  358. fw_rule() {
  359. if [ "$USE_NFT" = "1" ]; then
  360. fw_rule_nft
  361. else
  362. fw_rule_iptables
  363. fi
  364. return $?
  365. }
  366. fw_rule_nft() {
  367. # Exclude special local addresses
  368. if $NFT list chain inet ss_spec ss_spec_wan_fw >/dev/null 2>&1; then
  369. for net in 0.0.0.0/8 10.0.0.0/8 127.0.0.0/8 169.254.0.0/16 172.16.0.0/12 192.168.0.0/16 224.0.0.0/4 240.0.0.0/4; do
  370. $NFT add rule inet ss_spec ss_spec_wan_fw ip daddr $net return 2>/dev/null
  371. done
  372. fi
  373. # redirect/translation: when PROXY_PORTS present, redirect those tcp ports to local_port
  374. if [ -n "$PROXY_PORTS" ]; then
  375. PORTS=$(echo "$PROXY_PORTS" | sed 's/-m multiport --dports //')
  376. RULE="tcp dport { $PORTS } counter redirect to :"$local_port""
  377. else
  378. # default: redirect everything except ssh(22)
  379. RULE="tcp dport != 22 counter redirect to :"$local_port""
  380. fi
  381. if ! $NFT list chain inet ss_spec ss_spec_wan_fw 2>/dev/null | grep -q "$RULE"; then
  382. if ! $NFT add rule inet ss_spec ss_spec_wan_fw $RULE 2>/dev/null; then
  383. loger 3 "Can't redirect, please check nftables."
  384. return 1
  385. fi
  386. fi
  387. return $?
  388. }
  389. fw_rule_iptables() {
  390. $IPT -N SS_SPEC_WAN_FW
  391. $IPT -A SS_SPEC_WAN_FW -d 0.0.0.0/8 -j RETURN
  392. $IPT -A SS_SPEC_WAN_FW -d 10.0.0.0/8 -j RETURN
  393. $IPT -A SS_SPEC_WAN_FW -d 127.0.0.0/8 -j RETURN
  394. $IPT -A SS_SPEC_WAN_FW -d 169.254.0.0/16 -j RETURN
  395. $IPT -A SS_SPEC_WAN_FW -d 172.16.0.0/12 -j RETURN
  396. $IPT -A SS_SPEC_WAN_FW -d 192.168.0.0/16 -j RETURN
  397. $IPT -A SS_SPEC_WAN_FW -d 224.0.0.0/4 -j RETURN
  398. $IPT -A SS_SPEC_WAN_FW -d 240.0.0.0/4 -j RETURN
  399. $IPT -A SS_SPEC_WAN_FW -p tcp $PROXY_PORTS -j REDIRECT --to-ports "$local_port" 2>/dev/null || {
  400. loger 3 "Can't redirect, please check the iptables."
  401. exit 1
  402. }
  403. return $?
  404. }
  405. ac_rule() {
  406. if [ "$USE_NFT" = "1" ]; then
  407. ac_rule_nft
  408. else
  409. ac_rule_iptables
  410. fi
  411. return $?
  412. }
  413. ac_rule_nft() {
  414. local MATCH_SET=""
  415. if [ -n "$LAN_AC_IP" ]; then
  416. # Create LAN access control set if needed
  417. if ! $NFT list set inet ss_spec ss_spec_lan_ac >/dev/null 2>&1; then
  418. $NFT add set inet ss_spec ss_spec_lan_ac '{ type ipv4_addr; flags interval; }' 2>/dev/null
  419. else
  420. $NFT flush set inet ss_spec ss_spec_lan_ac 2>/dev/null
  421. fi
  422. for ip in ${LAN_AC_IP#?}; do
  423. [ -n "$ip" ] && $NFT add element inet ss_spec ss_spec_lan_ac "{ $ip }" 2>/dev/null
  424. done
  425. case "${LAN_AC_IP%${LAN_AC_IP#?}}" in
  426. w | W)
  427. MATCH_SET="ip saddr @ss_spec_lan_ac"
  428. ;;
  429. b | B)
  430. MATCH_SET="ip saddr != @ss_spec_lan_ac"
  431. ;;
  432. *)
  433. loger 3 "Bad argument \`-a $LAN_AC_IP\`."
  434. return 2
  435. ;;
  436. esac
  437. fi
  438. # 创建ss_spec_prerouting链
  439. if ! $NFT list chain inet ss_spec ss_spec_prerouting >/dev/null 2>&1; then
  440. $NFT add chain inet ss_spec ss_spec_prerouting '{ type nat hook prerouting priority 0; policy accept; }'
  441. fi
  442. $NFT flush chain inet ss_spec ss_spec_prerouting 2>/dev/null
  443. # 创建ss_spec_output链
  444. if ! $NFT list chain inet ss_spec ss_spec_output >/dev/null 2>&1; then
  445. $NFT add chain inet ss_spec ss_spec_output '{ type nat hook output priority 0; policy accept; }'
  446. fi
  447. $NFT flush chain inet ss_spec ss_spec_output 2>/dev/null
  448. # Build a rule in the prerouting hook chain that jumps to business chain with conditions
  449. EXT_ARGS=""
  450. if [ -n "$PROXY_PORTS" ]; then
  451. PORTS_ARGS=$(echo "$PROXY_PORTS" | sed 's/-m multiport --dports //')
  452. if [ -n "$PORTS_ARGS" ]; then
  453. EXT_ARGS="th dport { $PORTS_ARGS }"
  454. fi
  455. fi
  456. if [ -z "$Interface" ]; then
  457. # generic prerouting jump already exists (see ipset_nft), but if we have MATCH_SET_CONDITION we add a more specific rule
  458. if [ -n "$MATCH_SET" ]; then
  459. # add a more specific rule at the top of ss_spec_prerouting
  460. $NFT insert rule inet ss_spec ss_spec_prerouting meta l4proto tcp $EXT_ARGS $MATCH_SET jump ss_spec_wan_ac comment "\"$TAG\"" 2>/dev/null
  461. else
  462. $NFT insert rule inet ss_spec ss_spec_prerouting meta l4proto tcp $EXT_ARGS jump ss_spec_wan_ac comment "\"$TAG\"" 2>/dev/null
  463. fi
  464. else
  465. # For each Interface, find its actual ifname and add an iifname-limited prerouting rule
  466. for name in $Interface; do
  467. local IFNAME=$(uci -P /var/state get network."$name".ifname 2>/dev/null)
  468. [ -z "$IFNAME" ] && IFNAME=$(uci -P /var/state get network."$name".device 2>/dev/null)
  469. if [ -n "$IFNAME" ]; then
  470. if [ -n "$MATCH_SET" ]; then
  471. $NFT insert rule inet ss_spec ss_spec_prerouting meta iifname "$IFNAME" meta l4proto tcp $EXT_ARGS $MATCH_SET jump ss_spec_wan_ac comment "\"$TAG\"" 2>/dev/null
  472. else
  473. $NFT insert rule inet ss_spec ss_spec_prerouting meta iifname "$IFNAME" meta l4proto tcp $EXT_ARGS jump ss_spec_wan_ac comment "\"$TAG\"" 2>/dev/null
  474. fi
  475. fi
  476. done
  477. fi
  478. case "$OUTPUT" in
  479. 1)
  480. # create output hook chain & route output traffic into router chain
  481. $NFT insert rule inet ss_spec ss_spec_output meta l4proto tcp $EXT_ARGS jump ss_spec_wan_ac comment "\"$TAG\"" 2>/dev/null
  482. ;;
  483. 2)
  484. # router mode output chain: create ssr_gen_router set & router chain
  485. $NFT add set inet ss_spec ssr_gen_router '{ type ipv4_addr; flags interval; }' 2>/dev/null
  486. for ip in $(gen_spec_iplist); do
  487. [ -n "$ip" ] && $NFT add element inet ss_spec ssr_gen_router "{ $ip }" 2>/dev/null
  488. done
  489. $NFT add chain inet ss_spec ss_spec_router 2>/dev/null
  490. $NFT add rule inet ss_spec ss_spec_router ip daddr @ssr_gen_router return 2>/dev/null
  491. $NFT add rule inet ss_spec ss_spec_router jump ss_spec_wan_fw 2>/dev/null
  492. $NFT add rule inet ss_spec ss_spec_output meta l4proto tcp $EXT_ARGS jump ss_spec_router comment "\"$TAG\"" 2>/dev/null
  493. ;;
  494. esac
  495. return 0
  496. }
  497. ac_rule_iptables() {
  498. if [ -n "$LAN_AC_IP" ]; then
  499. case "${LAN_AC_IP%${LAN_AC_IP#?}}" in
  500. w | W)
  501. MATCH_SET="-m set --match-set ss_spec_lan_ac src"
  502. ;;
  503. b | B)
  504. MATCH_SET="-m set ! --match-set ss_spec_lan_ac src"
  505. ;;
  506. *)
  507. loger 3 "Bad argument \`-a $LAN_AC_IP\`."
  508. return 2
  509. ;;
  510. esac
  511. fi
  512. ipset -! -R <<-EOF || return 1
  513. create ss_spec_lan_ac hash:net
  514. $(for ip in ${LAN_AC_IP#?}; do echo "add ss_spec_lan_ac $ip"; done)
  515. EOF
  516. if [ -z "$Interface" ]; then
  517. $IPT -I PREROUTING 1 -p tcp $EXT_ARGS $MATCH_SET -m comment --comment "$TAG" -j SS_SPEC_WAN_AC
  518. else
  519. for name in $Interface; do
  520. local IFNAME=$(uci -P /var/state get network."$name".ifname 2>/dev/null)
  521. [ -z "$IFNAME" ] && IFNAME=$(uci -P /var/state get network."$name".device 2>/dev/null)
  522. [ -n "$IFNAME" ] && $IPT -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p tcp $EXT_ARGS $MATCH_SET -m comment --comment "$TAG" -j SS_SPEC_WAN_AC
  523. done
  524. fi
  525. case "$OUTPUT" in
  526. 1)
  527. $IPT -I OUTPUT 1 -p tcp $EXT_ARGS -m comment --comment "$TAG" -j SS_SPEC_WAN_AC
  528. ;;
  529. 2)
  530. ipset -! -R <<-EOF || return 1
  531. create ssr_gen_router hash:net
  532. $(gen_spec_iplist | sed -e "s/^/add ssr_gen_router /")
  533. EOF
  534. $IPT -N SS_SPEC_ROUTER && \
  535. $IPT -A SS_SPEC_ROUTER -m set --match-set ssr_gen_router dst -j RETURN && \
  536. $IPT -A SS_SPEC_ROUTER -j SS_SPEC_WAN_FW
  537. $IPT -I OUTPUT 1 -p tcp -m comment --comment "$TAG" -j SS_SPEC_ROUTER
  538. ;;
  539. esac
  540. return $?
  541. }
  542. tp_rule() {
  543. [ -n "$TPROXY" ] || return 0
  544. if [ "$USE_NFT" = "1" ]; then
  545. tp_rule_nft
  546. else
  547. tp_rule_iptables
  548. fi
  549. return $?
  550. }
  551. tp_rule_nft() {
  552. # set up routing table for tproxy
  553. ip rule add fwmark 0x01/0x01 table 100 2>/dev/null
  554. ip route add local 0.0.0.0/0 dev lo table 100 2>/dev/null
  555. # create mangle table and tproxy chain
  556. if ! $NFT list table ip ss_spec_mangle >/dev/null 2>&1; then
  557. $NFT add table ip ss_spec_mangle 2>/dev/null
  558. fi
  559. local MATCH_SET=""
  560. EXT_ARGS=""
  561. if [ -n "$PROXY_PORTS" ]; then
  562. PORTS_ARGS=$(echo "$PROXY_PORTS" | sed 's/-m multiport --dports //')
  563. if [ -n "$PORTS_ARGS" ]; then
  564. EXT_ARGS="th dport { $PORTS_ARGS }"
  565. else
  566. EXT_ARGS=""
  567. fi
  568. fi
  569. # 有端口 => 1,无端口 => 0
  570. HAS_PORTS=0
  571. [ -n "$EXT_ARGS" ] && HAS_PORTS=1
  572. if [ -n "$LAN_AC_IP" ]; then
  573. # Create LAN access control set if needed
  574. if ! $NFT list set ip ss_spec_mangle ss_spec_lan_ac >/dev/null 2>&1; then
  575. $NFT add set ip ss_spec_mangle ss_spec_lan_ac '{ type ipv4_addr; flags interval; auto-merge; }' 2>/dev/null
  576. else
  577. $NFT flush set ip ss_spec_mangle ss_spec_lan_ac 2>/dev/null
  578. fi
  579. for ip in ${LAN_AC_IP#?}; do
  580. [ -n "$ip" ] && $NFT add element ip ss_spec_mangle ss_spec_lan_ac "{ $ip }" 2>/dev/null
  581. done
  582. case "${LAN_AC_IP%${LAN_AC_IP#?}}" in
  583. w | W)
  584. MATCH_SET="ip saddr @ss_spec_lan_ac"
  585. ;;
  586. b | B)
  587. MATCH_SET="ip saddr != @ss_spec_lan_ac"
  588. ;;
  589. *)
  590. loger 3 "Bad argument \`-a $LAN_AC_IP\`."
  591. return 2
  592. ;;
  593. esac
  594. fi
  595. # Create necessary collections
  596. for setname in china gmlan fplan bplan whitelist; do
  597. if ! $NFT list set ip ss_spec_mangle $setname >/dev/null 2>&1; then
  598. $NFT add set ip ss_spec_mangle $setname '{ type ipv4_addr; flags interval; auto-merge; }'
  599. else
  600. $NFT flush set ip ss_spec_mangle $setname 2>/dev/null
  601. fi
  602. done
  603. # 批量导入中国IP列表
  604. if [ -f "${china_ip:=/etc/ssrplus/china_ssr.txt}" ]; then
  605. $NFT add element ip ss_spec_mangle china "{ $(tr '\n' ',' < "${china_ip}" | sed 's/,$//') }" 2>/dev/null
  606. fi
  607. # use priority mangle for compatibility with other rules
  608. if ! $NFT list chain ip ss_spec_mangle ss_spec_tproxy >/dev/null 2>&1; then
  609. $NFT add chain ip ss_spec_mangle ss_spec_tproxy 2>/dev/null
  610. else
  611. $NFT flush chain ip ss_spec_mangle ss_spec_tproxy 2>/dev/null
  612. fi
  613. if $NFT list chain ip ss_spec_mangle ss_spec_tproxy >/dev/null 2>&1; then
  614. for net in 0.0.0.0/8 10.0.0.0/8 127.0.0.0/8 169.254.0.0/16 172.16.0.0/12 192.168.0.0/16 224.0.0.0/4 240.0.0.0/4; do
  615. $NFT add rule ip ss_spec_mangle ss_spec_tproxy ip daddr $net return 2>/dev/null
  616. done
  617. fi
  618. # basic return rules in tproxy chain
  619. $NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport 53 return 2>/dev/null
  620. # avoid redirecting to udp server address
  621. if [ -n "$server" ]; then
  622. $NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport != 53 ip daddr "$server" return 2>/dev/null
  623. fi
  624. # if server != SERVER add SERVER to whitelist set (so tproxy won't touch it)
  625. if [ -n "$server" ]; then
  626. $NFT add rule ip ss_spec_mangle ss_spec_tproxy ip daddr "$server" return 2>/dev/null
  627. fi
  628. if [ -n "$SERVER" ] && [ "$server" != "$SERVER" ]; then
  629. $NFT add element ip ss_spec_mangle whitelist "{ $SERVER }" 2>/dev/null
  630. fi
  631. # access control and tproxy rules
  632. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip saddr @bplan return 2>/dev/null
  633. if [ $HAS_PORTS -eq 1 ]; then
  634. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp $EXT_ARGS ip saddr @fplan counter tproxy ip to :"$LOCAL_PORT" meta mark set 0x01
  635. else
  636. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip saddr @fplan counter tproxy ip to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
  637. fi
  638. # Handle different run modes for nftables
  639. case "$RUNMODE" in
  640. router)
  641. if ! $NFT list set ip ss_spec_mangle ss_spec_wan_ac >/dev/null 2>&1; then
  642. $NFT add set ip ss_spec_mangle ss_spec_wan_ac '{ type ipv4_addr; flags interval; auto-merge; }'
  643. else
  644. $NFT flush set ip ss_spec_mangle ss_spec_wan_ac 2>/dev/null
  645. fi
  646. # Add special IP ranges to WAN AC set
  647. for ip in $(gen_spec_iplist); do
  648. [ -n "$ip" ] && $NFT add element ip ss_spec_mangle ss_spec_wan_ac "{ $ip }" 2>/dev/null
  649. done
  650. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip daddr @ss_spec_wan_ac return 2>/dev/null
  651. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip daddr @china return 2>/dev/null
  652. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp dport 80 drop 2>/dev/null
  653. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip saddr @gmlan ip daddr != @china counter tproxy ip to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
  654. if [ $HAS_PORTS -eq 1 ]; then
  655. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp $EXT_ARGS ip daddr != @ss_spec_wan_ac counter tproxy ip to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
  656. else
  657. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip daddr != @ss_spec_wan_ac counter tproxy ip to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
  658. fi
  659. ;;
  660. gfw)
  661. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip daddr @china return 2>/dev/null
  662. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp dport 80 drop 2>/dev/null
  663. if [ $HAS_PORTS -eq 1 ]; then
  664. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp $EXT_ARGS ip daddr @gfwlist counter tproxy ip to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
  665. fi
  666. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip saddr @gmlan ip daddr != @china counter tproxy ip to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
  667. ;;
  668. oversea)
  669. if ! $NFT list set ip ss_spec_mangle oversea >/dev/null 2>&1; then
  670. $NFT add set ip ss_spec_mangle oversea '{ type ipv4_addr; flags interval; auto-merge; }' 2>/dev/null
  671. fi
  672. if ! $NFT list set ip ss_spec_mangle china >/dev/null 2>&1; then
  673. $NFT add set ip ss_spec_mangle china '{ type ipv4_addr; flags interval; auto-merge; }' 2>/dev/null
  674. fi
  675. if [ $HAS_PORTS -eq 1 ]; then
  676. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp $EXT_ARGS ip saddr @oversea counter tproxy ip to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
  677. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp $EXT_ARGS ip daddr @china counter tproxy ip to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
  678. fi
  679. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip saddr @gmlan counter tproxy ip to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
  680. ;;
  681. all)
  682. if [ $HAS_PORTS -eq 1 ]; then
  683. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp $EXT_ARGS counter tproxy ip to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
  684. else
  685. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp counter tproxy ip to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
  686. fi
  687. ;;
  688. esac
  689. # 创建 prerouting 链(hook prerouting)
  690. if ! $NFT list chain ip ss_spec_mangle prerouting >/dev/null 2>&1; then
  691. $NFT add chain ip ss_spec_mangle prerouting '{ type filter hook prerouting priority mangle; policy accept; }'
  692. fi
  693. # 添加规则到 prerouting 链
  694. if [ -z "$Interface" ]; then
  695. # 全局规则
  696. if [ -n "$MATCH_SET" ]; then
  697. $NFT add rule ip ss_spec_mangle prerouting meta l4proto udp $EXT_ARGS $MATCH_SET jump ss_spec_tproxy comment "\"$TAG\"" 2>/dev/null
  698. else
  699. $NFT add rule ip ss_spec_mangle prerouting meta l4proto udp $EXT_ARGS jump ss_spec_tproxy comment "\"$TAG\"" 2>/dev/null
  700. fi
  701. else
  702. # 指定接口
  703. for name in $Interface; do
  704. IFNAME=$(uci -P /var/state get network."$name".ifname 2>/dev/null)
  705. [ -z "$IFNAME" ] && IFNAME=$(uci -P /var/state get network."$name".device 2>/dev/null)
  706. if [ -n "$IFNAME" ]; then
  707. if [ -n "$MATCH_SET" ]; then
  708. $NFT add rule ip ss_spec_mangle prerouting meta iifname "$IFNAME" meta l4proto udp $EXT_ARGS $MATCH_SET jump ss_spec_tproxy comment "\"$TAG\"" 2>/dev/null
  709. else
  710. $NFT add rule ip ss_spec_mangle prerouting meta iifname "$IFNAME" meta l4proto udp $EXT_ARGS jump ss_spec_tproxy comment "\"$TAG\"" 2>/dev/null
  711. fi
  712. fi
  713. done
  714. fi
  715. return $?
  716. }
  717. tp_rule_iptables() {
  718. ip rule add fwmark 0x01/0x01 table 100
  719. ip route add local 0.0.0.0/0 dev lo table 100
  720. local ipt="iptables -t mangle"
  721. $ipt -N SS_SPEC_TPROXY
  722. $ipt -A SS_SPEC_TPROXY -p udp --dport 53 -j RETURN
  723. $ipt -A SS_SPEC_TPROXY -p udp -d 0.0.0.0/8 -j RETURN
  724. $ipt -A SS_SPEC_TPROXY -p udp -d 10.0.0.0/8 -j RETURN
  725. $ipt -A SS_SPEC_TPROXY -p udp -d 127.0.0.0/8 -j RETURN
  726. $ipt -A SS_SPEC_TPROXY -p udp -d 169.254.0.0/16 -j RETURN
  727. $ipt -A SS_SPEC_TPROXY -p udp -d 172.16.0.0/12 -j RETURN
  728. $ipt -A SS_SPEC_TPROXY -p udp -d 192.168.0.0/16 -j RETURN
  729. $ipt -A SS_SPEC_TPROXY -p udp -d 224.0.0.0/4 -j RETURN
  730. $ipt -A SS_SPEC_TPROXY -p udp -d 240.0.0.0/4 -j RETURN
  731. $ipt -A SS_SPEC_TPROXY -p udp ! --dport 53 -d "$SERVER" -j RETURN
  732. [ "$server" != "$SERVER" ] && ipset -! add whitelist "$SERVER"
  733. $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set bplan src -j RETURN
  734. $ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set --match-set fplan src -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
  735. case "$RUNMODE" in
  736. router)
  737. $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set ss_spec_wan_ac dst -j RETURN
  738. $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set china dst -j RETURN
  739. $ipt -A SS_SPEC_TPROXY -p udp --dport 80 -j DROP
  740. $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set gmlan src -m set ! --match-set china dst -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
  741. $ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set ! --match-set ss_spec_wan_ac dst -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
  742. ;;
  743. gfw)
  744. $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set china dst -j RETURN
  745. $ipt -A SS_SPEC_TPROXY -p udp --dport 80 -j DROP
  746. $ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set --match-set gfwlist dst -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
  747. $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set gmlan src -m set ! --match-set china dst -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
  748. ;;
  749. oversea)
  750. $ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set --match-set oversea src -m dst -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
  751. $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set gmlan src -m set -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
  752. $ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -m set --match-set china dst -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
  753. ;;
  754. all)
  755. $ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
  756. ;;
  757. esac
  758. if [ -z "$Interface" ]; then
  759. $ipt -I PREROUTING 1 -p udp $EXT_ARGS $MATCH_SET -m comment --comment "$TAG" -j SS_SPEC_TPROXY
  760. else
  761. for name in $Interface; do
  762. local IFNAME=$(uci -P /var/state get network."$name".ifname 2>/dev/null)
  763. [ -z "$IFNAME" ] && IFNAME=$(uci -P /var/state get network."$name".device 2>/dev/null)
  764. [ -n "$IFNAME" ] && $ipt -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p udp $EXT_ARGS $MATCH_SET -m comment --comment "$TAG" -j SS_SPEC_TPROXY
  765. done
  766. fi
  767. return $?
  768. }
  769. get_wan_ip() {
  770. cat <<-EOF | grep -E "^([0-9]{1,3}\.){3}[0-9]{1,3}"
  771. $server
  772. $SERVER
  773. $WAN_BP_IP
  774. EOF
  775. }
  776. gen_spec_iplist() {
  777. cat <<-EOF
  778. 0.0.0.0/8
  779. 10.0.0.0/8
  780. 100.64.0.0/10
  781. 127.0.0.0/8
  782. 169.254.0.0/16
  783. 172.16.0.0/12
  784. 192.0.0.0/24
  785. 192.0.2.0/24
  786. 192.88.99.0/24
  787. 192.168.0.0/16
  788. 198.18.0.0/15
  789. 198.51.100.0/24
  790. 203.0.113.0/24
  791. 224.0.0.0/4
  792. 240.0.0.0/4
  793. 255.255.255.255
  794. $(get_wan_ip)
  795. EOF
  796. }
  797. gen_include() {
  798. [ -n "$FWI" ] || return 0
  799. if [ "$USE_NFT" = "1" ]; then
  800. gen_include_nft
  801. else
  802. gen_include_iptables
  803. fi
  804. return $?
  805. }
  806. gen_include_nft() {
  807. # Generate nftables include file for firewall4
  808. [ -n "$FWI" ] && echo '#!/bin/sh' >"$FWI"
  809. cat <<-'EOF' >>"$FWI"
  810. # Clear existing ss_spec tables
  811. nft delete table inet ss_spec 2>/dev/null
  812. nft delete table ip ss_spec 2>/dev/null
  813. nft delete table ip ss_spec_mangle 2>/dev/null
  814. # Restore shadowsocks nftables rules
  815. nft list ruleset | awk '/^table (inet|ip) ss_spec/{flag=1} /^table / && !/^table (inet|ip) ss_spec/{flag=0} flag'
  816. EOF
  817. chmod +x "$FWI"
  818. }
  819. gen_include_iptables() {
  820. extract_rules() {
  821. echo "*$1"
  822. iptables-save -t $1 | grep SS_SPEC_ | sed -e "s/^-A \(OUTPUT\|PREROUTING\)/-I \1 1/"
  823. echo 'COMMIT'
  824. }
  825. cat <<-EOF >>$FWI
  826. iptables-save -c | grep -v "SS_SPEC" | iptables-restore -c
  827. iptables-restore -n <<-EOT
  828. $(extract_rules nat)
  829. $(extract_rules mangle)
  830. EOT
  831. EOF
  832. }
  833. while getopts ":m:s:l:S:L:i:e:a:B:b:w:p:G:D:F:N:M:I:oOuUfgrczh" arg; do
  834. case "$arg" in
  835. m)
  836. Interface=$OPTARG
  837. ;;
  838. s)
  839. server=$OPTARG
  840. ;;
  841. l)
  842. local_port=$OPTARG
  843. ;;
  844. S)
  845. SERVER=$OPTARG
  846. ;;
  847. L)
  848. LOCAL_PORT=$OPTARG
  849. ;;
  850. i)
  851. IGNORE_LIST=$OPTARG
  852. ;;
  853. e)
  854. EXT_ARGS=$OPTARG
  855. ;;
  856. a)
  857. LAN_AC_IP=$OPTARG
  858. ;;
  859. B)
  860. LAN_BP_IP=$OPTARG
  861. ;;
  862. b)
  863. WAN_BP_IP=$(for ip in $OPTARG; do echo "$ip"; done)
  864. ;;
  865. w)
  866. WAN_FW_IP=$OPTARG
  867. ;;
  868. p)
  869. LAN_FP_IP=$OPTARG
  870. ;;
  871. G)
  872. LAN_GM_IP=$OPTARG
  873. ;;
  874. D)
  875. PROXY_PORTS=$OPTARG
  876. ;;
  877. F)
  878. SHUNT_PORT=$OPTARG
  879. ;;
  880. N)
  881. SHUNT_IP=$OPTARG
  882. ;;
  883. M)
  884. SHUNT_PROXY=$OPTARG
  885. ;;
  886. I)
  887. SHUNT_LIST=$OPTARG
  888. ;;
  889. o)
  890. OUTPUT=1
  891. ;;
  892. O)
  893. OUTPUT=2
  894. ;;
  895. u)
  896. TPROXY=1
  897. ;;
  898. U)
  899. TPROXY=2
  900. ;;
  901. g)
  902. RUNMODE=gfw
  903. ;;
  904. r)
  905. RUNMODE=router
  906. ;;
  907. c)
  908. RUNMODE=oversea
  909. ;;
  910. z)
  911. RUNMODE=all
  912. ;;
  913. f)
  914. flush_r
  915. exit 0
  916. ;;
  917. h) usage 0 ;;
  918. esac
  919. done
  920. if [ -z "$server" ] || [ -z "$local_port" ]; then
  921. usage 2
  922. fi
  923. if ! echo "$local_port" | grep -qE '^[0-9]+$'; then
  924. loger 3 "Invalid local port: $local_port"
  925. exit 1
  926. fi
  927. case "$TPROXY" in
  928. 1)
  929. SERVER=$server
  930. LOCAL_PORT=$local_port
  931. ;;
  932. 2)
  933. : ${SERVER:?"You must assign an ip for the udp relay server."}
  934. : ${LOCAL_PORT:?"You must assign a port for the udp relay server."}
  935. ;;
  936. esac
  937. # First check whether nftables is working properly
  938. if [ "$USE_NFT" = "1" ]; then
  939. if ! $NFT list tables 2>/dev/null; then
  940. loger 3 "nftables is not working properly, check if nftables is installed and running"
  941. exit 1
  942. fi
  943. fi
  944. if [ "$USE_NFT" = "1" ]; then
  945. # NFTables
  946. if flush_r && ipset_r && fw_rule && ac_rule && tp_rule && gen_include; then
  947. loger 5 "NFTables rules applied successfully"
  948. exit 0
  949. else
  950. loger 3 "NFTables setup failed!"
  951. exit 1
  952. fi
  953. else
  954. # iptables
  955. if flush_r && fw_rule && ipset_r && ac_rule && tp_rule && gen_include; then
  956. loger 5 "iptables rules applied successfully"
  957. exit 0
  958. else
  959. loger 3 "iptables setup failed!"
  960. exit 1
  961. fi
  962. fi