b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame^] | 1 | #!/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 | |
| 9 | USE_PROCD=1 |
| 10 | START=99 |
| 11 | |
| 12 | ss_confdir=/var/etc/shadowsocks-libev |
| 13 | ss_bindir=/usr/bin |
| 14 | |
| 15 | ss_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 | |
| 26 | ss_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 | |
| 37 | ss_mkjson_ss_local_conf() { |
| 38 | ss_mkjson_server_conf |
| 39 | } |
| 40 | |
| 41 | ss_mkjson_ss_redir_conf() { |
| 42 | ss_mkjson_server_conf |
| 43 | } |
| 44 | |
| 45 | ss_mkjson_ss_server_conf() { |
| 46 | ss_mkjson_server_conf_ |
| 47 | } |
| 48 | |
| 49 | ss_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 | |
| 55 | ss_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 | |
| 96 | ss_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 | |
| 112 | ss_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 | |
| 140 | ss_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 | |
| 161 | start_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 | |
| 172 | stop_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 | |
| 182 | service_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 | |
| 195 | ss_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 | |
| 205 | ss_validate() { |
| 206 | uci_validate_section shadowsocks-libev "$@" |
| 207 | } |
| 208 | |
| 209 | validate_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 | |
| 227 | validate_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 | |
| 234 | validate_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 | |
| 252 | validate_server_section() { |
| 253 | validate_common_server_options_ server "$1" "$2" |
| 254 | } |
| 255 | |
| 256 | validate_ss_local_section() { |
| 257 | validate_common_client_options_ ss_local "$1" "$2" |
| 258 | } |
| 259 | |
| 260 | validate_ss_redir_section() { |
| 261 | validate_common_client_options_ ss_redir "$1" "$2" |
| 262 | } |
| 263 | |
| 264 | validate_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 | |
| 284 | validate_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 | |
| 294 | validate_ss_tunnel_section() { |
| 295 | validate_common_client_options_ ss_tunnel "$1" \ |
| 296 | "$2" \ |
| 297 | 'tunnel_address:regex(".+\:[0-9]+")' |
| 298 | } |