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.

260 lines
6.5 KiB

  1. #!/bin/sh
  2. #
  3. # Copyright (C) 2014-2017 Jian Chang <aa65535@live.com>
  4. #
  5. # This is free software, licensed under the GNU General Public License v3.
  6. # See /LICENSE for more information.
  7. #
  8. usage() {
  9. cat <<-EOF
  10. Usage: ss-rules [options]
  11. Valid options are:
  12. -s <server_ips> ip address of shadowsocks remote server
  13. -l <local_port> port number of shadowsocks local server
  14. -S <server_ips> ip address of shadowsocks remote UDP server
  15. -L <local_port> port number of shadowsocks local UDP server
  16. -B <ip_list_file> a file whose content is bypassed ip list
  17. -b <wan_ips> wan ip of will be bypassed
  18. -W <ip_list_file> a file whose content is forwarded ip list
  19. -w <wan_ips> wan ip of will be forwarded
  20. -I <interface> proxy only for the given interface
  21. -d <target> the default target of lan access control
  22. -a <lan_hosts> lan ip of access control, need a prefix to
  23. define proxy type
  24. -e <extra_args> extra arguments for iptables
  25. -o apply the rules to the OUTPUT chain
  26. -O apply the global rules to the OUTPUT chain
  27. -u enable udprelay mode, TPROXY is required
  28. -U enable udprelay mode, using different IP
  29. and ports for TCP and UDP
  30. -f flush the rules
  31. -h show this help message and exit
  32. EOF
  33. exit $1
  34. }
  35. loger() {
  36. # 1.alert 2.crit 3.err 4.warn 5.notice 6.info 7.debug
  37. logger -st ss-rules[$$] -p$1 $2
  38. }
  39. flush_rules() {
  40. iptables-save -c | grep -v "SS_SPEC" | iptables-restore -c
  41. if command -v ip >/dev/null 2>&1; then
  42. ip rule del fwmark 1 lookup 100 2>/dev/null
  43. ip route del local default dev lo table 100 2>/dev/null
  44. fi
  45. for setname in $(ipset -n list | grep "ss_spec"); do
  46. ipset destroy $setname 2>/dev/null
  47. done
  48. FWI=$(uci get firewall.shadowsocks.path 2>/dev/null)
  49. [ -n "$FWI" ] && echo '# firewall include file' >$FWI
  50. return 0
  51. }
  52. ipset_init() {
  53. ipset -! restore <<-EOF || return 1
  54. create ss_spec_src_ac hash:ip hashsize 64
  55. create ss_spec_src_bp hash:ip hashsize 64
  56. create ss_spec_src_fw hash:ip hashsize 64
  57. create ss_spec_dst_sp hash:net hashsize 64
  58. create ss_spec_dst_bp hash:net hashsize 64
  59. create ss_spec_dst_fw hash:net hashsize 64
  60. $(gen_lan_host_ipset_entry)
  61. $(gen_special_purpose_ip | sed -e "s/^/add ss_spec_dst_sp /")
  62. $(sed -e "s/^/add ss_spec_dst_bp /" ${WAN_BP_LIST:=/dev/null} 2>/dev/null)
  63. $(for ip in $WAN_BP_IP; do echo "add ss_spec_dst_bp $ip"; done)
  64. $(sed -e "s/^/add ss_spec_dst_fw /" ${WAN_FW_LIST:=/dev/null} 2>/dev/null)
  65. $(for ip in $WAN_FW_IP; do echo "add ss_spec_dst_fw $ip"; done)
  66. EOF
  67. return 0
  68. }
  69. ipt_nat() {
  70. include_ac_rules nat
  71. ipt="iptables -t nat"
  72. $ipt -A SS_SPEC_WAN_FW -p tcp \
  73. -j REDIRECT --to-ports $local_port || return 1
  74. if [ -n "$OUTPUT" ]; then
  75. $ipt -N SS_SPEC_WAN_DG
  76. $ipt -A SS_SPEC_WAN_DG -m set --match-set ss_spec_dst_sp dst -j RETURN
  77. $ipt -A SS_SPEC_WAN_DG -p tcp $EXT_ARGS -j $OUTPUT
  78. $ipt -I OUTPUT 1 -p tcp -j SS_SPEC_WAN_DG
  79. fi
  80. return $?
  81. }
  82. ipt_mangle() {
  83. [ -n "$TPROXY" ] || return 0
  84. if !(lsmod | grep -q TPROXY && command -v ip >/dev/null); then
  85. loger 4 "TPROXY or ip not found."
  86. return 0
  87. fi
  88. ip rule add fwmark 1 lookup 100
  89. ip route add local default dev lo table 100
  90. include_ac_rules mangle
  91. iptables -t mangle -A SS_SPEC_WAN_FW -p udp \
  92. -j TPROXY --on-port $LOCAL_PORT --tproxy-mark 0x01/0x01
  93. return $?
  94. }
  95. export_ipt_rules() {
  96. [ -n "$FWI" ] || return 0
  97. cat <<-CAT >>$FWI
  98. iptables-save -c | grep -v "SS_SPEC" | iptables-restore -c
  99. iptables-restore -n <<-EOF
  100. $(iptables-save | grep -E "SS_SPEC|^\*|^COMMIT" |\
  101. sed -e "s/^-A \(OUTPUT\|PREROUTING\)/-I \1 1/")
  102. EOF
  103. CAT
  104. return $?
  105. }
  106. gen_lan_host_ipset_entry() {
  107. for host in $LAN_HOSTS; do
  108. case "${host:0:1}" in
  109. n|N)
  110. echo add ss_spec_src_ac ${host:2}
  111. ;;
  112. b|B)
  113. echo add ss_spec_src_bp ${host:2}
  114. ;;
  115. g|G)
  116. echo add ss_spec_src_fw ${host:2}
  117. ;;
  118. esac
  119. done
  120. }
  121. gen_special_purpose_ip() {
  122. cat <<-EOF | grep -E "^([0-9]{1,3}\.){3}[0-9]{1,3}"
  123. 0.0.0.0/8
  124. 10.0.0.0/8
  125. 100.64.0.0/10
  126. 127.0.0.0/8
  127. 169.254.0.0/16
  128. 172.16.0.0/12
  129. 192.0.0.0/24
  130. 192.0.2.0/24
  131. 192.31.196.0/24
  132. 192.52.193.0/24
  133. 192.88.99.0/24
  134. 192.168.0.0/16
  135. 192.175.48.0/24
  136. 198.18.0.0/15
  137. 198.51.100.0/24
  138. 203.0.113.0/24
  139. 224.0.0.0/4
  140. 240.0.0.0/4
  141. 255.255.255.255
  142. $server
  143. $SERVER
  144. EOF
  145. }
  146. include_ac_rules() {
  147. local protocol=$([ "$1" = "mangle" ] && echo udp || echo tcp)
  148. iptables-restore -n <<-EOF
  149. *$1
  150. :SS_SPEC_LAN_DG - [0:0]
  151. :SS_SPEC_LAN_AC - [0:0]
  152. :SS_SPEC_WAN_AC - [0:0]
  153. :SS_SPEC_WAN_FW - [0:0]
  154. -A SS_SPEC_LAN_DG -m set --match-set ss_spec_dst_sp dst -j RETURN
  155. -A SS_SPEC_LAN_DG -p $protocol $EXT_ARGS -j SS_SPEC_LAN_AC
  156. -A SS_SPEC_LAN_AC -m set --match-set ss_spec_src_bp src -j RETURN
  157. -A SS_SPEC_LAN_AC -m set --match-set ss_spec_src_fw src -j SS_SPEC_WAN_FW
  158. -A SS_SPEC_LAN_AC -m set --match-set ss_spec_src_ac src -j SS_SPEC_WAN_AC
  159. -A SS_SPEC_LAN_AC -j ${LAN_TARGET:=SS_SPEC_WAN_AC}
  160. -A SS_SPEC_WAN_AC -m set --match-set ss_spec_dst_fw dst -j SS_SPEC_WAN_FW
  161. -A SS_SPEC_WAN_AC -m set --match-set ss_spec_dst_bp dst -j RETURN
  162. -A SS_SPEC_WAN_AC -j SS_SPEC_WAN_FW
  163. $(gen_prerouting_rules $protocol)
  164. COMMIT
  165. EOF
  166. }
  167. gen_prerouting_rules() {
  168. [ -z "$IFNAMES" ] && echo -I PREROUTING 1 -p $1 -j SS_SPEC_LAN_DG
  169. for ifname in $IFNAMES; do
  170. echo -I PREROUTING 1 -i $ifname -p $1 -j SS_SPEC_LAN_DG
  171. done
  172. }
  173. while getopts ":s:l:S:L:B:b:W:w:I:d:a:e:oOuUfh" arg; do
  174. case "$arg" in
  175. s)
  176. server=$(for ip in $OPTARG; do echo $ip; done)
  177. ;;
  178. l)
  179. local_port=$OPTARG
  180. ;;
  181. S)
  182. SERVER=$(for ip in $OPTARG; do echo $ip; done)
  183. ;;
  184. L)
  185. LOCAL_PORT=$OPTARG
  186. ;;
  187. B)
  188. WAN_BP_LIST=$OPTARG
  189. ;;
  190. b)
  191. WAN_BP_IP=$OPTARG
  192. ;;
  193. W)
  194. WAN_FW_LIST=$OPTARG
  195. ;;
  196. w)
  197. WAN_FW_IP=$OPTARG
  198. ;;
  199. I)
  200. IFNAMES=$OPTARG
  201. ;;
  202. d)
  203. LAN_TARGET=$OPTARG
  204. ;;
  205. a)
  206. LAN_HOSTS=$OPTARG
  207. ;;
  208. e)
  209. EXT_ARGS=$OPTARG
  210. ;;
  211. o)
  212. OUTPUT=SS_SPEC_WAN_AC
  213. ;;
  214. O)
  215. OUTPUT=SS_SPEC_WAN_FW
  216. ;;
  217. u)
  218. TPROXY=1
  219. ;;
  220. U)
  221. TPROXY=2
  222. ;;
  223. f)
  224. flush_rules
  225. exit 0
  226. ;;
  227. h)
  228. usage 0
  229. ;;
  230. esac
  231. done
  232. [ -z "$server" -o -z "$local_port" ] && usage 2
  233. if [ "$TPROXY" = 1 ]; then
  234. unset SERVER
  235. LOCAL_PORT=$local_port
  236. elif [ "$TPROXY" = 2 ]; then
  237. : ${SERVER:?"You must assign an ip for the udp relay server."}
  238. : ${LOCAL_PORT:?"You must assign a port for the udp relay server."}
  239. fi
  240. flush_rules && ipset_init && ipt_nat && ipt_mangle && export_ipt_rules
  241. RET=$?
  242. [ "$RET" = 0 ] || loger 3 "Start failed!"
  243. exit $RET