blob: dc94b952fd681d05cd32102f41d753fd057fad99 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001#!/bin/sh /etc/rc.common
2#
3# Copyright (C) 2017-2019 Yousong Zhou <yszhou4tech@gmail.com>
4#
5# This is free software, licensed under the GNU General Public License v3.
6# See /LICENSE for more information.
7#
8
9USE_PROCD=1
10START=99
11
12ss_confdir=/var/etc/shadowsocks-libev
13ss_bindir=/usr/bin
14
15ss_mkjson_server_conf() {
16 local cfgserver
17
18 config_get cfgserver "$cfg" server
19 [ -n "$cfgserver" ] || return 1
20 eval "$(validate_server_section "$cfg" ss_validate_mklocal)"
21 validate_server_section "$cfgserver" || return 1
22 [ "$disabled" = 0 ] || return 1
23 ss_mkjson_server_conf_ "$cfgserver"
24}
25
26ss_mkjson_server_conf_() {
27 [ -n "$server_port" ] || return 1
28 [ -z "$server" ] || json_add_string server "$server"
29 json_add_int server_port "$server_port"
30 [ -z "$method" ] || json_add_string method "$method"
31 [ -z "$key" ] || json_add_string key "$key"
32 [ -z "$password" ] || json_add_string password "$password"
33 [ -z "$plugin" ] || json_add_string plugin "$plugin"
34 [ -z "$plugin_opts" ] || json_add_string plugin_opts "$plugin_opts"
35}
36
37ss_mkjson_ss_local_conf() {
38 ss_mkjson_server_conf
39}
40
41ss_mkjson_ss_redir_conf() {
42 ss_mkjson_server_conf
43}
44
45ss_mkjson_ss_server_conf() {
46 ss_mkjson_server_conf_
47}
48
49ss_mkjson_ss_tunnel_conf() {
50 ss_mkjson_server_conf || return 1
51 [ -n "$tunnel_address" ] || return 1
52 json_add_string tunnel_address "$tunnel_address"
53}
54
55ss_xxx() {
56 local cfg="$1"
57 local cfgtype="$2"
58 local bin="$ss_bindir/${cfgtype/_/-}"
59 local confjson="$ss_confdir/$cfgtype.$cfg.json"
60
61 [ -x "$bin" ] || return
62 eval "$("validate_${cfgtype}_section" "$cfg" ss_validate_mklocal)"
63 "validate_${cfgtype}_section" "$cfg" || return
64 [ "$disabled" = 0 ] || return
65
66 json_init
67 ss_mkjson_${cfgtype}_conf || return
68 json_add_boolean use_syslog 1
69 json_add_boolean ipv6_first "$ipv6_first"
70 json_add_boolean fast_open "$fast_open"
71 json_add_boolean reuse_port "$reuse_port"
72 json_add_boolean no_delay "$no_delay"
73 [ -z "$local_address" ] || json_add_string local_address "$local_address"
74 [ -z "$local_port" ] || json_add_int local_port "$local_port"
75 [ -z "$local_ipv4_address" ] || json_add_string local_ipv4_address "$local_ipv4_address"
76 [ -z "$local_ipv6_address" ] || json_add_string local_ipv6_address "$local_ipv6_address"
77 [ -z "$mode" ] || json_add_string mode "$mode"
78 [ -z "$mtu" ] || json_add_int mtu "$mtu"
79 [ -z "$timeout" ] || json_add_int timeout "$timeout"
80 [ -z "$user" ] || json_add_string user "$user"
81 json_dump -i >"$confjson"
82
83 procd_open_instance "$cfgtype.$cfg"
84 procd_set_param command "$bin" -c "$confjson"
85 [ "$verbose" = 0 ] || procd_append_param command -v
86 if [ -n "$bind_address" ]; then
87 echo "$cfgtype $cfg: uci option bind_address deprecated, please switch to local_address" >&2
88 procd_append_param command -b "$bind_address"
89 fi
90 procd_set_param file "$confjson"
91 procd_set_param respawn
92 procd_close_instance
93 ss_rules_cb
94}
95
96ss_rules_cb() {
97 local cfgserver server
98
99 if [ "$cfgtype" = ss_redir ]; then
100 config_get cfgserver "$cfg" server
101 config_get server "$cfgserver" server
102 ss_redir_servers="$ss_redir_servers $server"
103 if [ "$mode" = tcp_only -o "$mode" = "tcp_and_udp" ]; then
104 eval "ss_rules_redir_tcp_$cfg=$local_port"
105 fi
106 if [ "$mode" = udp_only -o "$mode" = "tcp_and_udp" ]; then
107 eval "ss_rules_redir_udp_$cfg=$local_port"
108 fi
109 fi
110}
111
112ss_rules() {
113 local cfg="ss_rules"
114 local bin="$ss_bindir/ss-rules"
115 local cfgtype
116 local local_port_tcp local_port_udp
117 local args
118
119 [ -x "$bin" ] || return 1
120 "$bin" -f
121 "$bin" -6 -f
122
123 config_get cfgtype "$cfg" TYPE
124 [ "$cfgtype" = ss_rules ] || return 1
125
126 eval "$(validate_ss_rules_section "$cfg" ss_validate_mklocal)"
127 validate_ss_rules_section "$cfg" || return 1
128 [ "$disabled" = 0 ] || return 0
129
130 eval local_port_tcp="\$ss_rules_redir_tcp_$redir_tcp"
131 eval local_port_udp="\$ss_rules_redir_udp_$redir_udp"
132 [ -n "$local_port_tcp" -o -n "$local_port_udp" ] || return 1
133 ss_redir_servers="$(echo "$ss_redir_servers" | tr ' ' '\n' | sort -u)"
134 [ "$dst_forward_recentrst" = 0 ] || args="$args --dst-forward-recentrst"
135
136 ss_rules_call
137 ss_rules_call -6
138}
139
140ss_rules_call() {
141 "$bin" "$@" \
142 -s "$ss_redir_servers" \
143 -l "$local_port_tcp" \
144 -L "$local_port_udp" \
145 --src-default "$src_default" \
146 --dst-default "$dst_default" \
147 --local-default "$local_default" \
148 --dst-bypass-file "$dst_ips_bypass_file" \
149 --dst-forward-file "$dst_ips_forward_file" \
150 --dst-bypass "$dst_ips_bypass" \
151 --dst-forward "$dst_ips_forward" \
152 --src-bypass "$src_ips_bypass" \
153 --src-forward "$src_ips_forward" \
154 --src-checkdst "$src_ips_checkdst" \
155 --ifnames "$ifnames" \
156 --ipt-extra "$ipt_args" \
157 $args \
158 || "$bin" "$@" -f
159}
160
161start_service() {
162 local cfgtype
163
164 mkdir -p "$ss_confdir"
165 config_load shadowsocks-libev
166 for cfgtype in ss_local ss_redir ss_server ss_tunnel; do
167 config_foreach ss_xxx "$cfgtype" "$cfgtype"
168 done
169 ss_rules
170}
171
172stop_service() {
173 local bin="$ss_bindir/ss-rules"
174
175 [ -x "$bin" ] && {
176 "$bin" -f
177 "$bin" -6 -f
178 }
179 rm -rf "$ss_confdir"
180}
181
182service_triggers() {
183 procd_add_reload_interface_trigger wan
184 procd_add_reload_trigger shadowsocks-libev
185 procd_open_validate
186 validate_server_section
187 validate_ss_local_section
188 validate_ss_redir_section
189 validate_ss_rules_section
190 validate_ss_server_section
191 validate_ss_tunnel_section
192 procd_close_validate
193}
194
195ss_validate_mklocal() {
196 local tuple opts
197
198 shift 2
199 for tuple in "$@"; do
200 opts="${tuple%%:*} $opts"
201 done
202 [ -z "$opts" ] || echo "local $opts"
203}
204
205ss_validate() {
206 uci_validate_section shadowsocks-libev "$@"
207}
208
209validate_common_server_options_() {
210 local cfgtype="$1"; shift
211 local cfg="$1"; shift
212 local func="$1"; shift
213 local stream_methods='"table", "rc4", "rc4-md5", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "bf-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "salsa20", "chacha20", "chacha20-ietf"'
214 local aead_methods='"aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305"'
215
216 "${func:-ss_validate}" "$cfgtype" "$cfg" "$@" \
217 'disabled:bool:0' \
218 'server:host' \
219 'server_port:port' \
220 'password:string' \
221 'key:string' \
222 "method:or($stream_methods, $aead_methods)" \
223 'plugin:string' \
224 'plugin_opts:string'
225}
226
227validate_common_client_options_() {
228 validate_common_options_ "$@" \
229 'server:uci("shadowsocks-libev", "@server")' \
230 'local_address:ipaddr:0.0.0.0' \
231 'local_port:port'
232}
233
234validate_common_options_() {
235 local cfgtype="$1"; shift
236 local cfg="$1"; shift
237 local func="$1"; shift
238
239 "${func:-ss_validate}" "$cfgtype" "$cfg" "$@" \
240 'disabled:bool:0' \
241 'fast_open:bool:0' \
242 'ipv6_first:bool:0' \
243 'no_delay:bool:0' \
244 'reuse_port:bool:0' \
245 'verbose:bool:0' \
246 'mode:or("tcp_only", "udp_only", "tcp_and_udp"):tcp_only' \
247 'mtu:uinteger' \
248 'timeout:uinteger' \
249 'user:string'
250}
251
252validate_server_section() {
253 validate_common_server_options_ server "$1" "$2"
254}
255
256validate_ss_local_section() {
257 validate_common_client_options_ ss_local "$1" "$2"
258}
259
260validate_ss_redir_section() {
261 validate_common_client_options_ ss_redir "$1" "$2"
262}
263
264validate_ss_rules_section() {
265 "${2:-ss_validate}" ss_rules "$1" \
266 'disabled:bool:0' \
267 'redir_tcp:uci("shadowsocks-libev", "@ss_redir")' \
268 'redir_udp:uci("shadowsocks-libev", "@ss_redir")' \
269 'src_ips_bypass:or(ipaddr,cidr)' \
270 'src_ips_forward:or(ipaddr,cidr)' \
271 'src_ips_checkdst:or(ipaddr,cidr)' \
272 'dst_ips_bypass_file:file' \
273 'dst_ips_bypass:or(ipaddr,cidr)' \
274 'dst_ips_forward_file:file' \
275 'dst_ips_forward:or(ipaddr,cidr)' \
276 'src_default:or("bypass", "forward", "checkdst"):checkdst' \
277 'dst_default:or("bypass", "forward"):bypass' \
278 'local_default:or("bypass", "forward", "checkdst"):bypass' \
279 'dst_forward_recentrst:bool:0' \
280 'ifnames:maxlength(15)' \
281 'ipt_args:string'
282}
283
284validate_ss_server_section() {
285 validate_common_server_options_ ss_server "$1" \
286 validate_common_options_ \
287 "$2" \
288 'local_address:ipaddr' \
289 'local_ipv4_address:ip4addr' \
290 'local_ipv6_address:ip6addr' \
291 'bind_address:ipaddr'
292}
293
294validate_ss_tunnel_section() {
295 validate_common_client_options_ ss_tunnel "$1" \
296 "$2" \
297 'tunnel_address:regex(".+\:[0-9]+")'
298}