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