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.

264 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 local_target
  148. [ -n "$o_redir_tcp_port" ] || return 0
  149. ss_rules_iptchains_init_ nat tcp
  150. case "$o_local_default" in
  151. checkdst) local_target=ss_rules_dst ;;
  152. forward) local_target=ss_rules_forward ;;
  153. bypass|*) return 0;;
  154. esac
  155. iptables-restore --noflush <<-EOF
  156. *nat
  157. :ss_rules_local_out -
  158. -I OUTPUT 1 -p tcp -j ss_rules_local_out
  159. -A ss_rules_local_out -m set --match-set ss_rules_dst_bypass_ dst -j RETURN
  160. -A ss_rules_local_out -p tcp $o_ipt_extra -j $local_target -m comment --comment "local_default: $o_local_default"
  161. COMMIT
  162. EOF
  163. }
  164. ss_rules_iptchains_init_udp() {
  165. [ -n "$o_redir_udp_port" ] || return 0
  166. ss_rules_iptchains_init_ mangle udp
  167. }
  168. ss_rules_iptchains_init_() {
  169. local table="$1"
  170. local proto="$2"
  171. local forward_rules
  172. local src_default_target dst_default_target
  173. local recentrst_mangle_rules recentrst_addset_rules
  174. case "$proto" in
  175. tcp)
  176. forward_rules="-A ss_rules_forward -p tcp -j REDIRECT --to-ports $o_redir_tcp_port"
  177. if [ -n "$o_dst_forward_recentrst" ]; then
  178. recentrst_mangle_rules="
  179. *mangle
  180. -I PREROUTING 1 -p tcp -m tcp --tcp-flags RST RST -m recent --name ss_rules_recentrst --set --rsource
  181. COMMIT
  182. "
  183. recentrst_addset_rules="
  184. -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
  185. -A ss_rules_dst -m set --match-set ss_rules_dst_forward_recentrst_ dst -j ss_rules_forward
  186. "
  187. fi
  188. ;;
  189. udp)
  190. ip rule add fwmark 1 lookup 100
  191. ip route add local default dev lo table 100
  192. forward_rules="-A ss_rules_forward -p udp -j TPROXY --on-port "$o_redir_udp_port" --tproxy-mark 0x01/0x01"
  193. ;;
  194. esac
  195. case "$o_src_default" in
  196. forward) src_default_target=ss_rules_forward ;;
  197. checkdst) src_default_target=ss_rules_dst ;;
  198. bypass|*) src_default_target=RETURN ;;
  199. esac
  200. case "$o_dst_default" in
  201. forward) dst_default_target=ss_rules_forward ;;
  202. bypass|*) dst_default_target=RETURN ;;
  203. esac
  204. sed -e '/^\s*$/d' -e 's/^\s\+//' <<-EOF | iptables-restore --noflush
  205. *$table
  206. :ss_rules_pre_src -
  207. :ss_rules_src -
  208. :ss_rules_dst -
  209. :ss_rules_forward -
  210. $(ss_rules_iptchains_mkprerules "$proto")
  211. -A ss_rules_pre_src -m set --match-set ss_rules_dst_bypass_ dst -j RETURN
  212. -A ss_rules_pre_src -p $proto $o_ipt_extra -j ss_rules_src
  213. -A ss_rules_src -m set --match-set ss_rules_src_bypass src -j RETURN
  214. -A ss_rules_src -m set --match-set ss_rules_src_forward src -j ss_rules_forward
  215. -A ss_rules_src -m set --match-set ss_rules_src_checkdst src -j ss_rules_dst
  216. -A ss_rules_src -j $src_default_target -m comment --comment "src_default: $o_src_default"
  217. -A ss_rules_dst -m set --match-set ss_rules_dst_bypass dst -j RETURN
  218. -A ss_rules_dst -m set --match-set ss_rules_dst_forward dst -j ss_rules_forward
  219. $recentrst_addset_rules
  220. -A ss_rules_dst -j $dst_default_target -m comment --comment "dst_default: $o_dst_default"
  221. $forward_rules
  222. COMMIT
  223. $recentrst_mangle_rules
  224. EOF
  225. }
  226. ss_rules_iptchains_mkprerules() {
  227. local proto="$1"
  228. if [ -z "$o_ifnames" ]; then
  229. echo "-I PREROUTING 1 -p $proto -j ss_rules_pre_src"
  230. else
  231. echo $o_ifnames \
  232. | tr ' ' '\n' \
  233. | sed "s/.*/-I PREROUTING 1 -i \\0 -p $proto -j ss_rules_pre_src/"
  234. fi
  235. }
  236. ss_rules_parse_args "$@"
  237. ss_rules_flush
  238. ss_rules_ipset_init
  239. ss_rules_iptchains_init