diff --git a/Makefile b/Makefile index 27b25a50..5ce1d00c 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-shadowsocks -PKG_VERSION:=2.0.1 +PKG_VERSION:=2.0.2 PKG_RELEASE:=1 PKG_LICENSE:=GPLv3 diff --git a/files/root/etc/config/shadowsocks b/files/root/etc/config/shadowsocks index a8e392d1..f47371a6 100644 --- a/files/root/etc/config/shadowsocks +++ b/files/root/etc/config/shadowsocks @@ -3,23 +3,23 @@ config general option startup_delay '0' config transparent_proxy - list main_server 'nil' + option main_server 'nil' option udp_relay_server 'nil' option local_port '1234' config socks5_proxy - list server 'nil' + option server 'nil' option local_port '1080' config port_forward - list server 'nil' + option server 'nil' option local_port '5300' option destination '8.8.4.4:53' config servers option alias 'sample' + option type 'ss' option fast_open '0' - option no_delay '0' option server '127.0.0.1' option server_port '8388' option timeout '60' diff --git a/files/root/etc/init.d/shadowsocks b/files/root/etc/init.d/shadowsocks index 3f9d8be8..4faa0ce4 100644 --- a/files/root/etc/init.d/shadowsocks +++ b/files/root/etc/init.d/shadowsocks @@ -12,6 +12,8 @@ STOP=15 NAME=shadowsocks EXTRA_COMMANDS="rules" +. /usr/share/libubox/jshn.sh + uci_get_by_name() { local ret=$(uci get $NAME.$1.$2 2>/dev/null) echo ${ret:=$3} @@ -33,13 +35,6 @@ validate_server() { [ "$(uci get $NAME.$1 2>/dev/null)" = "servers" ] } -has_valid_server() { - for server in $@; do - validate_server $server && return 0 - done - return 1 -} - get_arg_udp() { local server=$(uci_get_by_type transparent_proxy udp_relay_server) [ "$server" = "same" ] || validate_server $server && echo "-u" @@ -69,30 +64,6 @@ get_lan_hosts() { echo "$(uci_get_by_name $1 type),$(uci_get_by_name $1 host)" } -get_plugin_config() { - local plugin=$(uci_get_by_name $1 plugin) - local plugin_opts=$(uci_get_by_name $1 plugin_opts) - if [ -n "$plugin" ]; then - echo $plugin >>/var/run/ss-plugin - echo -e "\n \"plugin\": \"$plugin\"," - if [ -n "$plugin_opts" ]; then - echo " \"plugin_opts\": \"$plugin_opts\"," - fi - fi -} - -get_crypto_config() { - local key=$(uci_get_by_name $1 key) - local password=$(uci_get_by_name $1 password) - if [ -n "$key" ]; then - echo "\"key\": \"$key\"," - elif [ -n "$password" ]; then - echo "\"password\": \"$password\"," - else - logger -st $NAME -p3 "The password or key is not set." - fi -} - get_processes() { local cores=$(grep 'processor' /proc/cpuinfo | wc -l) local processes=$(uci_get_by_type $1 processes $cores) @@ -104,35 +75,42 @@ get_processes() { } gen_config_file() { - local type=$(uci_get_by_name $1 type) local config_file=/var/etc/$NAME.$1.json - if [ "$type" = "ssr" ]; then - cat <<-EOF >$config_file - { - "server": "$(uci_get_by_name $1 server)", - "server_port": $(uci_get_by_name $1 server_port), - "password": "$(uci_get_by_name $1 password)", - "method": "$(uci_get_by_name $1 encrypt_method)", - "local_address": "0.0.0.0", - "timeout": $(uci_get_by_name $1 timeout 60), - "protocol": "$(uci_get_by_name $1 protocol)", - "protocol_param": "$(uci_get_by_name $1 protocol_param)", - "obfs": "$(uci_get_by_name $1 obfs)", - "obfs_param": "$(uci_get_by_name $1 obfs_param)" - } -EOF - else - cat <<-EOF >$config_file - { - "server": "$(uci_get_by_name $1 server)", - "server_port": $(uci_get_by_name $1 server_port), - $(get_crypto_config $1) - "method": "$(uci_get_by_name $1 encrypt_method)", - "local_address": "0.0.0.0",$(get_plugin_config $1) - "timeout": $(uci_get_by_name $1 timeout 60), - "reuse_port": true - } -EOF + if [ "$2" = "1" ]; then + json_init + json_add_string "server" "$(uci_get_by_name $1 server)" + json_add_int "server_port" $(uci_get_by_name $1 server_port) + json_add_string "method" "$(uci_get_by_name $1 encrypt_method)" + json_add_string "local_address" "0.0.0.0" + json_add_int "timeout" $(uci_get_by_name $1 timeout 60) + local type=$(uci_get_by_name $1 type) + if [ "$type" = "ssr" ]; then + json_add_string "password" "$(uci_get_by_name $1 password)" + json_add_string "protocol" "$(uci_get_by_name $1 protocol)" + json_add_string "protocol_param" "$(uci_get_by_name $1 protocol_param)" + json_add_string "obfs" "$(uci_get_by_name $1 obfs)" + json_add_string "obfs_param" "$(uci_get_by_name $1 obfs_param)" + else + local key=$(uci_get_by_name $1 key) + local password=$(uci_get_by_name $1 password) + if [ -n "$key" ]; then + json_add_string "key" "$key" + elif [ -n "$password" ]; then + json_add_string "password" "$password" + fi + local plugin=$(uci_get_by_name $1 plugin) + local plugin_opts=$(uci_get_by_name $1 plugin_opts) + if [ -n "$plugin" ]; then + echo $plugin >>/var/run/ss-plugin + json_add_string "plugin" "$plugin" + if [ -n "$plugin_opts" ]; then + json_add_string "plugin_opts" "$plugin_opts" + fi + fi + json_add_boolean "reuse_port" 1 + fi + json_close_object + json_dump -i >$config_file fi echo $config_file } @@ -163,13 +141,13 @@ start_redir() { local type=$(uci_get_by_name $1 type) if [ "$type" = "ssr" ]; then command -v ssr-redir >/dev/null || return 1 - ssr-redir -c $(gen_config_file $1) $3 $(get_arg_tfo $1) \ + ssr-redir -c $(gen_config_file $1 $2) $3 $(get_arg_tfo $1) \ -l $(uci_get_by_type transparent_proxy local_port 1234) \ --mtu $(uci_get_by_type transparent_proxy mtu 1492) \ -f /var/run/ssr-redir$4-$1-$2.pid else command -v ss-redir >/dev/null || return 1 - ss-redir -c $(gen_config_file $1) $3 $(get_arg_tfo $1) $(get_arg_tnd $1) \ + ss-redir -c $(gen_config_file $1 $2) $3 $(get_arg_tfo $1) $(get_arg_tnd $1) \ -l $(uci_get_by_type transparent_proxy local_port 1234) \ --mtu $(uci_get_by_type transparent_proxy mtu 1492) \ -f /var/run/ss-redir$4-$1-$2.pid @@ -179,27 +157,17 @@ start_redir() { ss_redir() { local processes=$(get_processes transparent_proxy) local main_server=$(uci_get_by_type transparent_proxy main_server) - has_valid_server $main_server || return 1 local udp_relay_server=$(uci_get_by_type transparent_proxy udp_relay_server) if [ "$udp_relay_server" = "same" ]; then - for server in $main_server; do - for i in $(seq $processes); do - start_redir $server $i -u - done - break + for i in $(seq $processes); do + start_redir $main_server $i -u done else - for server in $main_server; do - for i in $(seq $processes); do - start_redir $server $i - done - break + for i in $(seq $processes); do + start_redir $main_server $i done - for server in $udp_relay_server; do - for i in $(seq $processes); do - start_redir $server $i -U -udp - done - break + for i in $(seq $processes); do + start_redir $udp_relay_server $i -U -udp done fi } @@ -209,13 +177,13 @@ start_local() { local type=$(uci_get_by_name $1 type) if [ "$type" = "ssr" ]; then command -v ssr-local >/dev/null 2>&1 || return 0 - ssr-local -c $(gen_config_file $1) -u $(get_arg_tfo $1) \ + ssr-local -c $(gen_config_file $1 $2) -u $(get_arg_tfo $1) \ -l $(uci_get_by_type socks5_proxy local_port 1080) \ --mtu $(uci_get_by_type socks5_proxy mtu 1492) \ -f /var/run/ssr-local-$1-$2.pid else command -v ss-local >/dev/null 2>&1 || return 0 - ss-local -c $(gen_config_file $1) -u $(get_arg_tfo $1) $(get_arg_tnd $1) \ + ss-local -c $(gen_config_file $1 $2) -u $(get_arg_tfo $1) $(get_arg_tnd $1) \ -l $(uci_get_by_type socks5_proxy local_port 1080) \ --mtu $(uci_get_by_type socks5_proxy mtu 1492) \ -f /var/run/ss-local-$1-$2.pid @@ -224,11 +192,9 @@ start_local() { ss_local() { local processes=$(get_processes socks5_proxy) - for server in $(uci_get_by_type socks5_proxy server); do - for i in $(seq $processes); do - start_local $server $i - done - break + local server=$(uci_get_by_type socks5_proxy server) + for i in $(seq $processes); do + start_local $server $i done } @@ -237,14 +203,14 @@ start_tunnel() { local type=$(uci_get_by_name $1 type) if [ "$type" = "ssr" ]; then command -v ssr-tunnel >/dev/null 2>&1 || return 0 - ssr-tunnel -c $(gen_config_file $1) \ + ssr-tunnel -c $(gen_config_file $1 $2) \ -l $(uci_get_by_type port_forward local_port 5300) \ -L $(uci_get_by_type port_forward destination 8.8.4.4:53) \ --mtu $(uci_get_by_type port_forward mtu 1492) \ -f /var/run/ssr-tunnel-$1-$2.pid else command -v ss-tunnel >/dev/null 2>&1 || return 0 - ss-tunnel -c $(gen_config_file $1) -u $(get_arg_tnd $1) \ + ss-tunnel -c $(gen_config_file $1 $2) -u $(get_arg_tnd $1) \ -l $(uci_get_by_type port_forward local_port 5300) \ -L $(uci_get_by_type port_forward destination 8.8.4.4:53) \ --mtu $(uci_get_by_type port_forward mtu 1492) \ @@ -254,11 +220,9 @@ start_tunnel() { ss_tunnel() { local processes=$(get_processes port_forward) - for server in $(uci_get_by_type port_forward server); do - for i in $(seq $processes); do - start_tunnel $server $i - done - break + local server=$(uci_get_by_type port_forward server) + for i in $(seq $processes); do + start_tunnel $server $i done } @@ -283,6 +247,7 @@ kill_all() { stop() { /usr/bin/ss-rules -f kill_all ss-redir ss-local ss-tunnel ssr-redir ssr-local ssr-tunnel + rm -f /var/run/ss*.pid if [ -f /var/run/ss-plugin ]; then kill_all $(sort -u /var/run/ss-plugin) rm -f /var/run/ss-plugin diff --git a/files/root/usr/bin/ss-subscribe b/files/root/usr/bin/ss-subscribe index 1f99d593..b3652777 100644 --- a/files/root/usr/bin/ss-subscribe +++ b/files/root/usr/bin/ss-subscribe @@ -10,7 +10,7 @@ require "luci.util" require "luci.sys" require "nixio" -local shadowsocks = "shadowsocks" +local config = "shadowsocks" local uci = luci.model.uci.cursor() function base64_decode(text) @@ -30,7 +30,12 @@ function base64_decode(text) end function http_get(url) - return luci.util.trim(luci.sys.exec("/usr/bin/wget -q --no-check-certificate -O- '%s'" %{url})) + return luci.util.trim(luci.util.exec("/usr/bin/wget -q --no-check-certificate -O- '%s'" %{url})) +end + +function resolveip(host) + local ret = luci.util.split(luci.util.exec("resolveip -4 -t 5 %s 2>/dev/null" %{host}), "\n") + return luci.util.trim(ret[1]) end function parse_ss(data) @@ -50,7 +55,7 @@ function parse_ss(data) result.encrypt_method = info[1] result.password = info[2] result.host = host[1] - result.server = luci.util.trim(luci.sys.exec("resolveip %s 2>/dev/null" %{host[1]})) + result.server = resolveip(host[1]) result.server_port = host[2] for _, v in pairs(luci.util.split(data[2], "&")) do local t = luci.util.split(v, '=') @@ -74,7 +79,7 @@ function parse_ssr(data) local result = {type = "ssr", timeout = 300, fast_open = 0} local params = {} result.host = main[1] - result.server = luci.util.trim(luci.sys.exec("resolveip %s 2>/dev/null" %{main[1]})) + result.server = resolveip(main[1]) result.server_port = main[2] result.protocol = main[3] result.encrypt_method = main[4] @@ -93,7 +98,7 @@ end function check_filter_words(words, str) for _, w in pairs(words) do w = luci.util.trim(w) - if #w > 0 and str:find(w) then + if #w > 0 and str:find(w, 1, true) then return false end end @@ -101,13 +106,11 @@ function check_filter_words(words, str) end function exec_subscribe(section) - local url = uci:get(shadowsocks, section, "subscription_url") + local url = uci:get(config, section, "subscription_url") if not url then return false end local configs = {} - local group = uci:get(shadowsocks, section, "name") - local words = uci:get(shadowsocks, section, "filter_words") local lines = luci.util.split(base64_decode(http_get(url)), "\n") for _, v in pairs(lines) do if v:find("://") then @@ -119,7 +122,12 @@ function exec_subscribe(section) end end end - uci:delete_all(shadowsocks, "servers", function(s) + if #configs == 0 then + return false + end + local group = uci:get(config, section, "name") + local words = uci:get(config, section, "filter_words") + uci:delete_all(config, "servers", function(s) return s.group == group end) if words then @@ -128,7 +136,7 @@ function exec_subscribe(section) for _, v in pairs(configs) do if not words or check_filter_words(words, v.alias) then v.group = group - uci:section(shadowsocks, "servers", nil, v) + uci:section(config, "servers", nil, v) end end return true @@ -136,12 +144,12 @@ end if #arg > 0 then if arg[1]:lower() == "all" then - uci:foreach(shadowsocks, "subscription", function(s) + uci:foreach(config, "subscription", function(s) exec_subscribe(s[".name"]) end) elseif arg[1]:lower() == "auto" then local hour = os.date("%H") - uci:foreach(shadowsocks, "subscription", function(s) + uci:foreach(config, "subscription", function(s) if s.auto_update == "1" and s.update_hour == hour then exec_subscribe(s[".name"]) end @@ -151,14 +159,16 @@ if #arg > 0 then os.exit(1) end end - uci:commit(shadowsocks) + if uci:commit(config) then + os.execute("/etc/init.d/%s restart" %{config}) + end os.exit(0) else print("Syntax: subscribe.lua [command]") print("\nAvailable commands:") - print("\tall force subscribe all subscription section") - print("\tauto subscribe eligible subscription section") - print("\t[section name] subscribe a specific name subscription section") + print("\tall force subscribe all subscription section") + print("\tauto subscribe eligible subscription section") + print("\t[UCI section name] subscribe a specific name subscription section") end os.exit(1)