You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

265 lines
8.2 KiB

  1. #!/bin/sh -e
  2. #
  3. # Copyright (C) 2017 Yousong Zhou <yszhou4tech@gmail.com>
  4. #
  5. # The design idea was derived from ss-rules by Jian Chang <aa65535@live.com>
  6. #
  7. # This is free software, licensed under the GNU General Public License v3.
  8. # See /LICENSE for more information.
  9. #
  10. ss_rules_usage() {
  11. cat >&2 <<EOF
  12. Usage: ss-rules [options]
  13. -h, --help Show this help message then exit
  14. -f, --flush Flush rules, ipset then exit
  15. -l <port> Local port number of ss-redir with TCP mode
  16. -L <port> Local port number of ss-redir with UDP mode
  17. -s <ips> List of ip addresses of remote shadowsocks server
  18. --ifnames Only apply rules on packets from these ifnames
  19. --src-bypass <ips|cidr>
  20. --src-forward <ips|cidr>
  21. --src-checkdst <ips|cidr>
  22. --src-default <bypass|forward|checkdst>
  23. Packets will have their src ip checked in order against
  24. bypass, forward, checkdst list and will bypass, forward
  25. through, or continue to have their dst ip checked
  26. respectively on the first match. Otherwise, --src-default
  27. decide the default action
  28. --dst-bypass <ips|cidr>
  29. --dst-forward <ips|cidr>
  30. --dst-bypass-file <file>
  31. --dst-forward-file <file>
  32. --dst-default <bypass|forward>
  33. Same as with their --src-xx equivalent
  34. --dst-forward-recentrst
  35. Forward those packets whose destinations have recently
  36. sent to us multiple tcp-rst packets
  37. --local-default <bypass|forward|checkdst>
  38. Default action for local out TCP traffic
  39. The following ipsets will be created by ss-rules. They are also intended to be
  40. populated by other programs like dnsmasq with ipset support
  41. ss_rules_src_bypass
  42. ss_rules_src_forward
  43. ss_rules_src_checkdst
  44. ss_rules_dst_bypass
  45. ss_rules_dst_forward
  46. EOF
  47. }
  48. o_dst_bypass_="
  49. 0.0.0.0/8
  50. 10.0.0.0/8
  51. 100.64.0.0/10
  52. 127.0.0.0/8
  53. 169.254.0.0/16
  54. 172.16.0.0/12
  55. 192.0.0.0/24
  56. 192.0.2.0/24
  57. 192.31.196.0/24
  58. 192.52.193.0/24
  59. 192.88.99.0/24
  60. 192.168.0.0/16
  61. 192.175.48.0/24
  62. 198.18.0.0/15
  63. 198.51.100.0/24
  64. 203.0.113.0/24
  65. 224.0.0.0/4
  66. 240.0.0.0/4
  67. 255.255.255.255
  68. "
  69. o_src_default=bypass
  70. o_dst_default=bypass
  71. o_local_default=bypass
  72. __errmsg() {
  73. echo "ss-rules: $*" >&2
  74. }
  75. ss_rules_parse_args() {
  76. while [ "$#" -gt 0 ]; do
  77. case "$1" in
  78. -h|--help) ss_rules_usage; exit 0;;
  79. -f|--flush) ss_rules_flush; exit 0;;
  80. -l) o_redir_tcp_port="$2"; shift 2;;
  81. -L) o_redir_udp_port="$2"; shift 2;;
  82. -s) o_remote_servers="$2"; shift 2;;
  83. --ifnames) o_ifnames="$2"; shift 2;;
  84. --ipt-extra) o_ipt_extra="$2"; shift 2;;
  85. --src-default) o_src_default="$2"; shift 2;;
  86. --dst-default) o_dst_default="$2"; shift 2;;
  87. --local-default) o_local_default="$2"; shift 2;;
  88. --src-bypass) o_src_bypass="$2"; shift 2;;
  89. --src-forward) o_src_forward="$2"; shift 2;;
  90. --src-checkdst) o_src_checkdst="$2"; shift 2;;
  91. --dst-bypass) o_dst_bypass="$2"; shift 2;;
  92. --dst-forward) o_dst_forward="$2"; shift 2;;
  93. --dst-forward-recentrst) o_dst_forward_recentrst=1; shift 1;;
  94. --dst-bypass-file) o_dst_bypass_file="$2"; shift 2;;
  95. --dst-forward-file) o_dst_forward_file="$2"; shift 2;;
  96. *) __errmsg "unknown option $1"; return 1;;
  97. esac
  98. done
  99. if [ -z "$o_redir_tcp_port" -a -z "$o_redir_udp_port" ]; then
  100. __errmsg "Requires at least -l or -L option"
  101. return 1
  102. fi
  103. if [ -n "$o_dst_forward_recentrst" ] && ! iptables -m recent -h >/dev/null; then
  104. __errmsg "Please install iptables-mod-conntrack-extra with opkg"
  105. return 1
  106. fi
  107. o_remote_servers="$(for s in $o_remote_servers; do resolveip -4 "$s"; done)"
  108. }
  109. ss_rules_flush() {
  110. local setname
  111. iptables-save --counters | grep -v ss_rules_ | iptables-restore --counters
  112. while ip rule del fwmark 1 lookup 100 2>/dev/null; do true; done
  113. ip route flush table 100
  114. for setname in $(ipset -n list | grep "ss_rules_"); do
  115. ipset destroy "$setname" 2>/dev/null || true
  116. done
  117. }
  118. ss_rules_ipset_init() {
  119. ipset --exist restore <<-EOF
  120. create ss_rules_src_bypass hash:net hashsize 64
  121. create ss_rules_src_forward hash:net hashsize 64
  122. create ss_rules_src_checkdst hash:net hashsize 64
  123. create ss_rules_dst_bypass hash:net hashsize 64
  124. create ss_rules_dst_bypass_ hash:net hashsize 64
  125. create ss_rules_dst_forward hash:net hashsize 64
  126. create ss_rules_dst_forward_recentrst_ hash:ip hashsize 64 timeout 3600
  127. $(ss_rules_ipset_mkadd ss_rules_dst_bypass_ "$o_dst_bypass_ $o_remote_servers")
  128. $(ss_rules_ipset_mkadd ss_rules_src_bypass "$o_src_bypass")
  129. $(ss_rules_ipset_mkadd ss_rules_src_forward "$o_src_forward")
  130. $(ss_rules_ipset_mkadd ss_rules_src_checkdst "$o_src_checkdst")
  131. $(ss_rules_ipset_mkadd ss_rules_dst_bypass "$o_dst_bypass $(cat "$o_dst_bypass_file" 2>/dev/null)")
  132. $(ss_rules_ipset_mkadd ss_rules_dst_forward "$o_dst_forward $(cat "$o_dst_forward_file" 2>/dev/null)")
  133. EOF
  134. }
  135. ss_rules_ipset_mkadd() {
  136. local setname="$1"; shift
  137. local i
  138. for i in $*; do
  139. echo "add $setname $i"
  140. done
  141. }
  142. ss_rules_iptchains_init() {
  143. ss_rules_iptchains_init_tcp
  144. ss_rules_iptchains_init_udp
  145. }
  146. ss_rules_iptchains_init_tcp() {
  147. local ipt="iptables -t nat"
  148. local local_target
  149. [ -n "$o_redir_tcp_port" ] || return 0
  150. ss_rules_iptchains_init_ nat tcp
  151. case "$o_local_default" in
  152. checkdst) local_target=ss_rules_dst ;;
  153. forward) local_target=ss_rules_forward ;;
  154. bypass|*) return 0;;
  155. esac
  156. iptables-restore --noflush <<-EOF
  157. *nat
  158. :ss_rules_local_out -
  159. -I OUTPUT 1 -p tcp -j ss_rules_local_out
  160. -A ss_rules_local_out -m set --match-set ss_rules_dst_bypass_ dst -j RETURN
  161. -A ss_rules_local_out -p tcp $o_ipt_extra -j $local_target -m comment --comment "local_default: $o_local_default"
  162. COMMIT
  163. EOF
  164. }
  165. ss_rules_iptchains_init_udp() {
  166. [ -n "$o_redir_udp_port" ] || return 0
  167. ss_rules_iptchains_init_ mangle udp
  168. }
  169. ss_rules_iptchains_init_() {
  170. local table="$1"
  171. local proto="$2"
  172. local forward_rules
  173. local src_default_target dst_default_target
  174. local recentrst_mangle_rules recentrst_addset_rules
  175. case "$proto" in
  176. tcp)
  177. forward_rules="-A ss_rules_forward -p tcp -j REDIRECT --to-ports $o_redir_tcp_port"
  178. if [ -n "$o_dst_forward_recentrst" ]; then
  179. recentrst_mangle_rules="
  180. *mangle
  181. -I PREROUTING 1 -p tcp -m tcp --tcp-flags RST RST -m recent --name ss_rules_recentrst --set --rsource
  182. COMMIT
  183. "
  184. recentrst_addset_rules="
  185. -A ss_rules_dst -m recent --name ss_rules_recentrst --rcheck --rdest --seconds 3 --hitcount 3 -j SET --add-set ss_rules_dst_forward_recentrst_ dst --exist
  186. -A ss_rules_dst -m set --match-set ss_rules_dst_forward_recentrst_ dst -j ss_rules_forward
  187. "
  188. fi
  189. ;;
  190. udp)
  191. ip rule add fwmark 1 lookup 100
  192. ip route add local default dev lo table 100
  193. forward_rules="-A ss_rules_forward -p udp -j TPROXY --on-port "$o_redir_udp_port" --tproxy-mark 0x01/0x01"
  194. ;;
  195. esac
  196. case "$o_src_default" in
  197. forward) src_default_target=ss_rules_forward ;;
  198. checkdst) src_default_target=ss_rules_dst ;;
  199. bypass|*) src_default_target=RETURN ;;
  200. esac
  201. case "$o_dst_default" in
  202. forward) dst_default_target=ss_rules_forward ;;
  203. bypass|*) dst_default_target=RETURN ;;
  204. esac
  205. sed -e '/^\s*$/d' -e 's/^\s\+//' <<-EOF | iptables-restore --noflush
  206. *$table
  207. :ss_rules_pre_src -
  208. :ss_rules_src -
  209. :ss_rules_dst -
  210. :ss_rules_forward -
  211. $(ss_rules_iptchains_mkprerules "$proto")
  212. -A ss_rules_pre_src -m set --match-set ss_rules_dst_bypass_ dst -j RETURN
  213. -A ss_rules_pre_src -p $proto $o_ipt_extra -j ss_rules_src
  214. -A ss_rules_src -m set --match-set ss_rules_src_bypass src -j RETURN
  215. -A ss_rules_src -m set --match-set ss_rules_src_forward src -j ss_rules_forward
  216. -A ss_rules_src -m set --match-set ss_rules_src_checkdst src -j ss_rules_dst
  217. -A ss_rules_src -j $src_default_target -m comment --comment "src_default: $o_src_default"
  218. -A ss_rules_dst -m set --match-set ss_rules_dst_bypass dst -j RETURN
  219. -A ss_rules_dst -m set --match-set ss_rules_dst_forward dst -j ss_rules_forward
  220. $recentrst_addset_rules
  221. -A ss_rules_dst -j $dst_default_target -m comment --comment "dst_default: $o_dst_default"
  222. $forward_rules
  223. COMMIT
  224. $recentrst_mangle_rules
  225. EOF
  226. }
  227. ss_rules_iptchains_mkprerules() {
  228. local proto="$1"
  229. if [ -z "$o_ifnames" ]; then
  230. echo "-I PREROUTING 1 -p $proto -j ss_rules_pre_src"
  231. else
  232. echo $o_ifnames \
  233. | tr ' ' '\n' \
  234. | sed "s/.*/-I PREROUTING 1 -i \\0 -p $proto -j ss_rules_pre_src/"
  235. fi
  236. }
  237. ss_rules_parse_args "$@"
  238. ss_rules_flush
  239. ss_rules_ipset_init
  240. ss_rules_iptchains_init