Merge pull request #4632 from smutt/python-dpkt
[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 ipt="iptables -t nat"
163 local local_target
164
165 [ -n "$o_redir_tcp_port" ] || return 0
166
167 ss_rules_iptchains_init_ nat tcp
168
169 case "$o_local_default" in
170 checkdst) local_target=ss_rules_dst ;;
171 forward) local_target=ss_rules_forward ;;
172 bypass|*) return 0;;
173 esac
174
175 iptables-restore --noflush <<-EOF
176 *nat
177 :ss_rules_local_out -
178 -I OUTPUT 1 -p tcp -j ss_rules_local_out
179 -A ss_rules_local_out -m set --match-set ss_rules_dst_bypass_ dst -j RETURN
180 -A ss_rules_local_out -p tcp $o_ipt_extra -j $local_target -m comment --comment "local_default: $o_local_default"
181 COMMIT
182 EOF
183 }
184
185 ss_rules_iptchains_init_udp() {
186 [ -n "$o_redir_udp_port" ] || return 0
187 ss_rules_iptchains_init_ mangle udp
188 }
189
190 ss_rules_iptchains_init_() {
191 local table="$1"
192 local proto="$2"
193 local forward_rules
194 local src_default_target dst_default_target
195 local recentrst_mangle_rules recentrst_addset_rules
196
197 case "$proto" in
198 tcp)
199 forward_rules="-A ss_rules_forward -p tcp -j REDIRECT --to-ports $o_redir_tcp_port"
200 if [ -n "$o_dst_forward_recentrst" ]; then
201 recentrst_mangle_rules="
202 *mangle
203 -I PREROUTING 1 -p tcp -m tcp --tcp-flags RST RST -m recent --name ss_rules_recentrst --set --rsource
204 COMMIT
205 "
206 recentrst_addset_rules="
207 -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
208 -A ss_rules_dst -m set --match-set ss_rules_dst_forward_recentrst_ dst -j ss_rules_forward
209 "
210 fi
211 ;;
212 udp)
213 ip rule add fwmark 1 lookup 100
214 ip route add local default dev lo table 100
215 forward_rules="-A ss_rules_forward -p udp -j TPROXY --on-port "$o_redir_udp_port" --tproxy-mark 0x01/0x01"
216 ;;
217 esac
218 case "$o_src_default" in
219 forward) src_default_target=ss_rules_forward ;;
220 checkdst) src_default_target=ss_rules_dst ;;
221 bypass|*) src_default_target=RETURN ;;
222 esac
223 case "$o_dst_default" in
224 forward) dst_default_target=ss_rules_forward ;;
225 bypass|*) dst_default_target=RETURN ;;
226 esac
227 sed -e '/^\s*$/d' -e 's/^\s\+//' <<-EOF | iptables-restore --noflush
228 *$table
229 :ss_rules_pre_src -
230 :ss_rules_src -
231 :ss_rules_dst -
232 :ss_rules_forward -
233 $(ss_rules_iptchains_mkprerules "$proto")
234 -A ss_rules_pre_src -m set --match-set ss_rules_dst_bypass_ dst -j RETURN
235 -A ss_rules_pre_src -p $proto $o_ipt_extra -j ss_rules_src
236 -A ss_rules_src -m set --match-set ss_rules_src_bypass src -j RETURN
237 -A ss_rules_src -m set --match-set ss_rules_src_forward src -j ss_rules_forward
238 -A ss_rules_src -m set --match-set ss_rules_src_checkdst src -j ss_rules_dst
239 -A ss_rules_src -j $src_default_target -m comment --comment "src_default: $o_src_default"
240 -A ss_rules_dst -m set --match-set ss_rules_dst_bypass dst -j RETURN
241 -A ss_rules_dst -m set --match-set ss_rules_dst_forward dst -j ss_rules_forward
242 $recentrst_addset_rules
243 -A ss_rules_dst -j $dst_default_target -m comment --comment "dst_default: $o_dst_default"
244 $forward_rules
245 COMMIT
246 $recentrst_mangle_rules
247 EOF
248 }
249
250 ss_rules_iptchains_mkprerules() {
251 local proto="$1"
252
253 if [ -z "$o_ifnames" ]; then
254 echo "-I PREROUTING 1 -p $proto -j ss_rules_pre_src"
255 else
256 echo $o_ifnames \
257 | tr ' ' '\n' \
258 | sed "s/.*/-I PREROUTING 1 -i \\0 -p $proto -j ss_rules_pre_src/"
259 fi
260 }
261
262 ss_rules_parse_args "$@"
263 ss_rules_flush
264 ss_rules_ipset_init
265 ss_rules_iptchains_init