luci-app-passwall2: sync upstream

This commit is contained in:
sbwml 2023-09-06 10:57:10 +08:00
parent 0a9636efda
commit 714c9178fa
28 changed files with 3088 additions and 650 deletions

View File

@ -5,7 +5,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall2
PKG_VERSION:=1.19-6
PKG_VERSION:=1.20-4
PKG_RELEASE:=
PKG_CONFIG_DEPENDS:= \
@ -23,8 +23,8 @@ PKG_CONFIG_DEPENDS:= \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Simple_Obfs \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_SingBox \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_tuic_client \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_V2ray \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Plugin
LUCI_TITLE:=LuCI support for PassWall 2
@ -47,8 +47,8 @@ LUCI_DEPENDS:=+coreutils +coreutils-base64 +coreutils-nohup +curl \
+PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client:shadowsocksr-libev-ssr-redir \
+PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Server:shadowsocksr-libev-ssr-server \
+PACKAGE_$(PKG_NAME)_INCLUDE_Simple_Obfs:simple-obfs \
+PACKAGE_$(PKG_NAME)_INCLUDE_SingBox:sing-box \
+PACKAGE_$(PKG_NAME)_INCLUDE_tuic_client:tuic-client \
+PACKAGE_$(PKG_NAME)_INCLUDE_V2ray:v2ray-core \
+PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Plugin:v2ray-plugin
define Package/$(PKG_NAME)/config
@ -133,15 +133,15 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_Simple_Obfs
bool "Include Simple-Obfs (Shadowsocks Plugin)"
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_SingBox
bool "Include Sing-Box"
default y if aarch64||arm||i386||x86_64
config PACKAGE_$(PKG_NAME)_INCLUDE_tuic_client
bool "Include tuic-client"
depends on aarch64||arm||i386||x86_64
default n
config PACKAGE_$(PKG_NAME)_INCLUDE_V2ray
bool "Include V2ray"
default n
config PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Plugin
bool "Include V2ray-Plugin (Shadowsocks Plugin)"
default y if aarch64||arm||i386||x86_64

View File

@ -2,7 +2,7 @@ local api = require "luci.passwall2.api"
local appname = api.appname
local uci = api.uci
local datatypes = api.datatypes
local has_v2ray = api.is_finded("v2ray")
local has_singbox = api.is_finded("sing-box")
local has_xray = api.is_finded("xray")
m = Map(appname)
@ -36,6 +36,8 @@ end
m:append(Template(appname .. "/global/status"))
local global_cfgid = uci:get_all(appname, "@global[0]")[".name"]
s = m:section(TypedSection, "global")
s.anonymous = true
s.addremove = false
@ -51,7 +53,7 @@ node = s:taboption("Main", ListValue, "node", "<a style='color: red'>" .. transl
node:value("nil", translate("Close"))
-- 分流
if (has_v2ray or has_xray) and #nodes_table > 0 then
if (has_singbox or has_xray) and #nodes_table > 0 then
local normal_list = {}
local balancing_list = {}
local shunt_list = {}
@ -84,10 +86,10 @@ if (has_v2ray or has_xray) and #nodes_table > 0 then
if #normal_list > 0 then
for k, v in pairs(shunt_list) do
local vid = v.id
-- shunt node type, V2ray or Xray
-- shunt node type, Sing-Box or Xray
local type = s:taboption("Main", ListValue, vid .. "-type", translate("Type"))
if has_v2ray then
type:value("V2ray", translate("V2ray"))
if has_singbox then
type:value("sing-box", translate("Sing-Box"))
end
if has_xray then
type:value("Xray", translate("Xray"))
@ -119,7 +121,7 @@ if (has_v2ray or has_xray) and #nodes_table > 0 then
o.cfgvalue = get_cfgvalue(v.id, "main_node")
o.write = get_write(v.id, "main_node")
if (has_v2ray and has_xray) or (v.type == "V2ray" and not has_v2ray) or (v.type == "Xray" and not has_xray) then
if (has_singbox and has_xray) or (v.type == "sing-box" and not has_singbox) or (v.type == "Xray" and not has_xray) then
type:depends("node", v.id)
else
type:depends("node", "hide") --不存在的依赖,即始终隐藏
@ -212,14 +214,6 @@ node_socks_port = s:taboption("Main", Value, "node_socks_port", translate("Node"
node_socks_port.default = 1070
node_socks_port.datatype = "port"
--[[
if has_v2ray or has_xray then
node_http_port = s:taboption("Main", Value, "node_http_port", translate("Node") .. " HTTP " .. translate("Listen Port") .. " " .. translate("0 is not use"))
node_http_port.default = 0
node_http_port.datatype = "port"
end
]]--
s:tab("DNS", translate("DNS"))
o = s:taboption("DNS", ListValue, "remote_dns_protocol", translate("Remote DNS Protocol"))
@ -260,8 +254,6 @@ o = s:taboption("DNS", Value, "remote_dns_client_ip", translate("Remote DNS EDNS
o.description = translate("Notify the DNS server when the DNS query is notified, the location of the client (cannot be a private IP address).") .. "<br />" ..
translate("This feature requires the DNS server to support the Edns Client Subnet (RFC7871).")
o.datatype = "ipaddr"
o:depends("remote_dns_protocol", "tcp")
o:depends("remote_dns_protocol", "doh")
o = s:taboption("DNS", Flag, "remote_fakedns", "FakeDNS", translate("Use FakeDNS work in the shunt domain that proxy."))
o.default = "0"
@ -273,9 +265,16 @@ o:value("UseIP")
o:value("UseIPv4")
o:value("UseIPv6")
hosts = s:taboption("DNS", TextValue, "dns_hosts", translate("Domain Override"))
hosts.rows = 5
hosts.wrap = "off"
o = s:taboption("DNS", TextValue, "dns_hosts", translate("Domain Override"))
o.rows = 5
o.wrap = "off"
o.remove = function(self, section)
local node_value = node:formvalue(global_cfgid)
local node_t = m:get(node_value)
if node_t.type == "Xray" then
AbstractValue.remove(self, section)
end
end
o = s:taboption("DNS", Button, "clear_ipset", translate("Clear IPSET"), translate("Try this feature if the rule modification does not take effect."))
o.inputstyle = "remove"
@ -284,6 +283,14 @@ function o.write(e, e)
luci.http.redirect(api.url("log"))
end
for k, v in pairs(nodes_table) do
if v.type == "Xray" then
s.fields["remote_dns_client_ip"]:depends({ node = v.id, remote_dns_protocol = "tcp" })
s.fields["remote_dns_client_ip"]:depends({ node = v.id, remote_dns_protocol = "doh" })
s.fields["dns_hosts"]:depends({ node = v.id })
end
end
s:tab("log", translate("Log"))
o = s:taboption("log", Flag, "close_log", translate("Close Node Log"))
o.rmempty = false
@ -342,7 +349,7 @@ o.default = n + 1080
o.datatype = "port"
o.rmempty = false
if has_v2ray or has_xray then
if has_singbox or has_xray then
o = s:option(Value, "http_port", "HTTP " .. translate("Listen Port") .. " " .. translate("0 is not use"))
o.default = 0
o.datatype = "port"
@ -351,7 +358,7 @@ end
for k, v in pairs(nodes_table) do
node:value(v.id, v["remark"])
if v.type == "Socks" then
if has_v2ray or has_xray then
if has_singbox or has_xray then
socks_node:value(v.id, v["remark"])
end
else

View File

@ -83,7 +83,7 @@ o.cfgvalue = function(t, n)
local remarks = m:get(n, "remarks") or ""
local type = m:get(n, "type") or ""
str = str .. string.format("<input type='hidden' id='cbid.%s.%s.type' value='%s'/>", appname, n, type)
if type == "V2ray" or type == "Xray" then
if type == "sing-box" or type == "Xray" then
local protocol = m:get(n, "protocol")
if protocol == "_balancing" then
protocol = translate("Balancing")

View File

@ -2,7 +2,7 @@ local api = require "luci.passwall2.api"
local appname = api.appname
local has_ss = api.is_finded("ss-redir")
local has_ss_rust = api.is_finded("sslocal")
local has_v2ray = api.is_finded("v2ray")
local has_singbox = api.is_finded("sing-box")
local has_xray = api.is_finded("xray")
local ss_aead_type = {}
if has_ss then
@ -11,8 +11,8 @@ end
if has_ss_rust then
ss_aead_type[#ss_aead_type + 1] = "shadowsocks-rust"
end
if has_v2ray then
ss_aead_type[#ss_aead_type + 1] = "v2ray"
if has_singbox then
ss_aead_type[#ss_aead_type + 1] = "sing-box"
end
if has_xray then
ss_aead_type[#ss_aead_type + 1] = "xray"

View File

@ -3,7 +3,7 @@ local appname = api.appname
local sys = api.sys
local has_ss = api.is_finded("ss-redir")
local has_ss_rust = api.is_finded("sslocal")
local has_v2ray = api.is_finded("v2ray")
local has_singbox = api.is_finded("sing-box")
local has_xray = api.is_finded("xray")
local ss_aead_type = {}
if has_ss then
@ -12,8 +12,8 @@ end
if has_ss_rust then
ss_aead_type[#ss_aead_type + 1] = "shadowsocks-rust"
end
if has_v2ray then
ss_aead_type[#ss_aead_type + 1] = "v2ray"
if has_singbox then
ss_aead_type[#ss_aead_type + 1] = "sing-box"
end
if has_xray then
ss_aead_type[#ss_aead_type + 1] = "xray"

View File

@ -1,7 +1,8 @@
local api = require "luci.passwall2.api"
local appname = api.appname
local fs = api.fs
local has_v2ray = api.is_finded("v2ray")
local uci = api.uci
local has_singbox = api.is_finded("sing-box")
local has_xray = api.is_finded("xray")
local has_fw3 = api.is_finded("fw3")
local has_fw4 = api.is_finded("fw4")
@ -126,8 +127,8 @@ o = s:option(Flag, "accept_icmpv6", translate("Hijacking ICMPv6 (IPv6 PING)"))
o:depends("ipv6_tproxy", true)
o.default = 0
if has_v2ray or has_xray then
s = m:section(TypedSection, "global_xray", "V2Ray/Xray " .. translate("Settings"))
if has_xray then
s = m:section(TypedSection, "global_xray", "Xray " .. translate("Settings"))
s.anonymous = true
s.addremove = false
@ -158,4 +159,33 @@ if has_v2ray or has_xray then
end
end
if has_singbox then
s = m:section(TypedSection, "global_singbox", "Sing-Box " .. translate("Settings"))
s.anonymous = true
s.addremove = false
o = s:option(Flag, "sniff_override_destination", translate("Override the connection destination address"), translate("Override the connection destination address with the sniffed domain."))
o.default = 1
o.rmempty = false
o = s:option(Value, "geoip_path", translate("Custom geoip Path"))
o.default = "/tmp/singbox/geoip.db"
o.rmempty = false
o = s:option(Value, "geoip_url", translate("Custom geoip URL"))
o.default = "https://github.com/SagerNet/sing-geoip/releases/latest/download/geoip.db"
o:value("https://github.com/SagerNet/sing-geoip/releases/latest/download/geoip.db")
o.rmempty = false
o = s:option(Value, "geosite_path", translate("Custom geosite Path"))
o.default = "/tmp/singbox/geosite.db"
o.rmempty = false
o = s:option(Value, "geosite_url", translate("Custom geosite URL"))
o.default = "https://github.com/SagerNet/sing-geosite/releases/latest/download/geosite.db"
o:value("https://github.com/SagerNet/sing-geosite/releases/latest/download/geosite.db")
o.rmempty = false
end
return m

View File

@ -41,7 +41,7 @@ for e = 0, 23 do o:value(e, e .. translate("oclock")) end
o.default = 0
o:depends("auto_update", true)
s = m:section(TypedSection, "shunt_rules", "V2ray/Xray " .. translate("Shunt Rule"), "<a style='color: red'>" .. translate("Please note attention to the priority, the higher the order, the higher the priority.") .. "</a>")
s = m:section(TypedSection, "shunt_rules", "Xray " .. translate("Shunt Rule"), "<a style='color: red'>" .. translate("Please note attention to the priority, the higher the order, the higher the priority.") .. "</a>")
s.template = "cbi/tblsection"
s.anonymous = false
s.addremove = true

View File

@ -2,7 +2,7 @@ local api = require "luci.passwall2.api"
local appname = api.appname
local datatypes = api.datatypes
m = Map(appname, "V2ray/Xray " .. translate("Shunt Rule"))
m = Map(appname, "Xray " .. translate("Shunt Rule"))
m.redirect = api.url()
s = m:section(NamedSection, arg[1], "shunt_rules", "")

View File

@ -1,7 +1,7 @@
local api = require "luci.passwall2.api"
local appname = api.appname
local uci = api.uci
local has_v2ray = api.is_finded("v2ray")
local has_singbox = api.is_finded("sing-box")
local has_xray = api.is_finded("xray")
m = Map(appname)
@ -54,7 +54,7 @@ o.default = n + 1080
o.datatype = "port"
o.rmempty = false
if has_v2ray or has_xray then
if has_singbox or has_xray then
o = s:option(Value, "http_port", "HTTP " .. translate("Listen Port") .. " " .. translate("0 is not use"))
o.default = 0
o.datatype = "port"

View File

@ -2,13 +2,15 @@ local m, s = ...
local api = require "luci.passwall2.api"
if not api.is_finded("xray") and not api.is_finded("v2ray") then
if not api.is_finded("xray") then
return
end
local appname = api.appname
local uci = api.uci
local type_name = "Xray"
local option_prefix = "xray_"
local function option_name(name)
@ -21,52 +23,20 @@ local function rm_prefix_cfgvalue(self, section)
end
end
local function rm_prefix_write(self, section, value)
if s.fields["type"]:formvalue(arg[1]) == "Xray" or s.fields["type"]:formvalue(arg[1]) == "V2ray" then
if s.fields["type"]:formvalue(arg[1]) == type_name then
if self.option:find(option_prefix) == 1 then
m:set(section, self.option:sub(1 + #option_prefix), value)
end
end
end
local function rm_prefix_remove(self, section, value)
if s.fields["type"]:formvalue(arg[1]) == "Xray" or s.fields["type"]:formvalue(arg[1]) == "V2ray" then
if s.fields["type"]:formvalue(arg[1]) == type_name then
if self.option:find(option_prefix) == 1 then
m:del(section, self.option:sub(1 + #option_prefix))
end
end
end
local function add_xray_depends(o, field, value)
local deps = { type = "Xray" }
if field then
if type(field) == "string" then
deps[field] = value
else
for key, value in pairs(field) do
deps[key] = value
end
end
end
o:depends(deps)
end
local function add_v2ray_depends(o, field, value)
local deps = { type = "V2ray" }
if field then
if type(field) == "string" then
deps[field] = value
else
for key, value in pairs(field) do
deps[key] = value
end
end
end
o:depends(deps)
end
local v_ss_encrypt_method_list = {
"aes-128-gcm", "aes-256-gcm", "chacha20-poly1305"
}
local x_ss_encrypt_method_list = {
"aes-128-gcm", "aes-256-gcm", "chacha20-poly1305", "xchacha20-poly1305", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"
}
@ -79,12 +49,7 @@ local header_type_list = {
-- [[ Xray ]]
if api.is_finded("xray") then
s.fields["type"]:value("Xray", translate("Xray"))
end
if api.is_finded("v2ray") then
s.fields["type"]:value("V2ray", translate("V2ray"))
end
s.fields["type"]:value(type_name, "Xray")
o = s:option(ListValue, option_name("protocol"), translate("Protocol"))
o:value("vmess", translate("Vmess"))
@ -97,8 +62,6 @@ o:value("wireguard", translate("WireGuard"))
o:value("_balancing", translate("Balancing"))
o:value("_shunt", translate("Shunt"))
o:value("_iface", translate("Custom Interface") .. " (Only Support Xray)")
add_xray_depends(o)
add_v2ray_depends(o)
o = s:option(Value, option_name("iface"), translate("Interface"))
o.default = "eth1"
@ -131,31 +94,26 @@ end
-- 负载均衡列表
local o = s:option(DynamicList, option_name("balancing_node"), translate("Load balancing node list"), translate("Load balancing node list, <a target='_blank' href='https://toutyrater.github.io/routing/balance2.html'>document</a>"))
o:depends({ [option_name("protocol")] = "_balancing" })
add_v2ray_depends(o, { [option_name("protocol")] = "_balancing" })
for k, v in pairs(nodes_table) do o:value(v.id, v.remarks) end
local o = s:option(ListValue, option_name("balancingStrategy"), translate("Balancing Strategy"))
add_xray_depends(o, { [option_name("protocol")] = "_balancing" })
add_v2ray_depends(o, { [option_name("protocol")] = "_balancing" })
o:depends({ [option_name("protocol")] = "_balancing" })
o:value("random")
o:value("leastPing")
o.default = "random"
-- 探测地址
local o = s:option(Flag, option_name("useCustomProbeUrl"), translate("Use Custome Probe URL"), translate("By default the built-in probe URL will be used, enable this option to use a custom probe URL."))
add_xray_depends(o, { [option_name("balancingStrategy")] = "leastPing" })
add_v2ray_depends(o, { [option_name("balancingStrategy")] = "leastPing" })
o:depends({ [option_name("balancingStrategy")] = "leastPing" })
local o = s:option(Value, option_name("probeUrl"), translate("Probe URL"))
add_xray_depends(o, { [option_name("useCustomProbeUrl")] = true })
add_v2ray_depends(o, { [option_name("useCustomProbeUrl")] = true })
o:depends({ [option_name("useCustomProbeUrl")] = true })
o.default = "https://www.google.com/generate_204"
o.description = translate("The URL used to detect the connection status.")
-- 探测间隔
local o = s:option(Value, option_name("probeInterval"), translate("Probe Interval"))
add_xray_depends(o, { [option_name("balancingStrategy")] = "leastPing" })
add_v2ray_depends(o, { [option_name("balancingStrategy")] = "leastPing" })
o:depends({ [option_name("balancingStrategy")] = "leastPing" })
o.default = "1m"
o.description = translate("The interval between initiating probes. Every time this time elapses, a server status check is performed on a server. The time format is numbers + units, such as '10s', '2h45m', and the supported time units are <code>ns</code>, <code>us</code>, <code>ms</code>, <code>s</code>, <code>m</code>, <code>h</code>, which correspond to nanoseconds, microseconds, milliseconds, seconds, minutes, and hours, respectively.")
@ -163,11 +121,9 @@ o.description = translate("The interval between initiating probes. Every time th
if #nodes_table > 0 then
o = s:option(Flag, option_name("preproxy_enabled"), translate("Preproxy"))
o:depends({ [option_name("protocol")] = "_shunt" })
add_v2ray_depends(o, { [option_name("protocol")] = "_shunt" })
o = s:option(Value, option_name("main_node"), string.format('<a style="color:red">%s</a>', translate("Preproxy Node")), translate("Set the node to be used as a pre-proxy. Each rule (including <code>Default</code>) has a separate switch that controls whether this rule uses the pre-proxy or not."))
o:depends({ [option_name("protocol")] = "_shunt", [option_name("preproxy_enabled")] = true })
add_v2ray_depends(o, { [option_name("protocol")] = "_shunt", [option_name("preproxy_enabled")] = true })
for k, v in pairs(balancers_table) do
o:value(v.id, v.remarks)
end
@ -187,7 +143,6 @@ uci:foreach(appname, "shunt_rules", function(e)
o:value("_direct", translate("Direct Connection"))
o:value("_blackhole", translate("Blackhole"))
o:depends({ [option_name("protocol")] = "_shunt" })
add_v2ray_depends(o, { [option_name("protocol")] = "_shunt" })
if #nodes_table > 0 then
for k, v in pairs(balancers_table) do
@ -203,7 +158,6 @@ uci:foreach(appname, "shunt_rules", function(e)
for k, v in pairs(nodes_table) do
o:value(v.id, v.remarks)
pt:depends({ [option_name("protocol")] = "_shunt", [option_name("preproxy_enabled")] = true, [option_name(e[".name"])] = v.id })
add_v2ray_depends(o, { [option_name("protocol")] = "_shunt", [option_name("preproxy_enabled")] = true, [option_name(e[".name"])] = v.id })
end
end
end
@ -258,134 +212,88 @@ o:depends({ [option_name("protocol")] = "_shunt" })
-- [[ 分流模块 End ]]
o = s:option(Value, option_name("address"), translate("Address (Support Domain Name)"))
add_xray_depends(o, { [option_name("protocol")] = "vmess" })
add_xray_depends(o, { [option_name("protocol")] = "vless" })
add_xray_depends(o, { [option_name("protocol")] = "http" })
add_xray_depends(o, { [option_name("protocol")] = "socks" })
add_xray_depends(o, { [option_name("protocol")] = "shadowsocks" })
add_xray_depends(o, { [option_name("protocol")] = "trojan" })
add_xray_depends(o, { [option_name("protocol")] = "wireguard" })
add_v2ray_depends(o, { [option_name("protocol")] = "vmess" })
add_v2ray_depends(o, { [option_name("protocol")] = "vless" })
add_v2ray_depends(o, { [option_name("protocol")] = "http" })
add_v2ray_depends(o, { [option_name("protocol")] = "socks" })
add_v2ray_depends(o, { [option_name("protocol")] = "shadowsocks" })
add_v2ray_depends(o, { [option_name("protocol")] = "trojan" })
o = s:option(Value, option_name("port"), translate("Port"))
o.datatype = "port"
add_xray_depends(o, { [option_name("protocol")] = "vmess" })
add_xray_depends(o, { [option_name("protocol")] = "vless" })
add_xray_depends(o, { [option_name("protocol")] = "http" })
add_xray_depends(o, { [option_name("protocol")] = "socks" })
add_xray_depends(o, { [option_name("protocol")] = "shadowsocks" })
add_xray_depends(o, { [option_name("protocol")] = "trojan" })
add_xray_depends(o, { [option_name("protocol")] = "wireguard" })
add_v2ray_depends(o, { [option_name("protocol")] = "vmess" })
add_v2ray_depends(o, { [option_name("protocol")] = "vless" })
add_v2ray_depends(o, { [option_name("protocol")] = "http" })
add_v2ray_depends(o, { [option_name("protocol")] = "socks" })
add_v2ray_depends(o, { [option_name("protocol")] = "shadowsocks" })
add_v2ray_depends(o, { [option_name("protocol")] = "trojan" })
local protocols = s.fields[option_name("protocol")].keylist
if #protocols > 0 then
for index, value in ipairs(protocols) do
if not value:find("_") then
s.fields[option_name("address")]:depends({ [option_name("protocol")] = value })
s.fields[option_name("port")]:depends({ [option_name("protocol")] = value })
end
end
end
o = s:option(Value, option_name("username"), translate("Username"))
add_xray_depends(o, { [option_name("protocol")] = "http" })
add_xray_depends(o, { [option_name("protocol")] = "socks" })
add_v2ray_depends(o, { [option_name("protocol")] = "http" })
add_v2ray_depends(o, { [option_name("protocol")] = "socks" })
o:depends({ [option_name("protocol")] = "http" })
o:depends({ [option_name("protocol")] = "socks" })
o = s:option(Value, option_name("password"), translate("Password"))
o.password = true
add_xray_depends(o, { [option_name("protocol")] = "http" })
add_xray_depends(o, { [option_name("protocol")] = "socks" })
add_xray_depends(o, { [option_name("protocol")] = "shadowsocks" })
add_xray_depends(o, { [option_name("protocol")] = "trojan" })
add_v2ray_depends(o, { [option_name("protocol")] = "http" })
add_v2ray_depends(o, { [option_name("protocol")] = "socks" })
add_v2ray_depends(o, { [option_name("protocol")] = "shadowsocks" })
add_v2ray_depends(o, { [option_name("protocol")] = "trojan" })
o:depends({ [option_name("protocol")] = "http" })
o:depends({ [option_name("protocol")] = "socks" })
o:depends({ [option_name("protocol")] = "shadowsocks" })
o:depends({ [option_name("protocol")] = "trojan" })
o = s:option(ListValue, option_name("security"), translate("Encrypt Method"))
for a, t in ipairs(security_list) do o:value(t) end
add_xray_depends(o, { [option_name("protocol")] = "vmess" })
add_v2ray_depends(o, { [option_name("protocol")] = "vmess" })
o:depends({ [option_name("protocol")] = "vmess" })
o = s:option(Value, option_name("encryption"), translate("Encrypt Method"))
o.default = "none"
o:value("none")
add_xray_depends(o, { [option_name("protocol")] = "vless" })
add_v2ray_depends(o, { [option_name("protocol")] = "vless" })
o = s:option(ListValue, "v_ss_encrypt_method", translate("Encrypt Method"))
o.not_rewrite = true
for a, t in ipairs(v_ss_encrypt_method_list) do o:value(t) end
add_v2ray_depends(o, { [option_name("protocol")] = "shadowsocks" })
function o.cfgvalue(self, section)
return m:get(section, "method")
end
function o.write(self, section, value)
if s.fields["type"]:formvalue(arg[1]) == "Xray" or s.fields["type"]:formvalue(arg[1]) == "V2ray" then
m:set(section, "method", value)
end
end
o:depends({ [option_name("protocol")] = "vless" })
o = s:option(ListValue, option_name("x_ss_encrypt_method"), translate("Encrypt Method"))
o.not_rewrite = true
for a, t in ipairs(x_ss_encrypt_method_list) do o:value(t) end
add_xray_depends(o, { [option_name("protocol")] = "shadowsocks" })
o:depends({ [option_name("protocol")] = "shadowsocks" })
function o.cfgvalue(self, section)
return m:get(section, "method")
end
function o.write(self, section, value)
if s.fields["type"]:formvalue(arg[1]) == "Xray" or s.fields["type"]:formvalue(arg[1]) == "V2ray" then
if s.fields["type"]:formvalue(arg[1]) == type_name then
m:set(section, "method", value)
end
end
o = s:option(Flag, option_name("iv_check"), translate("IV Check"))
add_v2ray_depends(o, { [option_name("protocol")] = "shadowsocks" })
add_xray_depends(o, { [option_name("protocol")] = "shadowsocks", [option_name("x_ss_encrypt_method")] = "aes-128-gcm" })
add_xray_depends(o, { [option_name("protocol")] = "shadowsocks", [option_name("x_ss_encrypt_method")] = "aes-256-gcm" })
add_xray_depends(o, { [option_name("protocol")] = "shadowsocks", [option_name("x_ss_encrypt_method")] = "chacha20-poly1305" })
add_xray_depends(o, { [option_name("protocol")] = "shadowsocks", [option_name("x_ss_encrypt_method")] = "xchacha20-poly1305" })
o:depends({ [option_name("protocol")] = "shadowsocks", [option_name("x_ss_encrypt_method")] = "aes-128-gcm" })
o:depends({ [option_name("protocol")] = "shadowsocks", [option_name("x_ss_encrypt_method")] = "aes-256-gcm" })
o:depends({ [option_name("protocol")] = "shadowsocks", [option_name("x_ss_encrypt_method")] = "chacha20-poly1305" })
o:depends({ [option_name("protocol")] = "shadowsocks", [option_name("x_ss_encrypt_method")] = "xchacha20-poly1305" })
o = s:option(Flag, option_name("uot"), translate("UDP over TCP"), translate("Need Xray-core or sing-box as server side."))
add_xray_depends(o, { [option_name("protocol")] = "shadowsocks", [option_name("x_ss_encrypt_method")] = "2022-blake3-aes-128-gcm" })
add_xray_depends(o, { [option_name("protocol")] = "shadowsocks", [option_name("x_ss_encrypt_method")] = "2022-blake3-aes-256-gcm" })
add_xray_depends(o, { [option_name("protocol")] = "shadowsocks", [option_name("x_ss_encrypt_method")] = "2022-blake3-chacha20-poly1305" })
o:depends({ [option_name("protocol")] = "shadowsocks", [option_name("x_ss_encrypt_method")] = "2022-blake3-aes-128-gcm" })
o:depends({ [option_name("protocol")] = "shadowsocks", [option_name("x_ss_encrypt_method")] = "2022-blake3-aes-256-gcm" })
o:depends({ [option_name("protocol")] = "shadowsocks", [option_name("x_ss_encrypt_method")] = "2022-blake3-chacha20-poly1305" })
o = s:option(Value, option_name("uuid"), translate("ID"))
o.password = true
add_xray_depends(o, { [option_name("protocol")] = "vmess" })
add_xray_depends(o, { [option_name("protocol")] = "vless" })
add_v2ray_depends(o, { [option_name("protocol")] = "vmess" })
add_v2ray_depends(o, { [option_name("protocol")] = "vless" })
o:depends({ [option_name("protocol")] = "vmess" })
o:depends({ [option_name("protocol")] = "vless" })
o = s:option(Flag, option_name("tls"), translate("TLS"))
o.default = 0
add_xray_depends(o, { [option_name("protocol")] = "vmess" })
add_xray_depends(o, { [option_name("protocol")] = "vless" })
add_xray_depends(o, { [option_name("protocol")] = "socks" })
add_xray_depends(o, { [option_name("protocol")] = "trojan" })
add_xray_depends(o, { [option_name("protocol")] = "shadowsocks" })
add_v2ray_depends(o, { [option_name("protocol")] = "vmess" })
add_v2ray_depends(o, { [option_name("protocol")] = "vless" })
add_v2ray_depends(o, { [option_name("protocol")] = "socks" })
add_v2ray_depends(o, { [option_name("protocol")] = "trojan" })
add_v2ray_depends(o, { [option_name("protocol")] = "shadowsocks" })
o = s:option(Value, option_name("tlsflow"), translate("flow"))
o = s:option(ListValue, option_name("flow"), translate("flow"))
o.default = ""
o:value("", translate("Disable"))
o:value("xtls-rprx-vision")
o:value("xtls-rprx-vision-udp443")
add_xray_depends(o, { [option_name("protocol")] = "vless", [option_name("tls")] = true, [option_name("transport")] = "tcp" })
o:depends({ [option_name("protocol")] = "vless" })
o = s:option(Flag, option_name("reality"), translate("REALITY"), translate("Only recommend to use with VLESS-TCP-XTLS-Vision."))
o = s:option(Flag, option_name("tls"), translate("TLS"))
o.default = 0
add_xray_depends(o, { [option_name("tls")] = true, [option_name("transport")] = "tcp" })
add_xray_depends(o, { [option_name("tls")] = true, [option_name("transport")] = "h2" })
add_xray_depends(o, { [option_name("tls")] = true, [option_name("transport")] = "grpc" })
o:depends({ [option_name("protocol")] = "vmess" })
o:depends({ [option_name("protocol")] = "vless" })
o:depends({ [option_name("protocol")] = "socks" })
o:depends({ [option_name("protocol")] = "trojan" })
o:depends({ [option_name("protocol")] = "shadowsocks" })
o = s:option(Flag, option_name("reality"), translate("REALITY"))
o.default = 0
o:depends({ [option_name("tls")] = true, [option_name("transport")] = "tcp" })
o:depends({ [option_name("tls")] = true, [option_name("transport")] = "h2" })
o:depends({ [option_name("tls")] = true, [option_name("transport")] = "grpc" })
o = s:option(ListValue, option_name("alpn"), translate("alpn"))
o.default = "default"
@ -393,72 +301,49 @@ o:value("default", translate("Default"))
o:value("h2,http/1.1")
o:value("h2")
o:value("http/1.1")
add_xray_depends(o, { [option_name("tls")] = true, [option_name("reality")] = false })
add_v2ray_depends(o, { [option_name("tls")] = true })
o:depends({ [option_name("tls")] = true, [option_name("reality")] = false })
-- o = s:option(Value, option_name("minversion"), translate("minversion"))
-- o.default = "1.3"
-- o:value("1.3")
-- add_xray_depends(o, { [option_name("tls")] = true })
-- add_v2ray_depends(o, { [option_name("tls")] = true })
-- o:depends({ [option_name("tls")] = true })
o = s:option(Value, option_name("tls_serverName"), translate("Domain"))
add_xray_depends(o, { [option_name("tls")] = true })
add_v2ray_depends(o, { [option_name("tls")] = true })
o:depends({ [option_name("tls")] = true })
o = s:option(Flag, option_name("tls_allowInsecure"), translate("allowInsecure"), translate("Whether unsafe connections are allowed. When checked, Certificate validation will be skipped."))
o.default = "0"
add_xray_depends(o, { [option_name("tls")] = true, [option_name("reality")] = false })
add_v2ray_depends(o, { [option_name("tls")] = true })
o = s:option(Value, option_name("fingerprint"), translate("Finger Print"), translate("Avoid using randomized, unless you have to."))
o:value("", translate("Disable"))
o:value("chrome")
o:value("firefox")
o:value("safari")
o:value("ios")
-- o:value("android")
o:value("edge")
-- o:value("360")
o:value("qq")
o:value("random")
o:value("randomized")
o.default = ""
add_xray_depends(o, { [option_name("tls")] = true, [option_name("reality")] = false })
o:depends({ [option_name("tls")] = true, [option_name("reality")] = false })
-- [[ REALITY部分 ]] --
o = s:option(Value, option_name("reality_publicKey"), translate("Public Key"))
add_xray_depends(o, { [option_name("tls")] = true, [option_name("reality")] = true })
o:depends({ [option_name("tls")] = true, [option_name("reality")] = true })
o = s:option(Value, option_name("reality_shortId"), translate("Short Id"))
add_xray_depends(o, { [option_name("tls")] = true, [option_name("reality")] = true })
o:depends({ [option_name("tls")] = true, [option_name("reality")] = true })
o = s:option(Value, option_name("reality_spiderX"), translate("Spider X"))
o.placeholder = "/"
add_xray_depends(o, { [option_name("tls")] = true, [option_name("reality")] = true })
o:depends({ [option_name("tls")] = true, [option_name("reality")] = true })
o = s:option(Value, option_name("reality_fingerprint"), translate("Finger Print"), translate("Avoid using randomized, unless you have to."))
o.not_rewrite = true
o = s:option(Flag, option_name("utls"), translate("uTLS"))
o.default = "0"
o:depends({ [option_name("tls")] = true, [option_name("reality")] = false })
o = s:option(ListValue, option_name("fingerprint"), translate("Finger Print"))
o:value("chrome")
o:value("firefox")
o:value("safari")
o:value("ios")
-- o:value("android")
o:value("edge")
-- o:value("360")
o:value("safari")
o:value("360")
o:value("qq")
o:value("ios")
o:value("android")
o:value("random")
o:value("randomized")
o.default = "chrome"
add_xray_depends(o, { [option_name("tls")] = true, [option_name("reality")] = true })
function o.cfgvalue(self, section)
return m:get(section, "fingerprint")
end
function o.write(self, section, value)
if s.fields["type"]:formvalue(arg[1]) == "Xray" or s.fields["type"]:formvalue(arg[1]) == "V2ray" then
m:set(section, "fingerprint", value)
end
end
o:depends({ [option_name("tls")] = true, [option_name("utls")] = true })
o:depends({ [option_name("tls")] = true, [option_name("reality")] = true })
o = s:option(ListValue, option_name("transport"), translate("Transport"))
o:value("tcp", "TCP")
@ -468,50 +353,44 @@ o:value("h2", "HTTP/2")
o:value("ds", "DomainSocket")
o:value("quic", "QUIC")
o:value("grpc", "gRPC")
add_xray_depends(o, { [option_name("protocol")] = "vmess" })
add_xray_depends(o, { [option_name("protocol")] = "vless" })
add_xray_depends(o, { [option_name("protocol")] = "socks" })
add_xray_depends(o, { [option_name("protocol")] = "shadowsocks" })
add_xray_depends(o, { [option_name("protocol")] = "trojan" })
add_v2ray_depends(o, { [option_name("protocol")] = "vmess" })
add_v2ray_depends(o, { [option_name("protocol")] = "vless" })
add_v2ray_depends(o, { [option_name("protocol")] = "socks" })
add_v2ray_depends(o, { [option_name("protocol")] = "shadowsocks" })
add_v2ray_depends(o, { [option_name("protocol")] = "trojan" })
o:depends({ [option_name("protocol")] = "vmess" })
o:depends({ [option_name("protocol")] = "vless" })
o:depends({ [option_name("protocol")] = "socks" })
o:depends({ [option_name("protocol")] = "shadowsocks" })
o:depends({ [option_name("protocol")] = "trojan" })
--[[
o = s:option(ListValue, option_name("ss_transport"), translate("Transport"))
o:value("ws", "WebSocket")
o:value("h2", "HTTP/2")
o:value("h2+ws", "HTTP/2 & WebSocket")
add_xray_depends(o, { [option_name("protocol")] = "shadowsocks" })
add_v2ray_depends(o, { [option_name("protocol")] = "shadowsocks" })
o:depends({ [option_name("protocol")] = "shadowsocks" })
]]--
o = s:option(Value, option_name("wireguard_public_key"), translate("Public Key"))
add_xray_depends(o, { [option_name("protocol")] = "wireguard" })
o:depends({ [option_name("protocol")] = "wireguard" })
o = s:option(Value, option_name("wireguard_secret_key"), translate("Private Key"))
add_xray_depends(o, { [option_name("protocol")] = "wireguard" })
o:depends({ [option_name("protocol")] = "wireguard" })
o = s:option(Value, option_name("wireguard_preSharedKey"), translate("Pre shared key"))
add_xray_depends(o, { [option_name("protocol")] = "wireguard" })
o:depends({ [option_name("protocol")] = "wireguard" })
o = s:option(DynamicList, option_name("wireguard_local_address"), translate("Local Address"))
add_xray_depends(o, { [option_name("protocol")] = "wireguard" })
o:depends({ [option_name("protocol")] = "wireguard" })
o = s:option(Value, option_name("wireguard_mtu"), translate("MTU"))
o.default = "1420"
add_xray_depends(o, { [option_name("protocol")] = "wireguard" })
o:depends({ [option_name("protocol")] = "wireguard" })
if api.compare_versions(api.get_app_version("xray"), ">=", "1.8.0") then
o = s:option(Value, option_name("wireguard_reserved"), translate("Reserved"), translate("Decimal numbers separated by \",\" or Base64-encoded strings."))
add_xray_depends(o, { [option_name("protocol")] = "wireguard" })
o:depends({ [option_name("protocol")] = "wireguard" })
end
o = s:option(Value, option_name("wireguard_keepAlive"), translate("Keep Alive"))
o.default = "0"
add_xray_depends(o, { [option_name("protocol")] = "wireguard" })
o:depends({ [option_name("protocol")] = "wireguard" })
-- [[ TCP部分 ]]--
@ -519,194 +398,152 @@ add_xray_depends(o, { [option_name("protocol")] = "wireguard" })
o = s:option(ListValue, option_name("tcp_guise"), translate("Camouflage Type"))
o:value("none", "none")
o:value("http", "http")
add_xray_depends(o, { [option_name("transport")] = "tcp" })
add_v2ray_depends(o, { [option_name("transport")] = "tcp" })
o:depends({ [option_name("transport")] = "tcp" })
-- HTTP域名
o = s:option(DynamicList, option_name("tcp_guise_http_host"), translate("HTTP Host"))
add_xray_depends(o, { [option_name("tcp_guise")] = "http" })
add_v2ray_depends(o, { [option_name("tcp_guise")] = "http" })
o:depends({ [option_name("tcp_guise")] = "http" })
-- HTTP路径
o = s:option(DynamicList, option_name("tcp_guise_http_path"), translate("HTTP Path"))
o.placeholder = "/"
add_xray_depends(o, { [option_name("tcp_guise")] = "http" })
add_v2ray_depends(o, { [option_name("tcp_guise")] = "http" })
o:depends({ [option_name("tcp_guise")] = "http" })
-- [[ mKCP部分 ]]--
o = s:option(ListValue, option_name("mkcp_guise"), translate("Camouflage Type"), translate('<br />none: default, no masquerade, data sent is packets with no characteristics.<br />srtp: disguised as an SRTP packet, it will be recognized as video call data (such as FaceTime).<br />utp: packets disguised as uTP will be recognized as bittorrent downloaded data.<br />wechat-video: packets disguised as WeChat video calls.<br />dtls: disguised as DTLS 1.2 packet.<br />wireguard: disguised as a WireGuard packet. (not really WireGuard protocol)'))
for a, t in ipairs(header_type_list) do o:value(t) end
add_xray_depends(o, { [option_name("transport")] = "mkcp" })
add_v2ray_depends(o, { [option_name("transport")] = "mkcp" })
o:depends({ [option_name("transport")] = "mkcp" })
o = s:option(Value, option_name("mkcp_mtu"), translate("KCP MTU"))
o.default = "1350"
add_xray_depends(o, { [option_name("transport")] = "mkcp" })
add_v2ray_depends(o, { [option_name("transport")] = "mkcp" })
o:depends({ [option_name("transport")] = "mkcp" })
o = s:option(Value, option_name("mkcp_tti"), translate("KCP TTI"))
o.default = "20"
add_xray_depends(o, { [option_name("transport")] = "mkcp" })
add_v2ray_depends(o, { [option_name("transport")] = "mkcp" })
o:depends({ [option_name("transport")] = "mkcp" })
o = s:option(Value, option_name("mkcp_uplinkCapacity"), translate("KCP uplinkCapacity"))
o.default = "5"
add_xray_depends(o, { [option_name("transport")] = "mkcp" })
add_v2ray_depends(o, { [option_name("transport")] = "mkcp" })
o:depends({ [option_name("transport")] = "mkcp" })
o = s:option(Value, option_name("mkcp_downlinkCapacity"), translate("KCP downlinkCapacity"))
o.default = "20"
add_xray_depends(o, { [option_name("transport")] = "mkcp" })
add_v2ray_depends(o, { [option_name("transport")] = "mkcp" })
o:depends({ [option_name("transport")] = "mkcp" })
o = s:option(Flag, option_name("mkcp_congestion"), translate("KCP Congestion"))
add_xray_depends(o, { [option_name("transport")] = "mkcp" })
add_v2ray_depends(o, { [option_name("transport")] = "mkcp" })
o:depends({ [option_name("transport")] = "mkcp" })
o = s:option(Value, option_name("mkcp_readBufferSize"), translate("KCP readBufferSize"))
o.default = "1"
add_xray_depends(o, { [option_name("transport")] = "mkcp" })
add_v2ray_depends(o, { [option_name("transport")] = "mkcp" })
o:depends({ [option_name("transport")] = "mkcp" })
o = s:option(Value, option_name("mkcp_writeBufferSize"), translate("KCP writeBufferSize"))
o.default = "1"
add_xray_depends(o, { [option_name("transport")] = "mkcp" })
add_v2ray_depends(o, { [option_name("transport")] = "mkcp" })
o:depends({ [option_name("transport")] = "mkcp" })
o = s:option(Value, option_name("mkcp_seed"), translate("KCP Seed"))
add_xray_depends(o, { [option_name("transport")] = "mkcp" })
add_v2ray_depends(o, { [option_name("transport")] = "mkcp" })
o:depends({ [option_name("transport")] = "mkcp" })
-- [[ WebSocket部分 ]]--
o = s:option(Value, option_name("ws_host"), translate("WebSocket Host"))
add_xray_depends(o, { [option_name("transport")] = "ws" })
add_xray_depends(o, { [option_name("ss_transport")] = "ws" })
add_v2ray_depends(o, { [option_name("transport")] = "ws" })
add_v2ray_depends(o, { [option_name("ss_transport")] = "ws" })
o:depends({ [option_name("transport")] = "ws" })
o:depends({ [option_name("ss_transport")] = "ws" })
o = s:option(Value, option_name("ws_path"), translate("WebSocket Path"))
o.placeholder = "/"
add_xray_depends(o, { [option_name("transport")] = "ws" })
add_xray_depends(o, { [option_name("ss_transport")] = "ws" })
add_v2ray_depends(o, { [option_name("transport")] = "ws" })
add_v2ray_depends(o, { [option_name("ss_transport")] = "ws" })
o = s:option(Flag, "v2ray_ws_enableEarlyData", translate("Enable early data"))
add_v2ray_depends(o, { [option_name("transport")] = "ws" })
o = s:option(Value, "v2ray_ws_maxEarlyData", translate("Early data length"))
o.default = "1024"
add_v2ray_depends(o, { v2ray_ws_enableEarlyData = true })
o = s:option(Value, "v2ray_ws_earlyDataHeaderName", translate("Early data header name"), translate("Recommended value: Sec-WebSocket-Protocol"))
add_v2ray_depends(o, { v2ray_ws_enableEarlyData = true })
o:depends({ [option_name("transport")] = "ws" })
o:depends({ [option_name("ss_transport")] = "ws" })
-- [[ HTTP/2部分 ]]--
o = s:option(Value, option_name("h2_host"), translate("HTTP/2 Host"))
add_xray_depends(o, { [option_name("transport")] = "h2" })
add_xray_depends(o, { [option_name("ss_transport")] = "h2" })
add_v2ray_depends(o, { [option_name("transport")] = "h2" })
add_v2ray_depends(o, { [option_name("ss_transport")] = "h2" })
o:depends({ [option_name("transport")] = "h2" })
o:depends({ [option_name("ss_transport")] = "h2" })
o = s:option(Value, option_name("h2_path"), translate("HTTP/2 Path"))
o.placeholder = "/"
add_xray_depends(o, { [option_name("transport")] = "h2" })
add_xray_depends(o, { [option_name("ss_transport")] = "h2" })
add_v2ray_depends(o, { [option_name("transport")] = "h2" })
add_v2ray_depends(o, { [option_name("ss_transport")] = "h2" })
o:depends({ [option_name("transport")] = "h2" })
o:depends({ [option_name("ss_transport")] = "h2" })
o = s:option(Flag, option_name("h2_health_check"), translate("Health check"))
add_xray_depends(o, { [option_name("transport")] = "h2" })
o:depends({ [option_name("transport")] = "h2" })
o = s:option(Value, option_name("h2_read_idle_timeout"), translate("Idle timeout"))
o.default = "10"
add_xray_depends(o, { [option_name("h2_health_check")] = true })
o:depends({ [option_name("h2_health_check")] = true })
o = s:option(Value, option_name("h2_health_check_timeout"), translate("Health check timeout"))
o.default = "15"
add_xray_depends(o, { [option_name("h2_health_check")] = true })
o:depends({ [option_name("h2_health_check")] = true })
-- [[ DomainSocket部分 ]]--
o = s:option(Value, option_name("ds_path"), "Path", translate("A legal file path. This file must not exist before running."))
add_xray_depends(o, { [option_name("transport")] = "ds" })
add_v2ray_depends(o, { [option_name("transport")] = "ds" })
o:depends({ [option_name("transport")] = "ds" })
-- [[ QUIC部分 ]]--
o = s:option(ListValue, option_name("quic_security"), translate("Encrypt Method"))
o:value("none")
o:value("aes-128-gcm")
o:value("chacha20-poly1305")
add_xray_depends(o, { [option_name("transport")] = "quic" })
add_v2ray_depends(o, { [option_name("transport")] = "quic" })
o:depends({ [option_name("transport")] = "quic" })
o = s:option(Value, option_name("quic_key"), translate("Encrypt Method") .. translate("Key"))
add_xray_depends(o, { [option_name("transport")] = "quic" })
add_v2ray_depends(o, { [option_name("transport")] = "quic" })
o:depends({ [option_name("transport")] = "quic" })
o = s:option(ListValue, option_name("quic_guise"), translate("Camouflage Type"))
for a, t in ipairs(header_type_list) do o:value(t) end
add_xray_depends(o, { [option_name("transport")] = "quic" })
add_v2ray_depends(o, { [option_name("transport")] = "quic" })
o:depends({ [option_name("transport")] = "quic" })
-- [[ gRPC部分 ]]--
o = s:option(Value, option_name("grpc_serviceName"), "ServiceName")
add_xray_depends(o, { [option_name("transport")] = "grpc" })
add_v2ray_depends(o, { [option_name("transport")] = "grpc" })
o:depends({ [option_name("transport")] = "grpc" })
o = s:option(ListValue, option_name("grpc_mode"), "gRPC " .. translate("Transfer mode"))
o:value("gun")
o:value("multi")
add_xray_depends(o, { [option_name("transport")] = "grpc" })
o:depends({ [option_name("transport")] = "grpc" })
o = s:option(Flag, option_name("grpc_health_check"), translate("Health check"))
add_xray_depends(o, { [option_name("transport")] = "grpc" })
o:depends({ [option_name("transport")] = "grpc" })
o = s:option(Value, option_name("grpc_idle_timeout"), translate("Idle timeout"))
o.default = "10"
add_xray_depends(o, { [option_name("grpc_health_check")] = true })
o:depends({ [option_name("grpc_health_check")] = true })
o = s:option(Value, option_name("grpc_health_check_timeout"), translate("Health check timeout"))
o.default = "20"
add_xray_depends(o, { [option_name("grpc_health_check")] = true })
o:depends({ [option_name("grpc_health_check")] = true })
o = s:option(Flag, option_name("grpc_permit_without_stream"), translate("Permit without stream"))
o.default = "0"
add_xray_depends(o, { [option_name("grpc_health_check")] = true })
o:depends({ [option_name("grpc_health_check")] = true })
o = s:option(Value, option_name("grpc_initial_windows_size"), translate("Initial Windows Size"))
o.default = "0"
add_xray_depends(o, { [option_name("transport")] = "grpc" })
o:depends({ [option_name("transport")] = "grpc" })
-- [[ Mux ]]--
o = s:option(Flag, option_name("mux"), translate("Mux"))
add_v2ray_depends(o, { [option_name("protocol")] = "vmess" })
add_v2ray_depends(o, { [option_name("protocol")] = "vless" })
add_v2ray_depends(o, { [option_name("protocol")] = "http" })
add_v2ray_depends(o, { [option_name("protocol")] = "socks" })
add_v2ray_depends(o, { [option_name("protocol")] = "shadowsocks" })
add_v2ray_depends(o, { [option_name("protocol")] = "trojan" })
add_xray_depends(o, { [option_name("protocol")] = "vmess" })
add_xray_depends(o, { [option_name("protocol")] = "vless", [option_name("tlsflow")] = "" })
add_xray_depends(o, { [option_name("protocol")] = "http" })
add_xray_depends(o, { [option_name("protocol")] = "socks" })
add_xray_depends(o, { [option_name("protocol")] = "shadowsocks" })
add_xray_depends(o, { [option_name("protocol")] = "trojan" })
o:depends({ [option_name("protocol")] = "vmess" })
o:depends({ [option_name("protocol")] = "vless", [option_name("flow")] = "" })
o:depends({ [option_name("protocol")] = "http" })
o:depends({ [option_name("protocol")] = "socks" })
o:depends({ [option_name("protocol")] = "shadowsocks" })
o:depends({ [option_name("protocol")] = "trojan" })
o = s:option(Value, option_name("mux_concurrency"), translate("Mux concurrency"))
o.default = 8
add_xray_depends(o, { [option_name("mux")] = true })
add_v2ray_depends(o, { [option_name("mux")] = true })
o:depends({ [option_name("mux")] = true })
-- [[ XUDP Mux ]]--
o = s:option(Flag, option_name("xmux"), translate("xMux"))
o.default = 1
add_xray_depends(o, { [option_name("protocol")] = "vless", [option_name("tlsflow")] = "xtls-rprx-vision" })
add_xray_depends(o, { [option_name("protocol")] = "vless", [option_name("tlsflow")] = "xtls-rprx-vision-udp443" })
o:depends({ [option_name("protocol")] = "vless", [option_name("flow")] = "xtls-rprx-vision" })
o:depends({ [option_name("protocol")] = "vless", [option_name("flow")] = "xtls-rprx-vision-udp443" })
o = s:option(Value, option_name("xudp_concurrency"), translate("XUDP Mux concurrency"))
o.default = 8
add_xray_depends(o, { [option_name("xmux")] = true })
o:depends({ [option_name("xmux")] = true })
for key, value in pairs(s.fields) do
if key:find(option_prefix) == 1 then
@ -715,5 +552,14 @@ for key, value in pairs(s.fields) do
s.fields[key].write = rm_prefix_write
s.fields[key].remove = rm_prefix_remove
end
local deps = s.fields[key].deps
if #deps > 0 then
for index, value in ipairs(deps) do
deps[index]["type"] = type_name
end
else
s.fields[key]:depends({ type = type_name })
end
end
end

View File

@ -0,0 +1,567 @@
local m, s = ...
local api = require "luci.passwall2.api"
if not api.is_finded("sing-box") then
return
end
local singbox_tags = luci.sys.exec(api.finded("sing-box") .. " version | grep 'Tags:' | awk '{print $2}'")
local appname = api.appname
local uci = api.uci
local type_name = "sing-box"
local option_prefix = "singbox_"
local function option_name(name)
return option_prefix .. name
end
local function rm_prefix_cfgvalue(self, section)
if self.option:find(option_prefix) == 1 then
return m:get(section, self.option:sub(1 + #option_prefix))
end
end
local function rm_prefix_write(self, section, value)
if s.fields["type"]:formvalue(arg[1]) == type_name then
if self.option:find(option_prefix) == 1 then
m:set(section, self.option:sub(1 + #option_prefix), value)
end
end
end
local function rm_prefix_remove(self, section, value)
if s.fields["type"]:formvalue(arg[1]) == type_name then
if self.option:find(option_prefix) == 1 then
m:del(section, self.option:sub(1 + #option_prefix))
end
end
end
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"
}
local ss_method_old_list = {
"aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "rc4-md5", "chacha20-ietf", "xchacha20",
}
local security_list = { "none", "auto", "aes-128-gcm", "chacha20-poly1305", "zero" }
-- [[ sing-box ]]
s.fields["type"]:value(type_name, translate("Sing-Box"))
o = s:option(ListValue, option_name("protocol"), translate("Protocol"))
o:value("socks", "Socks")
o:value("http", "HTTP")
o:value("shadowsocks", "Shadowsocks")
if singbox_tags:find("with_shadowsocksr") then
o:value("shadowsocksr", "ShadowsocksR")
end
o:value("vmess", "Vmess")
o:value("trojan", "Trojan")
if singbox_tags:find("with_wireguard") then
o:value("wireguard", "WireGuard")
end
if singbox_tags:find("with_quic") then
o:value("hysteria", "Hysteria")
end
o:value("shadowtls", "ShadowTLS")
o:value("vless", "VLESS")
if singbox_tags:find("with_quic") then
o:value("tuic", "TUIC")
end
if singbox_tags:find("with_quic") then
o:value("hysteria2", "Hysteria2")
end
o:value("_shunt", translate("Shunt"))
o:value("_iface", translate("Custom Interface") .. " (Only Support Xray)")
o = s:option(Value, option_name("iface"), translate("Interface"))
o.default = "eth1"
o:depends({ [option_name("protocol")] = "_iface" })
local nodes_table = {}
local balancers_table = {}
local iface_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"],
remarks = e["remark"]
}
end
if e.protocol == "_iface" then
iface_table[#iface_table + 1] = {
id = e[".name"],
remarks = e["remark"]
}
end
end
-- [[ 分流模块 ]]
if #nodes_table > 0 then
o = s:option(Flag, option_name("preproxy_enabled"), translate("Preproxy"))
o:depends({ [option_name("protocol")] = "_shunt" })
o = s:option(Value, option_name("main_node"), string.format('<a style="color:red">%s</a>', translate("Preproxy Node")), translate("Set the node to be used as a pre-proxy. Each rule (including <code>Default</code>) has a separate switch that controls whether this rule uses the pre-proxy or not."))
o:depends({ [option_name("protocol")] = "_shunt", [option_name("preproxy_enabled")] = true })
for k, v in pairs(balancers_table) do
o:value(v.id, v.remarks)
end
for k, v in pairs(iface_table) do
o:value(v.id, v.remarks)
end
for k, v in pairs(nodes_table) do
o:value(v.id, v.remarks)
end
o.default = "nil"
end
uci:foreach(appname, "shunt_rules", function(e)
if e[".name"] and e.remarks then
o = s:option(Value, option_name(e[".name"]), string.format('* <a href="%s" target="_blank">%s</a>', api.url("shunt_rules", e[".name"]), e.remarks))
o:value("nil", translate("Close"))
o:value("_default", translate("Default"))
o:value("_direct", translate("Direct Connection"))
o:value("_blackhole", translate("Blackhole"))
o:depends({ [option_name("protocol")] = "_shunt" })
if #nodes_table > 0 then
for k, v in pairs(balancers_table) do
o:value(v.id, v.remarks)
end
for k, v in pairs(iface_table) do
o:value(v.id, v.remarks)
end
local pt = s:option(ListValue, option_name(e[".name"] .. "_proxy_tag"), string.format('* <a style="color:red">%s</a>', e.remarks .. " " .. translate("Preproxy")))
pt:value("nil", translate("Close"))
pt:value("main", translate("Preproxy Node"))
pt.default = "nil"
for k, v in pairs(nodes_table) do
o:value(v.id, v.remarks)
pt:depends({ [option_name("protocol")] = "_shunt", [option_name("preproxy_enabled")] = true, [option_name(e[".name"])] = v.id })
end
end
end
end)
o = s:option(DummyValue, option_name("shunt_tips"), " ")
o.not_rewrite = true
o.rawhtml = true
o.cfgvalue = function(t, n)
return string.format('<a style="color: red" href="../rule">%s</a>', translate("No shunt rules? Click me to go to add."))
end
o:depends({ [option_name("protocol")] = "_shunt" })
local o = s:option(Value, option_name("default_node"), string.format('* <a style="color:red">%s</a>', translate("Default")))
o:depends({ [option_name("protocol")] = "_shunt" })
o:value("_direct", translate("Direct Connection"))
o:value("_blackhole", translate("Blackhole"))
if #nodes_table > 0 then
for k, v in pairs(balancers_table) do
o:value(v.id, v.remarks)
end
for k, v in pairs(iface_table) do
o:value(v.id, v.remarks)
end
local dpt = s:option(ListValue, option_name("default_proxy_tag"), string.format('* <a style="color:red">%s</a>', translate("Default Preproxy")), translate("When using, localhost will connect this node first and then use this node to connect the default node."))
dpt:value("nil", translate("Close"))
dpt:value("main", translate("Preproxy Node"))
dpt.default = "nil"
for k, v in pairs(nodes_table) do
o:value(v.id, v.remarks)
dpt:depends({ [option_name("protocol")] = "_shunt", [option_name("preproxy_enabled")] = true, [option_name("default_node")] = v.id })
end
end
-- [[ 分流模块 End ]]
o = s:option(Value, option_name("address"), translate("Address (Support Domain Name)"))
o = s:option(Value, option_name("port"), translate("Port"))
o.datatype = "port"
local protocols = s.fields[option_name("protocol")].keylist
if #protocols > 0 then
for index, value in ipairs(protocols) do
if not value:find("_") then
s.fields[option_name("address")]:depends({ [option_name("protocol")] = value })
s.fields[option_name("port")]:depends({ [option_name("protocol")] = value })
end
end
end
o = s:option(ListValue, option_name("shadowtls_version"), translate("Version"))
o.default = "1"
o:value("1", "ShadowTLS v1")
o:value("2", "ShadowTLS v2")
o:value("3", "ShadowTLS v3")
o:depends({ [option_name("protocol")] = "shadowtls" })
o = s:option(Value, option_name("username"), translate("Username"))
o:depends({ [option_name("protocol")] = "http" })
o:depends({ [option_name("protocol")] = "socks" })
o = s:option(Value, option_name("password"), translate("Password"))
o.password = true
o:depends({ [option_name("protocol")] = "http" })
o:depends({ [option_name("protocol")] = "socks" })
o:depends({ [option_name("protocol")] = "shadowsocks" })
o:depends({ [option_name("protocol")] = "shadowsocksr" })
o:depends({ [option_name("protocol")] = "trojan" })
o:depends({ [option_name("protocol")] = "shadowtls", [option_name("shadowtls_version")] = "2" })
o:depends({ [option_name("protocol")] = "shadowtls", [option_name("shadowtls_version")] = "3" })
o:depends({ [option_name("protocol")] = "tuic" })
o = s:option(ListValue, option_name("security"), translate("Encrypt Method"))
for a, t in ipairs(security_list) do o:value(t) end
o:depends({ [option_name("protocol")] = "vmess" })
o = s:option(ListValue, option_name("ss_method"), translate("Encrypt Method"))
o.not_rewrite = true
for a, t in ipairs(ss_method_new_list) do o:value(t) end
for a, t in ipairs(ss_method_old_list) do o:value(t) end
o:depends({ [option_name("protocol")] = "shadowsocks" })
function o.cfgvalue(self, section)
return m:get(section, "method")
end
function o.write(self, section, value)
if s.fields["type"]:formvalue(arg[1]) == type_name then
m:set(section, "method", value)
end
end
if singbox_tags:find("with_shadowsocksr") then
o = s:option(ListValue, option_name("ssr_method"), translate("Encrypt Method"))
o.not_rewrite = true
for a, t in ipairs(ss_method_old_list) do o:value(t) end
o:depends({ [option_name("protocol")] = "shadowsocksr" })
function o.cfgvalue(self, section)
return m:get(section, "method")
end
function o.write(self, section, value)
if s.fields["type"]:formvalue(arg[1]) == type_name then
m:set(section, "method", value)
end
end
local ssr_protocol_list = {
"origin", "verify_simple", "verify_deflate", "verify_sha1", "auth_simple",
"auth_sha1", "auth_sha1_v2", "auth_sha1_v4", "auth_aes128_md5",
"auth_aes128_sha1", "auth_chain_a", "auth_chain_b", "auth_chain_c",
"auth_chain_d", "auth_chain_e", "auth_chain_f"
}
o = s:option(ListValue, option_name("ssr_protocol"), translate("Protocol"))
for a, t in ipairs(ssr_protocol_list) do o:value(t) end
o:depends({ [option_name("protocol")] = "shadowsocksr" })
o = s:option(Value, option_name("ssr_protocol_param"), translate("Protocol_param"))
o:depends({ [option_name("protocol")] = "shadowsocksr" })
local ssr_obfs_list = {
"plain", "http_simple", "http_post", "random_head", "tls_simple",
"tls1.0_session_auth", "tls1.2_ticket_auth"
}
o = s:option(ListValue, option_name("ssr_obfs"), translate("Obfs"))
for a, t in ipairs(ssr_obfs_list) do o:value(t) end
o:depends({ [option_name("protocol")] = "shadowsocksr" })
o = s:option(Value, option_name("ssr_obfs_param"), translate("Obfs_param"))
o:depends({ [option_name("protocol")] = "shadowsocksr" })
end
o = s:option(Flag, option_name("uot"), translate("UDP over TCP"), translate("Need Xray-core or sing-box as server side."))
o:depends({ [option_name("protocol")] = "shadowsocks", [option_name("ss_method")] = "2022-blake3-aes-128-gcm" })
o:depends({ [option_name("protocol")] = "shadowsocks", [option_name("ss_method")] = "2022-blake3-aes-256-gcm" })
o:depends({ [option_name("protocol")] = "shadowsocks", [option_name("ss_method")] = "2022-blake3-chacha20-poly1305" })
o = s:option(Value, option_name("uuid"), translate("ID"))
o.password = true
o:depends({ [option_name("protocol")] = "vmess" })
o:depends({ [option_name("protocol")] = "vless" })
o:depends({ [option_name("protocol")] = "tuic" })
o = s:option(ListValue, option_name("flow"), translate("flow"))
o.default = ""
o:value("", translate("Disable"))
o:value("xtls-rprx-vision")
o:depends({ [option_name("protocol")] = "vless", [option_name("tls")] = true })
if singbox_tags:find("with_quic") then
o = s:option(Value, option_name("hysteria_obfs"), translate("Obfs Password"))
o:depends({ [option_name("protocol")] = "hysteria" })
o = s:option(ListValue, option_name("hysteria_auth_type"), translate("Auth Type"))
o:value("disable", translate("Disable"))
o:value("string", translate("STRING"))
o:value("base64", translate("BASE64"))
o:depends({ [option_name("protocol")] = "hysteria" })
o = s:option(Value, option_name("hysteria_auth_password"), translate("Auth Password"))
o.password = true
o:depends({ [option_name("protocol")] = "hysteria", [option_name("hysteria_auth_type")] = "string"})
o:depends({ [option_name("protocol")] = "hysteria", [option_name("hysteria_auth_type")] = "base64"})
o = s:option(Value, option_name("hysteria_up_mbps"), translate("Max upload Mbps"))
o.default = "10"
o:depends({ [option_name("protocol")] = "hysteria" })
o = s:option(Value, option_name("hysteria_down_mbps"), translate("Max download Mbps"))
o.default = "50"
o:depends({ [option_name("protocol")] = "hysteria" })
o = s:option(Value, option_name("hysteria_recv_window_conn"), translate("QUIC stream receive window"))
o:depends({ [option_name("protocol")] = "hysteria" })
o = s:option(Value, option_name("hysteria_recv_window"), translate("QUIC connection receive window"))
o:depends({ [option_name("protocol")] = "hysteria" })
o = s:option(Flag, option_name("hysteria_disable_mtu_discovery"), translate("Disable MTU detection"))
o:depends({ [option_name("protocol")] = "hysteria" })
end
if singbox_tags:find("with_quic") then
o = s:option(ListValue, option_name("tuic_congestion_control"), translate("Congestion control algorithm"))
o.default = "cubic"
o:value("bbr", translate("BBR"))
o:value("cubic", translate("CUBIC"))
o:value("new_reno", translate("New Reno"))
o:depends({ [option_name("protocol")] = "tuic" })
o = s:option(ListValue, option_name("tuic_udp_relay_mode"), translate("UDP relay mode"))
o.default = "native"
o:value("native", translate("native"))
o:value("quic", translate("QUIC"))
o:depends({ [option_name("protocol")] = "tuic" })
--[[
o = s:option(Flag, option_name("tuic_udp_over_stream"), translate("UDP over stream"))
o:depends({ [option_name("protocol")] = "tuic" })
]]--
o = s:option(Flag, option_name("tuic_zero_rtt_handshake"), translate("Enable 0-RTT QUIC handshake"))
o.default = 0
o:depends({ [option_name("protocol")] = "tuic" })
o = s:option(Value, option_name("tuic_heartbeat"), translate("Heartbeat interval(second)"))
o.datatype = "uinteger"
o.default = "3"
o:depends({ [option_name("protocol")] = "tuic" })
end
if singbox_tags:find("with_quic") then
o = s:option(Value, option_name("hysteria2_up_mbps"), translate("Max upload Mbps"))
o:depends({ [option_name("protocol")] = "hysteria2" })
o = s:option(Value, option_name("hysteria2_down_mbps"), translate("Max download Mbps"))
o:depends({ [option_name("protocol")] = "hysteria2" })
o = s:option(ListValue, option_name("hysteria2_obfs_type"), translate("Obfs Type"))
o:value("", translate("Disable"))
o:value("salamander")
o:depends({ [option_name("protocol")] = "hysteria2" })
o = s:option(Value, option_name("hysteria2_obfs_password"), translate("Obfs Password"))
o:depends({ [option_name("protocol")] = "hysteria2" })
o = s:option(Value, option_name("hysteria2_auth_password"), translate("Auth Password"))
o.password = true
o:depends({ [option_name("protocol")] = "hysteria2"})
end
o = s:option(Flag, option_name("tls"), translate("TLS"))
o.default = 0
o:depends({ [option_name("protocol")] = "vmess" })
o:depends({ [option_name("protocol")] = "vless" })
o:depends({ [option_name("protocol")] = "socks" })
o:depends({ [option_name("protocol")] = "trojan" })
o:depends({ [option_name("protocol")] = "shadowsocks" })
o:depends({ [option_name("protocol")] = "shadowtls" })
if singbox_tags:find("with_reality") then
o = s:option(Flag, option_name("reality"), translate("REALITY"))
o.default = 0
o:depends({ [option_name("protocol")] = "vless", [option_name("tls")] = true })
-- [[ REALITY部分 ]] --
o = s:option(Value, option_name("reality_publicKey"), translate("Public Key"))
o:depends({ [option_name("tls")] = true, [option_name("reality")] = true })
o = s:option(Value, option_name("reality_shortId"), translate("Short Id"))
o:depends({ [option_name("tls")] = true, [option_name("reality")] = true })
end
o = s:option(ListValue, option_name("alpn"), translate("alpn"))
o.default = "default"
o:value("default", translate("Default"))
o:value("h2,http/1.1")
o:value("h2")
o:value("http/1.1")
o:depends({ [option_name("tls")] = true })
o = s:option(Value, option_name("tls_serverName"), translate("Domain"))
o:depends({ [option_name("tls")] = true })
o = s:option(Flag, option_name("tls_allowInsecure"), translate("allowInsecure"), translate("Whether unsafe connections are allowed. When checked, Certificate validation will be skipped."))
o.default = "0"
o:depends({ [option_name("tls")] = true })
if singbox_tags:find("with_utls") then
o = s:option(Flag, option_name("utls"), translate("uTLS"))
o.default = "0"
o:depends({ [option_name("tls")] = true, [option_name("reality")] = false })
o = s:option(ListValue, option_name("fingerprint"), translate("Finger Print"))
o:value("chrome")
o:value("firefox")
o:value("edge")
o:value("safari")
o:value("360")
o:value("qq")
o:value("ios")
o:value("android")
o:value("random")
o:value("randomized")
o.default = "chrome"
o:depends({ [option_name("tls")] = true, [option_name("utls")] = true })
o:depends({ [option_name("tls")] = true, [option_name("reality")] = true })
end
o = s:option(ListValue, option_name("transport"), translate("Transport"))
o:value("tcp", "TCP")
o:value("http", "HTTP")
o:value("ws", "WebSocket")
if singbox_tags:find("with_quic") then
o:value("quic", "QUIC")
end
if singbox_tags:find("with_grpc") then
o:value("grpc", "gRPC")
end
o:depends({ [option_name("protocol")] = "vmess" })
o:depends({ [option_name("protocol")] = "vless" })
o:depends({ [option_name("protocol")] = "socks" })
o:depends({ [option_name("protocol")] = "shadowsocks" })
o:depends({ [option_name("protocol")] = "trojan" })
if singbox_tags:find("with_wireguard") then
o = s:option(Value, option_name("wireguard_public_key"), translate("Public Key"))
o:depends({ [option_name("protocol")] = "wireguard" })
o = s:option(Value, option_name("wireguard_secret_key"), translate("Private Key"))
o:depends({ [option_name("protocol")] = "wireguard" })
o = s:option(Value, option_name("wireguard_preSharedKey"), translate("Pre shared key"))
o:depends({ [option_name("protocol")] = "wireguard" })
o = s:option(DynamicList, option_name("wireguard_local_address"), translate("Local Address"))
o:depends({ [option_name("protocol")] = "wireguard" })
o = s:option(Value, option_name("wireguard_mtu"), translate("MTU"))
o.default = "1420"
o:depends({ [option_name("protocol")] = "wireguard" })
o = s:option(Value, option_name("wireguard_reserved"), translate("Reserved"), translate("Decimal numbers separated by \",\" or Base64-encoded strings."))
o:depends({ [option_name("protocol")] = "wireguard" })
end
-- [[ HTTP部分 ]]--
o = s:option(Value, option_name("http_host"), translate("HTTP Host"))
o:depends({ [option_name("transport")] = "http" })
o = s:option(Value, option_name("http_path"), translate("HTTP Path"))
o.placeholder = "/"
o:depends({ [option_name("transport")] = "http" })
o = s:option(Flag, option_name("http_h2_health_check"), translate("Health check"))
o:depends({ [option_name("tls")] = true, [option_name("transport")] = "http" })
o = s:option(Value, option_name("http_h2_read_idle_timeout"), translate("Idle timeout"))
o.default = "10"
o:depends({ [option_name("tls")] = true, [option_name("transport")] = "http", [option_name("http_h2_health_check")] = true })
o = s:option(Value, option_name("http_h2_health_check_timeout"), translate("Health check timeout"))
o.default = "15"
o:depends({ [option_name("tls")] = true, [option_name("transport")] = "http", [option_name("http_h2_health_check")] = true })
-- [[ WebSocket部分 ]]--
o = s:option(Value, option_name("ws_host"), translate("WebSocket Host"))
o:depends({ [option_name("transport")] = "ws" })
o = s:option(Value, option_name("ws_path"), translate("WebSocket Path"))
o.placeholder = "/"
o:depends({ [option_name("transport")] = "ws" })
o = s:option(Flag, option_name("ws_enableEarlyData"), translate("Enable early data"))
o:depends({ [option_name("transport")] = "ws" })
o = s:option(Value, option_name("ws_maxEarlyData"), translate("Early data length"))
o.default = "1024"
o:depends({ [option_name("ws_enableEarlyData")] = true })
o = s:option(Value, option_name("ws_earlyDataHeaderName"), translate("Early data header name"), translate("Recommended value: Sec-WebSocket-Protocol"))
o:depends({ [option_name("ws_enableEarlyData")] = true })
-- [[ gRPC部分 ]]--
if singbox_tags:find("with_grpc") then
o = s:option(Value, option_name("grpc_serviceName"), "ServiceName")
o:depends({ [option_name("transport")] = "grpc" })
o = s:option(Flag, option_name("grpc_health_check"), translate("Health check"))
o:depends({ [option_name("transport")] = "grpc" })
o = s:option(Value, option_name("grpc_idle_timeout"), translate("Idle timeout"))
o.default = "10"
o:depends({ [option_name("grpc_health_check")] = true })
o = s:option(Value, option_name("grpc_health_check_timeout"), translate("Health check timeout"))
o.default = "20"
o:depends({ [option_name("grpc_health_check")] = true })
o = s:option(Flag, option_name("grpc_permit_without_stream"), translate("Permit without stream"))
o.default = "0"
o:depends({ [option_name("grpc_health_check")] = true })
end
-- [[ Mux ]]--
o = s:option(Flag, option_name("mux"), translate("Mux"))
o.rmempty = false
o:depends({ [option_name("protocol")] = "vmess" })
o:depends({ [option_name("protocol")] = "vless", [option_name("flow")] = "" })
o:depends({ [option_name("protocol")] = "http" })
o:depends({ [option_name("protocol")] = "socks" })
o:depends({ [option_name("protocol")] = "shadowsocks" })
o:depends({ [option_name("protocol")] = "trojan" })
o = s:option(ListValue, option_name("mux_type"), translate("Mux"))
o:value("smux")
o:value("yamux")
o:value("h2mux")
o:depends({ [option_name("mux")] = true })
o = s:option(Value, option_name("mux_concurrency"), translate("Mux concurrency"))
o.default = 8
o:depends({ [option_name("mux")] = true })
for key, value in pairs(s.fields) do
if key:find(option_prefix) == 1 then
if not s.fields[key].not_rewrite then
s.fields[key].cfgvalue = rm_prefix_cfgvalue
s.fields[key].write = rm_prefix_write
s.fields[key].remove = rm_prefix_remove
end
local deps = s.fields[key].deps
if #deps > 0 then
for index, value in ipairs(deps) do
deps[index]["type"] = type_name
end
else
s.fields[key]:depends({ type = type_name })
end
end
end

View File

@ -45,15 +45,8 @@ e = t:option(DummyValue, "type", translate("Type"))
e.cfgvalue = function(t, n)
local v = Value.cfgvalue(t, n)
if v then
if v == "V2ray" or v == "Xray" then
if v == "sing-box" or v == "Xray" then
local protocol = m:get(n, "protocol")
if protocol == "vmess" then
protocol = "VMess"
elseif protocol == "vless" then
protocol = "VLESS"
else
protocol = protocol:gsub("^%l",string.upper)
end
return v .. " -> " .. protocol
end
return v

View File

@ -2,10 +2,12 @@ local m, s = ...
local api = require "luci.passwall2.api"
if not api.is_finded("xray") and not api.is_finded("v2ray")then
if not api.is_finded("xray") then
return
end
local type_name = "Xray"
local option_prefix = "xray_"
local function option_name(name)
@ -18,52 +20,20 @@ local function rm_prefix_cfgvalue(self, section)
end
end
local function rm_prefix_write(self, section, value)
if s.fields["type"]:formvalue(arg[1]) == "Xray" or s.fields["type"]:formvalue(arg[1]) == "V2ray" then
if s.fields["type"]:formvalue(arg[1]) == type_name then
if self.option:find(option_prefix) == 1 then
m:set(section, self.option:sub(1 + #option_prefix), value)
end
end
end
local function rm_prefix_remove(self, section, value)
if s.fields["type"]:formvalue(arg[1]) == "Xray" or s.fields["type"]:formvalue(arg[1]) == "V2ray" then
if s.fields["type"]:formvalue(arg[1]) == type_name then
if self.option:find(option_prefix) == 1 then
m:del(section, self.option:sub(1 + #option_prefix))
end
end
end
local function add_xray_depends(o, field, value)
local deps = { type = "Xray" }
if field then
if type(field) == "string" then
deps[field] = value
else
for key, value in pairs(field) do
deps[key] = value
end
end
end
o:depends(deps)
end
local function add_v2ray_depends(o, field, value)
local deps = { type = "V2ray" }
if field then
if type(field) == "string" then
deps[field] = value
else
for key, value in pairs(field) do
deps[key] = value
end
end
end
o:depends(deps)
end
local v_ss_method_list = {
"aes-128-gcm", "aes-256-gcm", "chacha20-poly1305"
}
local x_ss_method_list = {
"aes-128-gcm", "aes-256-gcm", "chacha20-poly1305", "xchacha20-poly1305", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"
}
@ -74,12 +44,7 @@ local header_type_list = {
-- [[ Xray ]]
if api.is_finded("v2ray") then
s.fields["type"]:value("V2ray", translate("V2ray"))
end
if api.is_finded("xray") then
s.fields["type"]:value("Xray", translate("Xray"))
end
s.fields["type"]:value(type_name, "Xray")
o = s:option(ListValue, option_name("protocol"), translate("Protocol"))
o:value("vmess", "Vmess")
@ -89,13 +54,9 @@ o:value("socks", "Socks")
o:value("shadowsocks", "Shadowsocks")
o:value("trojan", "Trojan")
o:value("dokodemo-door", "dokodemo-door")
add_xray_depends(o)
add_v2ray_depends(o)
o = s:option(Value, option_name("port"), translate("Listen Port"))
o.datatype = "port"
add_xray_depends(o)
add_v2ray_depends(o)
o = s:option(Flag, option_name("auth"), translate("Auth"))
o.validate = function(self, value, t)
@ -108,60 +69,38 @@ o.validate = function(self, value, t)
end
return value
end
add_xray_depends(o, { [option_name("protocol")] = "socks" })
add_xray_depends(o, { [option_name("protocol")] = "http" })
add_v2ray_depends(o, { [option_name("protocol")] = "socks" })
add_v2ray_depends(o, { [option_name("protocol")] = "http" })
o:depends({ [option_name("protocol")] = "socks" })
o:depends({ [option_name("protocol")] = "http" })
o = s:option(Value, option_name("username"), translate("Username"))
add_xray_depends(o, { [option_name("auth")] = true })
add_v2ray_depends(o, { [option_name("auth")] = true })
o:depends({ [option_name("auth")] = true })
o = s:option(Value, option_name("password"), translate("Password"))
o.password = true
add_xray_depends(o, { [option_name("auth")] = true })
add_v2ray_depends(o, { [option_name("auth")] = true })
add_xray_depends(o, { [option_name("protocol")] = "shadowsocks" })
add_v2ray_depends(o, { [option_name("protocol")] = "shadowsocks" })
o:depends({ [option_name("auth")] = true })
o:depends({ [option_name("protocol")] = "shadowsocks" })
o = s:option(ListValue, option_name("d_protocol"), translate("Destination protocol"))
o:value("tcp", "TCP")
o:value("udp", "UDP")
o:value("tcp,udp", "TCP,UDP")
add_v2ray_depends(o, { [option_name("protocol")] = "dokodemo-door" })
add_xray_depends(o, { [option_name("protocol")] = "dokodemo-door" })
o:depends({ [option_name("protocol")] = "dokodemo-door" })
o = s:option(Value, option_name("d_address"), translate("Destination address"))
add_v2ray_depends(o, { [option_name("protocol")] = "dokodemo-door" })
add_xray_depends(o, { [option_name("protocol")] = "dokodemo-door" })
o:depends({ [option_name("protocol")] = "dokodemo-door" })
o = s:option(Value, option_name("d_port"), translate("Destination port"))
o.datatype = "port"
add_v2ray_depends(o, { [option_name("protocol")] = "dokodemo-door" })
add_xray_depends(o, { [option_name("protocol")] = "dokodemo-door" })
o:depends({ [option_name("protocol")] = "dokodemo-door" })
o = s:option(Value, option_name("decryption"), translate("Encrypt Method"))
o.default = "none"
add_v2ray_depends(o, { [option_name("protocol")] = "vless" })
add_xray_depends(o, { [option_name("protocol")] = "vless" })
o = s:option(ListValue, option_name("v_ss_method"), translate("Encrypt Method"))
o.not_rewrite = true
for a, t in ipairs(v_ss_method_list) do o:value(t) end
add_v2ray_depends(o, { [option_name("protocol")] = "shadowsocks" })
function o.cfgvalue(self, section)
return m:get(section, "method")
end
function o.write(self, section, value)
if s.fields["type"]:formvalue(arg[1]) == "V2ray" then
m:set(section, "method", value)
end
end
o:depends({ [option_name("protocol")] = "vless" })
o = s:option(ListValue, option_name("x_ss_method"), translate("Encrypt Method"))
o.not_rewrite = true
for a, t in ipairs(x_ss_method_list) do o:value(t) end
add_xray_depends(o, { [option_name("protocol")] = "shadowsocks" })
o:depends({ [option_name("protocol")] = "shadowsocks" })
function o.cfgvalue(self, section)
return m:get(section, "method")
end
@ -172,33 +111,33 @@ function o.write(self, section, value)
end
o = s:option(Flag, option_name("iv_check"), translate("IV Check"))
add_v2ray_depends(o, { [option_name("protocol")] = "shadowsocks" })
add_xray_depends(o, { [option_name("protocol")] = "shadowsocks" })
o:depends({ [option_name("protocol")] = "shadowsocks" })
o = s:option(ListValue, option_name("ss_network"), translate("Transport"))
o.default = "tcp,udp"
o:value("tcp", "TCP")
o:value("udp", "UDP")
o:value("tcp,udp", "TCP,UDP")
add_v2ray_depends(o, { [option_name("protocol")] = "shadowsocks" })
add_xray_depends(o, { [option_name("protocol")] = "shadowsocks" })
o:depends({ [option_name("protocol")] = "shadowsocks" })
o = s:option(Flag, option_name("udp_forward"), translate("UDP Forward"))
o.default = "1"
o.rmempty = false
add_v2ray_depends(o, { [option_name("protocol")] = "socks" })
add_xray_depends(o, { [option_name("protocol")] = "socks" })
o:depends({ [option_name("protocol")] = "socks" })
o = s:option(DynamicList, option_name("uuid"), translate("ID") .. "/" .. translate("Password"))
for i = 1, 3 do
o:value(api.gen_uuid(1))
end
add_v2ray_depends(o, { [option_name("protocol")] = "vmess" })
add_v2ray_depends(o, { [option_name("protocol")] = "vless" })
add_v2ray_depends(o, { [option_name("protocol")] = "trojan" })
add_xray_depends(o, { [option_name("protocol")] = "vmess" })
add_xray_depends(o, { [option_name("protocol")] = "vless" })
add_xray_depends(o, { [option_name("protocol")] = "trojan" })
o:depends({ [option_name("protocol")] = "vmess" })
o:depends({ [option_name("protocol")] = "vless" })
o:depends({ [option_name("protocol")] = "trojan" })
o = s:option(ListValue, option_name("flow"), translate("flow"))
o.default = ""
o:value("", translate("Disable"))
o:value("xtls-rprx-vision")
o:depends({ [option_name("protocol")] = "vless" })
o = s:option(Flag, option_name("tls"), translate("TLS"))
o.default = 0
@ -214,44 +153,29 @@ o.validate = function(self, value, t)
return value
end
end
add_v2ray_depends(o, { [option_name("protocol")] = "vmess" })
add_v2ray_depends(o, { [option_name("protocol")] = "vless" })
add_v2ray_depends(o, { [option_name("protocol")] = "socks" })
add_v2ray_depends(o, { [option_name("protocol")] = "shadowsocks" })
add_v2ray_depends(o, { [option_name("protocol")] = "trojan" })
add_xray_depends(o, { [option_name("protocol")] = "vmess" })
add_xray_depends(o, { [option_name("protocol")] = "vless" })
add_xray_depends(o, { [option_name("protocol")] = "socks" })
add_xray_depends(o, { [option_name("protocol")] = "shadowsocks" })
add_xray_depends(o, { [option_name("protocol")] = "trojan" })
o = s:option(Value, option_name("tlsflow"), translate("flow"))
o.default = ""
o:value("", translate("Disable"))
o:value("xtls-rprx-vision")
o:value("xtls-rprx-vision-udp443")
add_xray_depends(o, { [option_name("protocol")] = "vless", [option_name("tls")] = true })
o:depends({ [option_name("protocol")] = "vmess" })
o:depends({ [option_name("protocol")] = "vless" })
o:depends({ [option_name("protocol")] = "socks" })
o:depends({ [option_name("protocol")] = "shadowsocks" })
o:depends({ [option_name("protocol")] = "trojan" })
o = s:option(ListValue, option_name("alpn"), translate("alpn"))
o.default = "h2,http/1.1"
o:value("h2,http/1.1")
o:value("h2")
o:value("http/1.1")
add_v2ray_depends(o, { [option_name("tls")] = true })
add_xray_depends(o, { [option_name("tls")] = true })
o:depends({ [option_name("tls")] = true })
-- o = s:option(Value, option_name("minversion"), translate("minversion"))
-- o.default = "1.3"
-- o:value("1.3")
--add_v2ray_depends(o, { [option_name("tls")] = true })
--add_xray_depends(o, { [option_name("tls")] = true })
--o:depends({ [option_name("tls")] = true })
-- [[ TLS部分 ]] --
o = s:option(FileUpload, option_name("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"
add_v2ray_depends(o, { [option_name("tls")] = true })
add_xray_depends(o, { [option_name("tls")] = true })
o:depends({ [option_name("tls")] = true })
o.validate = function(self, value, t)
if value and value ~= "" then
if not nixio.fs.access(value) then
@ -265,8 +189,7 @@ end
o = s:option(FileUpload, option_name("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"
add_v2ray_depends(o, { [option_name("tls")] = true })
add_xray_depends(o, { [option_name("tls")] = true })
o:depends({ [option_name("tls")] = true })
o.validate = function(self, value, t)
if value and value ~= "" then
if not nixio.fs.access(value) then
@ -286,36 +209,27 @@ o:value("h2", "HTTP/2")
o:value("ds", "DomainSocket")
o:value("quic", "QUIC")
o:value("grpc", "gRPC")
add_v2ray_depends(o, { [option_name("protocol")] = "vmess" })
add_v2ray_depends(o, { [option_name("protocol")] = "vless" })
add_v2ray_depends(o, { [option_name("protocol")] = "socks" })
add_v2ray_depends(o, { [option_name("protocol")] = "shadowsocks" })
add_v2ray_depends(o, { [option_name("protocol")] = "trojan" })
add_xray_depends(o, { [option_name("protocol")] = "vmess" })
add_xray_depends(o, { [option_name("protocol")] = "vless" })
add_xray_depends(o, { [option_name("protocol")] = "socks" })
add_xray_depends(o, { [option_name("protocol")] = "shadowsocks" })
add_xray_depends(o, { [option_name("protocol")] = "trojan" })
o:depends({ [option_name("protocol")] = "vmess" })
o:depends({ [option_name("protocol")] = "vless" })
o:depends({ [option_name("protocol")] = "socks" })
o:depends({ [option_name("protocol")] = "shadowsocks" })
o:depends({ [option_name("protocol")] = "trojan" })
-- [[ WebSocket部分 ]]--
o = s:option(Value, option_name("ws_host"), translate("WebSocket Host"))
add_v2ray_depends(o, { [option_name("transport")] = "ws" })
add_xray_depends(o, { [option_name("transport")] = "ws" })
o:depends({ [option_name("transport")] = "ws" })
o = s:option(Value, option_name("ws_path"), translate("WebSocket Path"))
add_v2ray_depends(o, { [option_name("transport")] = "ws" })
add_xray_depends(o, { [option_name("transport")] = "ws" })
o:depends({ [option_name("transport")] = "ws" })
-- [[ HTTP/2部分 ]]--
o = s:option(Value, option_name("h2_host"), translate("HTTP/2 Host"))
add_v2ray_depends(o, { [option_name("transport")] = "h2" })
add_xray_depends(o, { [option_name("transport")] = "h2" })
o:depends({ [option_name("transport")] = "h2" })
o = s:option(Value, option_name("h2_path"), translate("HTTP/2 Path"))
add_v2ray_depends(o, { [option_name("transport")] = "h2" })
add_xray_depends(o, { [option_name("transport")] = "h2" })
o:depends({ [option_name("transport")] = "h2" })
-- [[ TCP部分 ]]--
@ -323,141 +237,111 @@ add_xray_depends(o, { [option_name("transport")] = "h2" })
o = s:option(ListValue, option_name("tcp_guise"), translate("Camouflage Type"))
o:value("none", "none")
o:value("http", "http")
add_v2ray_depends(o, { [option_name("transport")] = "tcp" })
add_xray_depends(o, { [option_name("transport")] = "tcp" })
o:depends({ [option_name("transport")] = "tcp" })
-- HTTP域名
o = s:option(DynamicList, option_name("tcp_guise_http_host"), translate("HTTP Host"))
add_v2ray_depends(o, { [option_name("tcp_guise")] = "http" })
add_xray_depends(o, { [option_name("tcp_guise")] = "http" })
o:depends({ [option_name("tcp_guise")] = "http" })
-- HTTP路径
o = s:option(DynamicList, option_name("tcp_guise_http_path"), translate("HTTP Path"))
add_v2ray_depends(o, { [option_name("tcp_guise")] = "http" })
add_xray_depends(o, { [option_name("tcp_guise")] = "http" })
o:depends({ [option_name("tcp_guise")] = "http" })
-- [[ mKCP部分 ]]--
o = s:option(ListValue, option_name("mkcp_guise"), translate("Camouflage Type"), translate('<br />none: default, no masquerade, data sent is packets with no characteristics.<br />srtp: disguised as an SRTP packet, it will be recognized as video call data (such as FaceTime).<br />utp: packets disguised as uTP will be recognized as bittorrent downloaded data.<br />wechat-video: packets disguised as WeChat video calls.<br />dtls: disguised as DTLS 1.2 packet.<br />wireguard: disguised as a WireGuard packet. (not really WireGuard protocol)'))
for a, t in ipairs(header_type_list) do o:value(t) end
add_v2ray_depends(o, { [option_name("transport")] = "mkcp" })
add_xray_depends(o, { [option_name("transport")] = "mkcp" })
o:depends({ [option_name("transport")] = "mkcp" })
o = s:option(Value, option_name("mkcp_mtu"), translate("KCP MTU"))
o.default = "1350"
add_v2ray_depends(o, { [option_name("transport")] = "mkcp" })
add_xray_depends(o, { [option_name("transport")] = "mkcp" })
o:depends({ [option_name("transport")] = "mkcp" })
o = s:option(Value, option_name("mkcp_tti"), translate("KCP TTI"))
o.default = "20"
add_v2ray_depends(o, { [option_name("transport")] = "mkcp" })
add_xray_depends(o, { [option_name("transport")] = "mkcp" })
o:depends({ [option_name("transport")] = "mkcp" })
o = s:option(Value, option_name("mkcp_uplinkCapacity"), translate("KCP uplinkCapacity"))
o.default = "5"
add_v2ray_depends(o, { [option_name("transport")] = "mkcp" })
add_xray_depends(o, { [option_name("transport")] = "mkcp" })
o:depends({ [option_name("transport")] = "mkcp" })
o = s:option(Value, option_name("mkcp_downlinkCapacity"), translate("KCP downlinkCapacity"))
o.default = "20"
add_v2ray_depends(o, { [option_name("transport")] = "mkcp" })
add_xray_depends(o, { [option_name("transport")] = "mkcp" })
o:depends({ [option_name("transport")] = "mkcp" })
o = s:option(Flag, option_name("mkcp_congestion"), translate("KCP Congestion"))
add_v2ray_depends(o, { [option_name("transport")] = "mkcp" })
add_xray_depends(o, { [option_name("transport")] = "mkcp" })
o:depends({ [option_name("transport")] = "mkcp" })
o = s:option(Value, option_name("mkcp_readBufferSize"), translate("KCP readBufferSize"))
o.default = "1"
add_v2ray_depends(o, { [option_name("transport")] = "mkcp" })
add_xray_depends(o, { [option_name("transport")] = "mkcp" })
o:depends({ [option_name("transport")] = "mkcp" })
o = s:option(Value, option_name("mkcp_writeBufferSize"), translate("KCP writeBufferSize"))
o.default = "1"
add_v2ray_depends(o, { [option_name("transport")] = "mkcp" })
add_xray_depends(o, { [option_name("transport")] = "mkcp" })
o:depends({ [option_name("transport")] = "mkcp" })
o = s:option(Value, option_name("mkcp_seed"), translate("KCP Seed"))
add_v2ray_depends(o, { [option_name("transport")] = "mkcp" })
add_xray_depends(o, { [option_name("transport")] = "mkcp" })
o:depends({ [option_name("transport")] = "mkcp" })
-- [[ DomainSocket部分 ]]--
o = s:option(Value, option_name("ds_path"), "Path", translate("A legal file path. This file must not exist before running."))
add_v2ray_depends(o, { [option_name("transport")] = "ds" })
add_xray_depends(o, { [option_name("transport")] = "ds" })
o:depends({ [option_name("transport")] = "ds" })
-- [[ QUIC部分 ]]--
o = s:option(ListValue, option_name("quic_security"), translate("Encrypt Method"))
o:value("none")
o:value("aes-128-gcm")
o:value("chacha20-poly1305")
add_v2ray_depends(o, { [option_name("transport")] = "quic" })
add_xray_depends(o, { [option_name("transport")] = "quic" })
o:depends({ [option_name("transport")] = "quic" })
o = s:option(Value, option_name("quic_key"), translate("Encrypt Method") .. translate("Key"))
add_v2ray_depends(o, { [option_name("transport")] = "quic" })
add_xray_depends(o, { [option_name("transport")] = "quic" })
o:depends({ [option_name("transport")] = "quic" })
o = s:option(ListValue, option_name("quic_guise"), translate("Camouflage Type"))
for a, t in ipairs(header_type_list) do o:value(t) end
add_v2ray_depends(o, { [option_name("transport")] = "quic" })
add_xray_depends(o, { [option_name("transport")] = "quic" })
o:depends({ [option_name("transport")] = "quic" })
-- [[ gRPC部分 ]]--
o = s:option(Value, option_name("grpc_serviceName"), "ServiceName")
add_v2ray_depends(o, { [option_name("transport")] = "grpc" })
add_xray_depends(o, { [option_name("transport")] = "grpc" })
o:depends({ [option_name("transport")] = "grpc" })
o = s:option(Flag, option_name("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."))
add_v2ray_depends(o, { [option_name("transport")] = "tcp" })
add_v2ray_depends(o, { [option_name("transport")] = "ws" })
add_xray_depends(o, { [option_name("transport")] = "tcp" })
add_xray_depends(o, { [option_name("transport")] = "ws" })
o:depends({ [option_name("transport")] = "tcp" })
o:depends({ [option_name("transport")] = "ws" })
-- [[ Fallback部分 ]]--
o = s:option(Flag, option_name("fallback"), translate("Fallback"))
add_v2ray_depends(o, { [option_name("protocol")] = "vless", [option_name("transport")] = "tcp" })
add_v2ray_depends(o, { [option_name("protocol")] = "trojan", [option_name("transport")] = "tcp" })
add_xray_depends(o, { [option_name("protocol")] = "vless", [option_name("transport")] = "tcp" })
add_xray_depends(o, { [option_name("protocol")] = "trojan", [option_name("transport")] = "tcp" })
o:depends({ [option_name("protocol")] = "vless", [option_name("transport")] = "tcp" })
o:depends({ [option_name("protocol")] = "trojan", [option_name("transport")] = "tcp" })
--[[
o = s:option(Value, option_name("fallback_alpn"), "Fallback alpn")
add_v2ray_depends(o, { [option_name("fallback")] = true })
add_xray_depends(o, { [option_name("fallback")] = true })
o:depends({ [option_name("fallback")] = true })
o = s:option(Value, option_name("fallback_path"), "Fallback path")
add_v2ray_depends(o, { [option_name("fallback")] = true })
add_xray_depends(o, { [option_name("fallback")] = true })
o:depends({ [option_name("fallback")] = true })
o = s:option(Value, option_name("fallback_dest"), "Fallback dest")
add_v2ray_depends(o, { [option_name("fallback")] = true })
add_xray_depends(o, { [option_name("fallback")] = true })
o:depends({ [option_name("fallback")] = true })
o = s:option(Value, option_name("fallback_xver"), "Fallback xver")
o.default = 0
add_v2ray_depends(o, { [option_name("fallback")] = true })
add_xray_depends(o, { [option_name("fallback")] = true })
o:depends({ [option_name("fallback")] = true })
]]--
o = s:option(DynamicList, option_name("fallback_list"), "Fallback", translate("dest,path"))
add_v2ray_depends(o, { [option_name("fallback")] = true })
add_xray_depends(o, { [option_name("fallback")] = true })
o:depends({ [option_name("fallback")] = true })
o = s:option(Flag, option_name("bind_local"), translate("Bind Local"), translate("When selected, it can only be accessed locally, It is recommended to turn on when using reverse proxies or be fallback."))
o.default = "0"
add_v2ray_depends(o)
add_xray_depends(o)
o = s:option(Flag, option_name("accept_lan"), translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!"))
o.default = "0"
add_v2ray_depends(o)
add_xray_depends(o)
local nodes_table = {}
for k, e in ipairs(api.get_valid_nodes()) do
if e.node_type == "normal" and (e.type == "V2ray" or e.type == "Xray") then
if e.node_type == "normal" and e.type == type_name then
nodes_table[#nodes_table + 1] = {
id = e[".name"],
remarks = e["remark"]
@ -472,45 +356,32 @@ o:value("_http", translate("Custom HTTP"))
o:value("_iface", translate("Custom Interface") .. " (Only Support Xray)")
for k, v in pairs(nodes_table) do o:value(v.id, v.remarks) end
o.default = "nil"
add_v2ray_depends(o)
add_xray_depends(o)
o = s:option(Value, option_name("outbound_node_address"), translate("Address (Support Domain Name)"))
add_v2ray_depends(o, { [option_name("outbound_node")] = "_socks"})
add_v2ray_depends(o, { [option_name("outbound_node")] = "_http"})
add_xray_depends(o, { [option_name("outbound_node")] = "_socks"})
add_xray_depends(o, { [option_name("outbound_node")] = "_http"})
o:depends({ [option_name("outbound_node")] = "_socks"})
o:depends({ [option_name("outbound_node")] = "_http"})
o = s:option(Value, option_name("outbound_node_port"), translate("Port"))
o.datatype = "port"
add_v2ray_depends(o, { [option_name("outbound_node")] = "_socks"})
add_v2ray_depends(o, { [option_name("outbound_node")] = "_http"})
add_xray_depends(o, { [option_name("outbound_node")] = "_socks"})
add_xray_depends(o, { [option_name("outbound_node")] = "_http"})
o:depends({ [option_name("outbound_node")] = "_socks"})
o:depends({ [option_name("outbound_node")] = "_http"})
o = s:option(Value, option_name("outbound_node_username"), translate("Username"))
add_v2ray_depends(o, { [option_name("outbound_node")] = "_socks"})
add_v2ray_depends(o, { [option_name("outbound_node")] = "_http"})
add_xray_depends(o, { [option_name("outbound_node")] = "_socks"})
add_xray_depends(o, { [option_name("outbound_node")] = "_http"})
o:depends({ [option_name("outbound_node")] = "_socks"})
o:depends({ [option_name("outbound_node")] = "_http"})
o = s:option(Value, option_name("outbound_node_password"), translate("Password"))
o.password = true
add_v2ray_depends(o, { [option_name("outbound_node")] = "_socks"})
add_v2ray_depends(o, { [option_name("outbound_node")] = "_http"})
add_xray_depends(o, { [option_name("outbound_node")] = "_socks"})
add_xray_depends(o, { [option_name("outbound_node")] = "_http"})
o:depends({ [option_name("outbound_node")] = "_socks"})
o:depends({ [option_name("outbound_node")] = "_http"})
o = s:option(Value, option_name("outbound_node_iface"), translate("Interface"))
o.default = "eth1"
add_v2ray_depends(o, { [option_name("outbound_node")] = "_iface"})
add_xray_depends(o, { [option_name("outbound_node")] = "_iface"})
o:depends({ [option_name("outbound_node")] = "_iface"})
o = s:option(Flag, option_name("log"), translate("Log"))
o.default = "1"
o.rmempty = false
add_v2ray_depends(o)
add_xray_depends(o)
o = s:option(ListValue, option_name("loglevel"), translate("Log Level"))
o.default = "warning"
@ -518,8 +389,7 @@ o:value("debug")
o:value("info")
o:value("warning")
o:value("error")
add_v2ray_depends(o, { [option_name("log")] = true })
add_xray_depends(o, { [option_name("log")] = true })
o:depends({ [option_name("log")] = true })
for key, value in pairs(s.fields) do
if key:find(option_prefix) == 1 then
@ -529,4 +399,13 @@ for key, value in pairs(s.fields) do
s.fields[key].remove = rm_prefix_remove
end
end
local deps = s.fields[key].deps
if #deps > 0 then
for index, value in ipairs(deps) do
deps[index]["type"] = type_name
end
else
s.fields[key]:depends({ type = type_name })
end
end

View File

@ -0,0 +1,377 @@
local m, s = ...
local api = require "luci.passwall2.api"
if not api.is_finded("sing-box")then
return
end
local singbox_tags = luci.sys.exec(api.finded("sing-box") .. " version | grep 'Tags:' | awk '{print $2}'")
local type_name = "sing-box"
local option_prefix = "singbox_"
local function option_name(name)
return option_prefix .. name
end
local function rm_prefix_cfgvalue(self, section)
if self.option:find(option_prefix) == 1 then
return m:get(section, self.option:sub(1 + #option_prefix))
end
end
local function rm_prefix_write(self, section, value)
if s.fields["type"]:formvalue(arg[1]) == type_name then
if self.option:find(option_prefix) == 1 then
m:set(section, self.option:sub(1 + #option_prefix), value)
end
end
end
local function rm_prefix_remove(self, section, value)
if s.fields["type"]:formvalue(arg[1]) == type_name then
if self.option:find(option_prefix) == 1 then
m:del(section, self.option:sub(1 + #option_prefix))
end
end
end
local ss_method_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"
}
-- [[ Sing-Box ]]
s.fields["type"]:value(type_name, "Sing-Box")
o = s:option(ListValue, option_name("protocol"), translate("Protocol"))
o:value("mixed", "Mixed")
o:value("socks", "Socks")
o:value("http", "HTTP")
o:value("shadowsocks", "Shadowsocks")
o:value("vmess", "Vmess")
o:value("vless", "VLESS")
o:value("trojan", "Trojan")
o:value("naive", "Naive")
if singbox_tags:find("with_quic") then
o:value("hysteria", "Hysteria")
end
if singbox_tags:find("with_quic") then
o:value("tuic", "TUIC")
end
if singbox_tags:find("with_quic") then
o:value("hysteria2", "Hysteria2")
end
o:value("direct", "Direct")
o = s:option(Value, option_name("port"), translate("Listen Port"))
o.datatype = "port"
o = s:option(Flag, option_name("auth"), translate("Auth"))
o.validate = function(self, value, t)
if value and value == "1" then
local user_v = s.fields[option_name("username")]:formvalue(t) or ""
local pass_v = s.fields[option_name("password")]:formvalue(t) or ""
if user_v == "" or pass_v == "" then
return nil, translate("Username and Password must be used together!")
end
end
return value
end
o:depends({ [option_name("protocol")] = "mixed" })
o:depends({ [option_name("protocol")] = "socks" })
o:depends({ [option_name("protocol")] = "http" })
o = s:option(Value, option_name("username"), translate("Username"))
o:depends({ [option_name("auth")] = true })
o:depends({ [option_name("protocol")] = "naive" })
o = s:option(Value, option_name("password"), translate("Password"))
o.password = true
o:depends({ [option_name("auth")] = true })
o:depends({ [option_name("protocol")] = "shadowsocks" })
o:depends({ [option_name("protocol")] = "naive" })
o:depends({ [option_name("protocol")] = "tuic" })
if singbox_tags:find("with_quic") then
o = s:option(Value, option_name("hysteria_up_mbps"), translate("Max upload Mbps"))
o.default = "100"
o:depends({ [option_name("protocol")] = "hysteria" })
o = s:option(Value, option_name("hysteria_down_mbps"), translate("Max download Mbps"))
o.default = "100"
o:depends({ [option_name("protocol")] = "hysteria" })
o = s:option(Value, option_name("hysteria_obfs"), translate("Obfs Password"))
o:depends({ [option_name("protocol")] = "hysteria" })
o = s:option(ListValue, option_name("hysteria_auth_type"), translate("Auth Type"))
o:value("disable", translate("Disable"))
o:value("string", translate("STRING"))
o:value("base64", translate("BASE64"))
o:depends({ [option_name("protocol")] = "hysteria" })
o = s:option(Value, option_name("hysteria_auth_password"), translate("Auth Password"))
o.password = true
o:depends({ [option_name("protocol")] = "hysteria", [option_name("hysteria_auth_type")] = "string"})
o:depends({ [option_name("protocol")] = "hysteria", [option_name("hysteria_auth_type")] = "base64"})
o = s:option(Value, option_name("hysteria_recv_window_conn"), translate("QUIC stream receive window"))
o:depends({ [option_name("protocol")] = "hysteria" })
o = s:option(Value, option_name("hysteria_recv_window_client"), translate("QUIC connection receive window"))
o:depends({ [option_name("protocol")] = "hysteria" })
o = s:option(Value, option_name("hysteria_max_conn_client"), translate("QUIC concurrent bidirectional streams"))
o.default = "1024"
o:depends({ [option_name("protocol")] = "hysteria" })
o = s:option(Flag, option_name("hysteria_disable_mtu_discovery"), translate("Disable MTU detection"))
o:depends({ [option_name("protocol")] = "hysteria" })
end
if singbox_tags:find("with_quic") then
o = s:option(ListValue, option_name("tuic_congestion_control"), translate("Congestion control algorithm"))
o.default = "cubic"
o:value("bbr", translate("BBR"))
o:value("cubic", translate("CUBIC"))
o:value("new_reno", translate("New Reno"))
o:depends({ [option_name("protocol")] = "tuic" })
o = s:option(Flag, option_name("tuic_zero_rtt_handshake"), translate("Enable 0-RTT QUIC handshake"))
o.default = 0
o:depends({ [option_name("protocol")] = "tuic" })
o = s:option(Value, option_name("tuic_heartbeat"), translate("Heartbeat interval(second)"))
o.datatype = "uinteger"
o.default = "3"
o:depends({ [option_name("protocol")] = "tuic" })
end
if singbox_tags:find("with_quic") then
o = s:option(Flag, option_name("hysteria2_ignore_client_bandwidth"), translate("Commands the client to use the BBR flow control algorithm"))
o.default = 0
o:depends({ [option_name("protocol")] = "hysteria2" })
o = s:option(Value, option_name("hysteria2_up_mbps"), translate("Max upload Mbps"))
o:depends({ [option_name("protocol")] = "hysteria2", [option_name("hysteria2_ignore_client_bandwidth")] = false })
o = s:option(Value, option_name("hysteria2_down_mbps"), translate("Max download Mbps"))
o:depends({ [option_name("protocol")] = "hysteria2", [option_name("hysteria2_ignore_client_bandwidth")] = false })
o = s:option(ListValue, option_name("hysteria2_obfs_type"), translate("Obfs Type"))
o:value("", translate("Disable"))
o:value("salamander")
o:depends({ [option_name("protocol")] = "hysteria2" })
o = s:option(Value, option_name("hysteria2_obfs_password"), translate("Obfs Password"))
o:depends({ [option_name("protocol")] = "hysteria2" })
o = s:option(Value, option_name("hysteria2_auth_password"), translate("Auth Password"))
o.password = true
o:depends({ [option_name("protocol")] = "hysteria2"})
end
o = s:option(ListValue, option_name("d_protocol"), translate("Destination protocol"))
o:value("tcp", "TCP")
o:value("udp", "UDP")
o:value("tcp,udp", "TCP,UDP")
o:depends({ [option_name("protocol")] = "direct" })
o = s:option(Value, option_name("d_address"), translate("Destination address"))
o:depends({ [option_name("protocol")] = "direct" })
o = s:option(Value, option_name("d_port"), translate("Destination port"))
o.datatype = "port"
o:depends({ [option_name("protocol")] = "direct" })
o = s:option(Value, option_name("decryption"), translate("Encrypt Method"))
o.default = "none"
o:depends({ [option_name("protocol")] = "vless" })
o = s:option(ListValue, option_name("ss_method"), translate("Encrypt Method"))
o.not_rewrite = true
for a, t in ipairs(ss_method_list) do o:value(t) end
o:depends({ [option_name("protocol")] = "shadowsocks" })
function o.cfgvalue(self, section)
return m:get(section, "method")
end
function o.write(self, section, value)
if s.fields["type"]:formvalue(arg[1]) == type_name then
m:set(section, "method", value)
end
end
o = s:option(DynamicList, option_name("uuid"), translate("ID") .. "/" .. translate("Password"))
for i = 1, 3 do
o:value(api.gen_uuid(1))
end
o:depends({ [option_name("protocol")] = "vmess" })
o:depends({ [option_name("protocol")] = "vless" })
o:depends({ [option_name("protocol")] = "trojan" })
o:depends({ [option_name("protocol")] = "tuic" })
o = s:option(ListValue, option_name("flow"), translate("flow"))
o.default = ""
o:value("", translate("Disable"))
o:value("xtls-rprx-vision")
o:depends({ [option_name("protocol")] = "vless" })
o = s:option(Flag, option_name("tls"), translate("TLS"))
o.default = 0
o.validate = function(self, value, t)
if value then
if value == "1" then
local ca = s.fields[option_name("tls_certificateFile")]:formvalue(t) or ""
local key = s.fields[option_name("tls_keyFile")]:formvalue(t) or ""
if ca == "" or key == "" then
return nil, translate("Public key and Private key path can not be empty!")
end
end
return value
end
end
o:depends({ [option_name("protocol")] = "http" })
o:depends({ [option_name("protocol")] = "shadowsocks" })
o:depends({ [option_name("protocol")] = "vmess" })
o:depends({ [option_name("protocol")] = "vless" })
o:depends({ [option_name("protocol")] = "trojan" })
-- [[ TLS部分 ]] --
o = s:option(FileUpload, option_name("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"
o:depends({ [option_name("tls")] = true })
o.validate = function(self, value, t)
if value and value ~= "" then
if not nixio.fs.access(value) then
return nil, translate("Can't find this file!")
else
return value
end
end
return nil
end
o = s:option(FileUpload, option_name("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"
o:depends({ [option_name("tls")] = true })
o.validate = function(self, value, t)
if value and value ~= "" then
if not nixio.fs.access(value) then
return nil, translate("Can't find this file!")
else
return value
end
end
return nil
end
o = s:option(ListValue, option_name("transport"), translate("Transport"))
o:value("tcp", "TCP")
o:value("http", "HTTP")
o:value("ws", "WebSocket")
o:value("quic", "QUIC")
o:value("grpc", "gRPC")
o:depends({ [option_name("protocol")] = "shadowsocks" })
o:depends({ [option_name("protocol")] = "vmess" })
o:depends({ [option_name("protocol")] = "vless" })
o:depends({ [option_name("protocol")] = "trojan" })
-- [[ HTTP部分 ]]--
o = s:option(Value, option_name("http_host"), translate("HTTP Host"))
o:depends({ [option_name("transport")] = "http" })
o = s:option(Value, option_name("http_path"), translate("HTTP Path"))
o:depends({ [option_name("transport")] = "http" })
-- [[ WebSocket部分 ]]--
o = s:option(Value, option_name("ws_host"), translate("WebSocket Host"))
o:depends({ [option_name("transport")] = "ws" })
o = s:option(Value, option_name("ws_path"), translate("WebSocket Path"))
o:depends({ [option_name("transport")] = "ws" })
-- [[ gRPC部分 ]]--
o = s:option(Value, option_name("grpc_serviceName"), "ServiceName")
o:depends({ [option_name("transport")] = "grpc" })
o = s:option(Flag, option_name("bind_local"), translate("Bind Local"), translate("When selected, it can only be accessed locally, It is recommended to turn on when using reverse proxies or be fallback."))
o.default = "0"
o = s:option(Flag, option_name("accept_lan"), translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!"))
o.default = "0"
local nodes_table = {}
for k, e in ipairs(api.get_valid_nodes()) do
if e.node_type == "normal" and e.type == type_name then
nodes_table[#nodes_table + 1] = {
id = e[".name"],
remarks = e["remark"]
}
end
end
o = s:option(ListValue, option_name("outbound_node"), translate("outbound node"))
o:value("nil", translate("Close"))
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.default = "nil"
o = s:option(Value, option_name("outbound_node_address"), translate("Address (Support Domain Name)"))
o:depends({ [option_name("outbound_node")] = "_socks" })
o:depends({ [option_name("outbound_node")] = "_http" })
o = s:option(Value, option_name("outbound_node_port"), translate("Port"))
o.datatype = "port"
o:depends({ [option_name("outbound_node")] = "_socks" })
o:depends({ [option_name("outbound_node")] = "_http" })
o = s:option(Value, option_name("outbound_node_username"), translate("Username"))
o:depends({ [option_name("outbound_node")] = "_socks" })
o:depends({ [option_name("outbound_node")] = "_http" })
o = s:option(Value, option_name("outbound_node_password"), translate("Password"))
o.password = true
o:depends({ [option_name("outbound_node")] = "_socks" })
o:depends({ [option_name("outbound_node")] = "_http" })
o = s:option(Value, option_name("outbound_node_iface"), translate("Interface"))
o.default = "eth1"
o:depends({ [option_name("outbound_node")] = "_iface" })
o = s:option(Flag, option_name("log"), translate("Log"))
o.default = "1"
o.rmempty = false
o = s:option(ListValue, option_name("loglevel"), translate("Log Level"))
o.default = "info"
o:value("debug")
o:value("info")
o:value("warn")
o:value("error")
o:depends({ [option_name("log")] = true })
for key, value in pairs(s.fields) do
if key:find(option_prefix) == 1 then
if not s.fields[key].not_rewrite then
s.fields[key].cfgvalue = rm_prefix_cfgvalue
s.fields[key].write = rm_prefix_write
s.fields[key].remove = rm_prefix_remove
end
local deps = s.fields[key].deps
if #deps > 0 then
for index, value in ipairs(deps) do
deps[index]["type"] = type_name
end
else
s.fields[key]:depends({ type = type_name })
end
end
end

View File

@ -282,7 +282,7 @@ function get_valid_nodes()
local address = e.address
if is_ip(address) or datatypes.hostname(address) then
local type = e.type
if (type == "V2ray" or type == "Xray") and e.protocol then
if (type == "sing-box" or type == "Xray") and e.protocol then
local protocol = e.protocol
if protocol == "vmess" then
protocol = "VMess"
@ -314,7 +314,7 @@ function get_node_remarks(n)
remarks = "%s[%s] " % {n.type .. " " .. i18n.translatef(n.protocol), n.remarks}
else
local type2 = n.type
if (n.type == "V2ray" or n.type == "Xray") and n.protocol then
if (n.type == "sing-box" or n.type == "Xray") and n.protocol then
local protocol = n.protocol
if protocol == "vmess" then
protocol = "VMess"
@ -381,8 +381,12 @@ function get_customed_path(e)
return uci_get_type("global_app", e .. "_file")
end
function finded(e)
return luci.sys.exec('echo -n $(type -t -p "/bin/%s" -p "/usr/bin/%s" -p "%s" "%s" | head -n1)' % {e, e, get_customed_path(e), e})
end
function is_finded(e)
return luci.sys.exec('type -t -p "/bin/%s" -p "/usr/bin/%s" -p "%s" "%s"' % {e, e, get_customed_path(e), e}) ~= "" and true or false
return finded(e) ~= "" and true or false
end
function clone(org)

View File

@ -33,13 +33,26 @@ _M.hysteria = {
}
}
_M.v2ray = {
name = "V2ray",
repo = "v2fly/v2ray-core",
_M.singbox = {
name = "Sing-Box",
repo = "SagerNet/sing-box",
get_url = gh_pre_release_url,
cmd_version = "version | awk '{print $3}' | sed -n 1P",
zipped = true,
default_path = "/usr/bin/sing-box",
match_fmt_str = "linux%%-%s",
file_tree = {
x86_64 = "amd64"
}
}
_M.xray = {
name = "Xray",
repo = "XTLS/Xray-core",
get_url = gh_pre_release_url,
cmd_version = "version | awk '{print $2}' | sed -n 1P",
zipped = true,
default_path = "/usr/bin/v2ray",
default_path = "/usr/bin/xray",
match_fmt_str = "linux%%-%s",
file_tree = {
x86_64 = "64",
@ -49,15 +62,4 @@ _M.v2ray = {
}
}
_M.xray = {
name = "Xray",
repo = "XTLS/Xray-core",
get_url = gh_pre_release_url,
cmd_version = _M.v2ray.cmd_version,
zipped = true,
default_path = "/usr/bin/xray",
match_fmt_str = _M.v2ray.match_fmt_str,
file_tree = _M.v2ray.file_tree
}
return _M

View File

@ -144,12 +144,12 @@ local function start()
elseif type == "SS-Rust" then
config = require(require_dir .. "util_shadowsocks").gen_config_server(user)
bin = ln_run("/usr/bin/ssserver", "ssserver", "-c " .. config_file, log_path)
elseif type == "V2ray" then
config = require(require_dir .. "util_xray").gen_config_server(user)
bin = ln_run(api.get_app_path("v2ray"), "v2ray", "run -c " .. config_file, log_path)
elseif type == "Xray" then
config = require(require_dir .. "util_xray").gen_config_server(user)
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)
bin = ln_run(api.get_app_path("singbox"), "sing-box", "run -c " .. config_file, log_path)
elseif type == "Brook" then
local brook_protocol = user.protocol
local brook_password = user.password

File diff suppressed because it is too large Load Diff

View File

@ -47,8 +47,8 @@ function gen_outbound(flag, node, tag, proxy_table)
proxy_tag = proxy_table.tag or "nil"
end
if node.type == "V2ray" or node.type == "Xray" then
if node.type == "Xray" and node.tlsflow == "xtls-rprx-vision" then
if node.type == "Xray" then
if node.flow == "xtls-rprx-vision" then
else
proxy = 0
if proxy_tag ~= "nil" then
@ -60,7 +60,7 @@ function gen_outbound(flag, node, tag, proxy_table)
end
end
if node.type ~= "V2ray" and node.type ~= "Xray" then
if node.type ~= "Xray" then
local relay_port = node.port
new_port = get_new_port()
local config_file = string.format("%s_%s_%s.json", flag, tag, new_port)
@ -87,10 +87,10 @@ function gen_outbound(flag, node, tag, proxy_table)
node.stream_security = "none"
end
if node.type == "V2ray" or node.type == "Xray" then
if node.type == "Xray" then
if node.tls and node.tls == "1" then
node.stream_security = "tls"
if node.type == "Xray" and node.reality and node.reality == "1" then
if node.reality and node.reality == "1" then
node.stream_security = "reality"
end
end
@ -133,7 +133,7 @@ function gen_outbound(flag, node, tag, proxy_table)
tlsSettings = (node.stream_security == "tls") and {
serverName = node.tls_serverName,
allowInsecure = (node.tls_allowInsecure == "1") and true or false,
fingerprint = (node.type == "Xray" and node.fingerprint and node.fingerprint ~= "") and node.fingerprint or nil
fingerprint = (node.type == "Xray" and node.utls == "1" and node.fingerprint and node.fingerprint ~= "") and node.fingerprint or nil
} or nil,
realitySettings = (node.stream_security == "reality") and {
serverName = node.tls_serverName,
@ -204,7 +204,7 @@ function gen_outbound(flag, node, tag, proxy_table)
level = 0,
security = (node.protocol == "vmess") and node.security or nil,
encryption = node.encryption or "none",
flow = (node.protocol == "vless" and node.tls == '1' and node.tlsflow) and node.tlsflow or nil
flow = (node.protocol == "vless" and node.tls == '1' and node.flow) and node.flow or nil
}
}
}
@ -267,7 +267,7 @@ function gen_config_server(node)
for i = 1, #node.uuid do
clients[i] = {
id = node.uuid[i],
flow = ("vless" == node.protocol and "1" == node.tls and node.tlsflow) and node.tlsflow or nil
flow = ("vless" == node.protocol and "1" == node.tls and node.flow) and node.flow or nil
}
end
settings = {
@ -760,10 +760,10 @@ function gen_config(var)
else
if proxy then
local pre_proxy = nil
if _node.type ~= "V2ray" and _node.type ~= "Xray" then
if _node.type ~= "Xray" then
pre_proxy = true
end
if _node.type == "Xray" and _node.tlsflow == "xtls-rprx-vision" then
if _node.type == "Xray" and _node.flow == "xtls-rprx-vision" then
pre_proxy = true
end
if pre_proxy then

View File

@ -91,7 +91,7 @@ https://github.com/pure-css/pure/blob/master/LICENSE.md
</div>
</div>
<div class="pure-u-2-3">
<h4 id="status_node">V2ray<br /><span class="red"><%:NOT RUNNING%></span></h4>
<h4 id="status_node">Xray<br /><span class="red"><%:NOT RUNNING%></span></h4>
</div>
</div>
</div>
@ -145,7 +145,7 @@ https://github.com/pure-css/pure/blob/master/LICENSE.md
if (true) {
var status_node = document.getElementById('status_node');
if (status_node) {
var text = 'V2ray<br />';
var text = 'Xray<br />';
if (data["global_status"])
text += '<span class="green"><%:RUNNING%></span>';
else

View File

@ -1,7 +1,6 @@
<%+cbi/valueheader%>
<%
local api = require "luci.passwall2.api"
local has_v2ray = api.is_finded("v2ray")
local has_xray = api.is_finded("xray")
-%>
<script type="text/javascript">//<![CDATA[
@ -141,7 +140,7 @@ local has_xray = api.is_finded("xray")
} else if (v_type === "Hysteria") {
dom_prefix = "hysteria_"
protocol = "hysteria"
} else if (v_type === "V2ray" || v_type === "Xray") {
} else if (v_type === "Xray") {
dom_prefix = "xray_"
}
var _address = ""
@ -230,7 +229,7 @@ local has_xray = api.is_finded("xray")
"&protoparam=" + b64encsafe(v_protocol_param.value) +
"&remarks=" + b64encutf8safe(v_alias.value);
url = b64encsafe(ssr_str);
} else if ((v_type === "V2ray" || v_type === "Xray") && opt.get(dom_prefix + "protocol").value === "vmess") {
} else if (v_type === "Xray" && opt.get(dom_prefix + "protocol").value === "vmess") {
protocol = "vmess";
var info = {};
info.v = "2";
@ -275,7 +274,7 @@ local has_xray = api.is_finded("xray")
info.sni = opt.get(dom_prefix + "tls_serverName").value;
}
url = b64EncodeUnicode(JSON.stringify(info));
} else if ((v_type === "V2ray" || v_type === "Xray") && opt.get(dom_prefix + "protocol").value === "vless") {
} else if (v_type === "Xray" && opt.get(dom_prefix + "protocol").value === "vless") {
protocol = "vless";
var v_password = opt.get(dom_prefix + "uuid");
var v_port = opt.get(dom_prefix + "port");
@ -328,8 +327,8 @@ local has_xray = api.is_finded("xray")
params += opt.query("sid", "reality_shortId");
params += opt.query("spx", "reality_spiderX");
}
if (opt.get(dom_prefix + "tlsflow") && opt.get(dom_prefix + "tlsflow").value) {
let v_flow = opt.get(dom_prefix + "tlsflow").value;
if (opt.get(dom_prefix + "flow") && opt.get(dom_prefix + "flow").value) {
let v_flow = opt.get(dom_prefix + "flow").value;
params += "&flow=" + v_flow;
}
params += "&security=" + v_security;
@ -341,7 +340,7 @@ local has_xray = api.is_finded("xray")
params = params.substring(1);
}
url += params;
} else if (((v_type === "V2ray" || v_type === "Xray") && opt.get(dom_prefix + "protocol").value === "trojan")) {
} else if ((v_type === "Xray" && opt.get(dom_prefix + "protocol").value === "trojan")) {
protocol = "trojan";
var v_password = opt.get(dom_prefix + "password");
var v_port = opt.get(dom_prefix + "port");
@ -649,9 +648,7 @@ local has_xray = api.is_finded("xray")
queryParam[decodeURIComponent(params[0]).toLowerCase()] = decodeURIComponent(params[1] || '');
}
}
<% if has_v2ray then %>
opt.set('type', "V2ray");
<% elseif has_xray then %>
<% if has_xray then %>
opt.set('type', "Xray");
<% end %>
opt.set(dom_prefix + 'protocol', "trojan");
@ -670,9 +667,7 @@ local has_xray = api.is_finded("xray")
dom_prefix = "xray_"
var sstr = b64DecodeUnicode(ssu[1]);
var ploc = sstr.indexOf("/?");
<% if has_v2ray then %>
opt.set('type', "V2ray");
<% elseif has_xray then %>
<% if has_xray then %>
opt.set('type', "Xray");
<% end %>
opt.set(dom_prefix + 'protocol', "vmess");
@ -723,8 +718,6 @@ local has_xray = api.is_finded("xray")
dom_prefix = "xray_"
<% if has_xray then %>
opt.set('type', "Xray");
<% elseif has_v2ray then %>
opt.set('type', "V2ray");
<% end %>
opt.set(dom_prefix + 'protocol', "vless");
var m = parseNodeUrl(ssrurl);
@ -753,7 +746,7 @@ local has_xray = api.is_finded("xray")
if (queryParam.security == "tls") {
opt.set(dom_prefix + 'tls', true);
opt.set('reality', false)
opt.set(dom_prefix + 'tlsflow', queryParam.flow || '');
opt.set(dom_prefix + 'flow', queryParam.flow || '');
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
opt.set(dom_prefix + 'tls_allowInsecure', true);
if (queryParam.allowinsecure === '0') {
@ -767,7 +760,7 @@ local has_xray = api.is_finded("xray")
if (queryParam.security == "reality") {
opt.set(dom_prefix + 'tls', true);
opt.set('reality', true)
opt.set(dom_prefix + 'tlsflow', queryParam.flow || '');
opt.set(dom_prefix + 'flow', queryParam.flow || '');
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
if (queryParam.fp && queryParam.fp.trim() != "") {
opt.set('reality_fingerprint', queryParam.fp);

View File

@ -8,7 +8,7 @@ local node = api.uci_get_type("global", "node", "nil")
if node ~= "nil" then
local node_type = api.uci_get_type_id(node, "type")
local node_protocol = api.uci_get_type_id(node, "protocol")
if (node_type == "V2ray" or node_type == "Xray") and node_protocol == "_shunt" then
if node_type == "Xray" and node_protocol == "_shunt" then
default_node_type = node_protocol
uci:foreach("passwall2", "shunt_rules", function(e)
if e[".name"] and e.remarks then

View File

@ -412,6 +412,9 @@ msgstr "传输层插件"
msgid "Shadowsocks secondary encryption"
msgstr "Shadowsocks 二次加密"
msgid "Obfs Type"
msgstr "混淆类型"
msgid "Obfs Password"
msgstr "混淆密码"
@ -421,6 +424,9 @@ msgstr "认证类型"
msgid "Auth Password"
msgstr "认证密码"
msgid "Commands the client to use the BBR flow control algorithm"
msgstr "命令客户端使用 BBR 流量控制算法"
msgid "Max upload Mbps"
msgstr "最大上行(Mbps)"
@ -433,6 +439,9 @@ msgstr "QUIC 流接收窗口"
msgid "QUIC connection receive window"
msgstr "QUIC 连接接收窗口"
msgid "QUIC concurrent bidirectional streams"
msgstr "QUIC 并发双向流的最大数量"
msgid "Disable MTU detection"
msgstr "禁用 MTU 检测"
@ -694,6 +703,9 @@ msgstr "启用自定义规则地址"
msgid "Rule status"
msgstr "规则版本"
msgid "Manually update"
msgstr "手动更新"
msgid "Enable auto update rules"
msgstr "开启自动更新规则"
@ -946,9 +958,6 @@ msgstr "从文件中加载 IP: 形如'ext:file:tag'必须以ext:(小写)
msgid "Clear logs"
msgstr "清空日志"
msgid "Only recommend to use with VLESS-TCP-XTLS-Vision."
msgstr "只推荐与 VLESS-TCP-XTLS-Vision 搭配使用。"
msgid "Password"
msgstr "密码"
@ -1003,9 +1012,6 @@ msgstr "使用TLS"
msgid "Naiveproxy Protocol"
msgstr "Naiveproxy协议"
msgid "V2ray Protocol"
msgstr "V2ray协议"
msgid "User Level"
msgstr "用户等级(level)"
@ -1336,9 +1342,15 @@ msgstr "缓冲区大小"
msgid "Buffer size for every connection (kB)"
msgstr "每一个连接的缓冲区大小kB"
msgid "Custom geoip Path"
msgstr "自定义geoip文件路径"
msgid "Custom geoip URL"
msgstr "自定义geoip文件更新链接"
msgid "Custom geosite Path"
msgstr "自定义geosite文件路径"
msgid "Custom geosite URL"
msgstr "自定义geosite文件更新链接"
@ -1353,3 +1365,9 @@ msgstr "端口跳跃时间 "
msgid "Additional ports for hysteria hop"
msgstr "端口跳跃额外端口"
msgid "Override the connection destination address"
msgstr "覆盖连接目标地址"
msgid "Override the connection destination address with the sniffed domain."
msgstr "用探测出的域名覆盖连接目标地址。"

View File

@ -56,6 +56,17 @@ global_xray=$(uci -q get passwall2.@global_xray[0])
uci -q commit passwall2
}
global_singbox=$(uci -q get passwall2.@global_singbox[0])
[ -z "${global_singbox}" ] && {
cfgid=$(uci add passwall2 global_singbox)
uci -q set passwall2.${cfgid}.sniff_override_destination=1
uci -q set passwall2.${cfgid}.geoip_path="/tmp/singbox/geoip.db"
uci -q set passwall2.${cfgid}.geoip_url="https://github.com/SagerNet/sing-geoip/releases/latest/download/geoip.db"
uci -q set passwall2.${cfgid}.geosite_path="/tmp/singbox/geosite.db"
uci -q set passwall2.${cfgid}.geosite_url="https://github.com/SagerNet/sing-geosite/releases/latest/download/geosite.db"
uci -q commit passwall2
}
rm -f /tmp/luci-indexcache
rm -rf /tmp/luci-modulecache/
killall -HUP rpcd 2>/dev/null

View File

@ -33,6 +33,8 @@ config global_forwarding
option use_nft '0'
option tcp_proxy_way 'redirect'
option ipv6_tproxy '0'
config global_xray
option sniffing '1'
option route_only '0'
@ -46,10 +48,10 @@ config global_rules
option v2ray_location_asset '/usr/share/v2ray/'
config global_app
option v2ray_file '/usr/bin/v2ray'
option xray_file '/usr/bin/xray'
option brook_file '/usr/bin/brook'
option hysteria_file '/usr/bin/hysteria'
option singbox_file '/usr/bin/sing-box'
config global_subscribe
option filter_keyword_mode '1'
@ -58,6 +60,13 @@ config global_subscribe
list filter_discard_list 'QQ群'
list filter_discard_list '官网'
config global_singbox
option sniff_override_destination '1'
option geoip_path '/tmp/singbox/geoip.db'
option geoip_url 'https://github.com/SagerNet/sing-geoip/releases/latest/download/geoip.db'
option geosite_path '/tmp/singbox/geosite.db'
option geosite_url 'https://github.com/SagerNet/sing-geosite/releases/latest/download/geosite.db'
config nodes 'myshunt'
option remarks '分流总节点'
option type 'Xray'
@ -229,7 +238,7 @@ config shunt_rules 'China'
config shunt_rules 'QUIC'
option remarks 'QUIC'
option port '80,443'
option port '443'
option network 'udp'
config shunt_rules 'UDP'

View File

@ -27,6 +27,7 @@ ENABLED_ACLS=0
PROXY_IPV6=0
PROXY_IPV6_UDP=0
LUA_UTIL_PATH=/usr/lib/lua/luci/passwall2
UTIL_SINGBOX=$LUA_UTIL_PATH/util_sing-box.lua
UTIL_SS=$LUA_UTIL_PATH/util_shadowsocks.lua
UTIL_XRAY=$LUA_UTIL_PATH/util_xray.lua
UTIL_NAIVE=$LUA_UTIL_PATH/util_naiveproxy.lua
@ -283,21 +284,16 @@ lua_api() {
echo $(lua -e "local api = require 'luci.passwall2.api' print(api.${func})")
}
run_v2ray() {
run_xray() {
local flag node redir_port socks_address socks_port socks_username socks_password http_address http_port http_username http_password
local dns_listen_port direct_dns_protocol direct_dns_udp_server direct_dns_tcp_server direct_dns_doh direct_dns_client_ip direct_dns_query_strategy 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
local loglevel log_file config_file
local _extra_param=""
eval_set_val $@
local type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z')
if [ "$type" != "v2ray" ] && [ "$type" != "xray" ]; then
if [ "$type" != "xray" ]; then
local bin=$(first_type $(config_t_get global_app xray_file) xray)
if [ -n "$bin" ]; then
type="xray"
else
bin=$(first_type $(config_t_get global_app v2ray_file) v2ray)
[ -n "$bin" ] && type="v2ray"
fi
[ -n "$bin" ] && type="xray"
fi
[ -z "$type" ] && return 1
[ -n "$log_file" ] || local log_file="/dev/null"
@ -412,6 +408,162 @@ run_v2ray() {
ln_run "$(first_type $(config_t_get global_app ${type}_file) ${type})" ${type} $log_file run -c "$config_file"
}
run_singbox() {
local flag node redir_port socks_address socks_port socks_username socks_password http_address http_port http_username http_password
local dns_listen_port direct_dns_protocol direct_dns_udp_server direct_dns_tcp_server direct_dns_doh direct_dns_client_ip direct_dns_query_strategy 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
local loglevel log_file config_file
local _extra_param=""
eval_set_val $@
local type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z')
[ -z "$type" ] && return 1
[ -n "$log_file" ] || local log_file="/dev/null"
_extra_param="${_extra_param} -log 1 -logfile ${log_file}"
if [ "$log_file" = "/dev/null" ]; then
_extra_param="${_extra_param} -log 0"
else
_extra_param="${_extra_param} -log 1 -logfile ${log_file}"
fi
[ -z "$loglevel" ] && local loglevel=$(config_t_get global loglevel "warn")
[ "$loglevel" = "warning" ] && loglevel="warn"
_extra_param="${_extra_param} -loglevel $loglevel"
_extra_param="${_extra_param} -tags $($(first_type $(config_t_get global_app singbox_file) sing-box) version | grep 'Tags:' | awk '{print $2}')"
[ -n "$flag" ] && pgrep -af "$TMP_BIN_PATH" | awk -v P1="${flag}" 'BEGIN{IGNORECASE=1}$0~P1{print $1}' | xargs kill -9 >/dev/null 2>&1
[ -n "$flag" ] && _extra_param="${_extra_param} -flag $flag"
[ -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_listen_port" ] && {
V2RAY_DNS_DIRECT_ARGS="-dns_out_tag direct"
V2RAY_DNS_DIRECT_CONFIG="${TMP_PATH}/${flag}_dns_direct.json"
V2RAY_DNS_DIRECT_LOG="${TMP_PATH}/${flag}_dns_direct.log"
V2RAY_DNS_DIRECT_ARGS="${V2RAY_DNS_DIRECT_ARGS} -log 1 -logfile ${V2RAY_DNS_DIRECT_LOG}"
dns_direct_listen_port=$(get_new_port $(expr $dns_listen_port + 1) udp)
V2RAY_DNS_DIRECT_ARGS="${V2RAY_DNS_DIRECT_ARGS} -dns_listen_port ${dns_direct_listen_port}"
[ "$direct_dns_protocol" = "auto" ] && {
direct_dns_protocol="udp"
direct_dns_udp_server=${AUTO_DNS}
direct_dns_query_strategy="UseIP"
}
case "$direct_dns_protocol" in
udp)
local _dns=$(get_first_dns direct_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}')
V2RAY_DNS_DIRECT_ARGS="${V2RAY_DNS_DIRECT_ARGS} -direct_dns_server ${_dns_address} -direct_dns_port ${_dns_port} -direct_dns_udp_server ${_dns_address}"
;;
esac
[ -n "$direct_dns_query_strategy" ] && V2RAY_DNS_DIRECT_ARGS="${V2RAY_DNS_DIRECT_ARGS} -dns_query_strategy ${direct_dns_query_strategy}"
[ -n "$direct_dns_client_ip" ] && V2RAY_DNS_DIRECT_ARGS="${V2RAY_DNS_DIRECT_ARGS} -dns_client_ip ${direct_dns_client_ip}"
lua $UTIL_SINGBOX gen_dns_config ${V2RAY_DNS_DIRECT_ARGS} > $V2RAY_DNS_DIRECT_CONFIG
ln_run "$(first_type $(config_t_get global_app singbox_file) sing-box)" "sing-box" "/dev/null" run -c "$V2RAY_DNS_DIRECT_CONFIG"
direct_dnsmasq_listen_port=$(get_new_port $(expr $dns_direct_listen_port + 1) udp)
local set_flag="${flag}"
local direct_ipset_conf=$TMP_PATH/dnsmasq_${flag}_direct.conf
[ -n "$(echo ${flag} | grep '^acl')" ] && {
direct_ipset_conf=${TMP_ACL_PATH}/${sid}/dnsmasq_${flag}_direct.conf
set_flag=$(echo ${flag} | awk -F '_' '{print $2}')
}
if [ "${nftflag}" = "1" ]; then
local direct_nftset="4#inet#fw4#passwall2_${set_flag}_whitelist,6#inet#fw4#passwall2_${set_flag}_whitelist6"
else
local direct_ipset="passwall2_${set_flag}_whitelist,passwall2_${set_flag}_whitelist6"
fi
run_ipset_dnsmasq listen_port=${direct_dnsmasq_listen_port} server_dns=127.0.0.1#${dns_direct_listen_port} ipset="${direct_ipset}" nftset="${direct_nftset}" config_file=${direct_ipset_conf}
_extra_param="${_extra_param} -direct_dns_port ${direct_dnsmasq_listen_port} -direct_dns_udp_server 127.0.0.1 -direct_dns_query_strategy ${direct_dns_query_strategy}"
:<<eof
V2RAY_DNS_REMOTE_ARGS="-dns_out_tag remote"
V2RAY_DNS_REMOTE_CONFIG="${TMP_PATH}/${flag}_dns_remote.json"
V2RAY_DNS_REMOTE_LOG="${TMP_PATH}/${flag}_dns_remote.log"
V2RAY_DNS_REMOTE_ARGS="${V2RAY_DNS_REMOTE_ARGS} -log 1 -logfile ${V2RAY_DNS_REMOTE_LOG}"
dns_remote_listen_port=$(get_new_port $(expr $direct_dnsmasq_listen_port + 1) udp)
V2RAY_DNS_REMOTE_ARGS="${V2RAY_DNS_REMOTE_ARGS} -dns_listen_port ${dns_remote_listen_port}"
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}')
V2RAY_DNS_REMOTE_ARGS="${V2RAY_DNS_REMOTE_ARGS} -remote_dns_server ${_dns_address} -remote_dns_port ${_dns_port} -remote_dns_udp_server ${_dns_address}"
;;
tcp)
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}')
V2RAY_DNS_REMOTE_ARGS="${V2RAY_DNS_REMOTE_ARGS} -remote_dns_server ${_dns_address} -remote_dns_port ${_dns_port} -remote_dns_tcp_server tcp://${_dns}"
;;
doh)
local _doh_url=$(echo $remote_dns_doh | awk -F ',' '{print $1}')
local _doh_host_port=$(lua_api "get_domain_from_url(\"${_doh_url}\")")
#local _doh_host_port=$(echo $_doh_url | sed "s/https:\/\///g" | awk -F '/' '{print $1}')
local _doh_host=$(echo $_doh_host_port | awk -F ':' '{print $1}')
local is_ip=$(lua_api "is_ip(\"${_doh_host}\")")
local _doh_port=$(echo $_doh_host_port | awk -F ':' '{print $2}')
[ -z "${_doh_port}" ] && _doh_port=443
local _doh_bootstrap=$(echo $remote_dns_doh | cut -d ',' -sf 2-)
[ "${is_ip}" = "true" ] && _doh_bootstrap=${_doh_host}
[ -n "$_doh_bootstrap" ] && V2RAY_DNS_REMOTE_ARGS="${V2RAY_DNS_REMOTE_ARGS} -remote_dns_server ${_doh_bootstrap}"
V2RAY_DNS_REMOTE_ARGS="${V2RAY_DNS_REMOTE_ARGS} -remote_dns_port ${_doh_port} -remote_dns_doh_url ${_doh_url} -remote_dns_doh_host ${_doh_host}"
;;
esac
[ -n "$remote_dns_query_strategy" ] && V2RAY_DNS_REMOTE_ARGS="${V2RAY_DNS_REMOTE_ARGS} -dns_query_strategy ${remote_dns_query_strategy}"
[ -n "$remote_dns_client_ip" ] && V2RAY_DNS_REMOTE_ARGS="${V2RAY_DNS_REMOTE_ARGS} -dns_client_ip ${remote_dns_client_ip}"
V2RAY_DNS_REMOTE_ARGS="${V2RAY_DNS_REMOTE_ARGS} -remote_dns_outbound_socks_address 127.0.0.1 -remote_dns_outbound_socks_port ${socks_port}"
lua $UTIL_SINGBOX gen_dns_config ${V2RAY_DNS_REMOTE_ARGS} > $V2RAY_DNS_REMOTE_CONFIG
ln_run "$(first_type $(config_t_get global_app singbox_file) sing-box)" "sing-box" "/dev/null" run -c "$V2RAY_DNS_REMOTE_CONFIG"
_extra_param="${_extra_param} -remote_dns_port ${dns_remote_listen_port} -remote_dns_udp_server 127.0.0.1"
eof
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_port ${_dns_port} -remote_dns_udp_server ${_dns_address}"
;;
tcp)
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_server ${_dns_address} -remote_dns_port ${_dns_port} -remote_dns_tcp_server tcp://${_dns}"
;;
doh)
local _doh_url=$(echo $remote_dns_doh | awk -F ',' '{print $1}')
local _doh_host_port=$(lua_api "get_domain_from_url(\"${_doh_url}\")")
#local _doh_host_port=$(echo $_doh_url | sed "s/https:\/\///g" | awk -F '/' '{print $1}')
local _doh_host=$(echo $_doh_host_port | awk -F ':' '{print $1}')
local is_ip=$(lua_api "is_ip(\"${_doh_host}\")")
local _doh_port=$(echo $_doh_host_port | awk -F ':' '{print $2}')
[ -z "${_doh_port}" ] && _doh_port=443
local _doh_bootstrap=$(echo $remote_dns_doh | cut -d ',' -sf 2-)
[ "${is_ip}" = "true" ] && _doh_bootstrap=${_doh_host}
[ -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}"
;;
esac
[ -n "$remote_dns_query_strategy" ] && _extra_param="${_extra_param} -remote_dns_query_strategy ${remote_dns_query_strategy}"
[ -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}"
[ "$remote_fakedns" = "1" ] && _extra_param="${_extra_param} -remote_dns_fake 1"
}
lua $UTIL_SINGBOX gen_config -node $node -redir_port $redir_port -tcp_proxy_way $tcp_proxy_way ${_extra_param} > $config_file
ln_run "$(first_type $(config_t_get global_app singbox_file) sing-box)" "sing-box" "${log_file}" run -c "$config_file"
}
run_socks() {
local flag node bind socks_port config_file http_port http_config_file relay_port log_file
eval_set_val $@
@ -444,7 +596,7 @@ run_socks() {
error_msg="某种原因,此 Socks 服务的相关配置已失联,启动中止!"
fi
if [ "$type" == "v2ray" ] || [ "$type" == "xray" ]; then
if [ "$type" == "sing-box" ] || [ "$type" == "xray" ]; then
local protocol=$(config_n_get $node protocol)
if [ "$protocol" == "_balancing" ] || [ "$protocol" == "_shunt" ] || [ "$protocol" == "_iface" ]; then
unset error_msg
@ -458,7 +610,15 @@ run_socks() {
[ "$bind" != "127.0.0.1" ] && echolog " - Socks节点[$remarks]${tmp},启动 ${bind}:${socks_port}"
case "$type" in
v2ray|\
sing-box)
[ "$http_port" != "0" ] && {
http_flag=1
config_file=$(echo $config_file | sed "s/SOCKS/HTTP_SOCKS/g")
local _extra_param="-local_http_port $http_port"
}
lua $UTIL_SINGBOX gen_config -flag SOCKS_$flag -node $node -local_socks_port $socks_port ${_extra_param} > $config_file
ln_run "$(first_type $(config_t_get global_app singbox_file) sing-box)" "sing-box" $log_file run -c "$config_file"
;;
xray)
[ "$http_port" != "0" ] && {
http_flag=1
@ -466,7 +626,7 @@ run_socks() {
local _extra_param="-local_http_port $http_port"
}
lua $UTIL_XRAY gen_config -flag SOCKS_$flag -node $node -local_socks_port $socks_port ${_extra_param} > $config_file
ln_run "$(first_type $(config_t_get global_app ${type}_file) ${type})" ${type} $log_file run -c "$config_file"
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
@ -520,17 +680,19 @@ run_socks() {
esac
# http to socks
[ -z "$http_flag" ] && [ "$http_port" != "0" ] && [ -n "$http_config_file" ] && [ "$type" != "v2ray" ] && [ "$type" != "xray" ] && [ "$type" != "socks" ] && {
local bin=$(first_type $(config_t_get global_app v2ray_file) v2ray)
[ -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 singbox_file) sing-box)
if [ -n "$bin" ]; then
type="v2ray"
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"
else
bin=$(first_type $(config_t_get global_app xray_file) xray)
[ -n "$bin" ] && type="xray"
fi
[ -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"
fi
}
unset http_flag
}
@ -646,7 +808,8 @@ run_global() {
node_http_port=$(config_t_get global node_http_port 0)
[ "$node_http_port" != "0" ] && V2RAY_ARGS="${V2RAY_ARGS} http_port=${node_http_port}"
run_v2ray $V2RAY_ARGS
[ "${TYPE}" = "xray" ] && run_xray $V2RAY_ARGS
[ "${TYPE}" = "sing-box" ] && run_singbox $V2RAY_ARGS
}
start_socks() {
@ -897,7 +1060,10 @@ acl_app() {
config_file=$TMP_ACL_PATH/${node}_TCP_UDP_DNS_${redir_port}.json
dns_port=$(get_new_port $(expr $dns_port + 1))
local acl_socks_port=$(get_new_port $(expr $redir_port + $index))
run_v2ray flag=acl_$sid node=$node redir_port=$redir_port socks_address=127.0.0.1 socks_port=$acl_socks_port dns_listen_port=${dns_port} direct_dns_protocol=${direct_dns_protocol} direct_dns_udp_server=${direct_dns} direct_dns_tcp_server=${direct_dns} direct_dns_doh="${direct_dns}" direct_dns_client_ip=${direct_dns_client_ip} direct_dns_query_strategy=${direct_dns_query_strategy} remote_dns_protocol=${remote_dns_protocol} remote_dns_tcp_server=${remote_dns} remote_dns_udp_server=${remote_dns} remote_dns_doh="${remote_dns}" remote_dns_client_ip=${remote_dns_client_ip} remote_fakedns=${remote_fakedns} remote_dns_query_strategy=${remote_dns_query_strategy} config_file=${config_file}
local run_func
[ "${TYPE}" = "xray" ] && run_func="run_xray"
[ "${TYPE}" = "sing-box" ] && run_func="run_singbox"
${run_func} flag=acl_$sid node=$node redir_port=$redir_port socks_address=127.0.0.1 socks_port=$acl_socks_port dns_listen_port=${dns_port} direct_dns_protocol=${direct_dns_protocol} direct_dns_udp_server=${direct_dns} direct_dns_tcp_server=${direct_dns} direct_dns_doh="${direct_dns}" direct_dns_client_ip=${direct_dns_client_ip} direct_dns_query_strategy=${direct_dns_query_strategy} remote_dns_protocol=${remote_dns_protocol} remote_dns_tcp_server=${remote_dns} remote_dns_udp_server=${remote_dns} remote_dns_doh="${remote_dns}" remote_dns_client_ip=${remote_dns_client_ip} remote_fakedns=${remote_fakedns} remote_dns_query_strategy=${remote_dns_query_strategy} config_file=${config_file}
fi
dnsmasq_port=$(get_new_port $(expr $dnsmasq_port + 1))
redirect_dns_port=$dnsmasq_port

View File

@ -12,7 +12,7 @@ local arg1 = arg[1]
local reboot = 0
local geoip_update = 0
local geosite_update = 0
local v2ray_asset_location = ucic:get_first(name, 'global_rules', "v2ray_location_asset", "/usr/share/v2ray/")
local asset_location = ucic:get_first(name, 'global_rules', "v2ray_location_asset", "/usr/share/v2ray/")
-- Custom geo file
local geoip_api = ucic:get_first(name, 'global_rules', "geoip_url", "https://api.github.com/repos/Loyalsoldier/v2ray-rules-dat/releases/latest")
@ -61,8 +61,8 @@ local function fetch_geoip()
f:write(content:gsub("geoip.dat", "/tmp/geoip.dat"), "")
f:close()
if nixio.fs.access(v2ray_asset_location .. "geoip.dat") then
luci.sys.call(string.format("cp -f %s %s", v2ray_asset_location .. "geoip.dat", "/tmp/geoip.dat"))
if nixio.fs.access(asset_location .. "geoip.dat") then
luci.sys.call(string.format("cp -f %s %s", asset_location .. "geoip.dat", "/tmp/geoip.dat"))
if luci.sys.call('sha256sum -c /tmp/geoip.dat.sha256sum > /dev/null 2>&1') == 0 then
log("geoip 版本一致,无需更新。")
return 1
@ -72,7 +72,7 @@ local function fetch_geoip()
if v2.name and v2.name == "geoip.dat" then
sret = curl(v2.browser_download_url, "/tmp/geoip.dat")
if luci.sys.call('sha256sum -c /tmp/geoip.dat.sha256sum > /dev/null 2>&1') == 0 then
luci.sys.call(string.format("mkdir -p %s && cp -f %s %s", v2ray_asset_location, "/tmp/geoip.dat", v2ray_asset_location .. "geoip.dat"))
luci.sys.call(string.format("mkdir -p %s && cp -f %s %s", asset_location, "/tmp/geoip.dat", asset_location .. "geoip.dat"))
reboot = 1
log("geoip 更新成功。")
return 1
@ -112,8 +112,8 @@ local function fetch_geosite()
f:write(content:gsub("geosite.dat", "/tmp/geosite.dat"), "")
f:close()
if nixio.fs.access(v2ray_asset_location .. "geosite.dat") then
luci.sys.call(string.format("cp -f %s %s", v2ray_asset_location .. "geosite.dat", "/tmp/geosite.dat"))
if nixio.fs.access(asset_location .. "geosite.dat") then
luci.sys.call(string.format("cp -f %s %s", asset_location .. "geosite.dat", "/tmp/geosite.dat"))
if luci.sys.call('sha256sum -c /tmp/geosite.dat.sha256sum > /dev/null 2>&1') == 0 then
log("geosite 版本一致,无需更新。")
return 1
@ -123,7 +123,7 @@ local function fetch_geosite()
if v2.name and v2.name == "geosite.dat" then
sret = curl(v2.browser_download_url, "/tmp/geosite.dat")
if luci.sys.call('sha256sum -c /tmp/geosite.dat.sha256sum > /dev/null 2>&1') == 0 then
luci.sys.call(string.format("mkdir -p %s && cp -f %s %s", v2ray_asset_location, "/tmp/geosite.dat", v2ray_asset_location .. "geosite.dat"))
luci.sys.call(string.format("mkdir -p %s && cp -f %s %s", asset_location, "/tmp/geosite.dat", asset_location .. "geosite.dat"))
reboot = 1
log("geosite 更新成功。")
return 1

View File

@ -23,7 +23,7 @@ uci:revert(appname)
local has_ss = api.is_finded("ss-redir")
local has_ss_rust = api.is_finded("sslocal")
local has_v2ray = api.is_finded("v2ray")
local has_singbox = api.is_finded("sing-box")
local has_xray = api.is_finded("xray")
local allowInsecure_default = true
local ss_aead_type_default = uci:get(appname, "@global_subscribe[0]", "ss_aead_type") or "shadowsocks-libev"
@ -387,10 +387,12 @@ local function processData(szType, content, add_mode, add_from)
result.remarks = base64Decode(params.remarks)
elseif szType == 'vmess' then
local info = jsonParse(content)
result.type = 'V2ray'
if has_xray then
result.type = 'Xray'
end
if has_singbox then
result.type = 'sing-box'
end
result.address = info.add
result.port = info.port
result.protocol = 'vmess'
@ -532,13 +534,9 @@ local function processData(szType, content, add_mode, add_from)
if method:lower() == "chacha20-poly1305" then
result.method = "chacha20-ietf-poly1305"
end
elseif ss_aead_type_default == "v2ray" and has_v2ray and not result.plugin then
result.type = 'V2ray'
elseif ss_aead_type_default == "sing-box" and has_singbox and not result.plugin then
result.type = 'sing-box'
result.protocol = 'shadowsocks'
result.transport = 'tcp'
if method:lower() == "chacha20-ietf-poly1305" then
result.method = "chacha20-poly1305"
end
elseif ss_aead_type_default == "xray" and has_xray and not result.plugin then
result.type = 'Xray'
result.protocol = 'shadowsocks'
@ -557,10 +555,12 @@ local function processData(szType, content, add_mode, add_from)
content = content:sub(0, idx_sp - 1)
end
result.remarks = UrlDecode(alias)
result.type = 'V2ray'
if has_xray then
result.type = 'Xray'
end
if has_singbox then
result.type = 'sing-box'
end
result.protocol = 'trojan'
if content:find("@") then
local Info = split(content, "@")
@ -622,10 +622,12 @@ local function processData(szType, content, add_mode, add_from)
result.group = content.airport
result.remarks = content.remarks
elseif szType == "vless" then
result.type = 'V2ray'
if has_xray then
result.type = 'Xray'
end
if has_singbox then
result.type = 'sing-box'
end
result.protocol = "vless"
local alias = ""
if content:find("#") then
@ -699,10 +701,11 @@ local function processData(szType, content, add_mode, add_from)
result.encryption = params.encryption or "none"
result.flow = params.flow or nil
result.tls = "0"
if params.security == "tls" or params.security == "reality" then
result.tls = "1"
result.tlsflow = params.flow or nil
result.tls_serverName = (params.sni and params.sni ~= "") and params.sni or params.host
result.fingerprint = (params.fp and params.fp ~= "") and params.fp or "chrome"
if params.security == "reality" then