diff --git a/luci-app-passwall2/Makefile b/luci-app-passwall2/Makefile index 899bf3305..3aabfca8b 100644 --- a/luci-app-passwall2/Makefile +++ b/luci-app-passwall2/Makefile @@ -5,7 +5,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall2 -PKG_VERSION:=25.4.22 +PKG_VERSION:=25.5.7 PKG_RELEASE:=1 PKG_CONFIG_DEPENDS:= \ diff --git a/luci-app-passwall2/luasrc/controller/passwall2.lua b/luci-app-passwall2/luasrc/controller/passwall2.lua index 712ea6862..428a263da 100644 --- a/luci-app-passwall2/luasrc/controller/passwall2.lua +++ b/luci-app-passwall2/luasrc/controller/passwall2.lua @@ -60,6 +60,7 @@ function index() entry({"admin", "services", appname, "link_add_node"}, call("link_add_node")).leaf = true entry({"admin", "services", appname, "socks_autoswitch_add_node"}, call("socks_autoswitch_add_node")).leaf = true entry({"admin", "services", appname, "socks_autoswitch_remove_node"}, call("socks_autoswitch_remove_node")).leaf = true + entry({"admin", "services", appname, "gen_client_config"}, call("gen_client_config")).leaf = true entry({"admin", "services", appname, "get_now_use_node"}, call("get_now_use_node")).leaf = true entry({"admin", "services", appname, "get_redir_log"}, call("get_redir_log")).leaf = true entry({"admin", "services", appname, "get_socks_log"}, call("get_socks_log")).leaf = true @@ -161,6 +162,19 @@ function socks_autoswitch_remove_node() luci.http.redirect(api.url("socks_config", id)) end +function gen_client_config() + local id = luci.http.formvalue("id") + local config_file = api.TMP_PATH .. "/config_" .. id + luci.sys.call(string.format("/usr/share/passwall2/app.sh run_socks flag=config_%s node=%s bind=127.0.0.1 socks_port=1080 config_file=%s no_run=1", id, id, config_file)) + if nixio.fs.access(config_file) then + luci.http.prepare_content("application/json") + luci.http.write(luci.sys.exec("cat " .. config_file)) + luci.sys.call("rm -f " .. config_file) + else + luci.http.redirect(api.url("node_list")) + end +end + function get_now_use_node() local e = {} local node = api.get_cache_var("ACL_GLOBAL_node") diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/index.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/index.lua index 1fb77ea66..70bec3f87 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/index.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/index.lua @@ -41,17 +41,42 @@ end e = t:option(DummyValue, "remarks", translate("Remarks")) e.width = "15%" ----- Type e = t:option(DummyValue, "type", translate("Type")) +e.width = "20%" +e.rawhtml = true e.cfgvalue = function(t, n) - local v = Value.cfgvalue(t, n) - if v then - if v == "sing-box" or v == "Xray" then - local protocol = m:get(n, "protocol") - return v .. " -> " .. protocol + local str = "" + local type = m:get(n, "type") or "" + if type == "sing-box" or type == "Xray" then + local protocol = m:get(n, "protocol") or "" + if protocol == "vmess" then + protocol = "VMess" + elseif protocol == "vless" then + protocol = "VLESS" + elseif protocol == "shadowsocks" then + protocol = "SS" + elseif protocol == "shadowsocksr" then + protocol = "SSR" + elseif protocol == "wireguard" then + protocol = "WG" + elseif protocol == "hysteria" then + protocol = "HY" + elseif protocol == "hysteria2" then + protocol = "HY2" + elseif protocol == "anytls" then + protocol = "AnyTLS" + else + protocol = protocol:gsub("^%l",string.upper) + local custom = m:get(n, "custom") or "0" + if custom == "1" then + protocol = translate("Custom Config") + end end - return v + if type == "sing-box" then type = "Sing-Box" end + type = type .. " " .. protocol end + str = str .. translate(type) + return str end e = t:option(DummyValue, "port", translate("Port")) diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/hysteria2.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/hysteria2.lua index c73f9328e..8bdacf88b 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/hysteria2.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/hysteria2.lua @@ -18,32 +18,42 @@ end s.fields["type"]:value(type_name, "Hysteria2") +o = s:option(Flag, _n("custom"), translate("Use Custom Config")) + o = s:option(Value, _n("port"), translate("Listen Port")) o.datatype = "port" +o:depends({ [_n("custom")] = false }) o = s:option(Value, _n("obfs"), translate("Obfs Password")) o.rewrite_option = o.option +o:depends({ [_n("custom")] = false }) o = s:option(Value, _n("auth_password"), translate("Auth Password")) o.password = true o.rewrite_option = o.option +o:depends({ [_n("custom")] = false }) o = s:option(Flag, _n("udp"), translate("UDP")) o.default = "1" o.rewrite_option = o.option +o:depends({ [_n("custom")] = false }) o = s:option(Value, _n("up_mbps"), translate("Max upload Mbps")) o.rewrite_option = o.option +o:depends({ [_n("custom")] = false }) o = s:option(Value, _n("down_mbps"), translate("Max download Mbps")) o.rewrite_option = o.option +o:depends({ [_n("custom")] = false }) o = s:option(Flag, _n("ignoreClientBandwidth"), translate("ignoreClientBandwidth")) o.default = "0" o.rewrite_option = o.option +o:depends({ [_n("custom")] = false }) o = s:option(FileUpload, _n("tls_certificateFile"), translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem") o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. arg[1] .. ".pem" +if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) end o.validate = function(self, value, t) if value and value ~= "" then if not nixio.fs.access(value) then @@ -54,9 +64,11 @@ o.validate = function(self, value, t) end return nil end +o:depends({ [_n("custom")] = false }) o = s:option(FileUpload, _n("tls_keyFile"), translate("Private key absolute path"), translate("as:") .. "/etc/ssl/private.key") o.default = m:get(s.section, "tls_keyFile") or "/etc/config/ssl/" .. arg[1] .. ".key" +if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) end o.validate = function(self, value, t) if value and value ~= "" then if not nixio.fs.access(value) then @@ -67,6 +79,28 @@ o.validate = function(self, value, t) end return nil end +o:depends({ [_n("custom")] = false }) + +o = s:option(TextValue, _n("custom_config"), translate("Custom Config")) +o.rows = 10 +o.wrap = "off" +o:depends({ [_n("custom")] = true }) +o.validate = function(self, value, t) + if value and api.jsonc.parse(value) then + return value + else + return nil, translate("Must be JSON text!") + end +end +o.custom_cfgvalue = function(self, section, value) + local config_str = m:get(section, "config_str") + if config_str then + return api.base64Decode(config_str) + end +end +o.custom_write = function(self, section, value) + m:set(section, "config_str", api.base64Encode(value)) +end o = s:option(Flag, _n("log"), translate("Log")) o.default = "1" diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ray.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ray.lua index 08246bfc5..7cd2a9f71 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ray.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ray.lua @@ -29,6 +29,8 @@ if not s.fields["type"].default then s.fields["type"].default = type_name end +o = s:option(Flag, _n("custom"), translate("Use Custom Config")) + o = s:option(ListValue, _n("protocol"), translate("Protocol")) o:value("vmess", "Vmess") o:value("vless", "VLESS") @@ -37,9 +39,11 @@ o:value("socks", "Socks") o:value("shadowsocks", "Shadowsocks") o:value("trojan", "Trojan") o:value("dokodemo-door", "dokodemo-door") +o:depends({ [_n("custom")] = false }) o = s:option(Value, _n("port"), translate("Listen Port")) o.datatype = "port" +o:depends({ [_n("custom")] = false }) o = s:option(Flag, _n("auth"), translate("Auth")) o.validate = function(self, value, t) @@ -191,6 +195,7 @@ o:depends({ [_n("tls")] = true }) -- [[ TLS部分 ]] -- o = s:option(FileUpload, _n("tls_certificateFile"), translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem") o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. arg[1] .. ".pem" +if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) end o:depends({ [_n("tls")] = true, [_n("reality")] = false }) o.validate = function(self, value, t) if value and value ~= "" then @@ -205,6 +210,7 @@ end o = s:option(FileUpload, _n("tls_keyFile"), translate("Private key absolute path"), translate("as:") .. "/etc/ssl/private.key") o.default = m:get(s.section, "tls_keyFile") or "/etc/config/ssl/" .. arg[1] .. ".key" +if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) end o:depends({ [_n("tls")] = true, [_n("reality")] = false }) o.validate = function(self, value, t) if value and value ~= "" then @@ -346,6 +352,7 @@ o:depends({ [_n("transport")] = "grpc" }) o = s:option(Flag, _n("acceptProxyProtocol"), translate("acceptProxyProtocol"), translate("Whether to receive PROXY protocol, when this node want to be fallback or forwarded by proxy, it must be enable, otherwise it cannot be used.")) o.default = "0" +o:depends({ [_n("custom")] = false }) -- [[ Fallback部分 ]]-- o = s:option(Flag, _n("fallback"), translate("Fallback")) @@ -372,9 +379,11 @@ o:depends({ [_n("fallback")] = true }) o = s:option(Flag, _n("bind_local"), translate("Bind Local"), translate("When selected, it can only be accessed localhost.")) o.default = "0" +o:depends({ [_n("custom")] = false }) o = s:option(Flag, _n("accept_lan"), translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!")) o.default = "0" +o:depends({ [_n("custom")] = false }) local nodes_table = {} for k, e in ipairs(api.get_valid_nodes()) do @@ -392,6 +401,7 @@ o:value("_socks", translate("Custom Socks")) o:value("_http", translate("Custom HTTP")) o:value("_iface", translate("Custom Interface")) for k, v in pairs(nodes_table) do o:value(v.id, v.remarks) end +o:depends({ [_n("custom")] = false }) o = s:option(Value, _n("outbound_node_address"), translate("Address (Support Domain Name)")) o:depends({ [_n("outbound_node")] = "_socks"}) @@ -415,6 +425,27 @@ o = s:option(Value, _n("outbound_node_iface"), translate("Interface")) o.default = "eth1" o:depends({ [_n("outbound_node")] = "_iface"}) +o = s:option(TextValue, _n("custom_config"), translate("Custom Config")) +o.rows = 10 +o.wrap = "off" +o:depends({ [_n("custom")] = true }) +o.validate = function(self, value, t) + if value and api.jsonc.parse(value) then + return value + else + return nil, translate("Must be JSON text!") + end +end +o.custom_cfgvalue = function(self, section, value) + local config_str = m:get(section, "config_str") + if config_str then + return api.base64Decode(config_str) + end +end +o.custom_write = function(self, section, value) + m:set(section, "config_str", api.base64Encode(value)) +end + o = s:option(Flag, _n("log"), translate("Log")) o.default = "1" o.rmempty = false diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/sing-box.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/sing-box.lua index 85a79dbb8..d8bd3bfc5 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/sing-box.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/sing-box.lua @@ -35,6 +35,8 @@ if not s.fields["type"].default then s.fields["type"].default = type_name end +o = s:option(Flag, _n("custom"), translate("Use Custom Config")) + o = s:option(ListValue, _n("protocol"), translate("Protocol")) o:value("mixed", "Mixed") o:value("socks", "Socks") @@ -57,9 +59,11 @@ if version_ge_1_12_0 then o:value("anytls", "AnyTLS") end o:value("direct", "Direct") +o:depends({ [_n("custom")] = false }) o = s:option(Value, _n("port"), translate("Listen Port")) o.datatype = "port" +o:depends({ [_n("custom")] = false }) o = s:option(Flag, _n("auth"), translate("Auth")) o.validate = function(self, value, t) @@ -263,6 +267,7 @@ end o = s:option(FileUpload, _n("tls_certificateFile"), translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem") o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. arg[1] .. ".pem" +if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) end o:depends({ [_n("tls")] = true, [_n("reality")] = false }) o:depends({ [_n("protocol")] = "naive" }) o:depends({ [_n("protocol")] = "hysteria" }) @@ -281,6 +286,7 @@ end o = s:option(FileUpload, _n("tls_keyFile"), translate("Private key absolute path"), translate("as:") .. "/etc/ssl/private.key") o.default = m:get(s.section, "tls_keyFile") or "/etc/config/ssl/" .. arg[1] .. ".key" +if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) end o:depends({ [_n("tls")] = true, [_n("reality")] = false }) o:depends({ [_n("protocol")] = "naive" }) o:depends({ [_n("protocol")] = "hysteria" }) @@ -392,9 +398,11 @@ o:depends({ [_n("tcpbrutal")] = true }) o = s:option(Flag, _n("bind_local"), translate("Bind Local"), translate("When selected, it can only be accessed localhost.")) o.default = "0" +o:depends({ [_n("custom")] = false }) o = s:option(Flag, _n("accept_lan"), translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!")) o.default = "0" +o:depends({ [_n("custom")] = false }) local nodes_table = {} for k, e in ipairs(api.get_valid_nodes()) do @@ -412,6 +420,7 @@ o:value("_socks", translate("Custom Socks")) o:value("_http", translate("Custom HTTP")) o:value("_iface", translate("Custom Interface")) for k, v in pairs(nodes_table) do o:value(v.id, v.remarks) end +o:depends({ [_n("custom")] = false }) o = s:option(Value, _n("outbound_node_address"), translate("Address (Support Domain Name)")) o:depends({ [_n("outbound_node")] = "_socks" }) @@ -435,6 +444,27 @@ o = s:option(Value, _n("outbound_node_iface"), translate("Interface")) o.default = "eth1" o:depends({ [_n("outbound_node")] = "_iface" }) +o = s:option(TextValue, _n("custom_config"), translate("Custom Config")) +o.rows = 10 +o.wrap = "off" +o:depends({ [_n("custom")] = true }) +o.validate = function(self, value, t) + if value and api.jsonc.parse(value) then + return value + else + return nil, translate("Must be JSON text!") + end +end +o.custom_cfgvalue = function(self, section, value) + local config_str = m:get(section, "config_str") + if config_str then + return api.base64Decode(config_str) + end +end +o.custom_write = function(self, section, value) + m:set(section, "config_str", api.base64Encode(value)) +end + o = s:option(Flag, _n("log"), translate("Log")) o.default = "1" o.rmempty = false diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ss-rust.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ss-rust.lua index ef4439094..4bcf51620 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ss-rust.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ss-rust.lua @@ -24,21 +24,49 @@ local ssrust_encrypt_method_list = { s.fields["type"]:value(type_name, translate("Shadowsocks Rust")) +o = s:option(Flag, _n("custom"), translate("Use Custom Config")) + o = s:option(Value, _n("port"), translate("Listen Port")) o.datatype = "port" +o:depends({ [_n("custom")] = false }) o = s:option(Value, _n("password"), translate("Password")) o.password = true +o:depends({ [_n("custom")] = false }) o = s:option(ListValue, _n("method"), translate("Encrypt Method")) for a, t in ipairs(ssrust_encrypt_method_list) do o:value(t) end +o:depends({ [_n("custom")] = false }) o = s:option(Value, _n("timeout"), translate("Connection Timeout")) o.datatype = "uinteger" o.default = 300 +o:depends({ [_n("custom")] = false }) o = s:option(Flag, _n("tcp_fast_open"), "TCP " .. translate("Fast Open")) o.default = "0" +o:depends({ [_n("custom")] = false }) + +o = s:option(TextValue, _n("custom_config"), translate("Custom Config")) +o.rows = 10 +o.wrap = "off" +o:depends({ [_n("custom")] = true }) +o.validate = function(self, value, t) + if value and api.jsonc.parse(value) then + return value + else + return nil, translate("Must be JSON text!") + end +end +o.custom_cfgvalue = function(self, section, value) + local config_str = m:get(section, "config_str") + if config_str then + return api.base64Decode(config_str) + end +end +o.custom_write = function(self, section, value) + m:set(section, "config_str", api.base64Encode(value)) +end o = s:option(Flag, _n("log"), translate("Log")) o.default = "1" diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ss.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ss.lua index 9efe89d29..e65957719 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ss.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ss.lua @@ -27,21 +27,49 @@ local ss_encrypt_method_list = { s.fields["type"]:value(type_name, translate("Shadowsocks")) +o = s:option(Flag, _n("custom"), translate("Use Custom Config")) + o = s:option(Value, _n("port"), translate("Listen Port")) o.datatype = "port" +o:depends({ [_n("custom")] = false }) o = s:option(Value, _n("password"), translate("Password")) o.password = true +o:depends({ [_n("custom")] = false }) o = s:option(ListValue, _n("method"), translate("Encrypt Method")) for a, t in ipairs(ss_encrypt_method_list) do o:value(t) end +o:depends({ [_n("custom")] = false }) o = s:option(Value, _n("timeout"), translate("Connection Timeout")) o.datatype = "uinteger" o.default = 300 +o:depends({ [_n("custom")] = false }) o = s:option(Flag, _n("tcp_fast_open"), "TCP " .. translate("Fast Open")) o.default = "0" +o:depends({ [_n("custom")] = false }) + +o = s:option(TextValue, _n("custom_config"), translate("Custom Config")) +o.rows = 10 +o.wrap = "off" +o:depends({ [_n("custom")] = true }) +o.validate = function(self, value, t) + if value and api.jsonc.parse(value) then + return value + else + return nil, translate("Must be JSON text!") + end +end +o.custom_cfgvalue = function(self, section, value) + local config_str = m:get(section, "config_str") + if config_str then + return api.base64Decode(config_str) + end +end +o.custom_write = function(self, section, value) + m:set(section, "config_str", api.base64Encode(value)) +end o = s:option(Flag, _n("log"), translate("Log")) o.default = "1" diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ssr.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ssr.lua index 8b9c576c1..65058c9f3 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ssr.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ssr.lua @@ -37,31 +37,63 @@ local ssr_obfs_list = { s.fields["type"]:value(type_name, translate("ShadowsocksR")) +o = s:option(Flag, _n("custom"), translate("Use Custom Config")) + o = s:option(Value, _n("port"), translate("Listen Port")) o.datatype = "port" +o:depends({ [_n("custom")] = false }) o = s:option(Value, _n("password"), translate("Password")) o.password = true +o:depends({ [_n("custom")] = false }) o = s:option(ListValue, _n("method"), translate("Encrypt Method")) for a, t in ipairs(ssr_encrypt_method_list) do o:value(t) end +o:depends({ [_n("custom")] = false }) o = s:option(ListValue, _n("protocol"), translate("Protocol")) for a, t in ipairs(ssr_protocol_list) do o:value(t) end +o:depends({ [_n("custom")] = false }) o = s:option(Value, _n("protocol_param"), translate("Protocol_param")) +o:depends({ [_n("custom")] = false }) o = s:option(ListValue, _n("obfs"), translate("Obfs")) for a, t in ipairs(ssr_obfs_list) do o:value(t) end +o:depends({ [_n("custom")] = false }) o = s:option(Value, _n("obfs_param"), translate("Obfs_param")) +o:depends({ [_n("custom")] = false }) o = s:option(Value, _n("timeout"), translate("Connection Timeout")) o.datatype = "uinteger" o.default = 300 +o:depends({ [_n("custom")] = false }) o = s:option(Flag, _n("tcp_fast_open"), "TCP " .. translate("Fast Open")) o.default = "0" +o:depends({ [_n("custom")] = false }) + +o = s:option(TextValue, _n("custom_config"), translate("Custom Config")) +o.rows = 10 +o.wrap = "off" +o:depends({ [_n("custom")] = true }) +o.validate = function(self, value, t) + if value and api.jsonc.parse(value) then + return value + else + return nil, translate("Must be JSON text!") + end +end +o.custom_cfgvalue = function(self, section, value) + local config_str = m:get(section, "config_str") + if config_str then + return api.base64Decode(config_str) + end +end +o.custom_write = function(self, section, value) + m:set(section, "config_str", api.base64Encode(value)) +end o = s:option(Flag, _n("udp_forward"), translate("UDP Forward")) o.default = "1" diff --git a/luci-app-passwall2/luasrc/passwall2/api.lua b/luci-app-passwall2/luasrc/passwall2/api.lua index 798310a5c..e514161d9 100644 --- a/luci-app-passwall2/luasrc/passwall2/api.lua +++ b/luci-app-passwall2/luasrc/passwall2/api.lua @@ -122,6 +122,11 @@ function base64Decode(text) end end +function base64Encode(text) + local result = nixio.bin.b64encode(text) + return result +end + --提取URL中的域名和端口(no ip) function get_domain_port_from_url(url) local scheme, domain, port = string.match(url, "^(https?)://([%w%.%-]+):?(%d*)") @@ -1222,11 +1227,16 @@ function luci_types(id, m, s, type_name, option_prefix) end s.fields[key].cfgvalue = function(self, section) - if self.rewrite_option then - return m:get(section, self.rewrite_option) + -- 添加自定义 custom_cfgvalue 属性,如果有自定义的 custom_cfgvalue 函数,则使用自定义的 cfgvalue 逻辑 + if self.custom_cfgvalue then + return self:custom_cfgvalue(section) else - if self.option:find(option_prefix) == 1 then - return m:get(section, self.option:sub(1 + #option_prefix)) + if self.rewrite_option then + return m:get(section, self.rewrite_option) + else + if self.option:find(option_prefix) == 1 then + return m:get(section, self.option:sub(1 + #option_prefix)) + end end end end diff --git a/luci-app-passwall2/luasrc/passwall2/server_app.lua b/luci-app-passwall2/luasrc/passwall2/server_app.lua index f3030d285..36bff1b36 100644 --- a/luci-app-passwall2/luasrc/passwall2/server_app.lua +++ b/luci-app-passwall2/luasrc/passwall2/server_app.lua @@ -120,20 +120,12 @@ local function start() local config_file = CONFIG_PATH .. "/" .. id .. ".json" local udp_forward = 1 local type = user.type or "" - if type == "Socks" then - local auth = "" - if user.auth and user.auth == "1" then - local username = user.username or "" - local password = user.password or "" - if username ~= "" and password ~= "" then - username = "-u " .. username - password = "-P " .. password - auth = username .. " " .. password - end + if type == "SS" or type == "SSR" then + if user.custom == "1" and user.config_str then + config = jsonc.parse(api.base64Decode(user.config_str)) + else + config = require(require_dir .. "util_shadowsocks").gen_config_server(user) end - bin = ln_run("/usr/bin/microsocks", "microsocks_" .. id, string.format("-i :: -p %s %s", port, auth), log_path) - elseif type == "SS" or type == "SSR" then - config = require(require_dir .. "util_shadowsocks").gen_config_server(user) local udp_param = "" udp_forward = tonumber(user.udp_forward) or 1 if udp_forward == 1 then @@ -142,16 +134,47 @@ local function start() type = type:lower() bin = ln_run("/usr/bin/" .. type .. "-server", type .. "-server", "-c " .. config_file .. " " .. udp_param, log_path) elseif type == "SS-Rust" then - config = require(require_dir .. "util_shadowsocks").gen_config_server(user) + if user.custom == "1" and user.config_str then + config = jsonc.parse(api.base64Decode(user.config_str)) + else + config = require(require_dir .. "util_shadowsocks").gen_config_server(user) + end bin = ln_run("/usr/bin/ssserver", "ssserver", "-c " .. config_file, log_path) elseif type == "Xray" then - config = require(require_dir .. "util_xray").gen_config_server(user) + if user.custom == "1" and user.config_str then + config = jsonc.parse(api.base64Decode(user.config_str)) + if log_path then + if not config.log then + config.log = {} + end + config.log.loglevel = user.loglevel + end + else + config = require(require_dir .. "util_xray").gen_config_server(user) + end bin = ln_run(api.get_app_path("xray"), "xray", "run -c " .. config_file, log_path) elseif type == "sing-box" then - config = require(require_dir .. "util_sing-box").gen_config_server(user) + if user.custom == "1" and user.config_str then + config = jsonc.parse(api.base64Decode(user.config_str)) + if log_path then + if not config.log then + config.log = {} + end + config.log.timestamp = true + config.log.disabled = false + config.log.level = user.loglevel + config.log.output = log_path + end + else + config = require(require_dir .. "util_sing-box").gen_config_server(user) + end bin = ln_run(api.get_app_path("sing-box"), "sing-box", "run -c " .. config_file, log_path) elseif type == "Hysteria2" then - config = require(require_dir .. "util_hysteria2").gen_config_server(user) + if user.custom == "1" and user.config_str then + config = jsonc.parse(api.base64Decode(user.config_str)) + else + config = require(require_dir .. "util_hysteria2").gen_config_server(user) + end bin = ln_run(api.get_app_path("hysteria"), "hysteria", "-c " .. config_file .. " server", log_path) end @@ -161,7 +184,7 @@ local function start() f:write(jsonc.stringify(config, 1)) f:close() end - log(string.format("%s %s 生成配置文件并运行 - %s", remarks, port, config_file)) + log(string.format("%s 生成配置文件并运行 - %s", remarks, config_file)) end if bin then @@ -169,7 +192,7 @@ local function start() end local bind_local = user.bind_local or 0 - if bind_local and tonumber(bind_local) ~= 1 then + if bind_local and tonumber(bind_local) ~= 1 and port then if nft_flag == "0" then ipt(string.format('-A PSW2-SERVER -p tcp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks)) ip6t(string.format('-A PSW2-SERVER -p tcp --dport %s -m comment --comment "%s" -j ACCEPT', port, remarks)) diff --git a/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua b/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua index 7ab92964a..db0f3be3f 100644 --- a/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua +++ b/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua @@ -31,8 +31,10 @@ function gen_outbound(flag, node, tag, proxy_table) end local proxy_tag = nil + local run_socks_instance = true if proxy_table ~= nil and type(proxy_table) == "table" then proxy_tag = proxy_table.tag or nil + run_socks_instance = proxy_table.run_socks_instance end if node.type ~= "sing-box" then @@ -42,18 +44,20 @@ function gen_outbound(flag, node, tag, proxy_table) if tag and node_id and tag ~= node_id then config_file = string.format("%s_%s_%s_%s.json", flag, tag, node_id, new_port) end - sys.call(string.format('/usr/share/%s/app.sh run_socks "%s"> /dev/null', - appname, - string.format("flag=%s node=%s bind=%s socks_port=%s config_file=%s relay_port=%s", - new_port, --flag - node_id, --node - "127.0.0.1", --bind - new_port, --socks port - config_file, --config file - (proxy_tag and relay_port) and tostring(relay_port) or "" --relay port + if run_socks_instance then + sys.call(string.format('/usr/share/%s/app.sh run_socks "%s"> /dev/null', + appname, + string.format("flag=%s node=%s bind=%s socks_port=%s config_file=%s relay_port=%s", + new_port, --flag + node_id, --node + "127.0.0.1", --bind + new_port, --socks port + config_file, --config file + (proxy_tag and relay_port) and tostring(relay_port) or "" --relay port + ) ) ) - ) + end node = { protocol = "socks", address = "127.0.0.1", @@ -820,6 +824,7 @@ function gen_config(var) local remote_dns_client_ip = var["-remote_dns_client_ip"] local dns_cache = var["-dns_cache"] local tags = var["-tags"] + local no_run = var["-no_run"] local dns_domain_rules = {} local dns = nil @@ -1114,7 +1119,7 @@ function gen_config(var) end end - local _outbound = gen_outbound(flag, _node, rule_name, { tag = use_proxy and preproxy_tag or nil }) + local _outbound = gen_outbound(flag, _node, rule_name, { tag = use_proxy and preproxy_tag or nil, run_socks_instance = not no_run}) if _outbound then _outbound.tag = _outbound.tag .. ":" .. _node.remarks rule_outboundTag, last_insert_outbound = set_outbound_detour(_node, _outbound, outbounds, rule_name) @@ -1577,7 +1582,7 @@ function gen_config(var) tag = "block" }) for index, value in ipairs(config.outbounds) do - if not value["_flag_proxy_tag"] and not value.detour and value["_id"] and value.server and value.server_port then + if not value["_flag_proxy_tag"] and not value.detour and value["_id"] and value.server and value.server_port and not no_run then sys.call(string.format("echo '%s' >> %s", value["_id"], api.TMP_PATH .. "/direct_node_list")) end for k, v in pairs(config.outbounds[index]) do diff --git a/luci-app-passwall2/luasrc/passwall2/util_xray.lua b/luci-app-passwall2/luasrc/passwall2/util_xray.lua index c3bd4f5ca..ca40a7a16 100644 --- a/luci-app-passwall2/luasrc/passwall2/util_xray.lua +++ b/luci-app-passwall2/luasrc/passwall2/util_xray.lua @@ -58,10 +58,12 @@ function gen_outbound(flag, node, tag, proxy_table) local proxy_tag = nil local fragment = nil local noise = nil + local run_socks_instance = true if proxy_table ~= nil and type(proxy_table) == "table" then proxy_tag = proxy_table.tag or nil fragment = proxy_table.fragment or nil noise = proxy_table.noise or nil + run_socks_instance = proxy_table.run_socks_instance end if node.type ~= "Xray" then @@ -71,18 +73,20 @@ function gen_outbound(flag, node, tag, proxy_table) if tag and node_id and tag ~= node_id then config_file = string.format("%s_%s_%s_%s.json", flag, tag, node_id, new_port) end - sys.call(string.format('/usr/share/%s/app.sh run_socks "%s"> /dev/null', - appname, - string.format("flag=%s node=%s bind=%s socks_port=%s config_file=%s relay_port=%s", - new_port, --flag - node_id, --node - "127.0.0.1", --bind - new_port, --socks port - config_file, --config file - (proxy_tag and relay_port) and tostring(relay_port) or "" --relay port + if run_socks_instance then + sys.call(string.format('/usr/share/%s/app.sh run_socks "%s"> /dev/null', + appname, + string.format("flag=%s node=%s bind=%s socks_port=%s config_file=%s relay_port=%s", + new_port, --flag + node_id, --node + "127.0.0.1", --bind + new_port, --socks port + config_file, --config file + (proxy_tag and relay_port) and tostring(relay_port) or "" --relay port + ) ) ) - ) + end node = {} node.protocol = "socks" node.transport = "tcp" @@ -577,6 +581,7 @@ function gen_config(var) local remote_dns_query_strategy = var["-remote_dns_query_strategy"] local remote_dns_detour = var["-remote_dns_detour"] local dns_cache = var["-dns_cache"] + local no_run = var["-no_run"] local dns_domain_rules = {} local dns = nil @@ -928,7 +933,8 @@ function gen_config(var) }) end local proxy_table = { - tag = use_proxy and preproxy_tag or nil + tag = use_proxy and preproxy_tag or nil, + run_socks_instance = not no_run } if not proxy_table.tag then if xray_settings.fragment == "1" then @@ -1580,7 +1586,7 @@ function gen_config(var) end for index, value in ipairs(config.outbounds) do - if not value["_flag_proxy_tag"] and value["_id"] and value.server and value.server_port then + if not value["_flag_proxy_tag"] and value["_id"] and value.server and value.server_port and not no_run then sys.call(string.format("echo '%s' >> %s", value["_id"], api.TMP_PATH .. "/direct_node_list")) end for k, v in pairs(config.outbounds[index]) do diff --git a/luci-app-passwall2/luasrc/view/passwall2/node_list/link_share_man.htm b/luci-app-passwall2/luasrc/view/passwall2/node_list/link_share_man.htm index 6c718a21d..44ebddbcd 100644 --- a/luci-app-passwall2/luasrc/view/passwall2/node_list/link_share_man.htm +++ b/luci-app-passwall2/luasrc/view/passwall2/node_list/link_share_man.htm @@ -1510,11 +1510,16 @@ local hysteria2_type = map:get("@global_subscribe[0]", "hysteria2_type") or "sin s.innerHTML = "<%:Import Finished %>"; return false; } + + function exportConfigFile(btn, sid) { + window.open('<%=api.url("gen_client_config")%>?id=' + sid, "_blank") + } //]]> + diff --git a/luci-app-passwall2/po/zh-cn/passwall2.po b/luci-app-passwall2/po/zh-cn/passwall2.po index ba99a1476..53e9186dd 100644 --- a/luci-app-passwall2/po/zh-cn/passwall2.po +++ b/luci-app-passwall2/po/zh-cn/passwall2.po @@ -424,6 +424,9 @@ msgstr "导出分享URL" msgid "Generate QRCode" msgstr "生成二维码" +msgid "Export Config File" +msgstr "导出配置文件" + msgid "Import Finished" msgstr "导入完成:" @@ -1692,3 +1695,12 @@ msgstr "端口跳跃范围" msgid "Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,)." msgstr "格式为:1000:2000 或 1000-2000 多组时用逗号(,)隔开。" + +msgid "Use Custom Config" +msgstr "使用自定义配置" + +msgid "Custom Config" +msgstr "自定义配置" + +msgid "Must be JSON text!" +msgstr "必须是 JSON 文本内容!" diff --git a/luci-app-passwall2/root/usr/share/passwall2/app.sh b/luci-app-passwall2/root/usr/share/passwall2/app.sh index 353fe8572..f5a1a6931 100755 --- a/luci-app-passwall2/root/usr/share/passwall2/app.sh +++ b/luci-app-passwall2/root/usr/share/passwall2/app.sh @@ -556,7 +556,7 @@ run_singbox() { } run_socks() { - local flag node bind socks_port config_file http_port http_config_file relay_port log_file + local flag node bind socks_port config_file http_port http_config_file relay_port log_file no_run eval_set_val $@ [ -n "$config_file" ] && [ -z "$(echo ${config_file} | grep $TMP_PATH)" ] && config_file=$TMP_PATH/$config_file [ -n "$http_port" ] || http_port=0 @@ -569,20 +569,20 @@ run_socks() { local type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z') local remarks=$(config_n_get $node remarks) local server_host=$(config_n_get $node address) - local port=$(config_n_get $node port) + local server_port=$(config_n_get $node port) [ -n "$relay_port" ] && { server_host="127.0.0.1" - port=$relay_port + server_port=$relay_port } local error_msg tmp - if [ -n "$server_host" ] && [ -n "$port" ]; then + if [ -n "$server_host" ] && [ -n "$server_port" ]; then check_host $server_host [ $? != 0 ] && { echolog " - Socks节点:[$remarks]${server_host} 是非法的服务器地址,无法启动!" return 1 } - tmp="${server_host}:${port}" + tmp="${server_host}:${server_port}" else error_msg="某种原因,此 Socks 服务的相关配置已失联,启动中止!" fi @@ -607,14 +607,15 @@ run_socks() { config_file=$(echo $config_file | sed "s/SOCKS/HTTP_SOCKS/g") local _extra_param="-local_http_address $bind -local_http_port $http_port" } - [ -n "$relay_port" ] && _extra_param="${_extra_param} -server_host $server_host -server_port $port" + [ -n "$relay_port" ] && _extra_param="${_extra_param} -server_host $server_host -server_port $server_port" [ "${log_file}" != "/dev/null" ] && { local loglevel=$(config_t_get global loglevel "warn") [ "$loglevel" = "warning" ] && loglevel="warn" _extra_param="${_extra_param} -log 1 -loglevel $loglevel -logfile $log_file" } + [ -n "$no_run" ] && _extra_param="${_extra_param} -no_run 1" lua $UTIL_SINGBOX gen_config -flag SOCKS_$flag -node $node -local_socks_address $bind -local_socks_port $socks_port ${_extra_param} > $config_file - ln_run "$(first_type $(config_t_get global_app singbox_file) sing-box)" "sing-box" /dev/null run -c "$config_file" + [ -n "$no_run" ] || ln_run "$(first_type $(config_t_get global_app singbox_file) sing-box)" "sing-box" /dev/null run -c "$config_file" ;; xray) [ "$http_port" != "0" ] && { @@ -622,21 +623,22 @@ run_socks() { config_file=$(echo $config_file | sed "s/SOCKS/HTTP_SOCKS/g") local _extra_param="-local_http_address $bind -local_http_port $http_port" } - [ -n "$relay_port" ] && _extra_param="${_extra_param} -server_host $server_host -server_port $port" + [ -n "$relay_port" ] && _extra_param="${_extra_param} -server_host $server_host -server_port $server_port" + [ -n "$no_run" ] && _extra_param="${_extra_param} -no_run 1" lua $UTIL_XRAY gen_config -flag SOCKS_$flag -node $node -local_socks_address $bind -local_socks_port $socks_port ${_extra_param} > $config_file - ln_run "$(first_type $(config_t_get global_app xray_file) xray)" "xray" $log_file run -c "$config_file" + [ -n "$no_run" ] || ln_run "$(first_type $(config_t_get global_app xray_file) xray)" "xray" $log_file run -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 $port > $config_file - ln_run "$(first_type naive)" naive $log_file "$config_file" + 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 + [ -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 $port > $config_file - ln_run "$(first_type ssr-local)" "ssr-local" $log_file -c "$config_file" -v -u + lua $UTIL_SS gen_config -node $node -local_addr $bind -local_port $socks_port -server_host $server_host -server_port $server_port > $config_file + [ -n "$no_run" ] || ln_run "$(first_type ssr-local)" "ssr-local" $log_file -c "$config_file" -v -u ;; ss) - lua $UTIL_SS gen_config -node $node -local_addr $bind -local_port $socks_port -server_host $server_host -server_port $port -mode tcp_and_udp > $config_file - ln_run "$(first_type ss-local)" "ss-local" $log_file -c "$config_file" -v + 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 > $config_file + [ -n "$no_run" ] || ln_run "$(first_type ss-local)" "ss-local" $log_file -c "$config_file" -v ;; ss-rust) [ "$http_port" != "0" ] && { @@ -644,8 +646,8 @@ run_socks() { config_file=$(echo $config_file | sed "s/SOCKS/HTTP_SOCKS/g") local _extra_param="-local_http_address $bind -local_http_port $http_port" } - lua $UTIL_SS gen_config -node $node -local_socks_address $bind -local_socks_port $socks_port -server_host $server_host -server_port $port ${_extra_param} > $config_file - ln_run "$(first_type sslocal)" "sslocal" $log_file -c "$config_file" -v + 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 + [ -n "$no_run" ] || ln_run "$(first_type sslocal)" "sslocal" $log_file -c "$config_file" -v ;; hysteria2) [ "$http_port" != "0" ] && { @@ -653,12 +655,12 @@ run_socks() { config_file=$(echo $config_file | sed "s/SOCKS/HTTP_SOCKS/g") local _extra_param="-local_http_address $bind -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 $port ${_extra_param} > $config_file - ln_run "$(first_type $(config_t_get global_app hysteria_file))" "hysteria" $log_file -c "$config_file" client + 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 + [ -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 $port > $config_file - ln_run "$(first_type tuic-client)" "tuic-client" $log_file -c "$config_file" + lua $UTIL_TUIC gen_config -node $node -local_addr $bind -local_port $socks_port -server_host $server_host -server_port $server_port > $config_file + [ -n "$no_run" ] || ln_run "$(first_type tuic-client)" "tuic-client" $log_file -c "$config_file" ;; esac @@ -668,18 +670,18 @@ run_socks() { if [ -n "$bin" ]; then type="sing-box" lua $UTIL_SINGBOX gen_proto_config -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 - ln_run "$bin" ${type} /dev/null run -c "$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_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 - ln_run "$bin" ${type} /dev/null run -c "$http_config_file" + [ -n "$no_run" ] || ln_run "$bin" ${type} /dev/null run -c "$http_config_file" fi } unset http_flag - [ "${server_host}" != "127.0.0.1" ] && [ "$type" != "sing-box" ] && [ "$type" != "xray" ] && echo "${node}" >> $TMP_PATH/direct_node_list + [ -z "$no_run" ] && [ "${server_host}" != "127.0.0.1" ] && [ "$type" != "sing-box" ] && [ "$type" != "xray" ] && echo "${node}" >> $TMP_PATH/direct_node_list } socks_node_switch() {