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.

243 lines
7.1 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_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. --local-default <bypass|forward|checkdst>
  35. Default action for local out TCP traffic
  36. The following ipsets will be created by ss-rules. They are also intended to be
  37. populated by other programs like dnsmasq with ipset support
  38. ss_rules_src_bypass
  39. ss_rules_src_forward
  40. ss_rules_src_checkdst
  41. ss_rules_dst_bypass
  42. ss_rules_dst_forward
  43. EOF
  44. }
  45. o_dst_bypass_="
  46. 0.0.0.0/8
  47. 10.0.0.0/8
  48. 100.64.0.0/10
  49. 127.0.0.0/8
  50. 169.254.0.0/16
  51. 172.16.0.0/12
  52. 192.0.0.0/24
  53. 192.0.2.0/24
  54. 192.31.196.0/24
  55. 192.52.193.0/24
  56. 192.88.99.0/24
  57. 192.168.0.0/16
  58. 192.175.48.0/24
  59. 198.18.0.0/15
  60. 198.51.100.0/24
  61. 203.0.113.0/24
  62. 224.0.0.0/4
  63. 240.0.0.0/4
  64. 255.255.255.255
  65. "
  66. o_src_default=bypass
  67. o_dst_default=bypass
  68. o_local_default=bypass
  69. __errmsg() {
  70. echo "ss-rules: $*" >&2
  71. }
  72. ss_rules_parse_args() {
  73. while [ "$#" -gt 0 ]; do
  74. case "$1" in
  75. -h|--help) ss_usage; exit 0;;
  76. -f|--flush) ss_rules_flush; exit 0;;
  77. -l) o_redir_tcp_port="$2"; shift 2;;
  78. -L) o_redir_udp_port="$2"; shift 2;;
  79. -s) o_remote_servers="$2"; shift 2;;
  80. --ifnames) o_ifnames="$2"; shift 2;;
  81. --ipt-extra) o_ipt_extra="$2"; shift 2;;
  82. --src-default) o_src_default="$2"; shift 2;;
  83. --dst-default) o_dst_default="$2"; shift 2;;
  84. --local-default) o_local_default="$2"; shift 2;;
  85. --src-bypass) o_src_bypass="$2"; shift 2;;
  86. --src-forward) o_src_forward="$2"; shift 2;;
  87. --src-checkdst) o_src_checkdst="$2"; shift 2;;
  88. --dst-bypass) o_dst_bypass="$2"; shift 2;;
  89. --dst-forward) o_dst_forward="$2"; shift 2;;
  90. --dst-bypass-file) o_dst_bypass_file="$2"; shift 2;;
  91. --dst-forward-file) o_dst_forward_file="$2"; shift 2;;
  92. *) __errmsg "unknown option $1"; return 1;;
  93. esac
  94. done
  95. if [ -z "$o_redir_tcp_port" -a -z "$o_redir_udp_port" ]; then
  96. __errmsg "Requires at least -l or -L option"
  97. return 1
  98. fi
  99. }
  100. ss_rules_flush() {
  101. local setname
  102. iptables-save --counters | grep -v ss_rules_ | iptables-restore --counters
  103. while ip rule del fwmark 1 lookup 100 2>/dev/null; do true; done
  104. ip route flush table 100
  105. for setname in $(ipset -n list | grep "ss_rules_"); do
  106. ipset destroy "$setname" 2>/dev/null || true
  107. done
  108. }
  109. ss_rules_ipset_init() {
  110. ipset --exist restore <<-EOF
  111. create ss_rules_src_bypass hash:net hashsize 64
  112. create ss_rules_src_forward hash:net hashsize 64
  113. create ss_rules_src_checkdst hash:net hashsize 64
  114. create ss_rules_dst_bypass hash:net hashsize 64
  115. create ss_rules_dst_bypass_ hash:net hashsize 64
  116. create ss_rules_dst_forward hash:net hashsize 64
  117. $(ss_rules_ipset_mkadd ss_rules_dst_bypass_ "$o_dst_bypass_ $o_remote_servers")
  118. $(ss_rules_ipset_mkadd ss_rules_src_bypass "$o_src_bypass")
  119. $(ss_rules_ipset_mkadd ss_rules_src_forward "$o_src_forward")
  120. $(ss_rules_ipset_mkadd ss_rules_src_checkdst "$o_src_checkdst")
  121. $(ss_rules_ipset_mkadd ss_rules_dst_bypass "$o_dst_bypass $(cat "$o_dst_bypass_file" 2>/dev/null)")
  122. $(ss_rules_ipset_mkadd ss_rules_dst_forward "$o_dst_forward $(cat "$o_dst_forward_file" 2>/dev/null)")
  123. EOF
  124. }
  125. ss_rules_ipset_mkadd() {
  126. local setname="$1"; shift
  127. local i
  128. for i in $*; do
  129. echo "add $setname $i"
  130. done
  131. }
  132. ss_rules_iptchains_init() {
  133. ss_rules_iptchains_init_tcp
  134. ss_rules_iptchains_init_udp
  135. }
  136. ss_rules_iptchains_init_tcp() {
  137. local ipt="iptables -t nat"
  138. local local_target
  139. local forward_rules
  140. local r
  141. [ -n "$o_redir_tcp_port" ] || return 0
  142. ss_rules_iptchains_init_ nat tcp
  143. case "$o_local_default" in
  144. checkdst) local_target=ss_rules_dst ;;
  145. forward) local_target=ss_rules_forward ;;
  146. bypass|*) return 0;;
  147. esac
  148. iptables-restore --noflush <<-EOF
  149. *nat
  150. :ss_rules_local_out -
  151. -I OUTPUT 1 -p tcp -j ss_rules_local_out
  152. -A ss_rules_local_out -m set --match-set ss_rules_dst_bypass_ dst -j RETURN
  153. -A ss_rules_local_out -p tcp $o_ipt_extra -j $local_target -m comment --comment "local_default: $o_local_default"
  154. COMMIT
  155. EOF
  156. }
  157. ss_rules_iptchains_init_udp() {
  158. [ -n "$o_redir_udp_port" ] || return 0
  159. ss_rules_iptchains_init_ mangle udp
  160. }
  161. ss_rules_iptchains_init_() {
  162. local table="$1"
  163. local proto="$2"
  164. local forward_rules
  165. local src_default_target dst_default_target
  166. case "$proto" in
  167. tcp)
  168. forward_rules="-A ss_rules_forward -p tcp -j REDIRECT --to-ports $o_redir_tcp_port"
  169. ;;
  170. udp)
  171. ip rule add fwmark 1 lookup 100
  172. ip route add local default dev lo table 100
  173. forward_rules="-A ss_rules_forward -p udp -j TPROXY --on-port "$o_redir_udp_port" --tproxy-mark 0x01/0x01"
  174. ;;
  175. esac
  176. case "$o_src_default" in
  177. forward) src_default_target=ss_rules_forward ;;
  178. checkdst) src_default_target=ss_rules_dst ;;
  179. bypass|*) src_default_target=RETURN ;;
  180. esac
  181. case "$o_dst_default" in
  182. forward) dst_default_target=ss_rules_forward ;;
  183. bypass|*) dst_default_target=RETURN ;;
  184. esac
  185. iptables-restore --noflush <<-EOF
  186. *$table
  187. :ss_rules_pre_src -
  188. :ss_rules_src -
  189. :ss_rules_dst -
  190. :ss_rules_forward -
  191. $(ss_rules_iptchains_mkprerules "$proto")
  192. -A ss_rules_pre_src -m set --match-set ss_rules_dst_bypass_ dst -j RETURN
  193. -A ss_rules_pre_src -p $proto $o_ipt_extra -j ss_rules_src
  194. -A ss_rules_src -m set --match-set ss_rules_src_bypass src -j RETURN
  195. -A ss_rules_src -m set --match-set ss_rules_src_forward src -j ss_rules_forward
  196. -A ss_rules_src -m set --match-set ss_rules_src_checkdst src -j ss_rules_dst
  197. -A ss_rules_src -j $src_default_target -m comment --comment "src_default: $o_src_default"
  198. -A ss_rules_dst -m set --match-set ss_rules_dst_bypass dst -j RETURN
  199. -A ss_rules_dst -m set --match-set ss_rules_dst_forward dst -j ss_rules_forward
  200. -A ss_rules_dst -j $dst_default_target -m comment --comment "dst_default: $o_dst_default"
  201. $forward_rules
  202. COMMIT
  203. EOF
  204. }
  205. ss_rules_iptchains_mkprerules() {
  206. local proto="$1"
  207. if [ -z "$o_ifnames" ]; then
  208. echo "-I PREROUTING 1 -p $proto -j ss_rules_pre_src"
  209. else
  210. echo "$o_ifnames" \
  211. | tr ' ' '\n' \
  212. | sed "s/.*/-I PREROUTING 1 -i \\0 -p $proto -j ss_rules_pre_src/"
  213. fi
  214. }
  215. ss_rules_parse_args "$@"
  216. ss_rules_flush
  217. ss_rules_ipset_init
  218. ss_rules_iptchains_init