diff --git a/applications/luci-app-passwall/Makefile b/applications/luci-app-passwall/Makefile index 44ae942705..19079f4fa3 100644 --- a/applications/luci-app-passwall/Makefile +++ b/applications/luci-app-passwall/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall -PKG_VERSION:=26.1.25 +PKG_VERSION:=26.1.30 PKG_RELEASE:=1 PKG_CONFIG_DEPENDS:= \ diff --git a/applications/luci-app-passwall/luasrc/controller/passwall.lua b/applications/luci-app-passwall/luasrc/controller/passwall.lua index cc50ae8c9e..33af58ba0c 100644 --- a/applications/luci-app-passwall/luasrc/controller/passwall.lua +++ b/applications/luci-app-passwall/luasrc/controller/passwall.lua @@ -49,6 +49,7 @@ function index() entry({"admin", "services", appname, "node_subscribe_config"}, cbi(appname .. "/client/node_subscribe_config")).leaf = true entry({"admin", "services", appname, "node_config"}, cbi(appname .. "/client/node_config")).leaf = true entry({"admin", "services", appname, "shunt_rules"}, cbi(appname .. "/client/shunt_rules")).leaf = true + entry({"admin", "services", appname, "shunt_config"}, cbi(appname .. "/client/shunt_config")).leaf = true entry({"admin", "services", appname, "socks_config"}, cbi(appname .. "/client/socks_config")).leaf = true entry({"admin", "services", appname, "acl"}, cbi(appname .. "/client/acl"), _("Access control"), 98).leaf = true entry({"admin", "services", appname, "acl_config"}, cbi(appname .. "/client/acl_config")).leaf = true @@ -83,6 +84,7 @@ function index() entry({"admin", "services", appname, "update_node"}, call("update_node")).leaf = true entry({"admin", "services", appname, "set_node"}, call("set_node")).leaf = true entry({"admin", "services", appname, "copy_node"}, call("copy_node")).leaf = true + entry({"admin", "services", appname, "edit_node"}, call("edit_node")).leaf = true entry({"admin", "services", appname, "clear_all_nodes"}, call("clear_all_nodes")).leaf = true entry({"admin", "services", appname, "delete_select_nodes"}, call("delete_select_nodes")).leaf = true entry({"admin", "services", appname, "reassign_group"}, call("reassign_group")).leaf = true @@ -90,6 +92,7 @@ function index() entry({"admin", "services", appname, "save_node_order"}, call("save_node_order")).leaf = true entry({"admin", "services", appname, "save_node_list_opt"}, call("save_node_list_opt")).leaf = true entry({"admin", "services", appname, "update_rules"}, call("update_rules")).leaf = true + entry({"admin", "services", appname, "rollback_rules"}, call("rollback_rules")).leaf = true entry({"admin", "services", appname, "subscribe_del_node"}, call("subscribe_del_node")).leaf = true entry({"admin", "services", appname, "subscribe_del_all"}, call("subscribe_del_all")).leaf = true entry({"admin", "services", appname, "subscribe_manual"}, call("subscribe_manual")).leaf = true @@ -414,6 +417,7 @@ function urltest_node() end function add_node() + local protocol = http.formvalue("protocol") or "" local redirect = http.formvalue("redirect") local uuid = api.gen_short_uuid() @@ -424,11 +428,19 @@ function add_node() uci:set(appname, uuid, "group", group) end - uci:set(appname, uuid, "type", "Xray") + if protocol == "shunt" then + uci:set(appname, uuid, "protocol", "_shunt") + else + uci:set(appname, uuid, "type", "Socks") + end if redirect == "1" then api.uci_save(uci, appname) - http.redirect(api.url("node_config", uuid)) + if protocol == "shunt" then + http.redirect(api.url("shunt_config", uuid)) + else + http.redirect(api.url("node_config", uuid)) + end else api.uci_save(uci, appname, true, true) http_write_json({result = uuid}) @@ -495,6 +507,16 @@ function copy_node() http.redirect(api.url("node_config", uuid)) end +function edit_node() + local section = http.formvalue("section") + local protocol = uci:get(appname, section, "protocol") + if protocol == "_shunt" then + http.redirect(api.url("shunt_config", section)) + else + http.redirect(api.url("node_config", section)) + end +end + function clear_all_nodes() uci:set(appname, '@global[0]', "enabled", "0") uci:set(appname, '@global[0]', "socks_enabled", "0") @@ -702,6 +724,24 @@ function update_rules() http_write_json() end +function rollback_rules() + local arg_type = http.formvalue("type") + local rules = http.formvalue("rules") or "" + if arg_type ~= "geoip" and arg_type ~= "geosite" then + http_write_json_error() + return + end + local bak_dir = "/tmp/bak_v2ray/" + local geo_dir = (uci:get(appname, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/") + local geo2rule = uci:get(appname, "@global_rules[0]", "geo2rule") or "0" + fs.move(bak_dir .. arg_type .. ".dat", geo_dir .. arg_type .. ".dat") + fs.rmdir(bak_dir) + if geo2rule == "1" and rules ~= "" then + luci.sys.call("lua /usr/share/passwall/rule_update.lua log '" .. rules .. "' rollback > /dev/null") + end + http_write_json_ok() +end + function server_user_status() local e = {} e.index = http.formvalue("index") @@ -864,6 +904,25 @@ function geo_view() http.write(i18n.translate("Please enter query content!")) return end + local function get_rules(str, type) + local remarks = {} + uci:foreach(appname, "shunt_rules", function(s) + local list + if type == "geoip" then list = s.ip_list else list = s.domain_list end + for line in string.gmatch((list or ""), "[^\r\n]+") do + if line ~= "" and not line:find("#") then + local prefix, main = line:match("^(.-):(.*)") + if not main then main = line end + if type == "geoip" and (api.datatypes.ipaddr(str) or api.datatypes.ip6addr(str)) then + if main:find(str, 1, true) and s.remarks then remarks[#remarks + 1] = s.remarks end + else + if main == str and s.remarks then remarks[#remarks + 1] = s.remarks end + end + end + end + end) + return remarks + end local geo_dir = (uci:get(appname, "@global_rules[0]", "v2ray_location_asset") or "/usr/share/v2ray/"):match("^(.*)/") local geosite_path = geo_dir .. "/geosite.dat" local geoip_path = geo_dir .. "/geoip.dat" @@ -878,13 +937,22 @@ function geo_view() cmd = string.format("geoview -type %s -action lookup -input '%s' -value '%s' -lowmem=true", geo_type, file_path, value) geo_string = luci.sys.exec(cmd):lower() if geo_string ~= "" then - local lines = {} - for line in geo_string:gmatch("([^\n]*)\n?") do - if line ~= "" then - table.insert(lines, geo_type .. ":" .. line) + local lines, rules, seen = {}, {}, {} + for line in geo_string:gmatch("([^\n]+)") do + lines[#lines + 1] = geo_type .. ":" .. line + for _, r in ipairs(get_rules(line, geo_type) or {}) do + if not seen[r] then seen[r] = true; rules[#rules + 1] = r end end end + for _, r in ipairs(get_rules(value, geo_type) or {}) do + if not seen[r] then seen[r] = true; rules[#rules + 1] = r end + end geo_string = table.concat(lines, "\n") + if #rules > 0 then + geo_string = geo_string .. "\n--------------------\n" + geo_string = geo_string .. i18n.translate("Rules containing this value:") .. "\n" + geo_string = geo_string .. table.concat(rules, "\n") + end end elseif action == "extract" then local prefix, list = value:match("^(geoip:)(.*)$") diff --git a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/acl_config.lua b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/acl_config.lua index 435390ce04..78ec4683d9 100644 --- a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/acl_config.lua +++ b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/acl_config.lua @@ -209,6 +209,10 @@ o.default = "" o:depends({ _hide_node_option = false, use_global_config = false }) o.template = appname .. "/cbi/nodes_listvalue" o.group = {} +o.remove = function(self, section) + m:del(section, self.option) + m:del(section, "udp_node") +end o = s:option(DummyValue, "_tcp_node_bool", "") o.template = "passwall/cbi/hidevalue" @@ -219,14 +223,36 @@ o = s:option(ListValue, "udp_node", "" .. translate("UDP N o.default = "" o:value("", translate("Close")) o:value("tcp", translate("Same as the tcp node")) -o:depends({ _tcp_node_bool = "1" }) +o:depends({ _tcp_node_bool = "1", _node_sel_other = "1" }) o.template = appname .. "/cbi/nodes_listvalue" o.group = {"",""} +o.remove = function(self, section) + local v = s.fields["shunt_udp_node"]:formvalue(section) + if not f then + return m:del(section, self.option) + end +end + +o = s:option(ListValue, "shunt_udp_node", "" .. translate("UDP Node") .. "") +o:value("close", translate("Close")) +o:value("tcp", translate("Same as the tcp node")) +o:depends({ _tcp_node_bool = "1", _node_sel_shunt = "1" }) +o.cfgvalue = function(self, section) + local v = m:get(section, "udp_node") or "" + if v == "" then v = "close" end + if v ~= "close" and v ~= "tcp" then v = "tcp" end + return v +end +o.write = function(self, section, value) + if value == "close" then value = "" end + return m:set(section, "udp_node", value) +end o = s:option(DummyValue, "_udp_node_bool", "") o.template = "passwall/cbi/hidevalue" o.value = "1" o:depends({ udp_node = "", ['!reverse'] = true }) +o:depends({ shunt_udp_node = "tcp" }) ---- TCP Proxy Drop Ports local TCP_PROXY_DROP_PORTS = m:get("@global_forwarding[0]", "tcp_proxy_drop_ports") @@ -471,7 +497,7 @@ o:depends({dns_mode = "sing-box"}) o:depends({dns_mode = "xray"}) o:depends({_node_sel_shunt = "1"}) -o = s:option(Flag, "remote_fakedns", "FakeDNS", translate("Use FakeDNS work in the shunt domain that proxy.")) +o = s:option(Flag, "remote_fakedns", "FakeDNS", translate("Use FakeDNS work in the domain that proxy.")) o.default = "0" o.rmempty = false o:depends({dns_mode = "sing-box"}) diff --git a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua index 181688f720..bb840acea3 100644 --- a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua +++ b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua @@ -95,8 +95,6 @@ end m:append(Template(appname .. "/global/status")) -local global_cfgid = m:get("@global[0]")[".name"] - s = m:section(TypedSection, "global") s.anonymous = true s.addremove = false @@ -119,208 +117,36 @@ o.template = appname .. "/cbi/nodes_listvalue" o:value("", translate("Close")) o:value("tcp", translate("Same as the tcp node")) o.group = {"",""} +o:depends("_node_sel_other", "1") +o.remove = function(self, section) + local v = s.fields["shunt_udp_node"]:formvalue(section) + if not f then + return m:del(section, self.option) + end +end -local tcp_node_id = m.uci:get(appname, global_cfgid, "tcp_node") -local tcp_node = tcp_node_id and m.uci:get_all(appname, tcp_node_id) or {} - --- 分流 -if (has_singbox or has_xray) and #nodes_table > 0 then - if #normal_list > 0 and tcp_node.protocol == "_shunt" then - local v = tcp_node - if v then - local function get_cfgvalue(shunt_node_id, option) - return function(self, section) - return m:get(shunt_node_id, option) - end - end - local function get_write(shunt_node_id, option) - return function(self, section, value) - if s.fields["tcp_node"]:formvalue(section) == shunt_node_id then - m:set(shunt_node_id, option, value) - end - end - end - local function get_remove(shunt_node_id, option) - return function(self, section) - if s.fields["tcp_node"]:formvalue(section) == shunt_node_id then - m:del(shunt_node_id, option) - end - end - end - v.id = v[".name"] - local vid = v.id - -- shunt node type, Sing-Box or Xray - o = s:taboption("Main", ListValue, vid .. "-type", translate("Type")) - if has_xray then - o:value("Xray", translate("Xray")) - end - if has_singbox then - o:value("sing-box", "Sing-Box") - end - o:depends("tcp_node", v.id) - o.cfgvalue = get_cfgvalue(v.id, "type") - o.write = get_write(v.id, "type") - - -- pre-proxy - o = s:taboption("Main", Flag, vid .. "-preproxy_enabled", translate("Preproxy")) - o:depends("tcp_node", v.id) - o.rmempty = false - o.cfgvalue = get_cfgvalue(v.id, "preproxy_enabled") - o.write = get_write(v.id, "preproxy_enabled") - - o = s:taboption("Main", ListValue, vid .. "-main_node", string.format('%s', translate("Preproxy Node")), translate("Set the node to be used as a pre-proxy. Each rule (including Default) has a separate switch that controls whether this rule uses the pre-proxy or not.")) - o:depends(vid .. "-preproxy_enabled", "1") - o.template = appname .. "/cbi/nodes_listvalue" - o.group = {} - for k1, v1 in pairs(socks_list) do - o:value(v1.id, v1.remark) - o.group[#o.group+1] = (v1.group and v1.group ~= "") and v1.group or translate("default") - end - for k1, v1 in pairs(balancing_list) do - o:value(v1.id, v1.remark) - o.group[#o.group+1] = (v1.group and v1.group ~= "") and v1.group or translate("default") - end - for k1, v1 in pairs(urltest_list) do - o:value(v1.id, v1.remark) - o.group[#o.group+1] = (v1.group and v1.group ~= "") and v1.group or translate("default") - end - for k1, v1 in pairs(iface_list) do - o:value(v1.id, v1.remark) - o.group[#o.group+1] = (v1.group and v1.group ~= "") and v1.group or translate("default") - end - for k1, v1 in pairs(normal_list) do - o:value(v1.id, v1.remark) - o.group[#o.group+1] = (v1.group and v1.group ~= "") and v1.group or translate("default") - end - o.cfgvalue = get_cfgvalue(v.id, "main_node") - o.write = get_write(v.id, "main_node") - - o = s:taboption("Main", Flag, vid .. "-fakedns", "FakeDNS", translate("Use FakeDNS work in the shunt domain that proxy.")) - o:depends("tcp_node", v.id) - o.cfgvalue = get_cfgvalue(v.id, "fakedns") - o.write = get_write(v.id, "fakedns") - o.remove = get_remove(v.id, "fakedns") - - m.uci:foreach(appname, "shunt_rules", function(e) - local id = e[".name"] - local node_option = vid .. "-" .. id .. "_node" - if id and e.remarks then - o = s:taboption("Main", ListValue, node_option, string.format('* %s', api.url("shunt_rules", id), e.remarks)) - o.cfgvalue = get_cfgvalue(v.id, id) - o.write = get_write(v.id, id) - o.remove = get_remove(v.id, id) - o:depends("tcp_node", v.id) - o:value("", translate("Close")) - o:value("_default", translate("Default")) - o:value("_direct", translate("Direct Connection")) - o:value("_blackhole", translate("Blackhole")) - o.template = appname .. "/cbi/nodes_listvalue" - o.group = {"","","",""} - - local pt = s:taboption("Main", ListValue, vid .. "-".. id .. "_proxy_tag", string.format('* %s', e.remarks .. " " .. translate("Preproxy"))) - pt.cfgvalue = get_cfgvalue(v.id, id .. "_proxy_tag") - pt.write = get_write(v.id, id .. "_proxy_tag") - pt.remove = get_remove(v.id, id .. "_proxy_tag") - pt:value("", translate("Close")) - pt:value("main", translate("Preproxy Node")) - pt:depends("__hide__", "1") - - local fakedns_tag = s:taboption("Main", Flag, vid .. "-".. id .. "_fakedns", string.format('* %s', e.remarks .. " " .. "FakeDNS")) - fakedns_tag.cfgvalue = get_cfgvalue(v.id, id .. "_fakedns") - fakedns_tag.write = get_write(v.id, id .. "_fakedns") - fakedns_tag.remove = get_remove(v.id, id .. "_fakedns") - - for k1, v1 in pairs(socks_list) do - o:value(v1.id, v1.remark) - o.group[#o.group+1] = (v1.group and v1.group ~= "") and v1.group or translate("default") - fakedns_tag:depends({ [node_option] = v1.id, [vid .. "-fakedns"] = "1" }) - end - for k1, v1 in pairs(balancing_list) do - o:value(v1.id, v1.remark) - o.group[#o.group+1] = (v1.group and v1.group ~= "") and v1.group or translate("default") - end - for k1, v1 in pairs(urltest_list) do - o:value(v1.id, v1.remark) - o.group[#o.group+1] = (v1.group and v1.group ~= "") and v1.group or translate("default") - end - for k1, v1 in pairs(iface_list) do - o:value(v1.id, v1.remark) - o.group[#o.group+1] = (v1.group and v1.group ~= "") and v1.group or translate("default") - end - for k1, v1 in pairs(normal_list) do - o:value(v1.id, v1.remark) - o.group[#o.group+1] = (v1.group and v1.group ~= "") and v1.group or translate("default") - if not api.is_local_ip(v1.address) then --本地节点禁止使用前置 - pt:depends({ [node_option] = v1.id, [vid .. "-preproxy_enabled"] = "1" }) - end - fakedns_tag:depends({ [node_option] = v1.id, [vid .. "-fakedns"] = "1" }) - end - if v.default_node ~= "_direct" or v.default_node ~= "_blackhole" then - fakedns_tag:depends({ [node_option] = "_default", [vid .. "-fakedns"] = "1" }) - end - end - end) - - local id = "default_node" - o = s:taboption("Main", ListValue, vid .. "-" .. id, string.format('* %s', translate("Default"))) - o.cfgvalue = get_cfgvalue(v.id, id) - o.write = get_write(v.id, id) - o.remove = get_remove(v.id, id) - o:depends("tcp_node", v.id) - o:value("_direct", translate("Direct Connection")) - o:value("_blackhole", translate("Blackhole")) - o.template = appname .. "/cbi/nodes_listvalue" - o.group = {"",""} - for k1, v1 in pairs(socks_list) do - o:value(v1.id, v1.remark) - o.group[#o.group+1] = (v1.group and v1.group ~= "") and v1.group or translate("default") - end - for k1, v1 in pairs(balancing_list) do - o:value(v1.id, v1.remark) - o.group[#o.group+1] = (v1.group and v1.group ~= "") and v1.group or translate("default") - end - for k1, v1 in pairs(urltest_list) do - o:value(v1.id, v1.remark) - o.group[#o.group+1] = (v1.group and v1.group ~= "") and v1.group or translate("default") - end - for k1, v1 in pairs(iface_list) do - o:value(v1.id, v1.remark) - o.group[#o.group+1] = (v1.group and v1.group ~= "") and v1.group or translate("default") - end - for k1, v1 in pairs(normal_list) do - o:value(v1.id, v1.remark) - o.group[#o.group+1] = (v1.group and v1.group ~= "") and v1.group or translate("default") - end +o = s:taboption("Main", ListValue, "shunt_udp_node", "" .. translate("UDP Node") .. "") +o:value("close", translate("Close")) +o:value("tcp", translate("Same as the tcp node")) +o:depends("_node_sel_shunt", "1") +o.cfgvalue = function(self, section) + local v = m:get(section, "udp_node") or "" + if v == "" then v = "close" end + if v ~= "close" and v ~= "tcp" then v = "tcp" end + return v +end +o.write = function(self, section, value) + if value == "close" then value = "" end + return m:set(section, "udp_node", value) +end - local id = "default_proxy_tag" - o = s:taboption("Main", ListValue, vid .. "-" .. id, string.format('* %s', translate("Default Preproxy")), translate("When using, localhost will connect this node first and then use this node to connect the default node.")) - o.cfgvalue = get_cfgvalue(v.id, id) - o.write = get_write(v.id, id) - o.remove = get_remove(v.id, id) - o:value("", translate("Close")) - o:value("main", translate("Preproxy Node")) - o:depends("__hide__", "1") - for k1, v1 in pairs(normal_list) do - if v1.protocol ~= "_balancing" and v1.protocol ~= "_urltest" and not api.is_local_ip(v1.address) then - o:depends({ [vid .. "-default_node"] = v1.id, [vid .. "-preproxy_enabled"] = "1" }) - end - end - end - else - local tips = s:taboption("Main", DummyValue, "tips", " ") - tips.rawhtml = true - tips.cfgvalue = function(t, n) - return string.format('%s', translate("There are no available nodes, please add or subscribe nodes first.")) - end - tips:depends({ tcp_node = "", ["!reverse"] = true }) - for k, v in pairs(shunt_list) do - tips:depends("udp_node", v.id) - end - for k, v in pairs(balancing_list) do - tips:depends("udp_node", v.id) - end - end +o = s:taboption("Main", DummyValue, "shunt_tips", " ") +o.rawhtml = true +o.cfgvalue = function(t, n) + return string.format('%s', + translate("To modify the shunt policy, click the Edit button.")) end +o:depends("_node_sel_shunt", "1") o = s:taboption("Main", Value, "tcp_node_socks_port", translate("TCP Node") .. " Socks " .. translate("Listen Port")) o.default = 1070 @@ -387,10 +213,14 @@ o.default = "0" -- TCP分流时dns过滤模式保存逻辑 function dns_mode_save(section) - for k, v in pairs(shunt_list) do - local f = s.fields[v.id .. "-type"] - if f then - local type_val = f:formvalue(section) + local f = s.fields["tcp_node"] + local id_val = f and f:formvalue(section) or "" + if id_val == "" then + return + end + for _, v in pairs(shunt_list) do + if v.id == id_val then + local type_val = v.type if type_val and (type_val == "Xray" or type_val == "sing-box") then local dns_shunt_val = s.fields["dns_shunt"]:formvalue(section) local dns_mode_val = (dns_shunt_val ~= "smartdns") and "dns_mode" or "smartdns_dns_mode" @@ -590,7 +420,7 @@ o:depends({dns_mode = "xray"}) o:depends("dns_shunt", "smartdns") o:depends("_node_sel_shunt", "1") -o = s:taboption("DNS", Flag, "remote_fakedns", "FakeDNS", translate("Use FakeDNS work in the shunt domain that proxy.")) +o = s:taboption("DNS", Flag, "remote_fakedns", "FakeDNS", translate("Use FakeDNS work in the domain that proxy.")) o.default = "0" o:depends({dns_mode = "sing-box", dns_shunt = "dnsmasq"}) o:depends({dns_mode = "sing-box", dns_shunt = "chinadns-ng"}) @@ -928,8 +758,11 @@ for k, v in pairs(nodes_table) do udp.group[#udp.group+1] = (v.group and v.group ~= "") and v.group or translate("default") s.fields["_node_sel_shunt"]:depends({ tcp_node = v.id }) - s.fields["xray_dns_mode"]:depends({ [v.id .. "-type"] = "Xray", _node_sel_shunt = "1" }) - s.fields["singbox_dns_mode"]:depends({ [v.id .. "-type"] = "sing-box", _node_sel_shunt = "1" }) + if m:get(v.id, "type") == "Xray" then + s.fields["xray_dns_mode"]:depends({ tcp_node = v.id }) + else + s.fields["singbox_dns_mode"]:depends({ tcp_node = v.id }) + end end else tcp:value(v.id, v["remark"]) @@ -950,8 +783,6 @@ end local footer = Template(appname .. "/global/footer") footer.api = api -footer.global_cfgid = global_cfgid -footer.shunt_list = api.jsonc.stringify(shunt_list) m:append(footer) return m diff --git a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/rule.lua b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/rule.lua index 9bdf13292f..fa5d6d87fb 100644 --- a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/rule.lua +++ b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/rule.lua @@ -52,14 +52,14 @@ o:value("https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/google o:value("https://cdn.jsdelivr.net/gh/blackmatrix7/ios_rule_script@master/rule/Clash/ChinaMax/ChinaMax_Domain.txt", translate("ios_rule_script/ChinaMax_Domain")) if has_xray or has_singbox then - o = s:option(ListValue, "geoip_url", translate("GeoIP Update URL")) + o = s:option(Value, "geoip_url", translate("GeoIP Update URL")) o:value("https://github.com/Loyalsoldier/geoip/releases/latest/download/geoip.dat", translate("Loyalsoldier/geoip")) o:value("https://github.com/MetaCubeX/meta-rules-dat/releases/latest/download/geoip.dat", translate("MetaCubeX/geoip")) o:value("https://cdn.jsdelivr.net/gh/Loyalsoldier/geoip@release/geoip.dat", translate("Loyalsoldier/geoip (CDN)")) o:value("https://cdn.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.dat", translate("MetaCubeX/geoip (CDN)")) o.default = o.keylist[1] - o = s:option(ListValue, "geosite_url", translate("Geosite Update URL")) + o = s:option(Value, "geosite_url", translate("Geosite Update URL")) o:value("https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat", translate("Loyalsoldier/geosite")) o:value("https://github.com/MetaCubeX/meta-rules-dat/releases/latest/download/geosite.dat", translate("MetaCubeX/geosite")) o:value("https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat", translate("Loyalsoldier/geosite (CDN)")) diff --git a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/shunt_config.lua b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/shunt_config.lua new file mode 100644 index 0000000000..b810f5e74e --- /dev/null +++ b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/shunt_config.lua @@ -0,0 +1,265 @@ +local api = require "luci.passwall.api" +local appname = api.appname +local has_singbox = api.finded_com("sing-box") +local has_xray = api.finded_com("xray") + +m = Map(appname, translate("Shunt Policy Config")) +m.redirect = api.url("node_list") +api.set_apply_on_parse(m) + +if not arg[1] or not m:get(arg[1]) then + luci.http.redirect(m.redirect) +end + +m:append(Template(appname .. "/cbi/nodes_listvalue_com")) + +s = m:section(NamedSection, arg[1], "nodes", "") +s.addremove = false +s.dynamic = false + +local nodes_table = {} +local iface_table = {} +local balancers_table = {} +local urltest_table = {} +for k, e in ipairs(api.get_valid_nodes()) do + if e.node_type == "normal" then + nodes_table[#nodes_table + 1] = { + id = e[".name"], + remark = e["remark"], + type = e["type"], + address = e["address"], + chain_proxy = e["chain_proxy"], + group = e["group"] + } + end + if e.protocol == "_iface" then + iface_table[#iface_table + 1] = { + id = e[".name"], + remark = e["remark"], + group = e["group"] + } + end + if e.protocol == "_balancing" then + balancers_table[#balancers_table + 1] = { + id = e[".name"], + remark = e["remark"], + group = e["group"] + } + end + if e.protocol == "_urltest" then + urltest_table[#urltest_table + 1] = { + id = e[".name"], + remark = e["remark"], + group = e["group"] + } + end +end + +local socks_list = {} +m.uci:foreach(appname, "socks", function(s) + if s.enabled == "1" and s.node then + socks_list[#socks_list + 1] = { + id = "Socks_" .. s[".name"], + remark = translate("Socks Config") .. " " .. string.format("[%s %s]", s.port, translate("Port")), + group = "Socks" + } + end +end) + +o = s:option(Value, "remarks", translate("Node Remarks")) +o.default = translate("Remarks") +o.rmempty = false + +o = s:option(Value, "group", translate("Group Name")) +o.default = "" +o:value("", translate("default")) +local groups = {} +m.uci:foreach(appname, "nodes", function(s) + if s[".name"] ~= arg[1] then + if s.group and s.group ~= "" then + groups[s.group] = true + end + end +end) +for k, v in pairs(groups) do + o:value(k) +end +o.write = function(self, section, value) + value = api.trim(value) + local lower = value:lower() + + if lower == "" or lower == "default" then + return m:del(section, self.option) + end + + for _, v in ipairs(self.keylist or {}) do + if v:lower() == lower then + return m:set(section, self.option, v) + end + end + m:set(section, self.option, value) +end + +local default_node = m.uci:get(appname, arg[1], "default_node") or "_direct" +-- [[ 分流模块 ]] +if #nodes_table > 0 then + local type = s:option(ListValue, "type", translate("Type")) + if has_xray then + type:value("Xray", translate("Xray")) + end + if has_singbox then + type:value("sing-box", translate("Sing-Box")) + end + + o = s:option(Flag, "preproxy_enabled", translate("Preproxy")) + + o = s:option(ListValue, "main_node", translate("Preproxy Node"), translate("Set the node to be used as a pre-proxy. Each rule (including Default) has a separate switch that controls whether this rule uses the pre-proxy or not.")) + o:depends({ ["preproxy_enabled"] = true }) + o.template = appname .. "/cbi/nodes_listvalue" + o.group = {} + for k, v in pairs(socks_list) do + o:value(v.id, v.remark) + o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") + end + for k, v in pairs(balancers_table) do + o:value(v.id, v.remark) + o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") + end + for k, v in pairs(urltest_table) do + o:value(v.id, v.remark) + o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") + end + for k, v in pairs(iface_table) do + o:value(v.id, v.remark) + o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") + end + for k, v in pairs(nodes_table) do + o:value(v.id, v.remark) + o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") + end + + o = s:option(Flag, "fakedns", 'FakeDNS', translate("Use FakeDNS work in the domain that proxy.") .. "
" .. + translate("Suitable scenarios for let the node servers get the target domain names.") .. "
" .. + translate("Such as: DNS unlocking of streaming media, reducing DNS query latency, etc.")) +end +m.uci:foreach(appname, "shunt_rules", function(e) + if e[".name"] and e.remarks then + o = s:option(ListValue, e[".name"], string.format('* %s', api.url("shunt_rules", e[".name"]), e.remarks)) + o:value("", translate("Close (Not use)")) + o:value("_default", translate("Use default node")) + o:value("_direct", translate("Direct Connection")) + o:value("_blackhole", translate("Blackhole (Block)")) + o.template = appname .. "/cbi/nodes_listvalue" + o.group = {"","","",""} + + if #nodes_table > 0 then + local pt = s:option(ListValue, e[".name"] .. "_proxy_tag", e.remarks .. " " .. translate("Preproxy")) + pt:value("", translate("Close (Not use)")) + pt:value("main", translate("Use preproxy node")) + pt:depends("__hide__", "1") + + local fakedns_tag = s:option(Flag, e[".name"] .. "_fakedns", string.format('* %s', e.remarks .. " " .. "FakeDNS")) + + for k, v in pairs(socks_list) do + o:value(v.id, v.remark) + o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") + fakedns_tag:depends({ ["fakedns"] = true, [e[".name"]] = v.id }) + end + for k, v in pairs(balancers_table) do + o:value(v.id, v.remark) + o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") + fakedns_tag:depends({ ["fakedns"] = true, [e[".name"]] = v.id }) + end + for k, v in pairs(urltest_table) do + o:value(v.id, v.remark) + o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") + fakedns_tag:depends({ ["fakedns"] = true, [e[".name"]] = v.id }) + end + for k, v in pairs(iface_table) do + o:value(v.id, v.remark) + o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") + end + for k, v in pairs(nodes_table) do + o:value(v.id, v.remark) + o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") + if not api.is_local_ip(v.address) then --本地节点禁止使用前置 + pt:depends({ ["preproxy_enabled"] = true, [e[".name"]] = v.id }) + end + fakedns_tag:depends({ ["fakedns"] = true, [e[".name"]] = v.id }) + end + if default_node ~= "_direct" or default_node ~= "_blackhole" then + fakedns_tag:depends({ ["fakedns"] = true, [e[".name"]] = "_default" }) + end + end + end +end) + +o = s:option(DummyValue, "shunt_tips", " ") +o.not_rewrite = true +o.rawhtml = true +o.cfgvalue = function(t, n) + return string.format('%s', translate("No shunt rules? Click me to go to add.")) +end + +local o = s:option(ListValue, "default_node", string.format('* %s', translate("Default"))) +o:value("_direct", translate("Direct Connection")) +o:value("_blackhole", translate("Blackhole (Block)")) +o.template = appname .. "/cbi/nodes_listvalue" +o.group = {"",""} + +if #nodes_table > 0 then + for k, v in pairs(socks_list) do + o:value(v.id, v.remark) + o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") + end + for k, v in pairs(balancers_table) do + o:value(v.id, v.remark) + o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") + end + for k, v in pairs(urltest_table) do + o:value(v.id, v.remark) + o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") + end + for k, v in pairs(iface_table) do + o:value(v.id, v.remark) + o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") + end + local dpt = s:option(ListValue, "default_proxy_tag", translate("Default Preproxy"), translate("When using, localhost will connect this node first and then use this node to connect the default node.")) + dpt:value("", translate("Close (Not use)")) + dpt:value("main", translate("Use preproxy node")) + dpt:depends("__hide__", "1") + for k, v in pairs(nodes_table) do + o:value(v.id, v.remark) + o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") + if not api.is_local_ip(v.address) then + dpt:depends({ ["preproxy_enabled"] = true, ["default_node"] = v.id }) + end + end +end + +o = s:option(ListValue, "domainStrategy", translate("Domain Strategy")) +o:value("AsIs") +o:value("IPIfNonMatch") +o:value("IPOnDemand") +o.default = "IPOnDemand" +o.description = "
" +o:depends({ ["type"] = "Xray" }) + +o = s:option(ListValue, "domainMatcher", translate("Domain matcher")) +o:value("hybrid") +o:value("linear") +o:depends({ ["type"] = "Xray" }) + +o = s:option(DummyValue, "exportConfig") +o.rawhtml = true +function o.cfgvalue(self, section) + return string.format( + [[]], + api.url("gen_client_config") .. "?id=" .. arg[1], + translate("Export Config File")) +end + +return m diff --git a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua index dad012f772..a76f80c34e 100644 --- a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua +++ b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua @@ -28,6 +28,13 @@ local function _n(name) return option_prefix .. name end +local formvalue_key = "cbid." .. appname .. "." .. arg[1] .. "." +local formvalue_proto = luci.http.formvalue(formvalue_key .. _n("protocol")) + +if formvalue_proto then s.val["protocol"] = formvalue_proto end + +local arg_select_proto = luci.http.formvalue("select_proto") or "" + local ss_method_list = { "none", "plain", "aes-128-gcm", "aes-256-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "xchacha20-poly1305", "xchacha20-ietf-poly1305", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" } @@ -54,8 +61,24 @@ end if api.compare_versions(xray_version, ">=", "1.8.12") then o:value("_balancing", translate("Balancing")) end -o:value("_shunt", translate("Shunt")) o:value("_iface", translate("Custom Interface")) +function o.custom_cfgvalue(self, section) + if arg_select_proto ~= "" then + return arg_select_proto + else + return m:get(section, self.option:sub(1 + #option_prefix)) + end +end + +local load_balancing_options = s.val["protocol"] == "_balancing" or arg_select_proto == "_balancing" +local load_iface_options = s.val["protocol"] == "_iface" or arg_select_proto == "_iface" +local load_normal_options = true +if load_balancing_options or load_iface_options then + load_normal_options = nil +end +if not arg_select_proto:find("_") then + load_normal_options = true +end local nodes_table = {} local balancers_table = {} @@ -110,7 +133,7 @@ m.uci:foreach(appname, "socks", function(s) end end) -if s.val["protocol"] == "_balancing" then -- [[ 负载均衡 Start ]] +if load_balancing_options then -- [[ 负载均衡 Start ]] o = s:option(MultiValue, _n("balancing_node"), translate("Load balancing node list"), translate("Load balancing node list, document")) o:depends({ [_n("protocol")] = "_balancing" }) o.widget = "checkbox" @@ -220,146 +243,14 @@ if s.val["protocol"] == "_balancing" then -- [[ 负载均衡 Start ]] o.description = translate("The load balancer selects the optimal number of nodes, and traffic is randomly distributed among them.") end -- [[ 负载均衡 End ]] -if s.val["protocol"] == "_shunt" then -- [[ 分流模块 Start ]] - local default_node = m.uci:get(appname, arg[1], "default_node") or "_direct" - if #nodes_table > 0 then - o = s:option(Flag, _n("preproxy_enabled"), translate("Preproxy")) - o:depends({ [_n("protocol")] = "_shunt" }) - - o = s:option(ListValue, _n("main_node"), string.format('%s', translate("Preproxy Node")), translate("Set the node to be used as a pre-proxy. Each rule (including Default) has a separate switch that controls whether this rule uses the pre-proxy or not.")) - o:depends({ [_n("protocol")] = "_shunt", [_n("preproxy_enabled")] = true }) - o.template = appname .. "/cbi/nodes_listvalue" - o.group = {} - for k, v in pairs(socks_list) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - end - for k, v in pairs(balancers_table) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - end - for k, v in pairs(iface_table) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - end - for k, v in pairs(nodes_table) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - end - - o = s:option(Flag, _n("fakedns"), "FakeDNS", translate("Use FakeDNS work in the shunt domain that proxy.")) - o:depends({ [_n("protocol")] = "_shunt" }) - end - m.uci:foreach(appname, "shunt_rules", function(e) - if e[".name"] and e.remarks then - o = s:option(ListValue, _n(e[".name"]), string.format('* %s', api.url("shunt_rules", e[".name"]), e.remarks)) - o:value("", translate("Close")) - o:value("_default", translate("Default")) - o:value("_direct", translate("Direct Connection")) - o:value("_blackhole", translate("Blackhole")) - o:depends({ [_n("protocol")] = "_shunt" }) - o.template = appname .. "/cbi/nodes_listvalue" - o.group = {"","","",""} - - if #nodes_table > 0 then - local pt = s:option(ListValue, _n(e[".name"] .. "_proxy_tag"), string.format('* %s', e.remarks .. " " .. translate("Preproxy"))) - pt:value("", translate("Close")) - pt:value("main", translate("Preproxy Node")) - pt:depends("__hide__", "1") - - local fakedns_tag = s:option(Flag, _n(e[".name"] .. "_fakedns"), string.format('* %s', e.remarks .. " " .. "FakeDNS")) - - for k, v in pairs(socks_list) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - fakedns_tag:depends({ [_n("protocol")] = "_shunt", [_n("fakedns")] = true, [_n(e[".name"])] = v.id }) - end - for k, v in pairs(balancers_table) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - end - for k, v in pairs(iface_table) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - end - for k, v in pairs(nodes_table) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - if not api.is_local_ip(v.address) then --本地节点禁止使用前置 - pt:depends({ [_n("protocol")] = "_shunt", [_n("preproxy_enabled")] = true, [_n(e[".name"])] = v.id }) - end - fakedns_tag:depends({ [_n("protocol")] = "_shunt", [_n("fakedns")] = true, [_n(e[".name"])] = v.id }) - end - if default_node ~= "_direct" or default_node ~= "_blackhole" then - fakedns_tag:depends({ [_n("protocol")] = "_shunt", [_n("fakedns")] = true, [_n(e[".name"])] = "_default" }) - end - end - end - end) - - o = s:option(DummyValue, _n("shunt_tips"), " ") - o.not_rewrite = true - o.rawhtml = true - o.cfgvalue = function(t, n) - return string.format('%s', translate("No shunt rules? Click me to go to add.")) - end - o:depends({ [_n("protocol")] = "_shunt" }) - - local o = s:option(ListValue, _n("default_node"), string.format('* %s', translate("Default"))) - o:depends({ [_n("protocol")] = "_shunt" }) - o:value("_direct", translate("Direct Connection")) - o:value("_blackhole", translate("Blackhole")) - o.template = appname .. "/cbi/nodes_listvalue" - o.group = {"",""} +if load_iface_options then -- [[ 自定义接口 Start ]] + o = s:option(Value, _n("iface"), translate("Interface")) + o.default = "eth1" + o:depends({ [_n("protocol")] = "_iface" }) +end -- [[ 自定义接口 End ]] - if #nodes_table > 0 then - for k, v in pairs(socks_list) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - end - for k, v in pairs(balancers_table) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - end - for k, v in pairs(iface_table) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - end - local dpt = s:option(ListValue, _n("default_proxy_tag"), string.format('* %s', translate("Default Preproxy")), translate("When using, localhost will connect this node first and then use this node to connect the default node.")) - dpt:value("", translate("Close")) - dpt:value("main", translate("Preproxy Node")) - dpt:depends("__hide__", "1") - for k, v in pairs(nodes_table) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - if not api.is_local_ip(v.address) then - dpt:depends({ [_n("protocol")] = "_shunt", [_n("preproxy_enabled")] = true, [_n("default_node")] = v.id }) - end - end - end - o = s:option(ListValue, _n("domainStrategy"), translate("Domain Strategy")) - o:value("AsIs") - o:value("IPIfNonMatch") - o:value("IPOnDemand") - o.default = "IPOnDemand" - o.description = "
" - o:depends({ [_n("protocol")] = "_shunt" }) - - o = s:option(ListValue, _n("domainMatcher"), translate("Domain matcher")) - o:value("hybrid") - o:value("linear") - o:depends({ [_n("protocol")] = "_shunt" }) -end -- [[ 分流模块 End ]] - -if s.val["protocol"] == "_iface" then -- [[ 自定义接口 Start ]] -o = s:option(Value, _n("iface"), translate("Interface")) -o.default = "eth1" -o:depends({ [_n("protocol")] = "_iface" }) -end -- [[ 自定义接口 End ]] +if load_normal_options then o = s:option(Value, _n("address"), translate("Address (Support Domain Name)")) @@ -509,7 +400,7 @@ o:depends({ [_n("tls")] = true, [_n("reality")] = false }) o = s:option(Flag, _n("ech"), translate("ECH")) o.default = "0" -o:depends({ [_n("tls")] = true, [_n("flow")] = "", [_n("reality")] = false }) +o:depends({ [_n("tls")] = true, [_n("reality")] = false }) o:depends({ [_n("protocol")] = "hysteria2" }) o = s:option(TextValue, _n("ech_config"), translate("ECH Config")) @@ -847,4 +738,6 @@ for i, v in ipairs(s.fields[_n("protocol")].keylist) do end end +end + api.luci_types(arg[1], m, s, type_name, option_prefix) diff --git a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua index 312cced5c3..874b00518c 100644 --- a/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua +++ b/applications/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua @@ -29,6 +29,13 @@ local function _n(name) return option_prefix .. name end +local formvalue_key = "cbid." .. appname .. "." .. arg[1] .. "." +local formvalue_proto = luci.http.formvalue(formvalue_key .. _n("protocol")) + +if formvalue_proto then s.val["protocol"] = formvalue_proto end + +local arg_select_proto = luci.http.formvalue("select_proto") or "" + local ss_method_new_list = { "none", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" } @@ -68,8 +75,24 @@ if version_ge_1_12_0 then end o:value("ssh", "SSH") o:value("_urltest", translate("URLTest")) -o:value("_shunt", translate("Shunt")) o:value("_iface", translate("Custom Interface")) +function o.custom_cfgvalue(self, section) + if arg_select_proto ~= "" then + return arg_select_proto + else + return m:get(section, self.option:sub(1 + #option_prefix)) + end +end + +local load_urltest_options = s.val["protocol"] == "_urltest" or arg_select_proto == "_urltest" +local load_iface_options = s.val["protocol"] == "_iface" or arg_select_proto == "_iface" +local load_normal_options = true +if load_urltest_options or load_iface_options then + load_normal_options = nil +end +if not arg_select_proto:find("_") then + load_normal_options = true +end local nodes_table = {} local iface_table = {} @@ -112,7 +135,7 @@ m.uci:foreach(appname, "socks", function(s) end end) -if s.val["protocol"] == "_urltest" then -- [[ URLTest Start ]] +if load_urltest_options then -- [[ URLTest Start ]] o = s:option(MultiValue, _n("urltest_node"), translate("URLTest node list"), translate("List of nodes to test, document")) o:depends({ [_n("protocol")] = "_urltest" }) o.widget = "checkbox" @@ -191,131 +214,15 @@ if s.val["protocol"] == "_urltest" then -- [[ URLTest Start ]] o.description = translate("Interrupt existing connections when the selected outbound has changed.") end -- [[ URLTest End ]] -if s.val["protocol"] == "_shunt" then -- [[ 分流模块 Start ]] - local default_node = m.uci:get(appname, arg[1], "default_node") or "_direct" - if #nodes_table > 0 then - o = s:option(Flag, _n("preproxy_enabled"), translate("Preproxy")) - o:depends({ [_n("protocol")] = "_shunt" }) - - o = s:option(ListValue, _n("main_node"), string.format('%s', translate("Preproxy Node")), translate("Set the node to be used as a pre-proxy. Each rule (including Default) has a separate switch that controls whether this rule uses the pre-proxy or not.")) - o:depends({ [_n("protocol")] = "_shunt", [_n("preproxy_enabled")] = true }) - o.template = appname .. "/cbi/nodes_listvalue" - o.group = {} - for k, v in pairs(socks_list) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - end - for k, v in pairs(urltest_table) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - end - for k, v in pairs(iface_table) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - end - for k, v in pairs(nodes_table) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - end - - o = s:option(Flag, _n("fakedns"), "FakeDNS", translate("Use FakeDNS work in the shunt domain that proxy.")) - o:depends({ [_n("protocol")] = "_shunt" }) - end - m.uci:foreach(appname, "shunt_rules", function(e) - if e[".name"] and e.remarks then - o = s:option(ListValue, _n(e[".name"]), string.format('* %s', api.url("shunt_rules", e[".name"]), e.remarks)) - o:value("", translate("Close")) - o:value("_default", translate("Default")) - o:value("_direct", translate("Direct Connection")) - o:value("_blackhole", translate("Blackhole")) - o:depends({ [_n("protocol")] = "_shunt" }) - o.template = appname .. "/cbi/nodes_listvalue" - o.group = {"","","",""} - - if #nodes_table > 0 then - local pt = s:option(ListValue, _n(e[".name"] .. "_proxy_tag"), string.format('* %s', e.remarks .. " " .. translate("Preproxy"))) - pt:value("", translate("Close")) - pt:value("main", translate("Preproxy Node")) - pt:depends("__hide__", "1") - - local fakedns_tag = s:option(Flag, _n(e[".name"] .. "_fakedns"), string.format('* %s', e.remarks .. " " .. "FakeDNS")) - - for k, v in pairs(socks_list) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - fakedns_tag:depends({ [_n("protocol")] = "_shunt", [_n("fakedns")] = true, [_n(e[".name"])] = v.id }) - end - for k, v in pairs(urltest_table) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - end - for k, v in pairs(iface_table) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - end - for k, v in pairs(nodes_table) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - if not api.is_local_ip(v.address) then --本地节点禁止使用前置 - pt:depends({ [_n("protocol")] = "_shunt", [_n("preproxy_enabled")] = true, [_n(e[".name"])] = v.id }) - end - fakedns_tag:depends({ [_n("protocol")] = "_shunt", [_n("fakedns")] = true, [_n(e[".name"])] = v.id }) - end - if default_node ~= "_direct" or default_node ~= "_blackhole" then - fakedns_tag:depends({ [_n("protocol")] = "_shunt", [_n("fakedns")] = true, [_n(e[".name"])] = "_default" }) - end - end - end - end) - - o = s:option(DummyValue, _n("shunt_tips"), " ") - o.not_rewrite = true - o.rawhtml = true - o.cfgvalue = function(t, n) - return string.format('%s', translate("No shunt rules? Click me to go to add.")) - end - o:depends({ [_n("protocol")] = "_shunt" }) - - local o = s:option(ListValue, _n("default_node"), string.format('* %s', translate("Default"))) - o:depends({ [_n("protocol")] = "_shunt" }) - o:value("_direct", translate("Direct Connection")) - o:value("_blackhole", translate("Blackhole")) - o.template = appname .. "/cbi/nodes_listvalue" - o.group = {"",""} - - if #nodes_table > 0 then - for k, v in pairs(socks_list) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - end - for k, v in pairs(urltest_table) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - end - for k, v in pairs(iface_table) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - end - local dpt = s:option(ListValue, _n("default_proxy_tag"), string.format('* %s', translate("Default Preproxy")), translate("When using, localhost will connect this node first and then use this node to connect the default node.")) - dpt:value("", translate("Close")) - dpt:value("main", translate("Preproxy Node")) - dpt:depends("__hide__", "1") - for k, v in pairs(nodes_table) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - if not api.is_local_ip(v.address) then - dpt:depends({ [_n("protocol")] = "_shunt", [_n("preproxy_enabled")] = true, [_n("default_node")] = v.id }) - end - end - end -end -- [[ 分流模块 End ]] - -if s.val["protocol"] == "_iface" then -- [[ 自定义接口 Start ]] +if load_iface_options then -- [[ 自定义接口 Start ]] o = s:option(Value, _n("iface"), translate("Interface")) o.default = "eth1" o:depends({ [_n("protocol")] = "_iface" }) end + +if load_normal_options then + o = s:option(Value, _n("address"), translate("Address (Support Domain Name)")) o = s:option(Value, _n("port"), translate("Port")) @@ -877,4 +784,6 @@ for k, v in pairs(nodes_table) do end end +end + api.luci_types(arg[1], m, s, type_name, option_prefix) diff --git a/applications/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ray.lua b/applications/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ray.lua index d42e2e3c57..7d0a2769b6 100644 --- a/applications/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ray.lua +++ b/applications/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ray.lua @@ -243,7 +243,7 @@ end o = s:option(Flag, _n("ech"), translate("ECH")) o.default = "0" -o:depends({ [_n("tls")] = true, [_n("flow")] = "", [_n("reality")] = false }) +o:depends({ [_n("tls")] = true, [_n("reality")] = false }) o = s:option(TextValue, _n("ech_key"), translate("ECH Key")) o.default = "" diff --git a/applications/luci-app-passwall/luasrc/passwall/util_hysteria2.lua b/applications/luci-app-passwall/luasrc/passwall/util_hysteria2.lua index f2668e4732..4053bc91f4 100644 --- a/applications/luci-app-passwall/luasrc/passwall/util_hysteria2.lua +++ b/applications/luci-app-passwall/luasrc/passwall/util_hysteria2.lua @@ -31,25 +31,25 @@ function gen_config_server(node) end function gen_config(var) - local node_id = var["-node"] + local node_id = var["node"] if not node_id then - print("-node 不能为空") + print("node 不能为空") return end local node = uci:get_all("passwall", node_id) - local local_tcp_redir_port = var["-local_tcp_redir_port"] - local local_udp_redir_port = var["-local_udp_redir_port"] - local local_socks_address = var["-local_socks_address"] or "0.0.0.0" - local local_socks_port = var["-local_socks_port"] - local local_socks_username = var["-local_socks_username"] - local local_socks_password = var["-local_socks_password"] - local local_http_address = var["-local_http_address"] or "0.0.0.0" - local local_http_port = var["-local_http_port"] - local local_http_username = var["-local_http_username"] - local local_http_password = var["-local_http_password"] - local tcp_proxy_way = var["-tcp_proxy_way"] - local server_host = var["-server_host"] or node.address - local server_port = var["-server_port"] or node.port + local local_tcp_redir_port = var["local_tcp_redir_port"] + local local_udp_redir_port = var["local_udp_redir_port"] + local local_socks_address = var["local_socks_address"] or "0.0.0.0" + local local_socks_port = var["local_socks_port"] + local local_socks_username = var["local_socks_username"] + local local_socks_password = var["local_socks_password"] + local local_http_address = var["local_http_address"] or "0.0.0.0" + local local_http_port = var["local_http_port"] + local local_http_username = var["local_http_username"] + local local_http_password = var["local_http_password"] + local tcp_proxy_way = var["tcp_proxy_way"] + local server_host = var["server_host"] or node.address + local server_port = var["server_port"] or node.port if api.is_ipv6(server_host) then server_host = api.get_ipv6_full(server_host) @@ -136,6 +136,10 @@ _G.gen_config = gen_config if arg[1] then local func =_G[arg[1]] if func then - print(func(api.get_function_args(arg))) + local var = nil + if arg[2] then + var = jsonc.parse(arg[2]) + end + print(func(var)) end end diff --git a/applications/luci-app-passwall/luasrc/passwall/util_naiveproxy.lua b/applications/luci-app-passwall/luasrc/passwall/util_naiveproxy.lua index ee095c1e6c..194a87ef7f 100644 --- a/applications/luci-app-passwall/luasrc/passwall/util_naiveproxy.lua +++ b/applications/luci-app-passwall/luasrc/passwall/util_naiveproxy.lua @@ -4,17 +4,17 @@ local uci = api.uci local jsonc = api.jsonc function gen_config(var) - local node_id = var["-node"] + local node_id = var["node"] if not node_id then - print("-node 不能为空") + print("node 不能为空") return end local node = uci:get_all("passwall", node_id) - local run_type = var["-run_type"] - local local_addr = var["-local_addr"] - local local_port = var["-local_port"] - local server_host = var["-server_host"] or node.address - local server_port = var["-server_port"] or node.port + local run_type = var["run_type"] + local local_addr = var["local_addr"] + local local_port = var["local_port"] + local server_host = var["server_host"] or node.address + local server_port = var["server_port"] or node.port if api.is_ipv6(server_host) then server_host = api.get_ipv6_full(server_host) @@ -34,6 +34,10 @@ _G.gen_config = gen_config if arg[1] then local func =_G[arg[1]] if func then - print(func(api.get_function_args(arg))) + local var = nil + if arg[2] then + var = jsonc.parse(arg[2]) + end + print(func(var)) end end diff --git a/applications/luci-app-passwall/luasrc/passwall/util_shadowsocks.lua b/applications/luci-app-passwall/luasrc/passwall/util_shadowsocks.lua index 4b70f06a98..d17e91e0d6 100644 --- a/applications/luci-app-passwall/luasrc/passwall/util_shadowsocks.lua +++ b/applications/luci-app-passwall/luasrc/passwall/util_shadowsocks.lua @@ -31,29 +31,29 @@ end local plugin_sh, plugin_bin function gen_config(var) - local node_id = var["-node"] + local node_id = var["node"] if not node_id then - print("-node 不能为空") + print("node 不能为空") return end local node = uci:get_all("passwall", node_id) - local server_host = var["-server_host"] or node.address - local server_port = var["-server_port"] or node.port - local local_addr = var["-local_addr"] - local local_port = var["-local_port"] - local mode = var["-mode"] - local local_socks_address = var["-local_socks_address"] or "0.0.0.0" - local local_socks_port = var["-local_socks_port"] - local local_socks_username = var["-local_socks_username"] - local local_socks_password = var["-local_socks_password"] - local local_http_address = var["-local_http_address"] or "0.0.0.0" - local local_http_port = var["-local_http_port"] - local local_http_username = var["-local_http_username"] - local local_http_password = var["-local_http_password"] - local local_tcp_redir_port = var["-local_tcp_redir_port"] - local local_tcp_redir_address = var["-local_tcp_redir_address"] or "0.0.0.0" - local local_udp_redir_port = var["-local_udp_redir_port"] - local local_udp_redir_address = var["-local_udp_redir_address"] or "0.0.0.0" + local server_host = var["server_host"] or node.address + local server_port = var["server_port"] or node.port + local local_addr = var["local_addr"] + local local_port = var["local_port"] + local mode = var["mode"] + local local_socks_address = var["local_socks_address"] or "0.0.0.0" + local local_socks_port = var["local_socks_port"] + local local_socks_username = var["local_socks_username"] + local local_socks_password = var["local_socks_password"] + local local_http_address = var["local_http_address"] or "0.0.0.0" + local local_http_port = var["local_http_port"] + local local_http_username = var["local_http_username"] + local local_http_password = var["local_http_password"] + local local_tcp_redir_port = var["local_tcp_redir_port"] + local local_tcp_redir_address = var["local_tcp_redir_address"] or "0.0.0.0" + local local_udp_redir_port = var["local_udp_redir_port"] + local local_udp_redir_address = var["local_udp_redir_address"] or "0.0.0.0" if api.is_ipv6(server_host) then server_host = api.get_ipv6_only(server_host) @@ -62,7 +62,7 @@ function gen_config(var) local plugin_file if node.plugin and node.plugin ~= "" and node.plugin ~= "none" then - plugin_sh = var["-plugin_sh"] or "" + plugin_sh = var["plugin_sh"] or "" plugin_file = (plugin_sh ~="") and plugin_sh or node.plugin plugin_bin = node.plugin end @@ -77,7 +77,7 @@ function gen_config(var) timeout = tonumber(node.timeout), fast_open = (node.tcp_fast_open and node.tcp_fast_open == "true") and true or false, reuse_port = true, - tcp_tproxy = var["-tcp_tproxy"] and true or nil + tcp_tproxy = var["tcp_tproxy"] and true or nil } if node.type == "SS" then @@ -123,7 +123,7 @@ function gen_config(var) table.insert(config.locals, { protocol = "redir", mode = "tcp_only", - tcp_redir = var["-tcp_tproxy"] and "tproxy" or nil, + tcp_redir = var["tcp_tproxy"] and "tproxy" or nil, local_address = local_tcp_redir_address, local_port = tonumber(local_tcp_redir_port) }) @@ -146,7 +146,11 @@ _G.gen_config = gen_config if arg[1] then local func =_G[arg[1]] if func then - print(func(api.get_function_args(arg))) + local var = nil + if arg[2] then + var = jsonc.parse(arg[2]) + end + print(func(var)) if plugin_sh and plugin_sh ~="" and plugin_bin then local f = io.open(plugin_sh, "w") f:write("#!/bin/sh\n") diff --git a/applications/luci-app-passwall/luasrc/passwall/util_sing-box.lua b/applications/luci-app-passwall/luasrc/passwall/util_sing-box.lua index 9f18299e8c..ba09924b9a 100644 --- a/applications/luci-app-passwall/luasrc/passwall/util_sing-box.lua +++ b/applications/luci-app-passwall/luasrc/passwall/util_sing-box.lua @@ -43,9 +43,9 @@ function geo_convert_srs(var) if check_geoview() ~= 1 then return end - local geo_path = var["-geo_path"] - local prefix = var["-prefix"] - local rule_name = var["-rule_name"] + local geo_path = var["geo_path"] + local prefix = var["prefix"] + local rule_name = var["rule_name"] local output_srs_file = GEO_VAR.TO_SRS_PATH .. prefix .. "-" .. rule_name .. ".srs" if not fs.access(output_srs_file) then local cmd = string.format("geoview -type %s -action convert -input '%s' -list '%s' -output '%s' -lowmem=true", @@ -72,7 +72,7 @@ local function convert_geofile() sys.call("rm -rf " .. GEO_VAR.TO_SRS_PATH .. prefix .. "-*.srs" ) end for k in pairs(tags) do - geo_convert_srs({["-geo_path"] = file_path, ["-prefix"] = prefix, ["-rule_name"] = k}) + geo_convert_srs({["geo_path"] = file_path, ["prefix"] = prefix, ["rule_name"] = k}) end end end @@ -892,42 +892,42 @@ function gen_config_server(node) end function gen_config(var) - local flag = var["-flag"] - local log = var["-log"] or "0" - local loglevel = var["-loglevel"] or "warn" - local logfile = var["-logfile"] or "/dev/null" - local node_id = var["-node"] - local server_host = var["-server_host"] - local server_port = var["-server_port"] - local tcp_proxy_way = var["-tcp_proxy_way"] - local tcp_redir_port = var["-tcp_redir_port"] - local udp_redir_port = var["-udp_redir_port"] - local local_socks_address = var["-local_socks_address"] or "0.0.0.0" - local local_socks_port = var["-local_socks_port"] - local local_socks_username = var["-local_socks_username"] - local local_socks_password = var["-local_socks_password"] - local local_http_address = var["-local_http_address"] or "0.0.0.0" - local local_http_port = var["-local_http_port"] - local local_http_username = var["-local_http_username"] - local local_http_password = var["-local_http_password"] - local dns_listen_port = var["-dns_listen_port"] - local direct_dns_port = var["-direct_dns_port"] - local direct_dns_udp_server = var["-direct_dns_udp_server"] - local direct_dns_tcp_server = var["-direct_dns_tcp_server"] - local direct_dns_query_strategy = var["-direct_dns_query_strategy"] - local remote_dns_server = var["-remote_dns_server"] - local remote_dns_port = var["-remote_dns_port"] - local remote_dns_udp_server = var["-remote_dns_udp_server"] - local remote_dns_tcp_server = var["-remote_dns_tcp_server"] - local remote_dns_doh_url = var["-remote_dns_doh_url"] - local remote_dns_doh_host = var["-remote_dns_doh_host"] - local remote_dns_client_ip = var["-remote_dns_client_ip"] - local remote_dns_query_strategy = var["-remote_dns_query_strategy"] - local remote_dns_fake = var["-remote_dns_fake"] - local dns_cache = var["-dns_cache"] - local dns_socks_address = var["-dns_socks_address"] - local dns_socks_port = var["-dns_socks_port"] - local no_run = var["-no_run"] + local flag = var["flag"] + local log = var["log"] or "0" + local loglevel = var["loglevel"] or "warn" + local logfile = var["logfile"] or "/dev/null" + local node_id = var["node"] + local server_host = var["server_host"] + local server_port = var["server_port"] + local tcp_proxy_way = var["tcp_proxy_way"] + local tcp_redir_port = var["tcp_redir_port"] + local udp_redir_port = var["udp_redir_port"] + local local_socks_address = var["local_socks_address"] or "0.0.0.0" + local local_socks_port = var["local_socks_port"] + local local_socks_username = var["local_socks_username"] + local local_socks_password = var["local_socks_password"] + local local_http_address = var["local_http_address"] or "0.0.0.0" + local local_http_port = var["local_http_port"] + local local_http_username = var["local_http_username"] + local local_http_password = var["local_http_password"] + local dns_listen_port = var["dns_listen_port"] + local direct_dns_port = var["direct_dns_port"] + local direct_dns_udp_server = var["direct_dns_udp_server"] + local direct_dns_tcp_server = var["direct_dns_tcp_server"] + local direct_dns_query_strategy = var["direct_dns_query_strategy"] + local remote_dns_server = var["remote_dns_server"] + local remote_dns_port = var["remote_dns_port"] + local remote_dns_udp_server = var["remote_dns_udp_server"] + local remote_dns_tcp_server = var["remote_dns_tcp_server"] + local remote_dns_doh_url = var["remote_dns_doh_url"] + local remote_dns_doh_host = var["remote_dns_doh_host"] + local remote_dns_client_ip = var["remote_dns_client_ip"] + local remote_dns_query_strategy = var["remote_dns_query_strategy"] + local remote_dns_fake = var["remote_dns_fake"] + local dns_cache = var["dns_cache"] + local dns_socks_address = var["dns_socks_address"] + local dns_socks_port = var["dns_socks_port"] + local no_run = var["no_run"] local dns_domain_rules = {} local dns = nil @@ -2050,19 +2050,19 @@ function gen_config(var) end function gen_proto_config(var) - local local_socks_address = var["-local_socks_address"] or "0.0.0.0" - local local_socks_port = var["-local_socks_port"] - local local_socks_username = var["-local_socks_username"] - local local_socks_password = var["-local_socks_password"] - local local_http_address = var["-local_http_address"] or "0.0.0.0" - local local_http_port = var["-local_http_port"] - local local_http_username = var["-local_http_username"] - local local_http_password = var["-local_http_password"] - local server_proto = var["-server_proto"] - local server_address = var["-server_address"] - local server_port = var["-server_port"] - local server_username = var["-server_username"] - local server_password = var["-server_password"] + local local_socks_address = var["local_socks_address"] or "0.0.0.0" + local local_socks_port = var["local_socks_port"] + local local_socks_username = var["local_socks_username"] + local local_socks_password = var["local_socks_password"] + local local_http_address = var["local_http_address"] or "0.0.0.0" + local local_http_port = var["local_http_port"] + local local_http_username = var["local_http_username"] + local local_http_password = var["local_http_password"] + local server_proto = var["server_proto"] + local server_address = var["server_address"] + local server_port = var["server_port"] + local server_username = var["server_username"] + local server_password = var["server_password"] local inbounds = {} local outbounds = {} @@ -2135,7 +2135,11 @@ _G.geo_convert_srs = geo_convert_srs if arg[1] then local func =_G[arg[1]] if func then - print(func(api.get_function_args(arg))) + local var = nil + if arg[2] then + var = jsonc.parse(arg[2]) + end + print(func(var)) if (next(GEO_VAR.SITE_TAGS) or next(GEO_VAR.IP_TAGS)) and not no_run then convert_geofile() end diff --git a/applications/luci-app-passwall/luasrc/passwall/util_trojan.lua b/applications/luci-app-passwall/luasrc/passwall/util_trojan.lua index 848b689a56..29cb467d8d 100644 --- a/applications/luci-app-passwall/luasrc/passwall/util_trojan.lua +++ b/applications/luci-app-passwall/luasrc/passwall/util_trojan.lua @@ -1,7 +1,7 @@ module("luci.passwall.util_trojan", package.seeall) local api = require "luci.passwall.api" local uci = api.uci -local json = api.jsonc +local jsonc = api.jsonc function gen_config_server(node) local cipher = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA" @@ -41,18 +41,18 @@ function gen_config_server(node) end function gen_config(var) - local node_id = var["-node"] + local node_id = var["node"] if not node_id then - print("-node 不能为空") + print("node 不能为空") return end local node = uci:get_all("passwall", node_id) - local run_type = var["-run_type"] - local local_addr = var["-local_addr"] - local local_port = var["-local_port"] - local server_host = var["-server_host"] or node.address - local server_port = var["-server_port"] or node.port - local loglevel = var["-loglevel"] or 2 + local run_type = var["run_type"] + local local_addr = var["local_addr"] + local local_port = var["local_port"] + local server_host = var["server_host"] or node.address + local server_port = var["server_port"] or node.port + local loglevel = var["loglevel"] or 2 local cipher = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:AES128-SHA:AES256-SHA:DES-CBC3-SHA" local cipher13 = "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384" @@ -83,7 +83,7 @@ function gen_config(var) }, udp_timeout = 60, tcp = { - use_tproxy = (node.type == "Trojan-Plus" and var["-use_tproxy"]) and true or nil, + use_tproxy = (node.type == "Trojan-Plus" and var["use_tproxy"]) and true or nil, no_delay = true, keep_alive = true, reuse_port = true, @@ -91,7 +91,7 @@ function gen_config(var) fast_open_qlen = 20 } } - return json.stringify(trojan, 1) + return jsonc.stringify(trojan, 1) end _G.gen_config = gen_config @@ -99,6 +99,10 @@ _G.gen_config = gen_config if arg[1] then local func =_G[arg[1]] if func then - print(func(api.get_function_args(arg))) + local var = nil + if arg[2] then + var = jsonc.parse(arg[2]) + end + print(func(var)) end end diff --git a/applications/luci-app-passwall/luasrc/passwall/util_tuic.lua b/applications/luci-app-passwall/luasrc/passwall/util_tuic.lua index e138b6da56..94853943cc 100644 --- a/applications/luci-app-passwall/luasrc/passwall/util_tuic.lua +++ b/applications/luci-app-passwall/luasrc/passwall/util_tuic.lua @@ -1,20 +1,20 @@ module("luci.passwall.util_tuic", package.seeall) local api = require "luci.passwall.api" local uci = api.uci -local json = api.jsonc +local jsonc = api.jsonc function gen_config(var) - local node_id = var["-node"] + local node_id = var["node"] if not node_id then - print("-node 不能为空") + print("node 不能为空") return end local node = uci:get_all("passwall", node_id) - local local_addr = var["-local_addr"] - local local_port = var["-local_port"] - local server_host = var["-server_host"] or node.address - local server_port = var["-server_port"] or node.port - local loglevel = var["-loglevel"] or "warn" + local local_addr = var["local_addr"] + local local_port = var["local_port"] + local server_host = var["server_host"] or node.address + local server_port = var["server_port"] or node.port + local loglevel = var["loglevel"] or "warn" local tuic= { relay = { @@ -44,7 +44,7 @@ function gen_config(var) }, log_level = loglevel } - return json.stringify(tuic, 1) + return jsonc.stringify(tuic, 1) end _G.gen_config = gen_config @@ -52,6 +52,10 @@ _G.gen_config = gen_config if arg[1] then local func =_G[arg[1]] if func then - print(func(api.get_function_args(arg))) + local var = nil + if arg[2] then + var = jsonc.parse(arg[2]) + end + print(func(var)) end end diff --git a/applications/luci-app-passwall/luasrc/passwall/util_xray.lua b/applications/luci-app-passwall/luasrc/passwall/util_xray.lua index a09af5d945..17beaf7253 100644 --- a/applications/luci-app-passwall/luasrc/passwall/util_xray.lua +++ b/applications/luci-app-passwall/luasrc/passwall/util_xray.lua @@ -151,7 +151,7 @@ function gen_outbound(flag, node, tag, proxy_table) serverName = node.tls_serverName, allowInsecure = (node.tls_allowInsecure == "1") and true or false, fingerprint = (node.type == "Xray" and node.utls == "1" and node.fingerprint and node.fingerprint ~= "") and node.fingerprint or nil, - pinnedPeerCertificateChainSha256 = node.tls_chain_fingerprint and { node.tls_chain_fingerprint } or nil, + pinnedPeerCertSha256 = node.tls_chain_fingerprint or nil, echConfigList = (node.ech == "1") and node.ech_config or nil, echForceQuery = (node.ech == "1") and (node.ech_ForceQuery or "none") or nil } or nil, @@ -614,42 +614,42 @@ function gen_config_server(node) end function gen_config(var) - local flag = var["-flag"] - local node_id = var["-node"] - local server_host = var["-server_host"] - local server_port = var["-server_port"] - local tcp_proxy_way = var["-tcp_proxy_way"] or "redirect" - local tcp_redir_port = var["-tcp_redir_port"] - local udp_redir_port = var["-udp_redir_port"] - local local_socks_address = var["-local_socks_address"] or "0.0.0.0" - local local_socks_port = var["-local_socks_port"] - local local_socks_username = var["-local_socks_username"] - local local_socks_password = var["-local_socks_password"] - local local_http_address = var["-local_http_address"] or "0.0.0.0" - local local_http_port = var["-local_http_port"] - local local_http_username = var["-local_http_username"] - local local_http_password = var["-local_http_password"] - local dns_listen_port = var["-dns_listen_port"] - local dns_cache = var["-dns_cache"] - local direct_dns_port = var["-direct_dns_port"] - local direct_dns_udp_server = var["-direct_dns_udp_server"] - local direct_dns_tcp_server = var["-direct_dns_tcp_server"] - local direct_dns_query_strategy = var["-direct_dns_query_strategy"] - local remote_dns_udp_server = var["-remote_dns_udp_server"] - local remote_dns_udp_port = var["-remote_dns_udp_port"] - local remote_dns_tcp_server = var["-remote_dns_tcp_server"] - local remote_dns_tcp_port = var["-remote_dns_tcp_port"] - local remote_dns_doh_url = var["-remote_dns_doh_url"] - local remote_dns_doh_host = var["-remote_dns_doh_host"] - local remote_dns_doh_ip = var["-remote_dns_doh_ip"] - local remote_dns_doh_port = var["-remote_dns_doh_port"] - local remote_dns_client_ip = var["-remote_dns_client_ip"] - local remote_dns_fake = var["-remote_dns_fake"] - local remote_dns_query_strategy = var["-remote_dns_query_strategy"] - local dns_socks_address = var["-dns_socks_address"] - local dns_socks_port = var["-dns_socks_port"] - local loglevel = var["-loglevel"] or "warning" - local no_run = var["-no_run"] + local flag = var["flag"] + local node_id = var["node"] + local server_host = var["server_host"] + local server_port = var["server_port"] + local tcp_proxy_way = var["tcp_proxy_way"] or "redirect" + local tcp_redir_port = var["tcp_redir_port"] + local udp_redir_port = var["udp_redir_port"] + local local_socks_address = var["local_socks_address"] or "0.0.0.0" + local local_socks_port = var["local_socks_port"] + local local_socks_username = var["local_socks_username"] + local local_socks_password = var["local_socks_password"] + local local_http_address = var["local_http_address"] or "0.0.0.0" + local local_http_port = var["local_http_port"] + local local_http_username = var["local_http_username"] + local local_http_password = var["local_http_password"] + local dns_listen_port = var["dns_listen_port"] + local dns_cache = var["dns_cache"] + local direct_dns_port = var["direct_dns_port"] + local direct_dns_udp_server = var["direct_dns_udp_server"] + local direct_dns_tcp_server = var["direct_dns_tcp_server"] + local direct_dns_query_strategy = var["direct_dns_query_strategy"] + local remote_dns_udp_server = var["remote_dns_udp_server"] + local remote_dns_udp_port = var["remote_dns_udp_port"] + local remote_dns_tcp_server = var["remote_dns_tcp_server"] + local remote_dns_tcp_port = var["remote_dns_tcp_port"] + local remote_dns_doh_url = var["remote_dns_doh_url"] + local remote_dns_doh_host = var["remote_dns_doh_host"] + local remote_dns_doh_ip = var["remote_dns_doh_ip"] + local remote_dns_doh_port = var["remote_dns_doh_port"] + local remote_dns_client_ip = var["remote_dns_client_ip"] + local remote_dns_fake = var["remote_dns_fake"] + local remote_dns_query_strategy = var["remote_dns_query_strategy"] + local dns_socks_address = var["dns_socks_address"] + local dns_socks_port = var["dns_socks_port"] + local loglevel = var["loglevel"] or "warning" + local no_run = var["no_run"] local dns_domain_rules = {} local dns = nil @@ -1686,19 +1686,19 @@ function gen_config(var) end function gen_proto_config(var) - local local_socks_address = var["-local_socks_address"] or "0.0.0.0" - local local_socks_port = var["-local_socks_port"] - local local_socks_username = var["-local_socks_username"] - local local_socks_password = var["-local_socks_password"] - local local_http_address = var["-local_http_address"] or "0.0.0.0" - local local_http_port = var["-local_http_port"] - local local_http_username = var["-local_http_username"] - local local_http_password = var["-local_http_password"] - local server_proto = var["-server_proto"] - local server_address = var["-server_address"] - local server_port = var["-server_port"] - local server_username = var["-server_username"] - local server_password = var["-server_password"] + local local_socks_address = var["local_socks_address"] or "0.0.0.0" + local local_socks_port = var["local_socks_port"] + local local_socks_username = var["local_socks_username"] + local local_socks_password = var["local_socks_password"] + local local_http_address = var["local_http_address"] or "0.0.0.0" + local local_http_port = var["local_http_port"] + local local_http_username = var["local_http_username"] + local local_http_password = var["local_http_password"] + local server_proto = var["server_proto"] + local server_address = var["server_address"] + local server_port = var["server_port"] + local server_username = var["server_username"] + local server_password = var["server_password"] local inbounds = {} local outbounds = {} @@ -1796,6 +1796,10 @@ _G.gen_proto_config = gen_proto_config if arg[1] then local func =_G[arg[1]] if func then - print(func(api.get_function_args(arg))) + local var = nil + if arg[2] then + var = jsonc.parse(arg[2]) + end + print(func(var)) end end diff --git a/applications/luci-app-passwall/luasrc/view/passwall/cbi/nodes_listvalue.htm b/applications/luci-app-passwall/luasrc/view/passwall/cbi/nodes_listvalue.htm index 2081a531b9..9ba659c4fb 100644 --- a/applications/luci-app-passwall/luasrc/view/passwall/cbi/nodes_listvalue.htm +++ b/applications/luci-app-passwall/luasrc/view/passwall/cbi/nodes_listvalue.htm @@ -113,8 +113,6 @@ -<%+cbi/valuefooter%> - + +<%+cbi/valuefooter%> diff --git a/applications/luci-app-passwall/luasrc/view/passwall/cbi/nodes_listvalue_com.htm b/applications/luci-app-passwall/luasrc/view/passwall/cbi/nodes_listvalue_com.htm index 84acd5a760..6e6951c08c 100644 --- a/applications/luci-app-passwall/luasrc/view/passwall/cbi/nodes_listvalue_com.htm +++ b/applications/luci-app-passwall/luasrc/view/passwall/cbi/nodes_listvalue_com.htm @@ -104,6 +104,7 @@ box-shadow: 0 6px 18px rgba(0,0,0,0.08); max-height: 50vh; overflow: auto; + overscroll-behavior: contain; } .lv-dropdown-search { width: 100%; @@ -669,6 +670,25 @@ } }); }); + + // 防止 panel 惯性滚动穿透 + panel.addEventListener('wheel', function (e) { + const deltaY = e.deltaY; + const scrollTop = panel.scrollTop; + const scrollHeight = panel.scrollHeight; + const clientHeight = panel.clientHeight; + const isAtTop = scrollTop === 0; + const isAtBottom = scrollTop + clientHeight >= scrollHeight; + if (deltaY < 0 && isAtTop) { + e.preventDefault(); + return; + } + if (deltaY > 0 && isAtBottom) { + e.preventDefault(); + return; + } + e.stopPropagation(); + }, { passive: false }); } const lv_adaptiveControls = new Set(); diff --git a/applications/luci-app-passwall/luasrc/view/passwall/cbi/nodes_multivalue.htm b/applications/luci-app-passwall/luasrc/view/passwall/cbi/nodes_multivalue.htm index 88920275ff..fde96d7deb 100644 --- a/applications/luci-app-passwall/luasrc/view/passwall/cbi/nodes_multivalue.htm +++ b/applications/luci-app-passwall/luasrc/view/passwall/cbi/nodes_multivalue.htm @@ -108,7 +108,6 @@ <%:Selected:%> <%=selected_count%>/<%=total_count%> -<%+cbi/valuefooter%> + +<%+cbi/valuefooter%> diff --git a/applications/luci-app-passwall/luasrc/view/passwall/cbi/nodes_value.htm b/applications/luci-app-passwall/luasrc/view/passwall/cbi/nodes_value.htm index 9745dd8348..76893ec7a6 100644 --- a/applications/luci-app-passwall/luasrc/view/passwall/cbi/nodes_value.htm +++ b/applications/luci-app-passwall/luasrc/view/passwall/cbi/nodes_value.htm @@ -126,8 +126,6 @@ -<%+cbi/valuefooter%> - + +<%+cbi/valuefooter%> diff --git a/applications/luci-app-passwall/luasrc/view/passwall/cbi/nodes_value_com.htm b/applications/luci-app-passwall/luasrc/view/passwall/cbi/nodes_value_com.htm index 9386e91417..95b3f532bb 100644 --- a/applications/luci-app-passwall/luasrc/view/passwall/cbi/nodes_value_com.htm +++ b/applications/luci-app-passwall/luasrc/view/passwall/cbi/nodes_value_com.htm @@ -91,6 +91,7 @@ box-shadow: 0 6px 18px rgba(0,0,0,0.08); max-height: 50vh; overflow: auto; + overscroll-behavior: contain; } .v-dropdown-search, .v-dropdown-custom { width: 100%; @@ -701,6 +702,25 @@ e.preventDefault(); v_customEnter(cbid, labelSpan, hiddenInput, searchInput, panel, listContainer, customInput); }); + + // 防止 panel 惯性滚动穿透 + panel.addEventListener('wheel', function (e) { + const deltaY = e.deltaY; + const scrollTop = panel.scrollTop; + const scrollHeight = panel.scrollHeight; + const clientHeight = panel.clientHeight; + const isAtTop = scrollTop === 0; + const isAtBottom = scrollTop + clientHeight >= scrollHeight; + if (deltaY < 0 && isAtTop) { + e.preventDefault(); + return; + } + if (deltaY > 0 && isAtBottom) { + e.preventDefault(); + return; + } + e.stopPropagation(); + }, { passive: false }); } const v_adaptiveControls = new Set(); diff --git a/applications/luci-app-passwall/luasrc/view/passwall/global/footer.htm b/applications/luci-app-passwall/luasrc/view/passwall/global/footer.htm index ddf3b139c8..10bac9bb9d 100644 --- a/applications/luci-app-passwall/luasrc/view/passwall/global/footer.htm +++ b/applications/luci-app-passwall/luasrc/view/passwall/global/footer.htm @@ -13,7 +13,26 @@ @@ -68,7 +71,14 @@ geosite -

+

+ + <% if has_old_geoip then %> + + <% end %> + <% if has_old_geosite then %> + + <% end %> @@ -123,8 +133,8 @@ var len = domList.length; while(len--) { var dom = domList[len];   - if(dom.type == 'checkbox' && dom.checked) {   - checkBoxList.push(dom.name);   + if(dom.type == 'checkbox' && dom.checked) { + checkBoxList.push(dom.name); } } XHR.get('<%=api.url("update_rules")%>', { @@ -142,6 +152,42 @@ ); } + function rollback_rules(btn, type) { + let ori_val = btn.value; + btn.disabled = true; + btn.value = '<%:Rollbacking...%>'; + var div = document.getElementById('_rule_div'); + var domList = div.getElementsByTagName('input'); + var checkBoxList = []; + var len = domList.length; + while(len--) { + var dom = domList[len];   + if(dom.type == 'checkbox' && dom.checked) { + if(type == 'geoip' && (dom.name === 'chnroute' || dom.name === 'chnroute6')) { + checkBoxList.push(dom.name); + } + if(type == 'geosite' && (dom.name === 'gfwlist' || dom.name === 'chnlist')) { + checkBoxList.push(dom.name); + } + } + } + XHR.get('<%=api.url("rollback_rules")%>', { + type: type, + rules: checkBoxList.join(",") + }, + function(x, data) { + if(x && x.status == 200 && data.code == 1) { + alert("<%:Success%>"); + btn.style.display = "none"; + } else { + alert("<%:Error%>"); + btn.disabled = false; + btn.value = ori_val; + } + } + ); + } + //分流规则添加拖拽排序 document.addEventListener("DOMContentLoaded", function () { function initSortableForTable() { diff --git a/applications/luci-app-passwall/po/zh_Hans/passwall.po b/applications/luci-app-passwall/po/zh_Hans/passwall.po index e69c473f37..79030dbc6a 100644 --- a/applications/luci-app-passwall/po/zh_Hans/passwall.po +++ b/applications/luci-app-passwall/po/zh_Hans/passwall.po @@ -61,6 +61,9 @@ msgstr "查看日志" msgid "Node Config" msgstr "节点配置" +msgid "Shunt Policy Config" +msgstr "分流方案配置" + msgid "Running Status" msgstr "运行状态" @@ -115,6 +118,9 @@ msgstr "0 为不使用" msgid "Same as the tcp node" msgstr "与 TCP 节点相同" +msgid "To modify the shunt policy, click the Edit button." +msgstr "如需调整分流方案,请点击编辑按钮。" + msgid "Current node: %s" msgstr "当前节点:%s" @@ -217,8 +223,14 @@ msgstr "过滤代理域名 IPv6" msgid "Experimental feature." msgstr "实验性功能。" -msgid "Use FakeDNS work in the shunt domain that proxy." -msgstr "需要代理的分流规则域名使用 FakeDNS。" +msgid "Use FakeDNS work in the domain that proxy." +msgstr "需要代理的域名使用 FakeDNS。" + +msgid "Suitable scenarios for let the node servers get the target domain names." +msgstr "适合让节点服务器获取目标域名的场景。" + +msgid "Such as: DNS unlocking of streaming media, reducing DNS query latency, etc." +msgstr "例如:流媒体的 DNS 解锁、减少 DNS 查询延迟等。" msgid "Redirect" msgstr "重定向" @@ -370,6 +382,9 @@ msgstr "添加节点" msgid "Add the node via the link" msgstr "通过链接添加节点" +msgid "Add shunt policy" +msgstr "添加分流方案" + msgid "Enter share links, one per line. Subscription links are not supported!" msgstr "输入分享链接,支持多个节点,每行一个。请勿输入订阅链接!" @@ -382,6 +397,9 @@ msgstr "清空所有节点" msgid "Are you sure to clear all nodes?" msgstr "你确定要清空所有节点吗?" +msgid "Success" +msgstr "成功" + msgid "Error" msgstr "错误" @@ -502,11 +520,20 @@ msgstr "前置代理节点" msgid "Set the node to be used as a pre-proxy. Each rule (including Default) has a separate switch that controls whether this rule uses the pre-proxy or not." msgstr "设置用作前置代理的节点。每条规则(包括默认)都有独立开关控制本规则是否使用前置代理。" +msgid "Close (Not use)" +msgstr "关闭(不使用)" + +msgid "Use default node" +msgstr "使用默认节点" + msgid "Direct Connection" msgstr "直连" -msgid "Blackhole" -msgstr "黑洞" +msgid "Blackhole (Block)" +msgstr "黑洞(屏蔽)" + +msgid "Use preproxy node" +msgstr "使用前置代理节点" msgid "Default Preproxy" msgstr "默认前置代理" @@ -931,6 +958,12 @@ msgstr "强制更新" msgid "Manually update" msgstr "手动更新" +msgid "Rollback" +msgstr "回滚" + +msgid "Rollbacking..." +msgstr "回滚中..." + msgid "Update Options" msgstr "更新选项" @@ -1996,6 +2029,9 @@ msgstr "请输入查询内容!" msgid "No results were found!" msgstr "未找到任何结果!" +msgid "Rules containing this value:" +msgstr "所在规则列表:" + msgid "Domain/IP Query" msgstr "域名/IP 查询" diff --git a/applications/luci-app-passwall/root/usr/share/passwall/app.sh b/applications/luci-app-passwall/root/usr/share/passwall/app.sh index 7c856d1986..653d339bb7 100755 --- a/applications/luci-app-passwall/root/usr/share/passwall/app.sh +++ b/applications/luci-app-passwall/root/usr/share/passwall/app.sh @@ -5,9 +5,9 @@ . /lib/functions.sh . /lib/functions/service.sh +. /usr/share/libubox/jshn.sh . /usr/share/passwall/utils.sh - GLOBAL_ACL_PATH=${TMP_ACL_PATH}/default LUA_UTIL_PATH=/usr/lib/lua/luci/passwall UTIL_SINGBOX=$LUA_UTIL_PATH/util_sing-box.lua @@ -100,7 +100,6 @@ run_singbox() { local flag type node tcp_redir_port tcp_proxy_way udp_redir_port socks_address socks_port socks_username socks_password http_address http_port http_username http_password local dns_listen_port direct_dns_query_strategy direct_dns_port direct_dns_udp_server direct_dns_tcp_server remote_dns_protocol remote_dns_udp_server remote_dns_tcp_server remote_dns_doh remote_dns_client_ip remote_fakedns remote_dns_query_strategy dns_cache dns_socks_address dns_socks_port local loglevel log_file config_file server_host server_port no_run - local _extra_param="" eval_set_val $@ [ -z "$type" ] && { local type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z') @@ -111,68 +110,83 @@ run_singbox() { } [ -z "$type" ] && return 1 [ -n "$log_file" ] || local log_file="/dev/null" - _extra_param="${_extra_param} -log 1 -logfile ${log_file}" + json_init if [ "$log_file" = "/dev/null" ]; then - _extra_param="${_extra_param} -log 0" + json_add_string "log" "0" else - _extra_param="${_extra_param} -log 1 -logfile ${log_file}" + json_add_string "log" "1" + json_add_string "logfile" "${log_file}" fi [ -z "$loglevel" ] && local loglevel=$(config_t_get global loglevel "warn") [ "$loglevel" = "warning" ] && loglevel="warn" - _extra_param="${_extra_param} -loglevel $loglevel" - - [ -n "$flag" ] && _extra_param="${_extra_param} -flag $flag" - [ -n "$node" ] && _extra_param="${_extra_param} -node $node" - [ -n "$server_host" ] && _extra_param="${_extra_param} -server_host $server_host" - [ -n "$server_port" ] && _extra_param="${_extra_param} -server_port $server_port" - [ -n "$tcp_redir_port" ] && _extra_param="${_extra_param} -tcp_redir_port $tcp_redir_port" - [ -n "$tcp_proxy_way" ] && _extra_param="${_extra_param} -tcp_proxy_way $tcp_proxy_way" - [ -n "$udp_redir_port" ] && _extra_param="${_extra_param} -udp_redir_port $udp_redir_port" - [ -n "$socks_address" ] && _extra_param="${_extra_param} -local_socks_address $socks_address" - [ -n "$socks_port" ] && _extra_param="${_extra_param} -local_socks_port $socks_port" - [ -n "$socks_username" ] && [ -n "$socks_password" ] && _extra_param="${_extra_param} -local_socks_username $socks_username -local_socks_password $socks_password" - [ -n "$http_address" ] && _extra_param="${_extra_param} -local_http_address $http_address" - [ -n "$http_port" ] && _extra_param="${_extra_param} -local_http_port $http_port" - [ -n "$http_username" ] && [ -n "$http_password" ] && _extra_param="${_extra_param} -local_http_username $http_username -local_http_password $http_password" - [ -n "$dns_socks_address" ] && [ -n "$dns_socks_port" ] && _extra_param="${_extra_param} -dns_socks_address ${dns_socks_address} -dns_socks_port ${dns_socks_port}" - [ -n "$dns_listen_port" ] && _extra_param="${_extra_param} -dns_listen_port ${dns_listen_port}" - [ -n "$dns_cache" ] && _extra_param="${_extra_param} -dns_cache ${dns_cache}" + json_add_string "loglevel" "$loglevel" + + [ -n "$flag" ] && json_add_string "flag" "$flag" + [ -n "$node" ] && json_add_string "node" "$node" + [ -n "$server_host" ] && json_add_string "server_host" "$server_host" + [ -n "$server_port" ] && json_add_string "server_port" "$server_port" + [ -n "$tcp_redir_port" ] && json_add_string "tcp_redir_port" "$tcp_redir_port" + [ -n "$tcp_proxy_way" ] && json_add_string "tcp_proxy_way" "$tcp_proxy_way" + [ -n "$udp_redir_port" ] && json_add_string "udp_redir_port" "$udp_redir_port" + [ -n "$socks_address" ] && json_add_string "local_socks_address" "$socks_address" + [ -n "$socks_port" ] && json_add_string "local_socks_port" "$socks_port" + [ -n "$socks_username" ] && [ -n "$socks_password" ] && { + json_add_string "local_socks_username" "$socks_username" + json_add_string "local_socks_password" "$socks_password" + } + [ -n "$http_address" ] && json_add_string "local_http_address" "$http_address" + [ -n "$http_port" ] && json_add_string "local_http_port" "$http_port" + [ -n "$http_username" ] && [ -n "$http_password" ] && { + json_add_string "local_http_username" "$http_username" + json_add_string "local_http_password" "$http_password" + } + [ -n "$dns_socks_address" ] && [ -n "$dns_socks_port" ] && { + json_add_string "dns_socks_address" "${dns_socks_address}" + json_add_string "dns_socks_port" "${dns_socks_port}" + } + [ -n "$dns_listen_port" ] && json_add_string "dns_listen_port" "${dns_listen_port}" + [ -n "$dns_cache" ] && json_add_string "dns_cache" "${dns_cache}" if [ -n "$direct_dns_udp_server" ]; then direct_dns_port=$(echo ${direct_dns_udp_server} | awk -F '#' '{print $2}') - _extra_param="${_extra_param} -direct_dns_udp_server $(echo ${direct_dns_udp_server} | awk -F '#' '{print $1}')" + json_add_string "direct_dns_udp_server" "$(echo ${direct_dns_udp_server} | awk -F '#' '{print $1}')" elif [ -n "$direct_dns_tcp_server" ]; then direct_dns_port=$(echo ${direct_dns_tcp_server} | awk -F '#' '{print $2}') - _extra_param="${_extra_param} -direct_dns_tcp_server $(echo ${direct_dns_tcp_server} | awk -F '#' '{print $1}')" + json_add_string "direct_dns_tcp_server" "$(echo ${direct_dns_tcp_server} | awk -F '#' '{print $1}')" else local local_dns=$(echo -n $(echo "${LOCAL_DNS}" | sed "s/,/\n/g" | head -n1) | tr " " ",") - _extra_param="${_extra_param} -direct_dns_udp_server $(echo ${local_dns} | awk -F '#' '{print $1}')" + json_add_string "direct_dns_udp_server" "$(echo ${local_dns} | awk -F '#' '{print $1}')" direct_dns_port=$(echo ${local_dns} | awk -F '#' '{print $2}') fi - _extra_param="${_extra_param} -direct_dns_port ${direct_dns_port:-53}" + json_add_string "direct_dns_port" "${direct_dns_port:-53}" direct_dns_query_strategy=${direct_dns_query_strategy:-UseIP} - _extra_param="${_extra_param} -direct_dns_query_strategy ${direct_dns_query_strategy}" + json_add_string "direct_dns_query_strategy" "${direct_dns_query_strategy}" - [ -n "$remote_dns_query_strategy" ] && _extra_param="${_extra_param} -remote_dns_query_strategy ${remote_dns_query_strategy}" + [ -n "$remote_dns_query_strategy" ] && json_add_string "remote_dns_query_strategy" "${remote_dns_query_strategy}" case "$remote_dns_protocol" in udp|tcp) local _proto="$remote_dns_protocol" local _dns=$(get_first_dns remote_dns_${_proto}_server 53 | sed 's/#/:/g') local _dns_address=$(echo ${_dns} | awk -F ':' '{print $1}') local _dns_port=$(echo ${_dns} | awk -F ':' '{print $2}') - _extra_param="${_extra_param} -remote_dns_server ${_dns_address} -remote_dns_port ${_dns_port} -remote_dns_${_proto}_server ${_proto}://${_dns}" + json_add_string "remote_dns_server" "${_dns_address}" + json_add_string "remote_dns_port" "${_dns_port}" + json_add_string "remote_dns_${_proto}_server" "${_proto}://${_dns}" ;; doh) local _doh_url _doh_host _doh_port _doh_bootstrap parse_doh "$remote_dns_doh" _doh_url _doh_host _doh_port _doh_bootstrap - [ -n "$_doh_bootstrap" ] && _extra_param="${_extra_param} -remote_dns_server ${_doh_bootstrap}" - _extra_param="${_extra_param} -remote_dns_port ${_doh_port} -remote_dns_doh_url ${_doh_url} -remote_dns_doh_host ${_doh_host}" + [ -n "$_doh_bootstrap" ] && json_add_string "remote_dns_server" "${_doh_bootstrap}" + json_add_string "remote_dns_port" "${_doh_port}" + json_add_string "remote_dns_doh_url" "${_doh_url}" + json_add_string "remote_dns_doh_host" "${_doh_host}" ;; esac - [ -n "$remote_dns_client_ip" ] && _extra_param="${_extra_param} -remote_dns_client_ip ${remote_dns_client_ip}" - [ "$remote_fakedns" = "1" ] && _extra_param="${_extra_param} -remote_dns_fake 1" - [ -n "$no_run" ] && _extra_param="${_extra_param} -no_run 1" - lua $UTIL_SINGBOX gen_config ${_extra_param} > $config_file + [ -n "$remote_dns_client_ip" ] && json_add_string "remote_dns_client_ip" "${remote_dns_client_ip}" + [ "$remote_fakedns" = "1" ] && json_add_string "remote_dns_fake" "1" + [ -n "$no_run" ] && json_add_string "no_run" "1" + local _json_arg="$(json_dump)" + lua $UTIL_SINGBOX gen_config "${_json_arg}" > $config_file [ -n "$no_run" ] || ln_run "$(first_type $(config_t_get global_app sing_box_file) sing-box)" "sing-box" $log_file run -c "$config_file" } @@ -180,7 +194,6 @@ run_xray() { local flag type node tcp_redir_port tcp_proxy_way udp_redir_port socks_address socks_port socks_username socks_password http_address http_port http_username http_password local dns_listen_port direct_dns_query_strategy direct_dns_port direct_dns_udp_server direct_dns_tcp_server remote_dns_protocol remote_dns_udp_server remote_dns_tcp_server remote_dns_doh remote_dns_client_ip remote_fakedns remote_dns_query_strategy dns_cache dns_socks_address dns_socks_port local loglevel log_file config_file server_host server_port no_run - local _extra_param="" eval_set_val $@ [ -z "$type" ] && { local type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z') @@ -190,67 +203,82 @@ run_xray() { fi } [ -z "$type" ] && return 1 + json_init [ -n "$log_file" ] || local log_file="/dev/null" [ -z "$loglevel" ] && local loglevel=$(config_t_get global loglevel "warning") - [ -n "$flag" ] && _extra_param="${_extra_param} -flag $flag" - [ -n "$node" ] && _extra_param="${_extra_param} -node $node" - [ -n "$server_host" ] && _extra_param="${_extra_param} -server_host $server_host" - [ -n "$server_port" ] && _extra_param="${_extra_param} -server_port $server_port" - [ -n "$tcp_redir_port" ] && _extra_param="${_extra_param} -tcp_redir_port $tcp_redir_port" - [ -n "$tcp_proxy_way" ] && _extra_param="${_extra_param} -tcp_proxy_way $tcp_proxy_way" - [ -n "$udp_redir_port" ] && _extra_param="${_extra_param} -udp_redir_port $udp_redir_port" - [ -n "$socks_address" ] && _extra_param="${_extra_param} -local_socks_address $socks_address" - [ -n "$socks_port" ] && _extra_param="${_extra_param} -local_socks_port $socks_port" - [ -n "$socks_username" ] && [ -n "$socks_password" ] && _extra_param="${_extra_param} -local_socks_username $socks_username -local_socks_password $socks_password" - [ -n "$http_address" ] && _extra_param="${_extra_param} -local_http_address $http_address" - [ -n "$http_port" ] && _extra_param="${_extra_param} -local_http_port $http_port" - [ -n "$http_username" ] && [ -n "$http_password" ] && _extra_param="${_extra_param} -local_http_username $http_username -local_http_password $http_password" - [ -n "$dns_socks_address" ] && [ -n "$dns_socks_port" ] && _extra_param="${_extra_param} -dns_socks_address ${dns_socks_address} -dns_socks_port ${dns_socks_port}" - [ -n "$dns_listen_port" ] && _extra_param="${_extra_param} -dns_listen_port ${dns_listen_port}" + [ -n "$flag" ] && json_add_string "flag" "$flag" + [ -n "$node" ] && json_add_string "node" "$node" + [ -n "$server_host" ] && json_add_string "server_host" "$server_host" + [ -n "$server_port" ] && json_add_string "server_port" "$server_port" + [ -n "$tcp_redir_port" ] && json_add_string "tcp_redir_port" "$tcp_redir_port" + [ -n "$tcp_proxy_way" ] && json_add_string "tcp_proxy_way" "$tcp_proxy_way" + [ -n "$udp_redir_port" ] && json_add_string "udp_redir_port" "$udp_redir_port" + [ -n "$socks_address" ] && json_add_string "local_socks_address" "$socks_address" + [ -n "$socks_port" ] && json_add_string "local_socks_port" "$socks_port" + [ -n "$socks_username" ] && [ -n "$socks_password" ] && { + json_add_string "local_socks_username" "$socks_username" + json_add_string "local_socks_password" "$socks_password" + } + [ -n "$http_address" ] && json_add_string "local_http_address" "$http_address" + [ -n "$http_port" ] && json_add_string "local_http_port" "$http_port" + [ -n "$http_username" ] && [ -n "$http_password" ] && { + json_add_string "local_http_username" "$http_username" + json_add_string "local_http_password" "$http_password" + } + [ -n "$dns_socks_address" ] && [ -n "$dns_socks_port" ] && { + json_add_string "dns_socks_address" "${dns_socks_address}" + json_add_string "dns_socks_port" "${dns_socks_port}" + } + [ -n "$dns_listen_port" ] && json_add_string "dns_listen_port" "${dns_listen_port}" if [ -n "$direct_dns_udp_server" ]; then direct_dns_port=$(echo ${direct_dns_udp_server} | awk -F '#' '{print $2}') - _extra_param="${_extra_param} -direct_dns_udp_server $(echo ${direct_dns_udp_server} | awk -F '#' '{print $1}')" + json_add_string "direct_dns_udp_server" "$(echo ${direct_dns_udp_server} | awk -F '#' '{print $1}')" elif [ -n "$direct_dns_tcp_server" ]; then direct_dns_port=$(echo ${direct_dns_tcp_server} | awk -F '#' '{print $2}') - _extra_param="${_extra_param} -direct_dns_tcp_server $(echo ${direct_dns_tcp_server} | awk -F '#' '{print $1}')" + json_add_string "direct_dns_tcp_server" "$(echo ${direct_dns_tcp_server} | awk -F '#' '{print $1}')" else local local_dns=$(echo -n $(echo "${LOCAL_DNS}" | sed "s/,/\n/g" | head -n1) | tr " " ",") - _extra_param="${_extra_param} -direct_dns_udp_server $(echo ${local_dns} | awk -F '#' '{print $1}')" + json_add_string "direct_dns_udp_server" "$(echo ${local_dns} | awk -F '#' '{print $1}')" direct_dns_port=$(echo ${local_dns} | awk -F '#' '{print $2}') fi - _extra_param="${_extra_param} -direct_dns_port ${direct_dns_port:-53}" + json_add_string "direct_dns_port" "${direct_dns_port:-53}" direct_dns_query_strategy=${direct_dns_query_strategy:-UseIP} - _extra_param="${_extra_param} -direct_dns_query_strategy ${direct_dns_query_strategy}" - [ -n "$remote_dns_query_strategy" ] && _extra_param="${_extra_param} -remote_dns_query_strategy ${remote_dns_query_strategy}" - [ -n "$remote_dns_client_ip" ] && _extra_param="${_extra_param} -remote_dns_client_ip ${remote_dns_client_ip}" - [ "$remote_fakedns" = "1" ] && _extra_param="${_extra_param} -remote_dns_fake 1" - [ -n "$dns_cache" ] && _extra_param="${_extra_param} -dns_cache ${dns_cache}" + json_add_string "direct_dns_query_strategy" "${direct_dns_query_strategy}" + [ -n "$remote_dns_query_strategy" ] && json_add_string "remote_dns_query_strategy" "${remote_dns_query_strategy}" + [ -n "$remote_dns_client_ip" ] && json_add_string "remote_dns_client_ip" "${remote_dns_client_ip}" + [ "$remote_fakedns" = "1" ] && json_add_string "remote_dns_fake" "1" + [ -n "$dns_cache" ] && json_add_string "dns_cache" "${dns_cache}" case "$remote_dns_protocol" in udp) local _dns=$(get_first_dns remote_dns_udp_server 53 | sed 's/#/:/g') local _dns_address=$(echo ${_dns} | awk -F ':' '{print $1}') local _dns_port=$(echo ${_dns} | awk -F ':' '{print $2}') - _extra_param="${_extra_param} -remote_dns_udp_server ${_dns_address} -remote_dns_udp_port ${_dns_port}" + json_add_string "remote_dns_udp_server" "${_dns_address}" + json_add_string "remote_dns_udp_port" "${_dns_port}" ;; tcp|tcp+doh) local _dns=$(get_first_dns remote_dns_tcp_server 53 | sed 's/#/:/g') local _dns_address=$(echo ${_dns} | awk -F ':' '{print $1}') local _dns_port=$(echo ${_dns} | awk -F ':' '{print $2}') - _extra_param="${_extra_param} -remote_dns_tcp_server ${_dns_address} -remote_dns_tcp_port ${_dns_port}" + json_add_string "remote_dns_tcp_server" "${_dns_address}" + json_add_string "remote_dns_tcp_port" "${_dns_port}" [ "$remote_dns_protocol" = "tcp+doh" ] && { local _doh_url _doh_host _doh_port _doh_bootstrap parse_doh "$remote_dns_doh" _doh_url _doh_host _doh_port _doh_bootstrap - [ -n "$_doh_bootstrap" ] && _extra_param="${_extra_param} -remote_dns_doh_ip ${_doh_bootstrap}" - _extra_param="${_extra_param} -remote_dns_doh_port ${_doh_port} -remote_dns_doh_url ${_doh_url} -remote_dns_doh_host ${_doh_host}" + [ -n "$_doh_bootstrap" ] && json_add_string "remote_dns_doh_ip" "${_doh_bootstrap}" + json_add_string "remote_dns_doh_port" "${_doh_port}" + json_add_string "remote_dns_doh_url" "${_doh_url}" + json_add_string "remote_dns_doh_host" "${_doh_host}" } ;; esac - _extra_param="${_extra_param} -loglevel $loglevel" - [ -n "$no_run" ] && _extra_param="${_extra_param} -no_run 1" - lua $UTIL_XRAY gen_config ${_extra_param} > $config_file + json_add_string "loglevel" "$loglevel" + [ -n "$no_run" ] && json_add_string "no_run" "1" + local _json_arg="$(json_dump)" + lua $UTIL_XRAY gen_config "${_json_arg}" > $config_file [ -n "$no_run" ] || ln_run "$(first_type $(config_t_get global_app ${type}_file) ${type})" ${type} $log_file run -c "$config_file" } @@ -350,6 +378,10 @@ run_socks() { } [ "$bind" != "127.0.0.1" ] && echolog " - Socks节点:[$remarks]${tmp},启动 ${bind}:${socks_port}" + json_init + json_add_string "node" "${node}" + json_add_string "server_host" "${server_host}" + json_add_string "server_port" "${server_port}" case "$type" in socks) local _socks_address _socks_port _socks_username _socks_password @@ -365,18 +397,28 @@ run_socks() { [ "$http_port" != "0" ] && { http_flag=1 config_file="${config_file//SOCKS/HTTP_SOCKS}" - local _extra_param="-local_http_address $bind -local_http_port $http_port" + json_add_string "local_http_address" "$bind" + json_add_string "local_http_port" "$http_port" } + json_add_null "server_host" + json_add_null "server_port" + json_add_string "local_socks_address" "$bind" + json_add_string "local_socks_port" "$socks_port" + json_add_string "server_proto" "socks" + json_add_string "server_address" "${_socks_address}" + json_add_string "server_port" "${_socks_port}" + json_add_string "server_username" "${_socks_username}" + json_add_string "server_password" "${_socks_password}" local bin=$(first_type $(config_t_get global_app sing_box_file) sing-box) if [ -n "$bin" ]; then type="sing-box" - lua $UTIL_SINGBOX gen_proto_config -local_socks_address $bind -local_socks_port $socks_port ${_extra_param} -server_proto socks -server_address ${_socks_address} -server_port ${_socks_port} -server_username ${_socks_username} -server_password ${_socks_password} > $config_file + lua $UTIL_SINGBOX gen_proto_config "$(json_dump)" > $config_file ln_run "$bin" ${type} $log_file run -c "$config_file" else bin=$(first_type $(config_t_get global_app xray_file) xray) [ -n "$bin" ] && { type="xray" - lua $UTIL_XRAY gen_proto_config -local_socks_address $bind -local_socks_port $socks_port ${_extra_param} -server_proto socks -server_address ${_socks_address} -server_port ${_socks_port} -server_username ${_socks_username} -server_password ${_socks_password} > $config_file + lua $UTIL_XRAY gen_proto_config "$(json_dump)" > $config_file ln_run "$bin" ${type} $log_file run -c "$config_file" } fi @@ -402,50 +444,68 @@ run_socks() { run_xray flag=$flag node=$node socks_address=$bind socks_port=$socks_port config_file=$config_file log_file=$log_file ${_args} ;; trojan*) - lua $UTIL_TROJAN gen_config -node $node -run_type client -local_addr $bind -local_port $socks_port -server_host $server_host -server_port $server_port > $config_file + json_add_string "run_type" "client" + json_add_string "local_addr" "$bind" + json_add_string "local_port" "$socks_port" + lua $UTIL_TROJAN gen_config "$(json_dump)" > $config_file [ -n "$no_run" ] || ln_run "$(first_type ${type})" "${type}" $log_file -c "$config_file" ;; naiveproxy) - lua $UTIL_NAIVE gen_config -node $node -run_type socks -local_addr $bind -local_port $socks_port -server_host $server_host -server_port $server_port > $config_file + json_add_string "run_type" "socks" + json_add_string "local_addr" "$bind" + json_add_string "local_port" "$socks_port" + lua $UTIL_NAIVE gen_config "$(json_dump)" > $config_file [ -n "$no_run" ] || ln_run "$(first_type naive)" naive $log_file "$config_file" ;; ssr) - lua $UTIL_SS gen_config -node $node -local_addr $bind -local_port $socks_port -server_host $server_host -server_port $server_port > $config_file + json_add_string "local_addr" "$bind" + json_add_string "local_port" "$socks_port" + lua $UTIL_SS gen_config "$(json_dump)" > $config_file [ -n "$no_run" ] || ln_run "$(first_type ssr-local)" "ssr-local" $log_file -c "$config_file" -v -u ;; ss) [ -n "$no_run" ] || { local plugin_sh="${config_file%.json}_plugin.sh" - local _extra_param="-plugin_sh $plugin_sh" + json_add_string "plugin_sh" "$plugin_sh" } - lua $UTIL_SS gen_config -node $node -local_addr $bind -local_port $socks_port -server_host $server_host -server_port $server_port -mode tcp_and_udp ${_extra_param} > $config_file + json_add_string "local_addr" "$bind" + json_add_string "local_port" "$socks_port" + json_add_string "mode" "tcp_and_udp" + lua $UTIL_SS gen_config "$(json_dump)" > $config_file [ -n "$no_run" ] || ln_run "$(first_type ss-local)" "ss-local" $log_file -c "$config_file" -v ;; ss-rust) - local _extra_param [ "$http_port" != "0" ] && { http_flag=1 config_file="${config_file//SOCKS/HTTP_SOCKS}" - _extra_param="-local_http_address $bind -local_http_port $http_port" + json_add_string "local_http_address" "$bind" + json_add_string "local_http_port" "$http_port" } [ -n "$no_run" ] || { local plugin_sh="${config_file%.json}_plugin.sh" - _extra_param="${_extra_param:+$_extra_param }-plugin_sh $plugin_sh" + json_add_string "plugin_sh" "$plugin_sh" } - lua $UTIL_SS gen_config -node $node -local_socks_address $bind -local_socks_port $socks_port -server_host $server_host -server_port $server_port ${_extra_param} > $config_file + json_add_string "local_socks_address" "$bind" + json_add_string "local_socks_port" "$socks_port" + lua $UTIL_SS gen_config "$(json_dump)" > $config_file [ -n "$no_run" ] || ln_run "$(first_type sslocal)" "sslocal" $log_file -c "$config_file" -v ;; hysteria2) [ "$http_port" != "0" ] && { http_flag=1 config_file="${config_file//SOCKS/HTTP_SOCKS}" - local _extra_param="-local_http_address $bind -local_http_port $http_port" + json_add_string "local_http_address" "$bind" + json_add_string "local_http_port" "$http_port" } - lua $UTIL_HYSTERIA2 gen_config -node $node -local_socks_address $bind -local_socks_port $socks_port -server_host $server_host -server_port $server_port ${_extra_param} > $config_file + json_add_string "local_socks_address" "$bind" + json_add_string "local_socks_port" "$socks_port" + lua $UTIL_HYSTERIA2 gen_config "$(json_dump)" > $config_file [ -n "$no_run" ] || ln_run "$(first_type $(config_t_get global_app hysteria_file))" "hysteria" $log_file -c "$config_file" client ;; tuic) - lua $UTIL_TUIC gen_config -node $node -local_addr $bind -local_port $socks_port -server_host $server_host -server_port $server_port > $config_file + json_add_string "local_addr" "$bind" + json_add_string "local_port" "$socks_port" + lua $UTIL_TUIC gen_config "$(json_dump)" > $config_file [ -n "$no_run" ] || ln_run "$(first_type tuic-client)" "tuic-client" $log_file -c "$config_file" ;; esac @@ -455,15 +515,25 @@ run_socks() { # http to socks [ -z "$http_flag" ] && [ "$http_port" != "0" ] && [ -n "$http_config_file" ] && [ "$type" != "sing-box" ] && [ "$type" != "xray" ] && [ "$type" != "socks" ] && { local bin=$(first_type $(config_t_get global_app sing_box_file) sing-box) + json_add_null "node" + json_add_null "server_host" + json_add_null "server_port" + json_add_string "local_http_address" "$bind" + json_add_string "local_http_port" "$http_port" + json_add_string "server_proto" "socks" + json_add_string "server_address" "127.0.0.1" + json_add_string "server_port" "$socks_port" + json_add_string "server_username" "$_username" + json_add_string "server_password" "$_password" if [ -n "$bin" ]; then type="sing-box" - lua $UTIL_SINGBOX gen_proto_config -local_http_address $bind -local_http_port $http_port -server_proto socks -server_address "127.0.0.1" -server_port $socks_port -server_username $_username -server_password $_password > $http_config_file + lua $UTIL_SINGBOX gen_proto_config "$(json_dump)" > $http_config_file [ -n "$no_run" ] || ln_run "$bin" ${type} /dev/null run -c "$http_config_file" else bin=$(first_type $(config_t_get global_app xray_file) xray) [ -n "$bin" ] && type="xray" [ -z "$type" ] && return 1 - lua $UTIL_XRAY gen_proto_config local_http_address $bind -local_http_port $http_port -server_proto socks -server_address "127.0.0.1" -server_port $socks_port -server_username $_username -server_password $_password > $http_config_file + lua $UTIL_XRAY gen_proto_config "$(json_dump)" > $http_config_file [ -n "$no_run" ] || ln_run "$bin" ${type} /dev/null run -c "$http_config_file" fi } @@ -513,6 +583,8 @@ run_redir() { } [ "$bind" != "127.0.0.1" ] && echolog "${PROTO}节点:[$remarks],监听端口:$local_port" + json_init + json_add_string "node" "${node}" case "$PROTO" in UDP) case "$type" in @@ -553,30 +625,41 @@ run_redir() { ;; trojan*) local loglevel=$(config_t_get global trojan_loglevel "2") - lua $UTIL_TROJAN gen_config -node $node -run_type nat -local_addr "0.0.0.0" -local_port $local_port -loglevel $loglevel > $config_file + json_add_string "run_type" "nat" + json_add_string "local_addr" "0.0.0.0" + json_add_string "local_port" "$local_port" + json_add_string "loglevel" "$loglevel" + lua $UTIL_TROJAN gen_config "$(json_dump)" > $config_file ln_run "$(first_type ${type})" "${type}" $log_file -c "$config_file" ;; naiveproxy) echolog "Naiveproxy不支持UDP转发!" ;; ssr) - lua $UTIL_SS gen_config -node $node -local_addr "0.0.0.0" -local_port $local_port > $config_file + json_add_string "local_addr" "0.0.0.0" + json_add_string "local_port" "$local_port" + lua $UTIL_SS gen_config "$(json_dump)" > $config_file ln_run "$(first_type ssr-redir)" "ssr-redir" $log_file -c "$config_file" -v -U ;; ss) local plugin_sh="${config_file%.json}_plugin.sh" - local _extra_param="-plugin_sh $plugin_sh" - lua $UTIL_SS gen_config -node $node -local_addr "0.0.0.0" -local_port $local_port -mode udp_only $_extra_param > $config_file + json_add_string "plugin_sh" "$plugin_sh" + json_add_string "local_addr" "0.0.0.0" + json_add_string "local_port" "$local_port" + json_add_string "mode" "udp_only" + lua $UTIL_SS gen_config "$(json_dump)" > $config_file ln_run "$(first_type ss-redir)" "ss-redir" $log_file -c "$config_file" -v ;; ss-rust) local plugin_sh="${config_file%.json}_plugin.sh" - local _extra_param="-plugin_sh $plugin_sh" - lua $UTIL_SS gen_config -node $node -local_udp_redir_port $local_port $_extra_param > $config_file + json_add_string "plugin_sh" "$plugin_sh" + json_add_string "local_udp_redir_port" "$local_port" + lua $UTIL_SS gen_config "$(json_dump)" > $config_file ln_run "$(first_type sslocal)" "sslocal" $log_file -c "$config_file" -v ;; hysteria2) - lua $UTIL_HYSTERIA2 gen_config -node $node -local_udp_redir_port $local_port > $config_file + json_add_string "local_udp_redir_port" "$local_port" + lua $UTIL_HYSTERIA2 gen_config "$(json_dump)" > $config_file ln_run "$(first_type $(config_t_get global_app hysteria_file))" "hysteria" $log_file -c "$config_file" client ;; tuic) @@ -794,89 +877,104 @@ run_redir() { run_xray flag=$_flag node=$node tcp_redir_port=$local_port tcp_proxy_way=$TCP_PROXY_WAY config_file=$config_file log_file=$log_file ${_args} ;; trojan*) - [ "${TCP_PROXY_WAY}" = "tproxy" ] && lua_tproxy_arg="-use_tproxy true" + [ "${TCP_PROXY_WAY}" = "tproxy" ] && json_add_string "use_tproxy" "true" [ "$TCP_UDP" = "1" ] && { config_file="${config_file//TCP/TCP_UDP}" UDP_REDIR_PORT=$TCP_REDIR_PORT unset UDP_NODE } local loglevel=$(config_t_get global trojan_loglevel "2") - lua $UTIL_TROJAN gen_config -node $node -run_type nat -local_addr "0.0.0.0" -local_port $local_port -loglevel $loglevel $lua_tproxy_arg > $config_file + json_add_string "run_type" "nat" + json_add_string "local_addr" "0.0.0.0" + json_add_string "local_port" "$local_port" + json_add_string "loglevel" "$loglevel" + lua $UTIL_TROJAN gen_config "$(json_dump)" > $config_file ln_run "$(first_type ${type})" "${type}" $log_file -c "$config_file" ;; naiveproxy) - lua $UTIL_NAIVE gen_config -node $node -run_type redir -local_addr "0.0.0.0" -local_port $local_port > $config_file + json_add_string "run_type" "redir" + json_add_string "local_addr" "0.0.0.0" + json_add_string "local_port" "$local_port" + lua $UTIL_NAIVE gen_config "$(json_dump)" > $config_file ln_run "$(first_type naive)" naive $log_file "$config_file" ;; ssr) - [ "${TCP_PROXY_WAY}" = "tproxy" ] && lua_tproxy_arg="-tcp_tproxy true" + [ "${TCP_PROXY_WAY}" = "tproxy" ] && json_add_string "tcp_tproxy" "true" + local _extra_param [ "$TCP_UDP" = "1" ] && { config_file="${config_file//TCP/TCP_UDP}" UDP_REDIR_PORT=$TCP_REDIR_PORT unset UDP_NODE _extra_param="-u" } - lua $UTIL_SS gen_config -node $node -local_addr "0.0.0.0" -local_port $local_port $lua_tproxy_arg > $config_file + json_add_string "local_addr" "0.0.0.0" + json_add_string "local_port" "$local_port" + lua $UTIL_SS gen_config "$(json_dump)" > $config_file ln_run "$(first_type ssr-redir)" "ssr-redir" $log_file -c "$config_file" -v ${_extra_param} ;; ss) - [ "${TCP_PROXY_WAY}" = "tproxy" ] && lua_tproxy_arg="-tcp_tproxy true" - local lua_mode_arg="-mode tcp_only" - [ "$TCP_UDP" = "1" ] && { + [ "${TCP_PROXY_WAY}" = "tproxy" ] && json_add_string "tcp_tproxy" "true" + if [ "$TCP_UDP" = "1" ]; then config_file="${config_file//TCP/TCP_UDP}" UDP_REDIR_PORT=$TCP_REDIR_PORT unset UDP_NODE - lua_mode_arg="-mode tcp_and_udp" - } + json_add_string "mode" "tcp_and_udp" + else + json_add_string "mode" "tcp_only" + fi local plugin_sh="${config_file%.json}_plugin.sh" - lua_mode_arg="${lua_mode_arg} -plugin_sh $plugin_sh" - lua $UTIL_SS gen_config -node $node -local_addr "0.0.0.0" -local_port $local_port $lua_mode_arg $lua_tproxy_arg > $config_file + json_add_string "plugin_sh" "$plugin_sh" + json_add_string "local_addr" "0.0.0.0" + json_add_string "local_port" "$local_port" + lua $UTIL_SS gen_config "$(json_dump)" > $config_file ln_run "$(first_type ss-redir)" "ss-redir" $log_file -c "$config_file" -v ;; ss-rust) - local _extra_param="-local_tcp_redir_port $local_port" - [ "${TCP_PROXY_WAY}" = "tproxy" ] && _extra_param="${_extra_param} -tcp_tproxy true" + json_add_string "local_tcp_redir_port" "$local_port" + [ "${TCP_PROXY_WAY}" = "tproxy" ] && json_add_string "tcp_tproxy" "true" [ "$tcp_node_socks" = "1" ] && { tcp_node_socks_flag=1 config_file="${config_file//TCP/TCP_SOCKS}" - _extra_param="${_extra_param} -local_socks_address ${tcp_node_socks_bind} -local_socks_port ${tcp_node_socks_port}" + json_add_string "local_socks_address" "${tcp_node_socks_bind}" + json_add_string "local_socks_port" "${tcp_node_socks_port}" } [ "$tcp_node_http" = "1" ] && { tcp_node_http_flag=1 config_file="${config_file//TCP/TCP_HTTP}" - _extra_param="${_extra_param} -local_http_port ${tcp_node_http_port}" + json_add_string "local_http_port" "${tcp_node_http_port}" } [ "$TCP_UDP" = "1" ] && { config_file="${config_file//TCP/TCP_UDP}" UDP_REDIR_PORT=$TCP_REDIR_PORT unset UDP_NODE - _extra_param="${_extra_param} -local_udp_redir_port $local_port" + json_add_string "local_udp_redir_port" "$local_port" } local plugin_sh="${config_file%.json}_plugin.sh" - _extra_param="${_extra_param} -plugin_sh $plugin_sh" - lua $UTIL_SS gen_config -node $node ${_extra_param} > $config_file + json_add_string "plugin_sh" "$plugin_sh" + lua $UTIL_SS gen_config "$(json_dump)" > $config_file ln_run "$(first_type sslocal)" "sslocal" $log_file -c "$config_file" -v ;; hysteria2) - local _extra_param="-local_tcp_redir_port $local_port" + json_add_string "local_tcp_redir_port" "$local_port" [ "$tcp_node_socks" = "1" ] && { tcp_node_socks_flag=1 config_file="${config_file//TCP/TCP_SOCKS}" - _extra_param="${_extra_param} -local_socks_address ${tcp_node_socks_bind} -local_socks_port ${tcp_node_socks_port}" + json_add_string "local_socks_address" "${tcp_node_socks_bind}" + json_add_string "local_socks_port" "${tcp_node_socks_port}" } [ "$tcp_node_http" = "1" ] && { tcp_node_http_flag=1 config_file="${config_file//TCP/TCP_HTTP}" - _extra_param="${_extra_param} -local_http_port ${tcp_node_http_port}" + json_add_string "local_http_port" "${tcp_node_http_port}" } [ "$TCP_UDP" = "1" ] && { config_file="${config_file//TCP/TCP_UDP}" UDP_REDIR_PORT=$TCP_REDIR_PORT unset UDP_NODE - _extra_param="${_extra_param} -local_udp_redir_port $local_port" + json_add_string "local_udp_redir_port" "$local_port" } - _extra_param="${_extra_param} -tcp_proxy_way ${TCP_PROXY_WAY}" - lua $UTIL_HYSTERIA2 gen_config -node $node ${_extra_param} > $config_file + json_add_string "tcp_proxy_way" "${TCP_PROXY_WAY}" + lua $UTIL_HYSTERIA2 gen_config "$(json_dump)" > $config_file ln_run "$(first_type $(config_t_get global_app hysteria_file))" "hysteria" $log_file -c "$config_file" client ;; esac @@ -1674,6 +1772,12 @@ acl_app() { fi } [ -n "$udp_node" ] && { + [ -n "$tcp_node" ] && { + local protocol=$(config_n_get $tcp_node protocol) + [ "$protocol" = "_shunt" ] && [ "$udp_node" != "default" ] && { + udp_node = "tcp" + } + } if [ "$udp_node" = "default" ]; then local GLOBAL_UDP_NODE=$(get_cache_var "ACL_GLOBAL_UDP_node") [ -n "${GLOBAL_UDP_NODE}" ] && GLOBAL_UDP_redir_port=$(get_cache_var "ACL_GLOBAL_UDP_redir_port") @@ -1840,6 +1944,13 @@ get_config() { elif [ "$UDP_NODE" = "$TCP_NODE" ]; then TCP_UDP=1 fi + [ -n "$TCP_NODE" ] && { + local protocol=$(config_n_get $TCP_NODE protocol) + [ "$protocol" = "_shunt" ] && [ -n "$UDP_NODE" ] && { + UDP_NODE=$TCP_NODE + TCP_UDP=1 + } + } [ "$ENABLED" = 1 ] && { local _node for _node in "$TCP_NODE" "$UDP_NODE"; do @@ -1930,8 +2041,6 @@ get_config() { SMARTDNS_LISTEN_PORT=${NEXT_DNS_LISTEN_PORT} NEXT_DNS_LISTEN_PORT=$(expr $NEXT_DNS_LISTEN_PORT + 1) LOCAL_DNS="127.0.0.1#${SMARTDNS_LOCAL_PORT}" - uci -q set smartdns.@smartdns[0].auto_set_dnsmasq=0 - uci commit smartdns } } diff --git a/applications/luci-app-passwall/root/usr/share/passwall/helper_chinadns_add.lua b/applications/luci-app-passwall/root/usr/share/passwall/helper_chinadns_add.lua index 00e7ceed35..b05479866e 100644 --- a/applications/luci-app-passwall/root/usr/share/passwall/helper_chinadns_add.lua +++ b/applications/luci-app-passwall/root/usr/share/passwall/helper_chinadns_add.lua @@ -33,6 +33,11 @@ local FLAG_PATH = TMP_ACL_PATH .. "/" .. FLAG local config_lines = {} local tmp_lines = {} local USE_GEOVIEW = uci:get(appname, "@global_rules[0]", "enable_geoview") +local IS_SHUNT_NODE = uci:get(appname, TCP_NODE, "protocol") == "_shunt" + +if IS_SHUNT_NODE then + REMOTE_FAKEDNS = uci:get(appname, TCP_NODE, "fakedns") or "0" +end local function log(...) if NO_LOGIC_LOG == "1" then @@ -354,7 +359,7 @@ if CHNLIST ~= "0" and is_file_nonzero(RULES_PATH .. "/chnlist") then end --分流规则 -if uci:get(appname, TCP_NODE, "protocol") == "_shunt" then +if IS_SHUNT_NODE then local white_domain, lookup_white_domain = {}, {} local shunt_domain, lookup_shunt_domain = {}, {} local file_white_host = FLAG_PATH .. "/shunt_direct_host" @@ -492,7 +497,7 @@ if CHNLIST == "proxy" then DEFAULT_TAG = "chn" end --全局模式,默认使用远程DNS if only_global then DEFAULT_TAG = "gfw" - if NO_IPV6_TRUST == "1" and uci:get(appname, TCP_NODE, "protocol") ~= "_shunt" then + if NO_IPV6_TRUST == "1" and not IS_SHUNT_NODE then table.insert(config_lines, "no-ipv6") end end diff --git a/applications/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq.lua b/applications/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq.lua index 2470f21634..44b8c6e37f 100644 --- a/applications/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq.lua +++ b/applications/luci-app-passwall/root/usr/share/passwall/helper_dnsmasq.lua @@ -181,6 +181,11 @@ function add_rule(var) local CACHE_DNS_PATH = CACHE_PATH .. "/" .. CACHE_FLAG local CACHE_TEXT_FILE = CACHE_DNS_PATH .. ".txt" local USE_CHINADNS_NG = "0" + local IS_SHUNT_NODE = uci:get(appname, TCP_NODE, "protocol") == "_shunt" + + if IS_SHUNT_NODE then + REMOTE_FAKEDNS = uci:get(appname, TCP_NODE, "fakedns") or "0" + end local list1 = {} local excluded_domain = {} @@ -540,7 +545,7 @@ function add_rule(var) end --分流规则 - if uci:get(appname, TCP_NODE, "protocol") == "_shunt" and USE_CHINADNS_NG == "0" then + if IS_SHUNT_NODE and USE_CHINADNS_NG == "0" then local t = uci:get_all(appname, TCP_NODE) local default_node_id = t["default_node"] or "_direct" uci:foreach(appname, "shunt_rules", function(s) diff --git a/applications/luci-app-passwall/root/usr/share/passwall/helper_smartdns_add.lua b/applications/luci-app-passwall/root/usr/share/passwall/helper_smartdns_add.lua index 82326583f0..2f75b831cd 100644 --- a/applications/luci-app-passwall/root/usr/share/passwall/helper_smartdns_add.lua +++ b/applications/luci-app-passwall/root/usr/share/passwall/helper_smartdns_add.lua @@ -40,6 +40,11 @@ local TMP_CONF_FILE = FLAG_PATH .. "/smartdns.conf" local config_lines = {} local tmp_lines = {} local USE_GEOVIEW = uci:get(appname, "@global_rules[0]", "enable_geoview") +local IS_SHUNT_NODE = uci:get(appname, TCP_NODE, "protocol") == "_shunt" + +if IS_SHUNT_NODE then + REMOTE_FAKEDNS = uci:get(appname, TCP_NODE, "fakedns") or "0" +end local function log(...) if NO_LOGIC_LOG == "1" then @@ -229,7 +234,7 @@ if DNS_MODE == "socks" then end table.insert(config_lines, server_param) end - REMOTE_FAKEDNS = 0 + if not IS_SHUNT_NODE then REMOTE_FAKEDNS = "0" end else local server_param = string.format("server %s -group %s -exclude-default-group", TUN_DNS:gsub("#", ":"), REMOTE_GROUP) table.insert(config_lines, server_param) @@ -513,7 +518,7 @@ if CHN_LIST ~= "0" and is_file_nonzero(RULES_PATH .. "/chnlist") then end --分流规则 -if uci:get(appname, TCP_NODE, "protocol") == "_shunt" then +if IS_SHUNT_NODE then local white_domain, lookup_white_domain = {}, {} local shunt_domain, lookup_shunt_domain = {}, {} local file_white_host = FLAG_PATH .. "/shunt_direct_host" diff --git a/applications/luci-app-passwall/root/usr/share/passwall/rule_update.lua b/applications/luci-app-passwall/root/usr/share/passwall/rule_update.lua index b69d73c84c..eac11ac664 100755 --- a/applications/luci-app-passwall/root/usr/share/passwall/rule_update.lua +++ b/applications/luci-app-passwall/root/usr/share/passwall/rule_update.lua @@ -33,9 +33,13 @@ local asset_location = uci:get(name, "@global_rules[0]", "v2ray_location_asset") local geo2rule = uci:get(name, "@global_rules[0]", "geo2rule") or "0" local geoip_update_ok, geosite_update_ok = false, false asset_location = asset_location:match("/$") and asset_location or (asset_location .. "/") +local backup_path = "/tmp/bak_v2ray/" +local rollback = false if arg3 == "cron" then arg2 = nil +elseif arg3 == "rollback" then + rollback, geoip_update_ok, geosite_update_ok = true, true, true end local log = function(...) @@ -388,7 +392,7 @@ local function GeoToRule(rule_name, rule_type, out_path) end --fetch rule -local function fetch_rule(rule_name,rule_type,url,exclude_domain, max_retries) +local function fetch_rule(rule_name, rule_type, url, exclude_domain, max_retries) local sret = 200 local max_attempts = max_retries or 2 local rule_dataset = {} @@ -504,7 +508,7 @@ local function fetch_rule(rule_name,rule_type,url,exclude_domain, max_retries) os.execute(string.format("mv -f %s %s.nft", nft_file, rule_final_path)) end os.execute(string.format("mv -f %s %s", file_tmp, rule_final_path)) - reboot = 1 + if not rollback then reboot = 1 end log(string.format("%s 更新成功,总规则数 %d 条。", rule_name, #result_list)) else log(rule_name .. " 版本一致,无需更新。") @@ -535,7 +539,7 @@ local function fetch_geofile(geo_name, geo_type, url) local content = f:read("*l") f:close() if content then - content = content:gsub(down_filename, tmp_path) + content = content:gsub("(%x+)%s+.+", "%1 " .. tmp_path) f = io.open(sha_path, "w") if f then f:write(content) @@ -565,7 +569,8 @@ local function fetch_geofile(geo_name, geo_type, url) if sret_tmp == 200 then if sha_verify then if verify_sha256(sha_path) then - sys.call(string.format("mkdir -p %s && cp -f %s %s", asset_location, tmp_path, asset_path)) + sys.call(string.format("mkdir -p %s && mv -f %s %s", backup_path, asset_path, backup_path)) + sys.call(string.format("mkdir -p %s && mv -f %s %s", asset_location, tmp_path, asset_path)) reboot = 1 log(geo_type .. " 更新成功。") if geo_type == "geoip" then @@ -582,7 +587,8 @@ local function fetch_geofile(geo_name, geo_type, url) log(geo_type .. " 版本一致,无需更新。") return 0 end - sys.call(string.format("mkdir -p %s && cp -f %s %s", asset_location, tmp_path, asset_path)) + sys.call(string.format("mkdir -p %s && mv -f %s %s", backup_path, asset_path, backup_path)) + sys.call(string.format("mkdir -p %s && mv -f %s %s", asset_location, tmp_path, asset_path)) reboot = 1 log(geo_type .. " 更新成功。") if geo_type == "geoip" then @@ -643,6 +649,7 @@ if arg2 then geosite_update = "1" end end) + if rollback then arg2 = nil end else gfwlist_update = uci:get(name, "@global_rules[0]", "gfwlist_update") or "1" chnroute_update = uci:get(name, "@global_rules[0]", "chnroute_update") or "1" @@ -670,13 +677,13 @@ local function remove_tmp_geofile(name) end if geo2rule == "1" then - if geoip_update == "1" then + if geoip_update == "1" and not rollback then log("geoip 开始更新...") safe_call(fetch_geoip, "更新geoip发生错误...") remove_tmp_geofile("geoip") end - if geosite_update == "1" then + if geosite_update == "1" and not rollback then log("geosite 开始更新...") safe_call(fetch_geosite, "更新geosite发生错误...") remove_tmp_geofile("geosite") @@ -685,22 +692,26 @@ if geo2rule == "1" then -- 如果是手动更新(arg2存在)始终生成规则 local force_generate = (arg2 ~= nil) - if geoip_update_ok or force_generate then - if fs.access(asset_location .. "geoip.dat") then - safe_call(fetch_chnroute, "生成chnroute发生错误...") - safe_call(fetch_chnroute6, "生成chnroute6发生错误...") - else - log("geoip.dat 文件不存在,跳过规则生成。") - end + if (geoip_update_ok or force_generate) and fs.access(asset_location .. "geoip.dat") then + if force_generate or chnroute_update == "1" then + safe_call(fetch_chnroute, "生成chnroute发生错误...") + end + if force_generate or chnroute6_update == "1" then + safe_call(fetch_chnroute6, "生成chnroute6发生错误...") + end + else + log("geoip.dat 文件不存在,跳过规则生成。") end - if geosite_update_ok or force_generate then - if fs.access(asset_location .. "geosite.dat") then - safe_call(fetch_gfwlist, "生成gfwlist发生错误...") - safe_call(fetch_chnlist, "生成chnlist发生错误...") - else - log("geosite.dat 文件不存在,跳过规则生成。") - end + if (geosite_update_ok or force_generate) and fs.access(asset_location .. "geosite.dat") then + if force_generate or gfwlist_update == "1" then + safe_call(fetch_gfwlist, "生成gfwlist发生错误...") + end + if force_generate or chnlist_update == "1" then + safe_call(fetch_chnlist, "生成chnlist发生错误...") + end + else + log("geosite.dat 文件不存在,跳过规则生成。") end else if gfwlist_update == "1" then @@ -732,13 +743,15 @@ else end end -uci:set(name, "@global_rules[0]", "gfwlist_update", gfwlist_update) -uci:set(name, "@global_rules[0]", "chnroute_update", chnroute_update) -uci:set(name, "@global_rules[0]", "chnroute6_update", chnroute6_update) -uci:set(name, "@global_rules[0]", "chnlist_update", chnlist_update) -uci:set(name, "@global_rules[0]", "geoip_update", geoip_update) -uci:set(name, "@global_rules[0]", "geosite_update", geosite_update) -api.uci_save(uci, name, true) +if not rollback then + uci:set(name, "@global_rules[0]", "gfwlist_update", gfwlist_update) + uci:set(name, "@global_rules[0]", "chnroute_update", chnroute_update) + uci:set(name, "@global_rules[0]", "chnroute6_update", chnroute6_update) + uci:set(name, "@global_rules[0]", "chnlist_update", chnlist_update) + uci:set(name, "@global_rules[0]", "geoip_update", geoip_update) + uci:set(name, "@global_rules[0]", "geosite_update", geosite_update) + api.uci_save(uci, name, true) +end if reboot == 1 then if arg3 == "cron" then