ssr-rules 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029
  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. # Add basic rules
  205. $NFT add rule inet ss_spec ss_spec_wan_ac tcp dport 53 ip daddr 127.0.0.0/8 return
  206. $NFT add rule inet ss_spec ss_spec_wan_ac tcp dport != 53 ip daddr "$server" return
  207. # Set up mode-specific rules
  208. case "$RUNMODE" in
  209. router)
  210. if ! $NFT list set inet ss_spec ss_spec_wan_ac >/dev/null 2>&1; then
  211. $NFT add set inet ss_spec ss_spec_wan_ac '{ type ipv4_addr; flags interval; auto-merge; }'
  212. else
  213. $NFT flush set inet ss_spec ss_spec_wan_ac 2>/dev/null
  214. fi
  215. # Add special IP ranges to WAN AC set
  216. for ip in $(gen_spec_iplist); do
  217. [ -n "$ip" ] && $NFT add element inet ss_spec ss_spec_wan_ac "{ $ip }" 2>/dev/null
  218. done
  219. $NFT add rule inet ss_spec ss_spec_wan_ac ip daddr @ss_spec_wan_ac return
  220. $NFT add rule inet ss_spec ss_spec_wan_ac ip daddr @china return 2>/dev/null
  221. if $NFT list chain inet ss_spec ss_spec_wan_fw >/dev/null 2>&1; then
  222. $NFT add rule inet ss_spec ss_spec_wan_ac ip saddr @gmlan ip daddr != @china jump ss_spec_wan_fw
  223. $NFT add rule inet ss_spec ss_spec_wan_ac jump ss_spec_wan_fw
  224. fi
  225. ;;
  226. gfw)
  227. if ! $NFT list set inet ss_spec gfwlist >/dev/null 2>&1; then
  228. $NFT add set inet ss_spec gfwlist '{ type ipv4_addr; flags interval; auto-merge; }' 2>/dev/null
  229. fi
  230. $NFT add rule inet ss_spec ss_spec_wan_ac ip daddr @china return 2>/dev/null
  231. $NFT add rule inet ss_spec ss_spec_wan_ac ip daddr @gfwlist jump ss_spec_wan_fw 2>/dev/null
  232. if $NFT list chain inet ss_spec ss_spec_wan_fw >/dev/null 2>&1; then
  233. $NFT add rule inet ss_spec ss_spec_wan_ac ip saddr @gmlan ip daddr != @china jump ss_spec_wan_fw
  234. fi
  235. ;;
  236. oversea)
  237. if ! $NFT list set inet ss_spec oversea >/dev/null 2>&1; then
  238. $NFT add set inet ss_spec oversea '{ type ipv4_addr; flags interval; auto-merge; }' 2>/dev/null
  239. fi
  240. if $NFT list chain inet ss_spec ss_spec_wan_fw >/dev/null 2>&1; then
  241. $NFT insert rule inet ss_spec ss_spec_wan_ac ip daddr @oversea jump ss_spec_wan_fw 2>/dev/null
  242. $NFT add rule inet ss_spec ss_spec_wan_ac ip saddr @gmlan jump ss_spec_wan_fw 2>/dev/null
  243. $NFT add rule inet ss_spec ss_spec_wan_ac ip daddr @china jump ss_spec_wan_fw 2>/dev/null
  244. fi
  245. ;;
  246. all)
  247. if $NFT list chain inet ss_spec ss_spec_wan_fw >/dev/null 2>&1; then
  248. $NFT add rule inet ss_spec ss_spec_wan_ac jump ss_spec_wan_fw
  249. fi
  250. ;;
  251. esac
  252. # Access control rules
  253. $NFT add rule inet ss_spec ss_spec_wan_ac ip saddr @fplan jump ss_spec_wan_fw
  254. $NFT add rule inet ss_spec ss_spec_wan_ac ip saddr @bplan return
  255. $NFT add rule inet ss_spec ss_spec_wan_ac ip daddr @blacklist jump ss_spec_wan_fw
  256. $NFT add rule inet ss_spec ss_spec_wan_ac ip daddr @whitelist return
  257. # Music unlocking support
  258. if $NFT list set inet ss_spec music >/dev/null 2>&1; then
  259. $NFT insert rule inet ss_spec ss_spec_wan_ac ip daddr @music return 2>/dev/null
  260. fi
  261. # Shunt/Netflix rules
  262. if [ "$SHUNT_PORT" != "0" ] && [ -f "$SHUNT_LIST" ]; then
  263. for ip in $(cat "$SHUNT_LIST" 2>/dev/null); do
  264. [ -n "$ip" ] && $NFT add element inet ss_spec netflix "{ $ip }" 2>/dev/null
  265. done
  266. case "$SHUNT_PORT" in
  267. 1)
  268. $NFT insert rule inet ss_spec ss_spec_wan_ac ip daddr @netflix meta l4proto tcp redirect to :"$local_port"
  269. ;;
  270. *)
  271. $NFT insert rule inet ss_spec ss_spec_wan_ac ip daddr @netflix meta l4proto tcp redirect to :"$SHUNT_PORT"
  272. if [ "$SHUNT_PROXY" = "1" ]; then
  273. $NFT insert rule inet ss_spec ss_spec_wan_ac ip daddr "$SHUNT_IP" meta l4proto tcp redirect to :"$local_port"
  274. else
  275. [ -n "$SHUNT_IP" ] && $NFT add element inet ss_spec whitelist "{ $SHUNT_IP }" 2>/dev/null
  276. fi
  277. ;;
  278. esac
  279. fi
  280. return $?
  281. }
  282. ipset_iptables() {
  283. [ -f "$IGNORE_LIST" ] && /usr/share/shadowsocksr/chinaipset.sh "$IGNORE_LIST"
  284. $IPT -N SS_SPEC_WAN_AC 2>/dev/null
  285. $IPT -I SS_SPEC_WAN_AC -p tcp --dport 53 -d 127.0.0.0/8 -j RETURN
  286. $IPT -I SS_SPEC_WAN_AC -p tcp ! --dport 53 -d "$server" -j RETURN
  287. ipset -N gmlan hash:net 2>/dev/null
  288. for ip in $LAN_GM_IP; do ipset -! add gmlan "$ip"; done
  289. case "$RUNMODE" in
  290. router)
  291. ipset -! -R <<-EOF || return 1
  292. create ss_spec_wan_ac hash:net
  293. $(gen_spec_iplist | sed -e "s/^/add ss_spec_wan_ac /")
  294. EOF
  295. $IPT -A SS_SPEC_WAN_AC -m set --match-set ss_spec_wan_ac dst -j RETURN
  296. $IPT -A SS_SPEC_WAN_AC -m set --match-set china dst -j RETURN
  297. $IPT -A SS_SPEC_WAN_AC -m set --match-set gmlan src -m set ! --match-set china dst -j SS_SPEC_WAN_FW
  298. $IPT -A SS_SPEC_WAN_AC -j SS_SPEC_WAN_FW
  299. ;;
  300. gfw)
  301. ipset -N gfwlist hash:net 2>/dev/null
  302. $IPT -A SS_SPEC_WAN_AC -m set --match-set china dst -j RETURN
  303. $IPT -A SS_SPEC_WAN_AC -m set --match-set gfwlist dst -j SS_SPEC_WAN_FW
  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. ;;
  306. oversea)
  307. ipset -N oversea hash:net 2>/dev/null
  308. $IPT -I SS_SPEC_WAN_AC -m set --match-set oversea dst -j SS_SPEC_WAN_FW
  309. $IPT -A SS_SPEC_WAN_AC -m set --match-set gmlan src -j SS_SPEC_WAN_FW
  310. $IPT -A SS_SPEC_WAN_AC -m set --match-set china dst -j SS_SPEC_WAN_FW
  311. ;;
  312. all)
  313. $IPT -A SS_SPEC_WAN_AC -j SS_SPEC_WAN_FW
  314. ;;
  315. esac
  316. ipset -N fplan hash:net 2>/dev/null
  317. for ip in $LAN_FP_IP; do ipset -! add fplan "$ip"; done
  318. $IPT -I SS_SPEC_WAN_AC -m set --match-set fplan src -j SS_SPEC_WAN_FW
  319. ipset -N bplan hash:net 2>/dev/null
  320. for ip in $LAN_BP_IP; do ipset -! add bplan "$ip"; done
  321. $IPT -I SS_SPEC_WAN_AC -m set --match-set bplan src -j RETURN
  322. ipset -N whitelist hash:net 2>/dev/null
  323. ipset -N blacklist hash:net 2>/dev/null
  324. $IPT -I SS_SPEC_WAN_AC -m set --match-set blacklist dst -j SS_SPEC_WAN_FW
  325. $IPT -I SS_SPEC_WAN_AC -m set --match-set whitelist dst -j RETURN
  326. if [ $(ipset list music -name -quiet | grep music) ]; then
  327. $IPT -I SS_SPEC_WAN_AC -m set --match-set music dst -j RETURN 2>/dev/null
  328. fi
  329. for ip in $WAN_BP_IP; do ipset -! add whitelist "$ip"; done
  330. for ip in $WAN_FW_IP; do ipset -! add blacklist "$ip"; done
  331. if [ "$SHUNT_PORT" != "0" ]; then
  332. ipset -N netflix hash:net 2>/dev/null
  333. for ip in $(cat "${SHUNT_LIST:=/dev/null}" 2>/dev/null); do ipset -! add netflix "$ip"; done
  334. case "$SHUNT_PORT" in
  335. 0) ;;
  336. 1)
  337. $IPT -I SS_SPEC_WAN_AC -p tcp -m set --match-set netflix dst -j REDIRECT --to-ports "$local_port"
  338. ;;
  339. *)
  340. $IPT -I SS_SPEC_WAN_AC -p tcp -m set --match-set netflix dst -j REDIRECT --to-ports "$SHUNT_PORT"
  341. if [ "$SHUNT_PROXY" = "1" ]; then
  342. $IPT -I SS_SPEC_WAN_AC -p tcp -d "$SHUNT_IP" -j REDIRECT --to-ports "$local_port"
  343. else
  344. ipset -! add whitelist "$SHUNT_IP"
  345. fi
  346. ;;
  347. esac
  348. fi
  349. return $?
  350. }
  351. fw_rule() {
  352. if [ "$USE_NFT" = "1" ]; then
  353. fw_rule_nft
  354. else
  355. fw_rule_iptables
  356. fi
  357. return $?
  358. }
  359. fw_rule_nft() {
  360. # Exclude special local addresses
  361. if $NFT list chain inet ss_spec ss_spec_wan_fw >/dev/null 2>&1; then
  362. 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
  363. $NFT add rule inet ss_spec ss_spec_wan_fw ip daddr $net return 2>/dev/null
  364. done
  365. fi
  366. # redirect/translation: when PROXY_PORTS present, redirect those tcp ports to local_port
  367. if [ -n "$PROXY_PORTS" ]; then
  368. PORTS=$(echo "$PROXY_PORTS" | sed 's/-m multiport --dports //')
  369. RULE="tcp dport { $PORTS } redirect to :"$local_port""
  370. else
  371. # default: redirect everything except ssh(22)
  372. RULE="tcp dport != 22 redirect to :"$local_port""
  373. fi
  374. if ! $NFT list chain inet ss_spec ss_spec_wan_fw 2>/dev/null | grep -q "$RULE"; then
  375. if ! $NFT add rule inet ss_spec ss_spec_wan_fw $RULE 2>/dev/null; then
  376. loger 3 "Can't redirect, please check nftables."
  377. return 1
  378. fi
  379. fi
  380. return $?
  381. }
  382. fw_rule_iptables() {
  383. $IPT -N SS_SPEC_WAN_FW
  384. $IPT -A SS_SPEC_WAN_FW -d 0.0.0.0/8 -j RETURN
  385. $IPT -A SS_SPEC_WAN_FW -d 10.0.0.0/8 -j RETURN
  386. $IPT -A SS_SPEC_WAN_FW -d 127.0.0.0/8 -j RETURN
  387. $IPT -A SS_SPEC_WAN_FW -d 169.254.0.0/16 -j RETURN
  388. $IPT -A SS_SPEC_WAN_FW -d 172.16.0.0/12 -j RETURN
  389. $IPT -A SS_SPEC_WAN_FW -d 192.168.0.0/16 -j RETURN
  390. $IPT -A SS_SPEC_WAN_FW -d 224.0.0.0/4 -j RETURN
  391. $IPT -A SS_SPEC_WAN_FW -d 240.0.0.0/4 -j RETURN
  392. $IPT -A SS_SPEC_WAN_FW -p tcp $PROXY_PORTS -j REDIRECT --to-ports "$local_port" 2>/dev/null || {
  393. loger 3 "Can't redirect, please check the iptables."
  394. exit 1
  395. }
  396. return $?
  397. }
  398. ac_rule() {
  399. if [ "$USE_NFT" = "1" ]; then
  400. ac_rule_nft
  401. else
  402. ac_rule_iptables
  403. fi
  404. return $?
  405. }
  406. ac_rule_nft() {
  407. local MATCH_SET=""
  408. if [ -n "$LAN_AC_IP" ]; then
  409. # Create LAN access control set if needed
  410. if ! $NFT list set inet ss_spec ss_spec_lan_ac >/dev/null 2>&1; then
  411. $NFT add set inet ss_spec ss_spec_lan_ac '{ type ipv4_addr; flags interval; }' 2>/dev/null
  412. else
  413. $NFT flush set inet ss_spec ss_spec_lan_ac 2>/dev/null
  414. fi
  415. for ip in ${LAN_AC_IP#?}; do
  416. [ -n "$ip" ] && $NFT add element inet ss_spec ss_spec_lan_ac "{ $ip }" 2>/dev/null
  417. done
  418. case "${LAN_AC_IP%${LAN_AC_IP#?}}" in
  419. w | W)
  420. MATCH_SET="ip saddr @ss_spec_lan_ac"
  421. ;;
  422. b | B)
  423. MATCH_SET="ip saddr != @ss_spec_lan_ac"
  424. ;;
  425. *)
  426. loger 3 "Bad argument \`-a $LAN_AC_IP\`."
  427. return 2
  428. ;;
  429. esac
  430. fi
  431. # 创建ss_spec_prerouting链
  432. if ! $NFT list chain inet ss_spec ss_spec_prerouting >/dev/null 2>&1; then
  433. $NFT add chain inet ss_spec ss_spec_prerouting '{ type nat hook prerouting priority -150; policy accept; }'
  434. fi
  435. $NFT flush chain inet ss_spec ss_spec_prerouting 2>/dev/null
  436. # 创建ss_spec_output链
  437. if ! $NFT list chain inet ss_spec ss_spec_output >/dev/null 2>&1; then
  438. $NFT add chain inet ss_spec ss_spec_output '{ type nat hook output priority -100; policy accept; }'
  439. fi
  440. $NFT flush chain inet ss_spec ss_spec_output 2>/dev/null
  441. # Build a rule in the prerouting hook chain that jumps to business chain with conditions
  442. if [ -n "$PROXY_PORTS" ]; then
  443. EXT_ARGS=$(echo "$PROXY_PORTS" | sed 's/-m multiport --dports //')
  444. fi
  445. if [ -z "$Interface" ]; then
  446. # generic prerouting jump already exists (see ipset_nft), but if we have MATCH_SET_CONDITION we add a more specific rule
  447. if [ -n "$MATCH_SET" ]; then
  448. # add a more specific rule at the top of ss_spec_prerouting
  449. $NFT insert rule inet ss_spec ss_spec_prerouting meta l4proto tcp th dport { $EXT_ARGS } $MATCH_SET jump ss_spec_wan_ac comment "\"$TAG\"" 2>/dev/null
  450. else
  451. $NFT insert rule inet ss_spec ss_spec_prerouting meta l4proto tcp th dport { $EXT_ARGS } jump ss_spec_wan_ac comment "\"$TAG\"" 2>/dev/null
  452. fi
  453. else
  454. # For each Interface, find its actual ifname and add an iifname-limited prerouting rule
  455. for name in $Interface; do
  456. local IFNAME=$(uci -P /var/state get network."$name".ifname 2>/dev/null)
  457. [ -z "$IFNAME" ] && IFNAME=$(uci -P /var/state get network."$name".device 2>/dev/null)
  458. if [ -n "$IFNAME" ]; then
  459. if [ -n "$MATCH_SET" ]; then
  460. $NFT insert rule inet ss_spec ss_spec_prerouting meta iifname "$IFNAME" meta l4proto tcp th dport { $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 iifname "$IFNAME" meta l4proto tcp th dport { $EXT_ARGS } jump ss_spec_wan_ac comment "\"$TAG\"" 2>/dev/null
  463. fi
  464. fi
  465. done
  466. fi
  467. case "$OUTPUT" in
  468. 1)
  469. # create output hook chain & route output traffic into router chain
  470. $NFT insert rule inet ss_spec ss_spec_output meta l4proto tcp th dport { $EXT_ARGS } jump ss_spec_wan_ac comment "\"$TAG\"" 2>/dev/null
  471. ;;
  472. 2)
  473. # router mode output chain: create ssr_gen_router set & router chain
  474. $NFT add set inet ss_spec ssr_gen_router '{ type ipv4_addr; flags interval; }' 2>/dev/null
  475. for ip in $(gen_spec_iplist); do
  476. [ -n "$ip" ] && $NFT add element inet ss_spec ssr_gen_router "{ $ip }" 2>/dev/null
  477. done
  478. $NFT add chain inet ss_spec ss_spec_router 2>/dev/null
  479. $NFT add rule inet ss_spec ss_spec_router ip daddr @ssr_gen_router return 2>/dev/null
  480. $NFT add rule inet ss_spec ss_spec_router jump ss_spec_wan_fw 2>/dev/null
  481. $NFT add rule inet ss_spec ss_spec_output meta l4proto tcp th dport { $EXT_ARGS } jump ss_spec_router comment "\"$TAG\"" 2>/dev/null
  482. ;;
  483. esac
  484. return 0
  485. }
  486. ac_rule_iptables() {
  487. if [ -n "$LAN_AC_IP" ]; then
  488. case "${LAN_AC_IP%${LAN_AC_IP#?}}" in
  489. w | W)
  490. MATCH_SET="-m set --match-set ss_spec_lan_ac src"
  491. ;;
  492. b | B)
  493. MATCH_SET="-m set ! --match-set ss_spec_lan_ac src"
  494. ;;
  495. *)
  496. loger 3 "Bad argument \`-a $LAN_AC_IP\`."
  497. return 2
  498. ;;
  499. esac
  500. fi
  501. ipset -! -R <<-EOF || return 1
  502. create ss_spec_lan_ac hash:net
  503. $(for ip in ${LAN_AC_IP#?}; do echo "add ss_spec_lan_ac $ip"; done)
  504. EOF
  505. if [ -z "$Interface" ]; then
  506. $IPT -I PREROUTING 1 -p tcp $EXT_ARGS $MATCH_SET -m comment --comment "$TAG" -j SS_SPEC_WAN_AC
  507. else
  508. for name in $Interface; do
  509. local IFNAME=$(uci -P /var/state get network."$name".ifname 2>/dev/null)
  510. [ -z "$IFNAME" ] && IFNAME=$(uci -P /var/state get network."$name".device 2>/dev/null)
  511. [ -n "$IFNAME" ] && $IPT -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p tcp $EXT_ARGS $MATCH_SET -m comment --comment "$TAG" -j SS_SPEC_WAN_AC
  512. done
  513. fi
  514. case "$OUTPUT" in
  515. 1)
  516. $IPT -I OUTPUT 1 -p tcp $EXT_ARGS -m comment --comment "$TAG" -j SS_SPEC_WAN_AC
  517. ;;
  518. 2)
  519. ipset -! -R <<-EOF || return 1
  520. create ssr_gen_router hash:net
  521. $(gen_spec_iplist | sed -e "s/^/add ssr_gen_router /")
  522. EOF
  523. $IPT -N SS_SPEC_ROUTER && \
  524. $IPT -A SS_SPEC_ROUTER -m set --match-set ssr_gen_router dst -j RETURN && \
  525. $IPT -A SS_SPEC_ROUTER -j SS_SPEC_WAN_FW
  526. $IPT -I OUTPUT 1 -p tcp -m comment --comment "$TAG" -j SS_SPEC_ROUTER
  527. ;;
  528. esac
  529. return $?
  530. }
  531. tp_rule() {
  532. [ -n "$TPROXY" ] || return 0
  533. if [ "$USE_NFT" = "1" ]; then
  534. tp_rule_nft
  535. else
  536. tp_rule_iptables
  537. fi
  538. return $?
  539. }
  540. tp_rule_nft() {
  541. # set up routing table for tproxy
  542. ip rule add fwmark 0x01/0x01 table 100 2>/dev/null
  543. ip route add local 0.0.0.0/0 dev lo table 100 2>/dev/null
  544. # create mangle table and tproxy chain
  545. if ! $NFT list table ip ss_spec_mangle >/dev/null 2>&1; then
  546. $NFT add table ip ss_spec_mangle 2>/dev/null
  547. fi
  548. local MATCH_SET=""
  549. local EXT_ARGS=""
  550. if [ -n "$PROXY_PORTS" ]; then
  551. EXT_ARGS=$(echo "$PROXY_PORTS" | sed 's/-m multiport --dports //')
  552. fi
  553. if [ -n "$LAN_AC_IP" ]; then
  554. # Create LAN access control set if needed
  555. if ! $NFT list set ip ss_spec_mangle ss_spec_lan_ac >/dev/null 2>&1; then
  556. $NFT add set ip ss_spec_mangle ss_spec_lan_ac '{ type ipv4_addr; flags interval; auto-merge; }' 2>/dev/null
  557. else
  558. $NFT flush set ip ss_spec_mangle ss_spec_lan_ac 2>/dev/null
  559. fi
  560. for ip in ${LAN_AC_IP#?}; do
  561. [ -n "$ip" ] && $NFT add element ip ss_spec_mangle ss_spec_lan_ac "{ $ip }" 2>/dev/null
  562. done
  563. case "${LAN_AC_IP%${LAN_AC_IP#?}}" in
  564. w | W)
  565. MATCH_SET="ip saddr @ss_spec_lan_ac"
  566. ;;
  567. b | B)
  568. MATCH_SET="ip saddr != @ss_spec_lan_ac"
  569. ;;
  570. *)
  571. loger 3 "Bad argument \`-a $LAN_AC_IP\`."
  572. return 2
  573. ;;
  574. esac
  575. fi
  576. # Create necessary collections
  577. for setname in china gmlan fplan bplan whitelist; do
  578. if ! $NFT list set ip ss_spec_mangle $setname >/dev/null 2>&1; then
  579. $NFT add set ip ss_spec_mangle $setname '{ type ipv4_addr; flags interval; auto-merge; }'
  580. else
  581. $NFT flush set ip ss_spec_mangle $setname 2>/dev/null
  582. fi
  583. done
  584. # 批量导入中国IP列表
  585. if [ -f "${china_ip:=/etc/ssrplus/china_ssr.txt}" ]; then
  586. $NFT add element ip ss_spec_mangle china "{ $(tr '\n' ',' < "${china_ip}" | sed 's/,$//') }" 2>/dev/null
  587. fi
  588. # use priority mangle for compatibility with other rules
  589. if ! $NFT list chain ip ss_spec_mangle ss_spec_tproxy >/dev/null 2>&1; then
  590. $NFT add chain ip ss_spec_mangle ss_spec_tproxy 2>/dev/null
  591. else
  592. $NFT flush chain ip ss_spec_mangle ss_spec_tproxy 2>/dev/null
  593. fi
  594. # basic return rules in tproxy chain
  595. $NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport 53 return 2>/dev/null
  596. if $NFT list chain ip ss_spec_mangle ss_spec_tproxy >/dev/null 2>&1; then
  597. 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
  598. $NFT add rule ip ss_spec_mangle ss_spec_tproxy ip daddr $net return 2>/dev/null
  599. done
  600. fi
  601. # avoid redirecting to udp server address
  602. if [ -n "$server" ]; then
  603. $NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport != 53 ip daddr "$server" return 2>/dev/null
  604. fi
  605. # if server != SERVER add SERVER to whitelist set (so tproxy won't touch it)
  606. if [ -n "$server" ]; then
  607. $NFT add rule ip ss_spec_mangle ss_spec_tproxy ip daddr "$server" return 2>/dev/null
  608. fi
  609. if [ -n "$SERVER" ] && [ "$server" != "$SERVER" ]; then
  610. $NFT add element ip ss_spec_mangle whitelist "{ $SERVER }" 2>/dev/null
  611. fi
  612. # access control and tproxy rules
  613. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip saddr @bplan return 2>/dev/null
  614. if [ -n "$EXT_ARGS" ]; then
  615. $NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport { $EXT_ARGS } ip saddr @fplan tproxy to :"$LOCAL_PORT" meta mark set 0x01
  616. else
  617. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip saddr @fplan tproxy to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
  618. fi
  619. # Handle different run modes for nftables
  620. case "$RUNMODE" in
  621. router)
  622. if ! $NFT list set ip ss_spec_mangle ss_spec_wan_ac >/dev/null 2>&1; then
  623. $NFT add set ip ss_spec_mangle ss_spec_wan_ac '{ type ipv4_addr; flags interval; auto-merge; }'
  624. else
  625. $NFT flush set ip ss_spec_mangle ss_spec_wan_ac 2>/dev/null
  626. fi
  627. # Add special IP ranges to WAN AC set
  628. for ip in $(gen_spec_iplist); do
  629. [ -n "$ip" ] && $NFT add element ip ss_spec_mangle ss_spec_wan_ac "{ $ip }" 2>/dev/null
  630. done
  631. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip daddr @ss_spec_wan_ac return 2>/dev/null
  632. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip daddr @china return 2>/dev/null
  633. $NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport 80 drop 2>/dev/null
  634. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip saddr @gmlan ip daddr != @china tproxy to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
  635. if [ -n "$EXT_ARGS" ]; then
  636. $NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport { $EXT_ARGS } ip daddr != @ss_spec_wan_ac tproxy to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
  637. else
  638. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip daddr != @ss_spec_wan_ac tproxy to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
  639. fi
  640. ;;
  641. gfw)
  642. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip daddr @china return 2>/dev/null
  643. $NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport 80 drop 2>/dev/null
  644. if [ -n "$EXT_ARGS" ]; then
  645. $NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport { $EXT_ARGS } ip daddr @gfwlist tproxy to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
  646. fi
  647. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip saddr @gmlan ip daddr != @china tproxy to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
  648. ;;
  649. oversea)
  650. if ! $NFT list set ip ss_spec_mangle oversea >/dev/null 2>&1; then
  651. $NFT add set ip ss_spec_mangle oversea '{ type ipv4_addr; flags interval; auto-merge; }' 2>/dev/null
  652. fi
  653. if ! $NFT list set ip ss_spec_mangle china >/dev/null 2>&1; then
  654. $NFT add set ip ss_spec_mangle china '{ type ipv4_addr; flags interval; auto-merge; }' 2>/dev/null
  655. fi
  656. if [ -n "$EXT_ARGS" ]; then
  657. $NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport { $EXT_ARGS } ip saddr @oversea tproxy to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
  658. $NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport { $EXT_ARGS } ip daddr @china tproxy to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
  659. fi
  660. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp ip saddr @gmlan tproxy to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
  661. ;;
  662. all)
  663. if [ -n "$EXT_ARGS" ]; then
  664. $NFT add rule ip ss_spec_mangle ss_spec_tproxy udp dport { $EXT_ARGS } tproxy to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
  665. else
  666. $NFT add rule ip ss_spec_mangle ss_spec_tproxy meta l4proto udp tproxy to :"$LOCAL_PORT" meta mark set 0x01 2>/dev/null
  667. fi
  668. ;;
  669. esac
  670. # 创建 prerouting 链(hook prerouting)
  671. if ! $NFT list chain ip ss_spec_mangle prerouting >/dev/null 2>&1; then
  672. $NFT add chain ip ss_spec_mangle prerouting '{ type filter hook prerouting priority mangle; policy accept; }'
  673. fi
  674. # 添加规则到 prerouting 链
  675. if [ -z "$Interface" ]; then
  676. # 全局规则
  677. if [ -n "$MATCH_SET" ]; then
  678. $NFT add rule ip ss_spec_mangle prerouting udp dport { $EXT_ARGS } $MATCH_SET jump ss_spec_tproxy comment "\"$TAG\"" 2>/dev/null
  679. else
  680. $NFT add rule ip ss_spec_mangle prerouting udp dport { $EXT_ARGS } jump ss_spec_tproxy comment "\"$TAG\"" 2>/dev/null
  681. fi
  682. else
  683. # 指定接口
  684. for name in $Interface; do
  685. IFNAME=$(uci -P /var/state get network."$name".ifname 2>/dev/null)
  686. [ -z "$IFNAME" ] && IFNAME=$(uci -P /var/state get network."$name".device 2>/dev/null)
  687. if [ -n "$IFNAME" ]; then
  688. if [ -n "$MATCH_SET" ]; then
  689. $NFT add rule ip ss_spec_mangle prerouting meta iifname "$IFNAME" udp dport { $EXT_ARGS } $MATCH_SET jump ss_spec_tproxy comment "\"$TAG\"" 2>/dev/null
  690. else
  691. $NFT add rule ip ss_spec_mangle prerouting meta iifname "$IFNAME" udp dport { $EXT_ARGS } jump ss_spec_tproxy comment "\"$TAG\"" 2>/dev/null
  692. fi
  693. fi
  694. done
  695. fi
  696. return $?
  697. }
  698. tp_rule_iptables() {
  699. ip rule add fwmark 0x01/0x01 table 100
  700. ip route add local 0.0.0.0/0 dev lo table 100
  701. local ipt="iptables -t mangle"
  702. $ipt -N SS_SPEC_TPROXY
  703. $ipt -A SS_SPEC_TPROXY -p udp --dport 53 -j RETURN
  704. $ipt -A SS_SPEC_TPROXY -p udp -d 0.0.0.0/8 -j RETURN
  705. $ipt -A SS_SPEC_TPROXY -p udp -d 10.0.0.0/8 -j RETURN
  706. $ipt -A SS_SPEC_TPROXY -p udp -d 127.0.0.0/8 -j RETURN
  707. $ipt -A SS_SPEC_TPROXY -p udp -d 169.254.0.0/16 -j RETURN
  708. $ipt -A SS_SPEC_TPROXY -p udp -d 172.16.0.0/12 -j RETURN
  709. $ipt -A SS_SPEC_TPROXY -p udp -d 192.168.0.0/16 -j RETURN
  710. $ipt -A SS_SPEC_TPROXY -p udp -d 224.0.0.0/4 -j RETURN
  711. $ipt -A SS_SPEC_TPROXY -p udp -d 240.0.0.0/4 -j RETURN
  712. $ipt -A SS_SPEC_TPROXY -p udp ! --dport 53 -d "$SERVER" -j RETURN
  713. [ "$server" != "$SERVER" ] && ipset -! add whitelist "$SERVER"
  714. $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set bplan src -j RETURN
  715. $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
  716. case "$RUNMODE" in
  717. router)
  718. $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set ss_spec_wan_ac dst -j RETURN
  719. $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set china dst -j RETURN
  720. $ipt -A SS_SPEC_TPROXY -p udp --dport 80 -j DROP
  721. $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
  722. $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
  723. ;;
  724. gfw)
  725. $ipt -A SS_SPEC_TPROXY -p udp -m set --match-set china dst -j RETURN
  726. $ipt -A SS_SPEC_TPROXY -p udp --dport 80 -j DROP
  727. $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
  728. $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
  729. ;;
  730. oversea)
  731. $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
  732. $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
  733. $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
  734. ;;
  735. all)
  736. $ipt -A SS_SPEC_TPROXY -p udp $PROXY_PORTS -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
  737. ;;
  738. esac
  739. if [ -z "$Interface" ]; then
  740. $ipt -I PREROUTING 1 -p udp $EXT_ARGS $MATCH_SET -m comment --comment "$TAG" -j SS_SPEC_TPROXY
  741. else
  742. for name in $Interface; do
  743. local IFNAME=$(uci -P /var/state get network."$name".ifname 2>/dev/null)
  744. [ -z "$IFNAME" ] && IFNAME=$(uci -P /var/state get network."$name".device 2>/dev/null)
  745. [ -n "$IFNAME" ] && $ipt -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p udp $EXT_ARGS $MATCH_SET -m comment --comment "$TAG" -j SS_SPEC_TPROXY
  746. done
  747. fi
  748. return $?
  749. }
  750. get_wan_ip() {
  751. cat <<-EOF | grep -E "^([0-9]{1,3}\.){3}[0-9]{1,3}"
  752. $server
  753. $SERVER
  754. $WAN_BP_IP
  755. EOF
  756. }
  757. gen_spec_iplist() {
  758. cat <<-EOF
  759. 0.0.0.0/8
  760. 10.0.0.0/8
  761. 100.64.0.0/10
  762. 127.0.0.0/8
  763. 169.254.0.0/16
  764. 172.16.0.0/12
  765. 192.0.0.0/24
  766. 192.0.2.0/24
  767. 192.88.99.0/24
  768. 192.168.0.0/16
  769. 198.18.0.0/15
  770. 198.51.100.0/24
  771. 203.0.113.0/24
  772. 224.0.0.0/4
  773. 240.0.0.0/4
  774. 255.255.255.255
  775. $(get_wan_ip)
  776. EOF
  777. }
  778. gen_include() {
  779. [ -n "$FWI" ] || return 0
  780. if [ "$USE_NFT" = "1" ]; then
  781. gen_include_nft
  782. else
  783. gen_include_iptables
  784. fi
  785. return $?
  786. }
  787. gen_include_nft() {
  788. # Generate nftables include file for firewall4
  789. [ -n "$FWI" ] && echo '#!/bin/sh' >"$FWI"
  790. cat <<-'EOF' >>"$FWI"
  791. # Clear existing ss_spec tables
  792. nft delete table inet ss_spec 2>/dev/null
  793. nft delete table ip ss_spec 2>/dev/null
  794. nft delete table ip ss_spec_mangle 2>/dev/null
  795. # Restore shadowsocks nftables rules
  796. nft list ruleset | awk '/^table (inet|ip) ss_spec/{flag=1} /^table / && !/^table (inet|ip) ss_spec/{flag=0} flag'
  797. EOF
  798. chmod +x "$FWI"
  799. }
  800. gen_include_iptables() {
  801. extract_rules() {
  802. echo "*$1"
  803. iptables-save -t $1 | grep SS_SPEC_ | sed -e "s/^-A \(OUTPUT\|PREROUTING\)/-I \1 1/"
  804. echo 'COMMIT'
  805. }
  806. cat <<-EOF >>$FWI
  807. iptables-save -c | grep -v "SS_SPEC" | iptables-restore -c
  808. iptables-restore -n <<-EOT
  809. $(extract_rules nat)
  810. $(extract_rules mangle)
  811. EOT
  812. EOF
  813. }
  814. while getopts ":m:s:l:S:L:i:e:a:B:b:w:p:G:D:F:N:M:I:oOuUfgrczh" arg; do
  815. case "$arg" in
  816. m)
  817. Interface=$OPTARG
  818. ;;
  819. s)
  820. server=$OPTARG
  821. ;;
  822. l)
  823. local_port=$OPTARG
  824. ;;
  825. S)
  826. SERVER=$OPTARG
  827. ;;
  828. L)
  829. LOCAL_PORT=$OPTARG
  830. ;;
  831. i)
  832. IGNORE_LIST=$OPTARG
  833. ;;
  834. e)
  835. EXT_ARGS=$OPTARG
  836. ;;
  837. a)
  838. LAN_AC_IP=$OPTARG
  839. ;;
  840. B)
  841. LAN_BP_IP=$OPTARG
  842. ;;
  843. b)
  844. WAN_BP_IP=$(for ip in $OPTARG; do echo "$ip"; done)
  845. ;;
  846. w)
  847. WAN_FW_IP=$OPTARG
  848. ;;
  849. p)
  850. LAN_FP_IP=$OPTARG
  851. ;;
  852. G)
  853. LAN_GM_IP=$OPTARG
  854. ;;
  855. D)
  856. PROXY_PORTS=$OPTARG
  857. ;;
  858. F)
  859. SHUNT_PORT=$OPTARG
  860. ;;
  861. N)
  862. SHUNT_IP=$OPTARG
  863. ;;
  864. M)
  865. SHUNT_PROXY=$OPTARG
  866. ;;
  867. I)
  868. SHUNT_LIST=$OPTARG
  869. ;;
  870. o)
  871. OUTPUT=1
  872. ;;
  873. O)
  874. OUTPUT=2
  875. ;;
  876. u)
  877. TPROXY=1
  878. ;;
  879. U)
  880. TPROXY=2
  881. ;;
  882. g)
  883. RUNMODE=gfw
  884. ;;
  885. r)
  886. RUNMODE=router
  887. ;;
  888. c)
  889. RUNMODE=oversea
  890. ;;
  891. z)
  892. RUNMODE=all
  893. ;;
  894. f)
  895. flush_r
  896. exit 0
  897. ;;
  898. h) usage 0 ;;
  899. esac
  900. done
  901. if [ -z "$server" ] || [ -z "$local_port" ]; then
  902. usage 2
  903. fi
  904. if ! echo "$local_port" | grep -qE '^[0-9]+$'; then
  905. loger 3 "Invalid local port: $local_port"
  906. exit 1
  907. fi
  908. case "$TPROXY" in
  909. 1)
  910. SERVER=$server
  911. LOCAL_PORT=$local_port
  912. ;;
  913. 2)
  914. : ${SERVER:?"You must assign an ip for the udp relay server."}
  915. : ${LOCAL_PORT:?"You must assign a port for the udp relay server."}
  916. ;;
  917. esac
  918. # First check whether nftables is working properly
  919. if [ "$USE_NFT" = "1" ]; then
  920. if ! $NFT list tables 2>/dev/null; then
  921. loger 3 "nftables is not working properly, check if nftables is installed and running"
  922. exit 1
  923. fi
  924. fi
  925. if [ "$USE_NFT" = "1" ]; then
  926. # NFTables
  927. if flush_r && ipset_r && fw_rule && ac_rule && tp_rule && gen_include; then
  928. loger 5 "NFTables rules applied successfully"
  929. exit 0
  930. else
  931. loger 3 "NFTables setup failed!"
  932. exit 1
  933. fi
  934. else
  935. # iptables
  936. if flush_r && fw_rule && ipset_r && ac_rule && tp_rule && gen_include; then
  937. loger 5 "iptables rules applied successfully"
  938. exit 0
  939. else
  940. loger 3 "iptables setup failed!"
  941. exit 1
  942. fi
  943. fi