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.

231 lines
5.3 KiB

  1. #!/bin/bash
  2. #
  3. # Copyright (C) 2015 OpenWrt-dist
  4. # Copyright (C) 2015 Jian Chang <aa65535@live.com>
  5. #
  6. # This is free software, licensed under the GNU General Public License v3.
  7. # See /LICENSE for more information.
  8. #
  9. TAG="SS_SPEC" # iptables tag
  10. IPT="iptables -t nat" # alias of iptables
  11. FWI=$(uci get firewall.shadowsocks.path 2>/dev/null) # firewall include file
  12. usage() {
  13. cat <<-EOF
  14. Copyright (C) 2015 OpenWrt-dist
  15. Copyright (C) 2015 Jian Chang <aa65535@live.com>
  16. Usage: ss-nat [options]
  17. Valid options are:
  18. -s <server_ip> ip address of shadowsocks remote server
  19. -l <local_port> port number of shadowsocks local server
  20. -S <server_ip> ip address of shadowsocks remote UDP server
  21. -L <local_port> port number of shadowsocks local UDP server
  22. -i <ip_list_file> a file content is bypassed ip list
  23. -a <lan_ips> lan ip of access control, need a prefix to
  24. define access control mode
  25. -b <wan_ips> wan ip of will be bypassed
  26. -w <wan_ips> wan ip of will be forwarded
  27. -e <extra_options> extra options for iptables
  28. -o apply the rules to the OUTPUT chain
  29. -u enable udprelay mode, TPROXY is required
  30. -U enable udprelay mode, using different IP
  31. and ports for TCP and UDP
  32. -f flush the rules
  33. -h show this help message and exit
  34. This is free software, licensed under the GNU General Public License v3.
  35. See /LICENSE for more information.
  36. EOF
  37. exit $1
  38. }
  39. loger() {
  40. # 1.alert 2.crit 3.err 4.warn 5.notice 6.info 7.debug
  41. logger -st ss-rules[$$] -p$1 $2
  42. }
  43. flush_r() {
  44. iptables-save -c | grep -v "$TAG" | iptables-restore -c
  45. ip rule del fwmark 0x01/0x01 table 100 2>/dev/null
  46. ip route del local 0.0.0.0/0 dev lo table 100 2>/dev/null
  47. ipset -X ss_spec_lan_ac 2>/dev/null
  48. ipset -X ss_spec_wan_ac 2>/dev/null
  49. [ -n "$FWI" ] && echo '#!/bin/sh' >$FWI
  50. return 0
  51. }
  52. ipset_r() {
  53. ipset -! -R <<-EOF || return 1
  54. create ss_spec_wan_ac hash:net
  55. $(gen_iplist | sed "/^\s*$/d" | sed -e "s/^/add ss_spec_wan_ac /")
  56. $(for ip in $WAN_FW_IP; do echo "add ss_spec_wan_ac $ip nomatch"; done)
  57. EOF
  58. $IPT -N SS_SPEC_WAN_AC && \
  59. $IPT -A SS_SPEC_WAN_AC -m set --match-set ss_spec_wan_ac dst -j RETURN && \
  60. $IPT -A SS_SPEC_WAN_AC -j SS_SPEC_WAN_FW
  61. return $?
  62. }
  63. fw_rule() {
  64. $IPT -N SS_SPEC_WAN_FW && \
  65. $IPT -A SS_SPEC_WAN_FW -p tcp \
  66. -j REDIRECT --to-ports $local_port 2>/dev/null || {
  67. loger 3 "Can't redirect, please check the iptables."
  68. exit 1
  69. }
  70. return $?
  71. }
  72. ac_rule() {
  73. if [ -n "$LAN_AC_IP" ]; then
  74. case "${LAN_AC_IP:0:1}" in
  75. w|W)
  76. MATCH_SET="-m set --match-set ss_spec_lan_ac src"
  77. ;;
  78. b|B)
  79. MATCH_SET="-m set ! --match-set ss_spec_lan_ac src"
  80. ;;
  81. *)
  82. loger 3 "Illegal argument \`-a $LAN_AC_IP\`."
  83. return 2
  84. ;;
  85. esac
  86. fi
  87. IFNAME=eth0
  88. ipset -! -R <<-EOF || return 1
  89. create ss_spec_lan_ac hash:net
  90. $(for ip in ${LAN_AC_IP:1}; do echo "add ss_spec_lan_ac $ip"; done)
  91. EOF
  92. $IPT -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p tcp $EXT_ARGS $MATCH_SET \
  93. -j SS_SPEC_WAN_AC
  94. if [ "$OUTPUT" = 1 ]; then
  95. $IPT -I OUTPUT 1 -p tcp $EXT_ARGS -j SS_SPEC_WAN_AC
  96. fi
  97. return $?
  98. }
  99. tp_rule() {
  100. lsmod | grep -q TPROXY || return 0
  101. [ -n "$TPROXY" ] || return 0
  102. ip rule add fwmark 0x01/0x01 table 100
  103. ip route add local 0.0.0.0/0 dev lo table 100
  104. local ipt="iptables -t mangle"
  105. $ipt -N SS_SPEC_TPROXY
  106. $ipt -A SS_SPEC_TPROXY -p udp -m set ! --match-set ss_spec_wan_ac dst \
  107. -j TPROXY --on-port "$LOCAL_PORT" --tproxy-mark 0x01/0x01
  108. $ipt -I PREROUTING 1 ${IFNAME:+-i $IFNAME} -p udp $EXT_ARGS $MATCH_SET \
  109. -j SS_SPEC_TPROXY
  110. return $?
  111. }
  112. get_wan_ip() {
  113. cat <<-EOF | grep -E "^([0-9]{1,3}\.){3}[0-9]{1,3}"
  114. $server
  115. $SERVER
  116. $WAN_BP_IP
  117. EOF
  118. }
  119. gen_iplist() {
  120. cat <<-EOF
  121. 0.0.0.0/8
  122. 10.0.0.0/8
  123. 100.64.0.0/10
  124. 127.0.0.0/8
  125. 169.254.0.0/16
  126. 172.16.0.0/12
  127. 192.0.0.0/24
  128. 192.0.2.0/24
  129. 192.88.99.0/24
  130. 192.168.0.0/16
  131. 198.18.0.0/15
  132. 198.51.100.0/24
  133. 203.0.113.0/24
  134. 224.0.0.0/4
  135. 240.0.0.0/4
  136. 255.255.255.255
  137. $(get_wan_ip)
  138. $(cat ${IGNORE_LIST:=/dev/null} 2>/dev/null)
  139. EOF
  140. }
  141. gen_include() {
  142. [ -n "$FWI" ] || return 0
  143. cat <<-EOF >>$FWI
  144. iptables-restore -n <<-EOT
  145. $(iptables-save | grep -E "$TAG|^\*|^COMMIT" |\
  146. sed -e "s/^-A \(OUTPUT\|PREROUTING\)/-I \1 1/")
  147. EOT
  148. EOF
  149. return $?
  150. }
  151. while getopts ":s:l:S:L:i:e:a:b:w:ouUfh" arg; do
  152. case "$arg" in
  153. s)
  154. server=$OPTARG
  155. ;;
  156. l)
  157. local_port=$OPTARG
  158. ;;
  159. S)
  160. SERVER=$OPTARG
  161. ;;
  162. L)
  163. LOCAL_PORT=$OPTARG
  164. ;;
  165. i)
  166. IGNORE_LIST=$OPTARG
  167. ;;
  168. e)
  169. EXT_ARGS=$OPTARG
  170. ;;
  171. a)
  172. LAN_AC_IP=$OPTARG
  173. ;;
  174. b)
  175. WAN_BP_IP=$(for ip in $OPTARG; do echo $ip; done)
  176. ;;
  177. w)
  178. WAN_FW_IP=$OPTARG
  179. ;;
  180. o)
  181. OUTPUT=1
  182. ;;
  183. u)
  184. TPROXY=1
  185. ;;
  186. U)
  187. TPROXY=2
  188. ;;
  189. f)
  190. flush_r
  191. exit 0
  192. ;;
  193. h)
  194. usage 0
  195. ;;
  196. esac
  197. done
  198. if [ -z "$server" -o -z "$local_port" ]; then
  199. usage 2
  200. fi
  201. if [ "$TPROXY" = 1 ]; then
  202. SERVER=$server
  203. LOCAL_PORT=$local_port
  204. elif [ "$TPROXY" = 2 ]; then
  205. : ${SERVER:?"You must assign an ip for the udp relay server."}
  206. : ${LOCAL_PORT:?"You must assign a port for the udp relay server."}
  207. fi
  208. flush_r && fw_rule && ipset_r && ac_rule && tp_rule && gen_include
  209. [ "$?" = 0 ] || loger 3 "Start failed!"
  210. exit $?