shadowsocks-libev: ss-rules: eliminiate not needed local var
[feed/packages.git] / net / shadowsocks-libev / files / ss-rules
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
11 ss_rules_usage() {
12 cat >&2 <<EOF
13 Usage: ss-rules [options]
14
15 -h, --help Show this help message then exit
16 -f, --flush Flush rules, ipset then exit
17 -l <port> Local port number of ss-redir with TCP mode
18 -L <port> Local port number of ss-redir with UDP mode
19 -s <ips> List of ip addresses of remote shadowsocks server
20 --ifnames Only apply rules on packets from these ifnames
21 --src-bypass <ips|cidr>
22 --src-forward <ips|cidr>
23 --src-checkdst <ips|cidr>
24 --src-default <bypass|forward|checkdst>
25 Packets will have their src ip checked in order against
26 bypass, forward, checkdst list and will bypass, forward
27 through, or continue to have their dst ip checked
28 respectively on the first match. Otherwise, --src-default
29 decide the default action
30 --dst-bypass <ips|cidr>
31 --dst-forward <ips|cidr>
32 --dst-bypass-file <file>
33 --dst-forward-file <file>
34 --dst-default <bypass|forward>
35 Same as with their --src-xx equivalent
36 --dst-forward-recentrst
37 Forward those packets whose destinations have recently
38 sent to us multiple tcp-rst packets
39 --local-default <bypass|forward|checkdst>
40 Default action for local out TCP traffic
41
42 The following ipsets will be created by ss-rules. They are also intended to be
43 populated by other programs like dnsmasq with ipset support
44
45 ss_rules_src_bypass
46 ss_rules_src_forward
47 ss_rules_src_checkdst
48 ss_rules_dst_bypass
49 ss_rules_dst_forward
50 EOF
51 }
52
53 o_dst_bypass_="
54 0.0.0.0/8
55 10.0.0.0/8
56 100.64.0.0/10
57 127.0.0.0/8
58 169.254.0.0/16
59 172.16.0.0/12
60 192.0.0.0/24
61 192.0.2.0/24
62 192.31.196.0/24
63 192.52.193.0/24
64 192.88.99.0/24
65 192.168.0.0/16
66 192.175.48.0/24
67 198.18.0.0/15
68 198.51.100.0/24
69 203.0.113.0/24
70 224.0.0.0/4
71 240.0.0.0/4
72 255.255.255.255
73 "
74 o_src_default=bypass
75 o_dst_default=bypass
76 o_local_default=bypass
77
78 __errmsg() {
79 echo "ss-rules: $*" >&2
80 }
81
82 ss_rules_parse_args() {
83 while [ "$#" -gt 0 ]; do
84 case "$1" in
85 -h|--help) ss_rules_usage; exit 0;;
86 -f|--flush) ss_rules_flush; exit 0;;
87 -l) o_redir_tcp_port="$2"; shift 2;;
88 -L) o_redir_udp_port="$2"; shift 2;;
89 -s) o_remote_servers="$2"; shift 2;;
90 --ifnames) o_ifnames="$2"; shift 2;;
91 --ipt-extra) o_ipt_extra="$2"; shift 2;;
92 --src-default) o_src_default="$2"; shift 2;;
93 --dst-default) o_dst_default="$2"; shift 2;;
94 --local-default) o_local_default="$2"; shift 2;;
95 --src-bypass) o_src_bypass="$2"; shift 2;;
96 --src-forward) o_src_forward="$2"; shift 2;;
97 --src-checkdst) o_src_checkdst="$2"; shift 2;;
98 --dst-bypass) o_dst_bypass="$2"; shift 2;;
99 --dst-forward) o_dst_forward="$2"; shift 2;;
100 --dst-forward-recentrst) o_dst_forward_recentrst=1; shift 1;;
101 --dst-bypass-file) o_dst_bypass_file="$2"; shift 2;;
102 --dst-forward-file) o_dst_forward_file="$2"; shift 2;;
103 *) __errmsg "unknown option $1"; return 1;;
104 esac
105 done
106
107 if [ -z "$o_redir_tcp_port" -a -z "$o_redir_udp_port" ]; then
108 __errmsg "Requires at least -l or -L option"
109 return 1
110 fi
111 if [ -n "$o_dst_forward_recentrst" ] && ! iptables -m recent -h >/dev/null; then
112 __errmsg "Please install iptables-mod-conntrack-extra with opkg"
113 return 1
114 fi
115 o_remote_servers="$(for s in $o_remote_servers; do resolveip -4 "$s"; done)"
116 }
117
118 ss_rules_flush() {
119 local setname
120
121 iptables-save --counters | grep -v ss_rules_ | iptables-restore --counters
122 while ip rule del fwmark 1 lookup 100 2>/dev/null; do true; done
123 ip route flush table 100
124 for setname in $(ipset -n list | grep "ss_rules_"); do
125 ipset destroy "$setname" 2>/dev/null || true
126 done
127 }
128
129 ss_rules_ipset_init() {
130 ipset --exist restore <<-EOF
131 create ss_rules_src_bypass hash:net hashsize 64
132 create ss_rules_src_forward hash:net hashsize 64
133 create ss_rules_src_checkdst hash:net hashsize 64
134 create ss_rules_dst_bypass hash:net hashsize 64
135 create ss_rules_dst_bypass_ hash:net hashsize 64
136 create ss_rules_dst_forward hash:net hashsize 64
137 create ss_rules_dst_forward_recentrst_ hash:ip hashsize 64 timeout 3600
138 $(ss_rules_ipset_mkadd ss_rules_dst_bypass_ "$o_dst_bypass_ $o_remote_servers")
139 $(ss_rules_ipset_mkadd ss_rules_src_bypass "$o_src_bypass")
140 $(ss_rules_ipset_mkadd ss_rules_src_forward "$o_src_forward")
141 $(ss_rules_ipset_mkadd ss_rules_src_checkdst "$o_src_checkdst")
142 $(ss_rules_ipset_mkadd ss_rules_dst_bypass "$o_dst_bypass $(cat "$o_dst_bypass_file" 2>/dev/null)")
143 $(ss_rules_ipset_mkadd ss_rules_dst_forward "$o_dst_forward $(cat "$o_dst_forward_file" 2>/dev/null)")
144 EOF
145 }
146
147 ss_rules_ipset_mkadd() {
148 local setname="$1"; shift
149 local i
150
151 for i in $*; do
152 echo "add $setname $i"
153 done
154 }
155
156 ss_rules_iptchains_init() {
157 ss_rules_iptchains_init_tcp
158 ss_rules_iptchains_init_udp
159 }
160
161 ss_rules_iptchains_init_tcp() {
162 local local_target
163
164 [ -n "$o_redir_tcp_port" ] || return 0
165
166 ss_rules_iptchains_init_ nat tcp
167
168 case "$o_local_default" in
169 checkdst) local_target=ss_rules_dst ;;
170 forward) local_target=ss_rules_forward ;;
171 bypass|*) return 0;;
172 esac
173
174 iptables-restore --noflush <<-EOF
175 *nat
176 :ss_rules_local_out -
177 -I OUTPUT 1 -p tcp -j ss_rules_local_out
178 -A ss_rules_local_out -m set --match-set ss_rules_dst_bypass_ dst -j RETURN
179 -A ss_rules_local_out -p tcp $o_ipt_extra -j $local_target -m comment --comment "local_default: $o_local_default"
180 COMMIT
181 EOF
182 }
183
184 ss_rules_iptchains_init_udp() {
185 [ -n "$o_redir_udp_port" ] || return 0
186 ss_rules_iptchains_init_ mangle udp
187 }
188
189 ss_rules_iptchains_init_() {
190 local table="$1"
191 local proto="$2"
192 local forward_rules
193 local src_default_target dst_default_target
194 local recentrst_mangle_rules recentrst_addset_rules
195
196 case "$proto" in
197 tcp)
198 forward_rules="-A ss_rules_forward -p tcp -j REDIRECT --to-ports $o_redir_tcp_port"
199 if [ -n "$o_dst_forward_recentrst" ]; then
200 recentrst_mangle_rules="
201 *mangle
202 -I PREROUTING 1 -p tcp -m tcp --tcp-flags RST RST -m recent --name ss_rules_recentrst --set --rsource
203 COMMIT
204 "
205 recentrst_addset_rules="
206 -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
207 -A ss_rules_dst -m set --match-set ss_rules_dst_forward_recentrst_ dst -j ss_rules_forward
208 "
209 fi
210 ;;
211 udp)
212 ip rule add fwmark 1 lookup 100
213 ip route add local default dev lo table 100
214 forward_rules="-A ss_rules_forward -p udp -j TPROXY --on-port "$o_redir_udp_port" --tproxy-mark 0x01/0x01"
215 ;;
216 esac
217 case "$o_src_default" in
218 forward) src_default_target=ss_rules_forward ;;
219 checkdst) src_default_target=ss_rules_dst ;;
220 bypass|*) src_default_target=RETURN ;;
221 esac
222 case "$o_dst_default" in
223 forward) dst_default_target=ss_rules_forward ;;
224 bypass|*) dst_default_target=RETURN ;;
225 esac
226 sed -e '/^\s*$/d' -e 's/^\s\+//' <<-EOF | iptables-restore --noflush
227 *$table
228 :ss_rules_pre_src -
229 :ss_rules_src -
230 :ss_rules_dst -
231 :ss_rules_forward -
232 $(ss_rules_iptchains_mkprerules "$proto")
233 -A ss_rules_pre_src -m set --match-set ss_rules_dst_bypass_ dst -j RETURN
234 -A ss_rules_pre_src -p $proto $o_ipt_extra -j ss_rules_src
235 -A ss_rules_src -m set --match-set ss_rules_src_bypass src -j RETURN
236 -A ss_rules_src -m set --match-set ss_rules_src_forward src -j ss_rules_forward
237 -A ss_rules_src -m set --match-set ss_rules_src_checkdst src -j ss_rules_dst
238 -A ss_rules_src -j $src_default_target -m comment --comment "src_default: $o_src_default"
239 -A ss_rules_dst -m set --match-set ss_rules_dst_bypass dst -j RETURN
240 -A ss_rules_dst -m set --match-set ss_rules_dst_forward dst -j ss_rules_forward
241 $recentrst_addset_rules
242 -A ss_rules_dst -j $dst_default_target -m comment --comment "dst_default: $o_dst_default"
243 $forward_rules
244 COMMIT
245 $recentrst_mangle_rules
246 EOF
247 }
248
249 ss_rules_iptchains_mkprerules() {
250 local proto="$1"
251
252 if [ -z "$o_ifnames" ]; then
253 echo "-I PREROUTING 1 -p $proto -j ss_rules_pre_src"
254 else
255 echo $o_ifnames \
256 | tr ' ' '\n' \
257 | sed "s/.*/-I PREROUTING 1 -i \\0 -p $proto -j ss_rules_pre_src/"
258 fi
259 }
260
261 ss_rules_parse_args "$@"
262 ss_rules_flush
263 ss_rules_ipset_init
264 ss_rules_iptchains_init