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.

219 lines
4.8 KiB

  1. #!/bin/sh
  2. usage() {
  3. cat <<-EOF
  4. Usage: ss-rules [options]
  5. Valid options are:
  6. -s <server_host> hostname or ip of shadowsocks remote server
  7. -l <local_port> port number of shadowsocks local server
  8. -i <ip_list_file> a file content is bypassed ip list
  9. -a <lan_ips> lan ip of access control, need a prefix to
  10. define access control mode
  11. -b <wan_ips> wan ip of will be bypassed
  12. -w <wan_ips> wan ip of will be forwarded
  13. -e <extra_options> extra options for iptables
  14. -o apply the rules to the OUTPUT chain
  15. -u enable udprelay mode, TPROXY is required
  16. -U enable udprelay mode, using different IP
  17. and ports for TCP and UDP
  18. -f flush the rules
  19. EOF
  20. }
  21. loger() {
  22. # 1.alert 2.crit 3.err 4.warn 5.notice 6.info 7.debug
  23. logger -st ss-rules[$$] -p$1 $2
  24. }
  25. ipt_n="iptables -t nat"
  26. ipt_m="iptables -t mangle"
  27. flush_r() {
  28. local IPT
  29. IPT=$(iptables-save -t nat)
  30. eval $(echo "$IPT" | grep "_SS_SPEC_RULE_" | \
  31. sed -e 's/^-A/$ipt_n -D/' -e 's/$/;/')
  32. for chain in $(echo "$IPT" | awk '/^:SS_SPEC/{print $1}'); do
  33. $ipt_n -F ${chain:1} 2>/dev/null && $ipt_n -X ${chain:1}
  34. done
  35. IPT=$(iptables-save -t mangle)
  36. eval $(echo "$IPT" | grep "_SS_SPEC_RULE_" | \
  37. sed -e 's/^-A/$ipt_m -D/' -e 's/$/;/')
  38. for chain in $(echo "$IPT" | awk '/^:SS_SPEC/{print $1}'); do
  39. $ipt_m -F ${chain:1} 2>/dev/null && $ipt_m -X ${chain:1}
  40. done
  41. ip rule del fwmark 0x01/0x01 table 100 2>/dev/null
  42. ip route del local 0.0.0.0/0 dev lo table 100 2>/dev/null
  43. ipset -X ss_spec_lan_ac 2>/dev/null
  44. ipset -X ss_spec_wan_ac 2>/dev/null
  45. return 0
  46. }
  47. ipset_r() {
  48. ipset -! -R <<-EOF || return 1
  49. create ss_spec_wan_ac hash:net
  50. $(echo -e "$IPLIST" | sed -e "s/^/add ss_spec_wan_ac /")
  51. $(for ip in $WAN_FW_IP; do echo "add ss_spec_wan_ac $ip nomatch"; done)
  52. EOF
  53. $ipt_n -N SS_SPEC_WAN_AC && \
  54. $ipt_n -A SS_SPEC_WAN_AC -m set --match-set ss_spec_wan_ac dst -j RETURN && \
  55. $ipt_n -A SS_SPEC_WAN_AC -j SS_SPEC_WAN_FW
  56. return $?
  57. }
  58. fw_rule() {
  59. $ipt_n -N SS_SPEC_WAN_FW && \
  60. $ipt_n -A SS_SPEC_WAN_FW -p tcp \
  61. -j REDIRECT --to-ports $local_port 2>/dev/null || {
  62. loger 3 "Can't redirect, please check the iptables."
  63. exit 1
  64. }
  65. return $?
  66. }
  67. ac_rule() {
  68. local TAG ROUTECHAIN
  69. if [ -n "$LAN_AC_IP" ]; then
  70. if [ "${LAN_AC_IP:0:1}" = "w" ]; then
  71. TAG="nomatch"
  72. else
  73. if [ "${LAN_AC_IP:0:1}" != "b" ]; then
  74. loger 3 "Bad argument \`-a $LAN_AC_IP\`."
  75. return 2
  76. fi
  77. fi
  78. fi
  79. ROUTECHAIN=PREROUTING
  80. if iptables-save -t nat | grep -q "^:zone_lan_prerouting"; then
  81. ROUTECHAIN=zone_lan_prerouting
  82. fi
  83. ipset -! -R <<-EOF || return 1
  84. create ss_spec_lan_ac hash:net
  85. $(for ip in ${LAN_AC_IP:1}; do echo "add ss_spec_lan_ac $ip $TAG"; done)
  86. EOF
  87. $ipt_n -A $ROUTECHAIN -p tcp $EXT_ARGS \
  88. -m set ! --match-set ss_spec_lan_ac src \
  89. -m comment --comment "_SS_SPEC_RULE_" -j SS_SPEC_WAN_AC
  90. if [ "$OUTPUT" = 1 ]; then
  91. $ipt_n -A OUTPUT -p tcp $EXT_ARGS \
  92. -m comment --comment "_SS_SPEC_RULE_" -j SS_SPEC_WAN_AC
  93. fi
  94. return $?
  95. }
  96. tp_rule() {
  97. [ -n "$TPROXY" ] || return 0
  98. ip rule add fwmark 0x01/0x01 table 100
  99. ip route add local 0.0.0.0/0 dev lo table 100
  100. $ipt_m -N SS_SPEC_TPROXY
  101. $ipt_m -A SS_SPEC_TPROXY -p udp -m set ! --match-set ss_spec_wan_ac dst \
  102. -j TPROXY --on-port $LOCAL_PORT --tproxy-mark 0x01/0x01
  103. $ipt_m -A PREROUTING -p udp $EXT_ARGS \
  104. -m set ! --match-set ss_spec_lan_ac src \
  105. -m comment --comment "_SS_SPEC_RULE_" -j SS_SPEC_TPROXY
  106. return $?
  107. }
  108. while getopts ":s:l:S:L:i:e:a:b:w:ouUf" arg; do
  109. case $arg in
  110. s)
  111. server=$OPTARG
  112. ;;
  113. l)
  114. local_port=$OPTARG
  115. ;;
  116. S)
  117. SERVER=$OPTARG
  118. ;;
  119. L)
  120. LOCAL_PORT=$OPTARG
  121. ;;
  122. i)
  123. IGNORE=$OPTARG
  124. ;;
  125. e)
  126. EXT_ARGS=$OPTARG
  127. ;;
  128. a)
  129. LAN_AC_IP=$OPTARG
  130. ;;
  131. b)
  132. WAN_BP_IP=$(for ip in $OPTARG; do echo $ip; done)
  133. ;;
  134. w)
  135. WAN_FW_IP=$OPTARG
  136. ;;
  137. o)
  138. OUTPUT=1
  139. ;;
  140. u)
  141. TPROXY=1
  142. ;;
  143. U)
  144. TPROXY=2
  145. ;;
  146. f)
  147. flush_r
  148. exit 0
  149. ;;
  150. esac
  151. done
  152. if [ -z "$server" -o -z "$local_port" ]; then
  153. usage
  154. exit 2
  155. fi
  156. if [ "$TPROXY" = 1 ]; then
  157. SERVER=$server
  158. LOCAL_PORT=$local_port
  159. fi
  160. if [ "$TPROXY" = 2 ]; then
  161. if [ -z "$SERVER" -o -z "$LOCAL_PORT" ]; then
  162. loger 3 "Please use -S and -L specifies IP and port for UDP."
  163. fi
  164. fi
  165. if [ -f "$IGNORE" ]; then
  166. IGNORE_IP=$(cat $IGNORE 2>/dev/null)
  167. fi
  168. IPLIST=$(cat <<-EOF | grep -E "^([0-9]{1,3}\.){3}[0-9]{1,3}"
  169. $server
  170. $SERVER
  171. 0.0.0.0/8
  172. 10.0.0.0/8
  173. 100.64.0.0/10
  174. 127.0.0.0/8
  175. 169.254.0.0/16
  176. 172.16.0.0/12
  177. 192.0.0.0/24
  178. 192.0.2.0/24
  179. 192.88.99.0/24
  180. 192.168.0.0/16
  181. 198.18.0.0/15
  182. 198.51.100.0/24
  183. 203.0.113.0/24
  184. 224.0.0.0/4
  185. 240.0.0.0/4
  186. 255.255.255.255
  187. $WAN_BP_IP
  188. $IGNORE_IP
  189. EOF
  190. )
  191. flush_r && fw_rule && ipset_r && ac_rule && tp_rule
  192. exit $?