🐶 Sync 2026-05-23 08:41:38

This commit is contained in:
github-actions[bot] 2026-05-23 08:41:38 +08:00
parent 51d7860e60
commit 00106d0a89
37 changed files with 353 additions and 771 deletions

View File

@ -1,8 +1,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=fan2go
PKG_VERSION:=0.13.0
PKG_RELEASE:=1
PKG_VERSION:=0.14.0
PKG_RELEASE:=2
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/markusressel/fan2go/tar.gz/$(PKG_VERSION)?

View File

@ -10,8 +10,8 @@ include $(TOPDIR)/rules.mk
PKG_ARCH_kai:=$(ARCH)
PKG_NAME:=kai
PKG_VERSION:=0.0.5
PKG_RELEASE:=4
PKG_VERSION:=0.0.6
PKG_RELEASE:=5
PKG_SOURCE:=$(PKG_NAME)-binary-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://github.com/linkease/istore-packages/releases/download/prebuilt/
PKG_HASH:=skip

View File

@ -10,8 +10,8 @@ include $(TOPDIR)/rules.mk
PKG_ARCH_kai_session:=$(ARCH)
PKG_NAME:=kai_session
PKG_VERSION:=0.0.5
PKG_RELEASE:=4
PKG_VERSION:=0.0.6
PKG_RELEASE:=5
PKG_SOURCE:=$(PKG_NAME)-binary-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://github.com/linkease/istore-packages/releases/download/prebuilt/
PKG_HASH:=skip

View File

@ -7,8 +7,8 @@
include $(TOPDIR)/rules.mk
LUCI_TITLE:=kai
PKG_VERSION:=1.0.1
PKG_RELEASE:=7
PKG_VERSION:=1.0.2
PKG_RELEASE:=8
LUCI_DEPENDS:=+kai +kai_session +luci-compat
LUCI_MINIFY_CSS:=0
LUCI_MINIFY_JS:=0

View File

@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall2
PKG_VERSION:=26.5.19
PKG_RELEASE:=46
PKG_RELEASE:=47
PKG_PO_VERSION:=$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \
@ -16,14 +16,11 @@ PKG_CONFIG_DEPENDS:= \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Server \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server \
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_tuic_client \
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Plugin
LUCI_TITLE:=LuCI support for PassWall 2
@ -119,17 +116,6 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy
select PACKAGE_naiveproxy
default n
config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client
bool "Include Shadowsocks Libev Client"
select PACKAGE_shadowsocks-libev-ss-local
select PACKAGE_shadowsocks-libev-ss-redir
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Server
bool "Include Shadowsocks Libev Server"
select PACKAGE_shadowsocks-libev-ss-server
default n
config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client
bool "Include Shadowsocks Rust Client"
depends on !i386
@ -158,12 +144,6 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_Simple_Obfs
select PACKAGE_simple-obfs-client
default y
config PACKAGE_$(PKG_NAME)_INCLUDE_tuic_client
bool "Include tuic-client"
depends on aarch64||arm||i386||x86_64
select PACKAGE_tuic-client
default n
config PACKAGE_$(PKG_NAME)_INCLUDE_V2ray_Plugin
bool "Include V2ray-Plugin (Shadowsocks Plugin)"
select PACKAGE_v2ray-plugin

View File

@ -59,6 +59,7 @@ function index()
entry({"admin", "services", appname, "server_user"}, cbi(appname .. "/server/user")).leaf = true
--[[ API ]]
entry({"admin", "services", appname, "server_user_update"}, call("server_user_update")).leaf = true
entry({"admin", "services", appname, "server_user_status"}, call("server_user_status")).leaf = true
entry({"admin", "services", appname, "server_user_log"}, call("server_user_log")).leaf = true
entry({"admin", "services", appname, "server_get_log"}, call("server_get_log")).leaf = true
@ -685,6 +686,23 @@ function rollback_rules()
http_write_json_ok()
end
function server_user_update()
local id = http.formvalue("id") -- Node id
local data = http.formvalue("data") -- json new Data
if id and data then
local data_t = jsonParse(data) or {}
if next(data_t) then
for k, v in pairs(data_t) do
uci:set(appname .. "_server", id, k, v)
end
api.uci_save(uci, appname .. "_server")
http_write_json_ok()
return
end
end
http_write_json_error()
end
function server_user_status()
local e = {}
e.index = http.formvalue("index")

View File

@ -78,103 +78,10 @@ o.rmempty = false
o = s:option(Value, "interface", translate("Source Interface"))
o:value("", translate("All"))
-- Populate with actual kernel network devices instead of UCI interface names,
-- because the backend (nftables iifname / iptables -i) matches kernel device names.
do
local nfs = require "nixio.fs"
local _cursor = require("luci.model.uci").cursor()
local _sysnet = "/sys/class/net/"
-- Map UCI interface names to their device names and vice versa
local _iface_to_dev = {}
local _dev_to_ifaces = {}
local _iface_proto = {}
_cursor:foreach("network", "interface", function(sec)
local name = sec[".name"]
if name ~= "loopback" then
_iface_proto[name] = sec.proto
if sec.device then
_iface_to_dev[name] = sec.device
_dev_to_ifaces[sec.device] = _dev_to_ifaces[sec.device] or {}
table.insert(_dev_to_ifaces[sec.device], name)
end
end
end)
-- Classify device type using sysfs attributes
local function classify_sysfs(dev)
if nfs.stat(_sysnet .. dev .. "/bridge", "type") == "dir" then
return translate("Bridge")
elseif nfs.stat(_sysnet .. dev .. "/wireless", "type") == "dir" then
return translate("Wireless Adapter")
elseif dev:match("^tun") or dev:match("^tap") or dev:match("^wg") or dev:match("^ppp") then
return translate("Tunnel Interface")
else
return translate("Ethernet Adapter")
end
end
-- Classify offline UCI interfaces by config hints
local function classify_uci(dev_name, proto)
if dev_name and dev_name:match("^br%-") then
return translate("Bridge")
elseif proto == "wireguard" or proto == "pppoe" or proto == "pptp" or proto == "l2tp" then
return translate("Tunnel Interface")
else
return translate("Interface")
end
end
local _seen = {}
local _devices = {}
-- Active kernel devices from /sys/class/net/.
-- Skip bridge member ports (/master) and DSA master devices (/dsa) because
-- nftables iifname matches the parent bridge for routed traffic, not
-- individual member ports. Also skip internal virtual devices.
local _iter = nfs.dir(_sysnet)
if _iter then
for dev in _iter do
if dev ~= "lo"
and not dev:match("^veth")
and not dev:match("^ifb")
and not dev:match("^gre")
and not dev:match("^sit")
and not dev:match("^ip6tnl")
and not dev:match("^erspan")
and not nfs.stat(_sysnet .. dev .. "/master", "type")
and not nfs.stat(_sysnet .. dev .. "/dsa", "type")
then
local dtype = classify_sysfs(dev)
local label = dtype .. ': "' .. dev .. '"'
if _dev_to_ifaces[dev] then
label = label .. " (" .. table.concat(_dev_to_ifaces[dev], ", ") .. ")"
end
_devices[#_devices + 1] = { name = dev, label = label, sort = dtype .. ":" .. dev }
_seen[dev] = true
end
end
end
-- UCI interfaces whose device does not currently exist (down tunnels, VPNs, etc.).
-- Stored by UCI name since the kernel device is not available yet.
-- Dedup by device: if two interfaces share a device, only one is shown.
for iface, dev in pairs(_iface_to_dev) do
if not _seen[dev] then
local dtype = classify_uci(dev, _iface_proto[iface])
local label = dtype .. ': "' .. iface .. '"'
-- Sort offline entries after active devices
_devices[#_devices + 1] = { name = iface, label = label, sort = "zzz:" .. iface }
_seen[dev] = true
end
end
table.sort(_devices, function(a, b) return a.sort < b.sort end)
for _, d in ipairs(_devices) do
o:value(d.name, d.label)
end
local iface = api.get_network_devices()
for _, d in ipairs(iface) do
o:value(d.name, d.label)
end
o.validate = function(self, value, section)
if value == "" or value:match("^[a-zA-Z0-9][a-zA-Z0-9%.%_%-]*$") then
return value

View File

@ -14,6 +14,7 @@ formvalue_key = "cbid." .. appname .. "." .. arg[1] .. "."
local header = Template(appname .. "/node_config/header")
header.api = api
header.config = m.config
header.section = arg[1]
m:append(header)
@ -91,6 +92,7 @@ end
local footer = Template(appname .. "/node_config/footer")
footer.api = api
footer.config = m.config
footer.section = arg[1]
m:append(footer)

View File

@ -1,7 +1,6 @@
local api = require "luci.passwall2.api"
local appname = api.appname
local uci = api.uci
local has_ss = api.is_finded("ss-redir")
local has_ss_rust = api.is_finded("sslocal")
local has_singbox = api.finded_com("sing-box")
local has_xray = api.finded_com("xray")
@ -12,10 +11,6 @@ local vmess_type = {}
local vless_type = {}
local hysteria2_type = {}
local xray_version = api.get_app_version("xray")
if has_ss then
local s = "shadowsocks-libev"
table.insert(ss_type, s)
end
if has_ss_rust then
local s = "shadowsocks-rust"
table.insert(ss_type, s)

View File

@ -15,7 +15,6 @@ end
m:append(Template(appname .. "/cbi/nodes_listvalue_com"))
local has_ss = api.is_finded("ss-redir")
local has_ss_rust = api.is_finded("sslocal")
local has_singbox = api.finded_com("sing-box")
local has_xray = api.finded_com("xray")
@ -26,10 +25,6 @@ local vmess_type = {}
local vless_type = {}
local hysteria2_type = {}
local xray_version = api.get_app_version("xray")
if has_ss then
local s = "shadowsocks-libev"
table.insert(ss_type, s)
end
if has_ss_rust then
local s = "shadowsocks-rust"
table.insert(ss_type, s)
@ -223,6 +218,14 @@ if #hysteria2_type > 0 then
for key, value in pairs(hysteria2_type) do
o:value(value)
end
o = s:option(Value, "hysteria_up_mbps", "Hy/Hy2 " .. translate("Max upload Mbps"))
o.datatype = "uinteger"
o.default = "100"
o = s:option(Value, "hysteria_down_mbps", "Hy/Hy2 " .. translate("Max download Mbps"))
o.datatype = "uinteger"
o.default = "100"
end
o = s:option(Flag, "boot_update", translate("Update Once on Boot"), translate("Updates the subscription the first time runs automatically after each system boot."))
@ -287,6 +290,7 @@ o = s:option(ListValue, "chain_proxy", translate("Chain Proxy"))
o:value("", translate("Close(Not use)"))
o:value("1", translate("Preproxy Node"))
o:value("2", translate("Landing Node"))
o:value("3", translate("Outbound Interface"))
local descrStr = "Chained proxy works only with Xray or Sing-box nodes.<br>"
descrStr = descrStr .. "You can only use manual or imported nodes as chained nodes."
@ -304,6 +308,14 @@ o2.description = descrStr
o2.template = appname .. "/cbi/nodes_listvalue"
o2.group = {}
o3 = s:option(Value, "outbound_iface", translate("Outbound Interface"))
o3:depends({ ["chain_proxy"] = "3" })
o3:value("", translate("All"))
local iface = api.get_network_devices()
for _, d in ipairs(iface) do
o3:value(d.name, d.label)
end
for k, v in pairs(nodes_table) do
if (v.type == "Xray" or v.type == "sing-box") and (not v.chain_proxy or v.chain_proxy == "") and v.add_mode ~= "2" then
o1:value(v.id, v.remark)

View File

@ -78,6 +78,7 @@ if not arg_select_proto:find("_") then
load_normal_options = true
end
local netdev_list = api.get_network_devices()
local node_list = api.get_node_list()
local fallback_list = {}
local is_balancer = nil
@ -270,8 +271,10 @@ end -- [[ Load balancing End ]]
if load_iface_options then -- [[ Custom Interface Start ]]
o = s:option(Value, _n("iface"), translate("Interface"))
o.default = "eth1"
o:depends({ [_n("protocol")] = "_iface" })
for _, d in ipairs(netdev_list) do
o:value(d.name, d.label)
end
end -- [[ Custom Interface End ]]
@ -793,6 +796,7 @@ if not load_shunt_options then
if not (load_iface_options or load_balancing_options) then
-- Special node cannot be use pre-proxy.
o:value("1", translate("Preproxy Node"))
o:value("3", translate("Outbound Interface"))
end
o:value("2", translate("Landing Node"))
@ -801,6 +805,13 @@ if not load_shunt_options then
o1.template = appname .. "/cbi/nodes_listvalue"
o1.group = {}
o3 = s:option(Value, _n("outbound_iface"), translate("Outbound Interface"))
o3:depends({ [_n("chain_proxy")] = "3" })
o3:value("", translate("All"))
for _, d in ipairs(netdev_list) do
o3:value(d.name, d.label)
end
o2 = s:option(ListValue, _n("to_node"), translate("Landing Node"), translate("Only support a layer of proxy."))
o2:depends({ [_n("chain_proxy")] = "2" })
o2.template = appname .. "/cbi/nodes_listvalue"

View File

@ -94,6 +94,7 @@ if not arg_select_proto:find("_") then
load_normal_options = true
end
local netdev_list = api.get_network_devices()
local node_list = api.get_node_list()
if load_urltest_options then -- [[ URLTest Start ]]
@ -198,8 +199,10 @@ end -- [[ URLTest End ]]
if load_iface_options then -- [[ Custom Interface Start ]]
o = s:option(Value, _n("iface"), translate("Interface"))
o.default = "eth1"
o:depends({ [_n("protocol")] = "_iface" })
for _, d in ipairs(netdev_list) do
o:value(d.name, d.label)
end
end -- [[ Custom Interface End ]]
@ -875,8 +878,11 @@ if not load_shunt_options then
o1.group = {}
o3 = s:option(Value, _n("outbound_iface"), translate("Outbound Interface"))
o3.default = "eth1"
o3:depends({ [_n("chain_proxy")] = "3" })
o3:value("", translate("All"))
for _, d in ipairs(netdev_list) do
o3:value(d.name, d.label)
end
o2 = s:option(ListValue, _n("to_node"), translate("Landing Node"), translate("Only support a layer of proxy."))
o2:depends({ [_n("chain_proxy")] = "2", [_n("hysteria2_realms")] = false })

View File

@ -1,62 +0,0 @@
local m, s = ...
if not api.is_finded("ss-local") then
return
end
type_name = "SS"
-- [[ Shadowsocks Libev ]]
s.fields["type"]:value(type_name, "Shadowsocks Libev")
if s.val["type"] ~= type_name then
return
end
local option_prefix = "ss_"
local function _n(name)
return option_prefix .. name
end
local ss_encrypt_method_list = {
"rc4-md5", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr",
"aes-192-ctr", "aes-256-ctr", "bf-cfb", "salsa20", "chacha20", "chacha20-ietf",
"aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305",
"xchacha20-ietf-poly1305"
}
o = s:option(Value, _n("address"), translate("Address (Support Domain Name)"))
o = s:option(Value, _n("port"), translate("Port"))
o.datatype = "port"
o = s:option(Value, _n("password"), translate("Password"))
o.password = true
o = s:option(Value, _n("method"), translate("Encrypt Method"))
for a, t in ipairs(ss_encrypt_method_list) do o:value(t) end
o = s:option(Value, _n("timeout"), translate("Connection Timeout"))
o.datatype = "uinteger"
o.default = 300
o = s:option(Flag, _n("tcp_fast_open"), "TCP " .. translate("Fast Open"), translate("Need node support required"))
o.default = 0
o = s:option(Flag, _n("plugin_enabled"), translate("plugin"))
o.default = 0
o = s:option(ListValue, _n("plugin"), "SIP003 " .. translate("plugin"))
o.default = "none"
o:value("none", translate("none"))
if api.is_finded("xray-plugin") then o:value("xray-plugin") end
if api.is_finded("v2ray-plugin") then o:value("v2ray-plugin") end
if api.is_finded("obfs-local") then o:value("obfs-local") end
o:depends({ [_n("plugin_enabled")] = true })
o = s:option(Value, _n("plugin_opts"), translate("opts"))
o:depends({ [_n("plugin_enabled")] = true })
api.luci_types(arg[1], m, s, type_name, option_prefix)

View File

@ -1,145 +0,0 @@
local m, s = ...
if not api.is_finded("tuic-client") then
return
end
type_name = "TUIC"
-- [[ TUIC ]]
s.fields["type"]:value(type_name, "TUIC")
if s.val["type"] ~= type_name then
return
end
local option_prefix = "tuic_"
local function _n(name)
return option_prefix .. name
end
o = s:option(Value, _n("address"), translate("Address (Support Domain Name)"))
o = s:option(Value, _n("port"), translate("Port"))
o.datatype = "port"
o = s:option(Value, _n("uuid"), translate("ID"))
o.password = true
-- Tuic Password for remote server connect
o = s:option(Value, _n("password"), translate("TUIC User Password For Connect Remote Server"))
o.password = true
o.rmempty = true
o.default = ""
o.rewrite_option = o.option
--[[
-- Tuic username for local socks connect
o = s:option(Value, _n("socks_username"), translate("TUIC UserName For Local Socks"))
o.rmempty = true
o.default = ""
o.rewrite_option = o.option
-- Tuic Password for local socks connect
o = s:option(Value, _n("socks_password"), translate("TUIC Password For Local Socks"))
o.password = true
o.rmempty = true
o.default = ""
o.rewrite_option = o.option
--]]
o = s:option(Value, _n("ip"), translate("Set the TUIC proxy server ip address"))
o.datatype = "ipaddr"
o.rmempty = true
o.rewrite_option = o.option
o = s:option(ListValue, _n("udp_relay_mode"), translate("UDP relay mode"))
o:value("native", translate("native"))
o:value("quic", translate("QUIC"))
o.default = "native"
o.rmempty = true
o.rewrite_option = o.option
o = s:option(ListValue, _n("congestion_control"), translate("Congestion control algorithm"))
o:value("bbr", translate("BBR"))
o:value("cubic", translate("CUBIC"))
o:value("new_reno", translate("New Reno"))
o.default = "cubic"
o.rmempty = true
o.rewrite_option = o.option
o = s:option(Value, _n("heartbeat"), translate("Heartbeat interval(second)"))
o.datatype = "uinteger"
o.default = "3"
o.rmempty = true
o.rewrite_option = o.option
o = s:option(Value, _n("timeout"), translate("Timeout for establishing a connection to server(second)"))
o.datatype = "uinteger"
o.default = "8"
o.rmempty = true
o.rewrite_option = o.option
o = s:option(Value, _n("gc_interval"), translate("Garbage collection interval(second)"))
o.datatype = "uinteger"
o.default = "3"
o.rmempty = true
o.rewrite_option = o.option
o = s:option(Value, _n("gc_lifetime"), translate("Garbage collection lifetime(second)"))
o.datatype = "uinteger"
o.default = "15"
o.rmempty = true
o.rewrite_option = o.option
o = s:option(Value, _n("send_window"), translate("TUIC send window"))
o.datatype = "uinteger"
o.default = 20971520
o.rmempty = true
o.rewrite_option = o.option
o = s:option(Value, _n("receive_window"), translate("TUIC receive window"))
o.datatype = "uinteger"
o.default = 10485760
o.rmempty = true
o.rewrite_option = o.option
o = s:option(Value, _n("max_package_size"), translate("TUIC Maximum packet size the socks5 server can receive from external, in bytes"))
o.datatype = "uinteger"
o.default = 1500
o.rmempty = true
o.rewrite_option = o.option
--Tuic settings for the local inbound socks5 server
o = s:option(Flag, _n("dual_stack"), translate("Set if the listening socket should be dual-stack"))
o.default = 0
o.rmempty = true
o.rewrite_option = o.option
o = s:option(Flag, _n("disable_sni"), translate("Disable SNI"))
o.default = 0
o.rmempty = true
o.rewrite_option = o.option
o = s:option(Flag, _n("zero_rtt_handshake"), translate("Enable 0-RTT QUIC handshake"))
o.default = 0
o.rmempty = true
o.rewrite_option = o.option
o = s:option(ListValue, _n("tls_alpn"), translate("TLS ALPN"))
o.rmempty = true
o.default = ""
o:value("", translate("Default"))
o:value("h3")
o:value("h2")
o:value("h3,h2")
o:value("http/1.1")
o:value("h2,http/1.1")
o:value("h3,h2,http/1.1")
o:value("spdy/3.1")
o:value("h3,spdy/3.1")
o.rewrite_option = o.option
api.luci_types(arg[1], m, s, type_name, option_prefix)

View File

@ -1,28 +1,29 @@
local m, s = ...
local api = require "luci.passwall2.api"
if not api.finded_com("hysteria") then
return
end
local type_name = "Hysteria2"
-- [[ Hysteria2 ]]
s.fields["type"]:value(type_name, "Hysteria2")
if s.val["type"] and s.val["type"] ~= type_name then
return
end
local option_prefix = "hysteria2_"
local function _n(name)
return option_prefix .. name
end
-- [[ Hysteria2 ]]
s.fields["type"]:value(type_name, "Hysteria2")
o = s:option(Flag, _n("custom"), translate("Use Custom Config"))
o = s:option(Value, _n("port"), translate("Listen Port"))
o.datatype = "port"
o.rmempty = false
o:depends({ [_n("custom")] = false })
o = s:option(Flag, _n("realms"), translate("Realms"))

View File

@ -1,13 +1,22 @@
local m, s = ...
local api = require "luci.passwall2.api"
if not api.finded_com("xray") then
return
end
local type_name = "Xray"
-- [[ Xray ]]
s.fields["type"]:value(type_name, "Xray")
if not s.fields["type"].default then
s.fields["type"].default = type_name
end
if s.val["type"] and s.val["type"] ~= type_name then
return
end
local option_prefix = "xray_"
local function _n(name)
@ -22,13 +31,6 @@ local header_type_list = {
"none", "srtp", "utp", "wechat-video", "dtls", "wireguard", "dns"
}
-- [[ Xray ]]
s.fields["type"]:value(type_name, "Xray")
if not s.fields["type"].default then
s.fields["type"].default = type_name
end
o = s:option(Flag, _n("custom"), translate("Use Custom Config"))
o = s:option(ListValue, _n("protocol"), translate("Protocol"))
@ -487,8 +489,11 @@ o:depends({ [_n("outbound_node")] = "_socks"})
o:depends({ [_n("outbound_node")] = "_http"})
o = s:option(Value, _n("outbound_node_iface"), translate("Interface"))
o.default = "eth1"
o:depends({ [_n("outbound_node")] = "_iface"})
local netdev_list = api.get_network_devices()
for _, d in ipairs(netdev_list) do
o:value(d.name, d.label)
end
o = s:option(TextValue, _n("custom_config"), translate("Custom Config"))
o.rows = 10

View File

@ -1,30 +1,13 @@
local m, s = ...
local api = require "luci.passwall2.api"
local singbox_bin = api.finded_com("sing-box")
if not singbox_bin then
return
end
local fs = api.fs
local singbox_tags = luci.sys.exec(singbox_bin .. " version | grep 'Tags:' | awk '{print $2}'")
local type_name = "sing-box"
local option_prefix = "singbox_"
local function _n(name)
return option_prefix .. name
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")
@ -32,6 +15,23 @@ if not s.fields["type"].default then
s.fields["type"].default = type_name
end
if s.val["type"] and s.val["type"] ~= type_name then
return
end
local option_prefix = "singbox_"
local function _n(name)
return option_prefix .. name
end
local singbox_tags = luci.sys.exec(singbox_bin .. " version | grep 'Tags:' | awk '{print $2}'")
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"
}
o = s:option(Flag, _n("custom"), translate("Use Custom Config"))
o = s:option(ListValue, _n("protocol"), translate("Protocol"))
@ -58,7 +58,6 @@ o:depends({ [_n("custom")] = false })
o = s:option(Value, _n("port"), translate("Listen Port"))
o.datatype = "port"
o.rmempty = false
o:depends({ [_n("custom")] = false })
o = s:option(Flag, _n("auth"), translate("Auth"))
@ -302,7 +301,7 @@ o:depends({ [_n("protocol")] = "tuic" })
o:depends({ [_n("protocol")] = "hysteria2" })
o.validate = function(self, value, t)
if value and value ~= "" then
if not nixio.fs.access(value) then
if not fs.access(value) then
return nil, translate("Can't find this file!")
else
return value
@ -321,7 +320,7 @@ o:depends({ [_n("protocol")] = "tuic" })
o:depends({ [_n("protocol")] = "hysteria2" })
o.validate = function(self, value, t)
if value and value ~= "" then
if not nixio.fs.access(value) then
if not fs.access(value) then
return nil, translate("Can't find this file!")
else
return value
@ -464,8 +463,11 @@ o:depends({ [_n("outbound_node")] = "_socks" })
o:depends({ [_n("outbound_node")] = "_http" })
o = s:option(Value, _n("outbound_node_iface"), translate("Interface"))
o.default = "eth1"
o:depends({ [_n("outbound_node")] = "_iface" })
local netdev_list = api.get_network_devices()
for _, d in ipairs(netdev_list) do
o:value(d.name, d.label)
end
o = s:option(TextValue, _n("custom_config"), translate("Custom Config"))
o.rows = 10

View File

@ -1,13 +1,19 @@
local m, s = ...
local api = require "luci.passwall2.api"
if not api.is_finded("ssserver") then
return
end
local type_name = "SS-Rust"
-- [[ Shadowsocks Rust ]]
s.fields["type"]:value(type_name, translate("Shadowsocks Rust"))
if s.val["type"] and s.val["type"] ~= type_name then
return
end
local option_prefix = "ssrust_"
local function _n(name)
@ -20,10 +26,6 @@ local ssrust_encrypt_method_list = {
"2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha8-poly1305", "2022-blake3-chacha20-poly1305"
}
-- [[ Shadowsocks Rust ]]
s.fields["type"]:value(type_name, translate("Shadowsocks Rust"))
o = s:option(Flag, _n("custom"), translate("Use Custom Config"))
o = s:option(Value, _n("port"), translate("Listen Port"))

View File

@ -1,78 +0,0 @@
local m, s = ...
local api = require "luci.passwall2.api"
if not api.is_finded("ss-server") then
return
end
local type_name = "SS"
local option_prefix = "ss_"
local function _n(name)
return option_prefix .. name
end
local ss_encrypt_method_list = {
"rc4-md5", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr",
"aes-192-ctr", "aes-256-ctr", "bf-cfb", "camellia-128-cfb",
"camellia-192-cfb", "camellia-256-cfb", "salsa20", "chacha20",
"chacha20-ietf", -- aead
"aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305",
"xchacha20-ietf-poly1305"
}
-- [[ Shadowsocks ]]
s.fields["type"]:value(type_name, translate("Shadowsocks"))
o = s:option(Flag, _n("custom"), translate("Use Custom Config"))
o = s:option(Value, _n("port"), translate("Listen Port"))
o.datatype = "port"
o:depends({ [_n("custom")] = false })
o = s:option(Value, _n("password"), translate("Password"))
o.password = true
o:depends({ [_n("custom")] = false })
o = s:option(ListValue, _n("method"), translate("Encrypt Method"))
for a, t in ipairs(ss_encrypt_method_list) do o:value(t) end
o:depends({ [_n("custom")] = false })
o = s:option(Value, _n("timeout"), translate("Connection Timeout"))
o.datatype = "uinteger"
o.default = 300
o:depends({ [_n("custom")] = false })
o = s:option(Flag, _n("tcp_fast_open"), "TCP " .. translate("Fast Open"))
o.default = "0"
o:depends({ [_n("custom")] = false })
o = s:option(TextValue, _n("custom_config"), translate("Custom Config"))
o.rows = 10
o.wrap = "off"
o:depends({ [_n("custom")] = true })
o.validate = function(self, value, t)
if value and api.jsonc.parse(value) then
return value
else
return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!")
end
end
o.custom_cfgvalue = function(self, section, value)
local config_str = m:get(section, "config_str")
if config_str then
return api.base64Decode(config_str)
end
end
o.custom_write = function(self, section, value)
m:set(section, "config_str", api.base64Encode(value) or "")
end
o = s:option(Flag, _n("log"), translate("Log"))
o.default = "1"
o.rmempty = false
api.luci_types(arg[1], m, s, type_name, option_prefix)

View File

@ -1,13 +1,19 @@
local m, s = ...
local api = require "luci.passwall2.api"
if not api.is_finded("ssr-server") then
return
end
local type_name = "SSR"
-- [[ ShadowsocksR ]]
s.fields["type"]:value(type_name, translate("ShadowsocksR"))
if s.val["type"] and s.val["type"] ~= type_name then
return
end
local option_prefix = "ssr_"
local function _n(name)
@ -33,10 +39,6 @@ local ssr_obfs_list = {
"tls1.0_session_auth", "tls1.2_ticket_auth"
}
-- [[ ShadowsocksR ]]
s.fields["type"]:value(type_name, translate("ShadowsocksR"))
o = s:option(Flag, _n("custom"), translate("Use Custom Config"))
o = s:option(Value, _n("port"), translate("Listen Port"))

View File

@ -1,7 +1,6 @@
local api = require "luci.passwall2.api"
local appname = api.appname
local fs = api.fs
local types_dir = "/usr/lib/lua/luci/model/cbi/" .. appname .. "/server/type/"
api = require "luci.passwall2.api"
appname = api.appname
fs = api.fs
m = Map("passwall2_server", translate("Server Config"))
m.redirect = api.url("server")
@ -11,12 +10,21 @@ if not arg[1] or not m:get(arg[1]) then
luci.http.redirect(m.redirect)
end
local header = Template(appname .. "/server/config_header")
header.api = api
header.config = m.config
header.section = arg[1]
m:append(header)
m:append(Template(appname .. "/cbi/nodes_listvalue_com"))
s = m:section(NamedSection, arg[1], "user", "")
s.addremove = false
s.dynamic = false
local types_dir = "/usr/lib/lua/luci/model/cbi/" .. appname .. "/server/type/"
s.val = m:get(arg[1]) or {}
o = s:option(Flag, "enable", translate("Enable"))
o.default = "1"
o.rmempty = false
@ -32,8 +40,6 @@ for filename in fs.dir(types_dir) do
table.insert(type_table, filename)
end
table.sort(type_table, function(a, b)
if a == "socks.lua" then return true end
if b == "socks.lua" then return false end
return a < b
end)
@ -42,4 +48,10 @@ for index, value in ipairs(type_table) do
setfenv(p_func, getfenv(1))(m, s)
end
local footer = Template(appname .. "/server/config_footer")
footer.api = api
footer.config = m.config
footer.section = arg[1]
m:append(footer)
return m

View File

@ -1367,6 +1367,11 @@ function set_apply_on_parse(map)
end
function luci_types(id, m, s, type_name, option_prefix)
local fv_type
local field_type = s.fields["type"]
if field_type then
fv_type = field_type:formvalue(id)
end
local rewrite_option_table = {}
for key, value in pairs(s.fields) do
if key:find(option_prefix) == 1 then
@ -1435,6 +1440,10 @@ function luci_types(id, m, s, type_name, option_prefix)
else
s.fields[key]:depends({ type = type_name })
end
if fv_type and fv_type ~= type_name then
s.fields[key].rmempty = true
end
end
end
end
@ -1623,3 +1632,83 @@ function parse_realm_uri(uri)
end
return realm
end
function get_network_devices()
local _sysnet = "/sys/class/net/"
-- Map UCI interface names to their device names and vice versa
local _iface_to_dev = {}
local _dev_to_ifaces = {}
local _iface_proto = {}
uci:foreach("network", "interface", function(sec)
local name = sec[".name"]
if name ~= "loopback" then
_iface_proto[name] = sec.proto
if sec.device then
_iface_to_dev[name] = sec.device
_dev_to_ifaces[sec.device] = _dev_to_ifaces[sec.device] or {}
table.insert(_dev_to_ifaces[sec.device], name)
end
end
end)
-- Classify device type using sysfs attributes
local function classify_sysfs(dev)
if fs.stat(_sysnet .. dev .. "/bridge", "type") == "dir" then
return i18n.translate("Bridge")
elseif fs.stat(_sysnet .. dev .. "/wireless", "type") == "dir" then
return i18n.translate("Wireless Adapter")
elseif dev:match("^tun") or dev:match("^tap") or dev:match("^wg") or dev:match("^ppp") then
return i18n.translate("Tunnel Interface")
else
return i18n.translate("Ethernet Adapter")
end
end
-- Classify offline UCI interfaces by config hints
local function classify_uci(dev_name, proto)
if dev_name and dev_name:match("^br%-") then
return i18n.translate("Bridge")
elseif proto == "wireguard" or proto == "pppoe" or proto == "pptp" or proto == "l2tp" then
return i18n.translate("Tunnel Interface")
else
return i18n.translate("Interface")
end
end
local _seen = {}
local _devices = {}
-- Active kernel devices from /sys/class/net/
-- Skip bridge member ports (/master) and DSA master devices (/dsa)
local _iter = fs.dir(_sysnet)
if _iter then
for dev in _iter do
if dev ~= "lo"
and not dev:match("^veth")
and not dev:match("^ifb")
and not dev:match("^gre")
and not dev:match("^sit")
and not dev:match("^ip6tnl")
and not dev:match("^erspan")
and not fs.stat(_sysnet .. dev .. "/master", "type")
and not fs.stat(_sysnet .. dev .. "/dsa", "type")
then
local dtype = classify_sysfs(dev)
local label = dtype .. ': "' .. dev .. '"'
if _dev_to_ifaces[dev] then
label = label .. " (" .. table.concat(_dev_to_ifaces[dev], ", ") .. ")"
end
_devices[#_devices + 1] = { name = dev, label = label, sort = dtype .. ":" .. dev }
_seen[dev] = true
end
end
end
-- UCI interfaces whose device does not currently exist
for iface, dev in pairs(_iface_to_dev) do
if not _seen[dev] then
local dtype = classify_uci(dev, _iface_proto[iface])
local label = dtype .. ': "' .. iface .. '"'
_devices[#_devices + 1] = { name = iface, label = label, sort = "zzz:" .. iface }
_seen[dev] = true
end
end
table.sort(_devices, function(a, b) return a.sort < b.sort end)
return _devices
end

View File

@ -120,7 +120,7 @@ local function start()
local config_file = CONFIG_PATH .. "/" .. id .. ".json"
local udp_forward = 1
local type = user.type or ""
if type == "SS" or type == "SSR" then
if type == "SSR" then
if user.custom == "1" and user.config_str then
config = jsonc.parse(api.base64Decode(user.config_str))
else

View File

@ -75,11 +75,7 @@ function gen_config(var)
reuse_port = true
}
if node.type == "SS" then
config.plugin = plugin_file or nil
config.plugin_opts = (plugin_file) and node.plugin_opts or nil
config.mode = mode
elseif node.type == "SSR" then
if node.type == "SSR" then
config.protocol = node.protocol
config.protocol_param = node.protocol_param
config.obfs = node.obfs

View File

@ -1,68 +0,0 @@
module("luci.passwall2.util_tuic", package.seeall)
local api = require "luci.passwall2.api"
local uci = api.uci
local jsonc = api.jsonc
function gen_config(var)
local node_id = var["node"]
if not node_id then
print("node Cannot be empty!")
return
end
local node = uci:get_all("passwall2", node_id)
local local_addr = var["local_addr"]
local local_port = var["local_port"]
local server_host = var["server_host"] or (node.address or ""):lower()
local server_port = var["server_port"] or node.port
local loglevel = var["loglevel"] or "warn"
local tuic= {
relay = {
server = server_host .. ":" .. server_port,
ip = node.tuic_ip,
uuid = node.uuid,
password = node.tuic_password,
-- certificates = node.tuic_certificate and { node.tuic_certpath } or nil,
udp_relay_mode = node.tuic_udp_relay_mode,
congestion_control = node.tuic_congestion_control,
heartbeat = (tonumber(node.tuic_heartbeat) or 3) .. "s",
timeout = (tonumber(node.tuic_timeout) or 8) .. "s",
gc_interval = (tonumber(node.tuic_gc_interval) or 3) .. "s",
gc_lifetime = (tonumber(node.tuic_gc_lifetime) or 15) .. "s",
alpn = (node.tuic_tls_alpn and node.tuic_tls_alpn ~= "") and (function()
local alpn = {}
string.gsub(node.tuic_tls_alpn, '[^,]+', function(w)
table.insert(alpn, w)
end)
if #alpn > 0 then return alpn end
return nil
end)() or nil,
disable_sni = (node.tuic_disable_sni == "1"),
zero_rtt_handshake = (node.tuic_zero_rtt_handshake == "1"),
send_window = tonumber(node.tuic_send_window),
receive_window = tonumber(node.tuic_receive_window)
},
["local"] = {
server = "[::]:" .. local_port,
username = node.tuic_socks_username,
password = node.tuic_socks_password,
dual_stack = (node.tuic_dual_stack == "1") and true or false,
max_packet_size = tonumber(node.tuic_max_package_size)
},
log_level = loglevel
}
return jsonc.stringify(tuic, 1)
end
_G.gen_config = gen_config
if arg[1] then
local func =_G[arg[1]]
if func then
local var = nil
if arg[2] then
var = jsonc.parse(arg[2])
end
print(func(var))
end
end

View File

@ -1219,6 +1219,11 @@ function gen_config(var)
end
end
end
if node.chain_proxy == "3" and node.outbound_iface then
if outbound.streamSettings and outbound.streamSettings.sockopt then
outbound.streamSettings.sockopt.interface = node.outbound_iface
end
end
return default_outTag, last_insert_outbound
end

View File

@ -4,7 +4,7 @@ local api = self.api
<script type="text/javascript">
//<![CDATA[
document.addEventListener("DOMContentLoaded", function () {
waitForElement('select[name*="<%=api.appname%>"][name*="type"]', function(el) {
waitForElement('select[name*="<%=self.config%>"][name*="type"]', function(el) {
let o_val = el.value;
el.addEventListener("change", () => {
el.blur();
@ -22,7 +22,7 @@ local api = self.api
}
});
});
waitForElement('select[name*="<%=api.appname%>"][name*="protocol"]', function(el) {
waitForElement('select[name*="<%=self.config%>"][name*="protocol"]', function(el) {
let o_val = el.value;
el.addEventListener("change", () => {
el.blur();

View File

@ -21,7 +21,7 @@ local api = self.api
function getOption(opt) {
var obj;
var id = 'cbid.<%=api.appname%>.' + node_id + '.' + opt;
var id = 'cbid.<%=self.config%>.' + node_id + '.' + opt;
obj = document.getElementsByName(id)[0] || document.getElementById(id);
if (obj) {
var combobox = document.getElementById('cbi.combobox.' + id);

View File

@ -4,13 +4,12 @@ local api = require "luci.passwall2.api"
local appname = api.appname
local map = self.map
local has_ss = api.is_finded("ss-redir")
local has_ss_rust = api.is_finded("sslocal")
local has_singbox = api.finded_com("sing-box")
local has_xray = api.finded_com("xray")
local has_hysteria2 = api.finded_com("hysteria")
local ss_type = api.get_core("ss_type", {{has_ss,"shadowsocks-libev"},{has_ss_rust,"shadowsocks-rust"},{has_singbox,"sing-box"},{has_xray,"xray"}})
local ss_type = api.get_core("ss_type", {{has_ss_rust,"shadowsocks-rust"},{has_singbox,"sing-box"},{has_xray,"xray"}})
local trojan_type = api.get_core("trojan_type", {{has_singbox,"sing-box"},{has_xray,"xray"}})
local vmess_type = api.get_core("vmess_type", {{has_xray,"xray"},{has_singbox,"sing-box"}})
local vless_type = api.get_core("vless_type", {{has_xray,"xray"},{has_singbox,"sing-box"}})
@ -165,10 +164,7 @@ local current_node = map:get(section)
var dom_prefix = null
var protocol = ""
if (v_type === "SS") {
dom_prefix = "ss_"
protocol = "ss"
} else if (v_type === "SS-Rust") {
if (v_type === "SS-Rust") {
dom_prefix = "ssrust_"
protocol = "ss"
} else if (v_type === "SSR") {
@ -196,7 +192,7 @@ local current_node = map:get(section)
}
}
var url = null;
if (v_type === "SS" || v_type === "SS-Rust" || ((v_type === "sing-box" || v_type === "Xray") && opt.get(dom_prefix + "protocol").value === "shadowsocks")) {
if (v_type === "SS-Rust" || ((v_type === "sing-box" || v_type === "Xray") && opt.get(dom_prefix + "protocol").value === "shadowsocks")) {
protocol = "ss"
var v_port = opt.get(dom_prefix + "port");
var v_method = opt.get(dom_prefix + "method") || opt.get(dom_prefix + "ss_method");
@ -1003,14 +999,6 @@ local current_node = map:get(section)
} else if (ss_type == "shadowsocks-rust") {
dom_prefix = "ssrust_"
opt.set('type', "SS-Rust");
} else {
if (["2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"].includes(method)) {
dom_prefix = "ssrust_"
opt.set('type', "SS-Rust");
} else {
dom_prefix = "ss_"
opt.set('type', "SS");
}
}
const _method = (method || "none").toLowerCase();

View File

@ -0,0 +1,27 @@
<%
local api = self.api
-%>
<script type="text/javascript">
//<![CDATA[
document.addEventListener("DOMContentLoaded", function () {
waitForElement('select[name*="<%=self.config%>"][name*="type"]', function(el) {
let o_val = el.value;
el.addEventListener("change", () => {
el.blur();
if (o_val != el.value) {
let save = true;
if (save) {
//document.getElementsByClassName('cbi-button-save')[0].click();
update_node({
enable: getOption("enable").value,
remarks: getOption("remarks").value,
type: getOption("type").value,
protocol: ''
});
}
}
});
});
});
//]]>
</script>

View File

@ -0,0 +1,56 @@
<%
local api = self.api
-%>
<script type="text/javascript">
//<![CDATA[
let node_id = "<%=self.section%>";
let node_config_url = '<%=api.url("server_user")%>/' + node_id;
function waitForElement(selector, callback) {
const el = document.querySelector(selector);
if (el) return callback(el);
const observer = new MutationObserver(() => {
const el = document.querySelector(selector);
if (el) {
observer.disconnect();
callback(el);
}
});
observer.observe(document.body, { childList: true, subtree: true });
}
function getOption(opt) {
var obj;
var id = 'cbid.<%=self.config%>.' + node_id + '.' + opt;
obj = document.getElementsByName(id)[0] || document.getElementById(id);
if (obj) {
var combobox = document.getElementById('cbi.combobox.' + id);
if (combobox) {
obj.combobox = combobox;
}
var div = document.getElementById(id);
if (div && div.getElementsByTagName("li").length > 0) {
obj = div;
}
return obj;
} else {
return null;
}
}
function update_node(data) {
XHR.get('<%=api.url("server_user_update")%>', {
id: node_id,
data: JSON.stringify(data)
},
function(x, data) {
if (x && x.status == 200 && data.code == 1) {
window.location.href = node_config_url;
}
else {
alert("<%:Error%>");
}
});
}
//]]>
</script>

View File

@ -564,9 +564,6 @@ msgstr "اصلی"
msgid "Transport Plugin"
msgstr "افزونه انتقال"
msgid "Shadowsocks secondary encryption"
msgstr "رمزنگاری ثانویه Shadowsocks"
msgid "Obfs Type"
msgstr "نوع مبهم‌سازی (Obfs)"
@ -1365,18 +1362,6 @@ msgstr "زمانی استفاده می‌شود که لینک گره شامل ا
msgid "%s Node Use Type"
msgstr "نوع استفاده گره %s"
msgid "Set the TUIC proxy server ip address"
msgstr "تنظیم آدرس IP سرور پروکسی TUIC"
msgid "TUIC User Password For Connect Remote Server"
msgstr "رمز عبور کاربر TUIC برای اتصال به سرور راه دور"
msgid "TUIC UserName For Local Socks"
msgstr "نام کاربری TUIC برای Socks محلی"
msgid "TUIC Password For Local Socks"
msgstr "رمز عبور TUIC برای Socks محلی"
msgid "UDP relay mode"
msgstr "حالت بازپخش UDP"
@ -1389,33 +1374,12 @@ msgstr "الگوریتم کنترل ازدحام"
msgid "Heartbeat interval(second)"
msgstr "بازه ضربان قلب (ثانیه)"
msgid "Timeout for establishing a connection to server(second)"
msgstr "مهلت زمانی برای برقراری اتصال به سرور (ثانیه)"
msgid "Garbage collection interval(second)"
msgstr "بازه جمع‌آوری زباله (ثانیه)"
msgid "Garbage collection lifetime(second)"
msgstr "طول عمر جمع‌آوری زباله (ثانیه)"
msgid "Disable SNI"
msgstr "غیرفعال کردن SNI"
msgid "Enable 0-RTT QUIC handshake"
msgstr "فعال‌سازی دست تکان دادن 0-RTT QUIC"
msgid "TUIC send window"
msgstr "پنجره ارسال TUIC"
msgid "TUIC receive window"
msgstr "پنجره دریافت TUIC"
msgid "TUIC Maximum packet size the socks5 server can receive from external, in bytes"
msgstr "حداکثر اندازه بسته TUIC که سرور socks5 می‌تواند از خارج دریافت کند، به بایت"
msgid "Set if the listening socket should be dual-stack"
msgstr "تنظیم کنید که سوکت شنونده دو پشته‌ای (dual-stack) باشد یا خیر"
msgid "<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)<br />dns: Disguising traffic as DNS requests."
msgstr "<br />none: پیش‌فرض، بدون استتار، داده‌های ارسالی بسته‌های بدون مشخصه هستند.<br />srtp: مبدل شده به بسته SRTP، به عنوان داده تماس تصویری (مانند FaceTime) شناخته می‌شود.<br />utp: بسته‌های مبدل شده به uTP به عنوان داده دانلود شده bittorrent شناخته می‌شوند.<br />wechat-video: بسته‌های مبدل شده به تماس‌های تصویری WeChat.<br />dtls: مبدل شده به بسته DTLS 1.2.<br />wireguard: مبدل شده به بسته WireGuard. (نه واقعاً پروتکل WireGuard)<br />dns: پنهان کردن ترافیک به عنوان درخواست‌های DNS."
@ -2323,9 +2287,6 @@ msgstr "Xray از افزونه %s پشتیبانی نمی‌کند."
msgid "Plugin options Incomplete."
msgstr "گزینه‌های افزونه ناقص است."
msgid "shadowsocks-libev unsupport 2022 encryption."
msgstr "shadowsocks-libev از رمزنگاری 2022 پشتیبانی نمی‌کند."
msgid "Please replace %s to support %s transmission method."
msgstr "لطفا برای پشتیبانی از روش انتقال %s، %s را جایگزین کنید."

View File

@ -559,9 +559,6 @@ msgstr "Оригинал"
msgid "Transport Plugin"
msgstr "Плагин транспорта"
msgid "Shadowsocks secondary encryption"
msgstr "Дополнительное шифрование Shadowsocks"
msgid "global_padding"
msgstr "Включить padding-заполнение"
@ -1366,18 +1363,6 @@ msgstr "Используется, если в ссылке на узел это
msgid "%s Node Use Type"
msgstr "Тип использования сервера %s"
msgid "Set the TUIC proxy server ip address"
msgstr "Указать IP-адрес сервера TUIC"
msgid "TUIC User Password For Connect Remote Server"
msgstr "Пароль для подключения к удалённому серверу TUIC"
msgid "TUIC UserName For Local Socks"
msgstr "Имя пользователя для локального SOCKS TUIC"
msgid "TUIC Password For Local Socks"
msgstr "Пароль для локального SOCKS TUIC"
msgid "UDP relay mode"
msgstr "Режим ретрансляции UDP"
@ -1390,33 +1375,12 @@ msgstr "Алгоритм контроля перегрузок"
msgid "Heartbeat interval(second)"
msgstr "Интервал heartbeat-пакетов (сек)"
msgid "Timeout for establishing a connection to server(second)"
msgstr "Тайм-аут установки соединения с сервером (сек)"
msgid "Garbage collection interval(second)"
msgstr "Интервал очистки фрагментов UDP (сек)"
msgid "Garbage collection lifetime(second)"
msgstr "Время жизни фрагментов UDP на сервере (сек)"
msgid "Disable SNI"
msgstr "Отключить SNI"
msgid "Enable 0-RTT QUIC handshake"
msgstr "Включить 0-RTT рукопожатие QUIC"
msgid "TUIC send window"
msgstr "Окно отправки TUIC (макс. байт без подтверждения: по умолчанию 8 МБ × 2)"
msgid "TUIC receive window"
msgstr "Окно приёма TUIC (макс. байт без подтверждения: по умолчанию 8 МБ)"
msgid "TUIC Maximum packet size the socks5 server can receive from external, in bytes"
msgstr "Макс. размер пакета, который SOCKS5-сервер TUIC может принять извне (в байтах)"
msgid "Set if the listening socket should be dual-stack"
msgstr "Включить поддержку dual-stack для слушающего сокета"
msgid "<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)<br />dns: Disguising traffic as DNS requests."
msgstr "<br />none: по умолчанию, без маскировки, данные отправляются обычными пакетами.<br />srtp: маскировка под SRTP — трафик определяется как видеозвонок (например, FaceTime).<br />utp: маскировка под uTP — трафик определяется как BitTorrent.<br />wechat-video: маскировка под видеозвонок WeChat.<br />dtls: маскировка под DTLS 1.2.<br />wireguard: маскировка под WireGuard (не настоящий протокол WireGuard).<br />dns: маскировка трафика под DNS-запросы."
@ -2321,9 +2285,6 @@ msgstr "Xray не поддерживает плагин %s."
msgid "Plugin options Incomplete."
msgstr "Опции плагина указаны не полностью."
msgid "shadowsocks-libev unsupport 2022 encryption."
msgstr "shadowsocks-libev не поддерживает шифрование 2022."
msgid "Please replace %s to support %s transmission method."
msgstr "Пожалуйста, замените %s, чтобы поддержать метод передачи %s."

View File

@ -556,9 +556,6 @@ msgstr "原版"
msgid "Transport Plugin"
msgstr "传输层插件"
msgid "Shadowsocks secondary encryption"
msgstr "Shadowsocks 二次加密"
msgid "Obfs Type"
msgstr "混淆类型"
@ -1357,18 +1354,6 @@ msgstr "当节点链接未包含该参数时,将使用此设置。"
msgid "%s Node Use Type"
msgstr "%s 节点使用类型"
msgid "Set the TUIC proxy server ip address"
msgstr "指定远程TUIC服务器IP"
msgid "TUIC User Password For Connect Remote Server"
msgstr "用于远程TUIC服务器连接的密码"
msgid "TUIC UserName For Local Socks"
msgstr "用于本地Socks服务器连接的用户名"
msgid "TUIC Password For Local Socks"
msgstr "用于本地Socks服务器连接的密码"
msgid "UDP relay mode"
msgstr "UDP中继模式"
@ -1381,33 +1366,12 @@ msgstr "拥塞控制算法"
msgid "Heartbeat interval(second)"
msgstr "保活心跳包发送间隔(单位:秒)"
msgid "Timeout for establishing a connection to server(second)"
msgstr "连接超时时间(单位:秒)"
msgid "Garbage collection interval(second)"
msgstr "UDP数据包片残片清理间隔单位"
msgid "Garbage collection lifetime(second)"
msgstr "UDP数据包残片在服务器的保留时间单位"
msgid "Disable SNI"
msgstr "关闭SNI服务器名称指示"
msgid "Enable 0-RTT QUIC handshake"
msgstr "客户端启用 0-RTT QUIC 连接握手"
msgid "TUIC send window"
msgstr "发送窗口无需确认即可发送的最大字节数默认8Mb*2"
msgid "TUIC receive window"
msgstr "接收窗口无需确认即可接收的最大字节数默认8Mb"
msgid "TUIC Maximum packet size the socks5 server can receive from external, in bytes"
msgstr "TUIC socks5 服务器可以从外部接收的最大数据包大小(以字节为单位)"
msgid "Set if the listening socket should be dual-stack"
msgstr "设置监听套接字为双栈"
msgid "<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)<br />dns: Disguising traffic as DNS requests."
msgstr "<br />none默认值不进行伪装发送的数据是没有特征的数据包。<br />srtp伪装成 SRTP 数据包,会被识别为视频通话数据(如 FaceTime。<br />utp伪装成 uTP 数据包,会被识别为 BT 下载数据。<br />wechat-video伪装成微信视频通话的数据包。<br />dtls伪装成 DTLS 1.2 数据包。<br />wireguard伪装成 WireGuard 数据包。(并不是真正的 WireGuard 协议)<br />dns把流量伪装成 DNS 请求。"
@ -2309,9 +2273,6 @@ msgstr "Xray 不支持 %s 插件。"
msgid "Plugin options Incomplete."
msgstr "插件选项不完整。"
msgid "shadowsocks-libev unsupport 2022 encryption."
msgstr "shadowsocks-libev 不支持2022加密。"
msgid "Please replace %s to support %s transmission method."
msgstr "请更换 %s 以支持 %s 传输方式。"

View File

@ -556,9 +556,6 @@ msgstr "原版"
msgid "Transport Plugin"
msgstr "傳輸層插件"
msgid "Shadowsocks secondary encryption"
msgstr "Shadowsocks 二次加密"
msgid "Obfs Type"
msgstr "混淆類型"
@ -1357,18 +1354,6 @@ msgstr "當節點連結未包含該參數時,將使用此設定。"
msgid "%s Node Use Type"
msgstr "%s 節點使用類型"
msgid "Set the TUIC proxy server ip address"
msgstr "指定遠程TUIC服務器IP"
msgid "TUIC User Password For Connect Remote Server"
msgstr "用於遠程TUIC服務器連接的密碼"
msgid "TUIC UserName For Local Socks"
msgstr "用於本地Socks服務器連接的用戶名"
msgid "TUIC Password For Local Socks"
msgstr "用於本地Socks服務器連接的密碼"
msgid "UDP relay mode"
msgstr "UDP中继模式"
@ -1381,33 +1366,12 @@ msgstr "拥塞控制算法"
msgid "Heartbeat interval(second)"
msgstr "保活心跳包發送間隔(單位:秒)"
msgid "Timeout for establishing a connection to server(second)"
msgstr "連接超時時間(單位:秒)"
msgid "Garbage collection interval(second)"
msgstr "UDP數据包片残片清理間隔單位"
msgid "Garbage collection lifetime(second)"
msgstr "UDP數据包残片在服務器的保留時間單位"
msgid "Disable SNI"
msgstr "關閉SNI服務器名称指示"
msgid "Enable 0-RTT QUIC handshake"
msgstr "客戶端啟用 0-RTT QUIC 連接握手"
msgid "TUIC send window"
msgstr "發送窗口無需確認即可發送的最大字节數默認8Mb*2"
msgid "TUIC receive window"
msgstr "接收窗口無需確認即可接收的最大字节數默認8Mb"
msgid "TUIC Maximum packet size the socks5 server can receive from external, in bytes"
msgstr "TUIC socks5 服務器可以从外部接收的最大數据包大小(以字节為單位)"
msgid "Set if the listening socket should be dual-stack"
msgstr "設置監聽套接字為双栈"
msgid "<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)<br />dns: Disguising traffic as DNS requests."
msgstr "<br />none默認值不进行伪装發送的數据是沒有特征的數据包。<br />srtp伪装成 SRTP 數据包,会被识别為視频通话數据(如 FaceTime。<br />utp伪装成 uTP 數据包,会被识别為 BT 下載數据。<br />wechat-video伪装成微信視频通话的數据包。<br />dtls伪装成 DTLS 1.2 數据包。<br />wireguard伪装成 WireGuard 數据包。(並不是真正的 WireGuard 協議)<br />dns把流量伪装成 DNS 請求。"
@ -2315,9 +2279,6 @@ msgstr "Xray 不支持 %s 插件。"
msgid "Plugin options Incomplete."
msgstr "插件選項不完整。"
msgid "shadowsocks-libev unsupport 2022 encryption."
msgstr "shadowsocks-libev 不支持2022加密。"
msgid "Please replace %s to support %s transmission method."
msgstr "請更換 %s 以支援 %s 傳輸方式。"

View File

@ -14,7 +14,6 @@ UTIL_SS=$LUA_UTIL_PATH/util_shadowsocks.lua
UTIL_XRAY=$LUA_UTIL_PATH/util_xray.lua
UTIL_NAIVE=$LUA_UTIL_PATH/util_naiveproxy.lua
UTIL_HYSTERIA2=$LUA_UTIL_PATH/util_hysteria2.lua
UTIL_TUIC=$LUA_UTIL_PATH/util_tuic.lua
SINGBOX_BIN=$(first_type $(config_t_get global_app sing_box_file) sing-box)
XRAY_BIN=$(first_type $(config_t_get global_app xray_file) xray)
@ -467,18 +466,6 @@ run_socks() {
lua $UTIL_SS gen_config "${_json_arg}" > $config_file
[ -z "$no_run" ] && ln_run ${QUEUE_RUN} "$(first_type ssr-local)" "ssr-local" $log_file -c "$config_file" -v -u
;;
ss)
json_add_string "local_addr" "${bind}"
json_add_string "local_port" "${socks_port}"
json_add_string "mode" "tcp_and_udp"
[ -z "$no_run" ] && {
local plugin_sh="${config_file%.json}_plugin.sh"
json_add_string "plugin_sh" "${plugin_sh}"
}
local _json_arg="$(json_dump)"
lua $UTIL_SS gen_config "${_json_arg}" > $config_file
[ -z "$no_run" ] && ln_run ${QUEUE_RUN} "$(first_type ss-local)" "ss-local" $log_file -c "$config_file" -v
;;
ss-rust)
json_add_string "local_socks_address" "${bind}"
json_add_string "local_socks_port" "${socks_port}"
@ -509,13 +496,6 @@ run_socks() {
lua $UTIL_HYSTERIA2 gen_config "${_json_arg}" > $config_file
[ -z "$no_run" ] && ln_run ${QUEUE_RUN} "$(first_type $(config_t_get global_app hysteria_file))" "hysteria" $log_file -c "$config_file" client
;;
tuic)
json_add_string "local_addr" "${bind}"
json_add_string "local_port" "${socks_port}"
local _json_arg="$(json_dump)"
lua $UTIL_TUIC gen_config "${_json_arg}" > $config_file
[ -z "$no_run" ] && ln_run ${QUEUE_RUN} "$(first_type tuic-client)" "tuic-client" $log_file -c "$config_file"
;;
esac
# http to socks

View File

@ -25,7 +25,6 @@ local log = api.log
local i18n = api.i18n
local lyaml = require "lyaml"
local has_ss = api.is_finded("ss-redir")
local has_ss_rust = api.is_finded("sslocal")
local has_ssr = api.is_finded("ssr-local") and api.is_finded("ssr-redir")
local has_singbox = api.finded_com("sing-box")
@ -36,7 +35,7 @@ local DEFAULT_FILTER_KEYWORD_MODE = uci:get(appname, "@global_subscribe[0]", "fi
local DEFAULT_FILTER_KEYWORD_DISCARD_LIST = uci:get(appname, "@global_subscribe[0]", "filter_discard_list") or {}
local DEFAULT_FILTER_KEYWORD_KEEP_LIST = uci:get(appname, "@global_subscribe[0]", "filter_keep_list") or {}
-- Nodes should be retrieved using the core type (if not set on the node subscription page, the default type will be used automatically).
local DEFAULT_SS_TYPE = api.get_core("ss_type", {{has_ss,"shadowsocks-libev"},{has_ss_rust,"shadowsocks-rust"},{has_singbox,"sing-box"},{has_xray,"xray"}})
local DEFAULT_SS_TYPE = api.get_core("ss_type", {{has_ss_rust,"shadowsocks-rust"},{has_singbox,"sing-box"},{has_xray,"xray"}})
local DEFAULT_TROJAN_TYPE = api.get_core("trojan_type", {{has_singbox,"sing-box"},{has_xray,"xray"}})
local DEFAULT_VMESS_TYPE = api.get_core("vmess_type", {{has_xray,"xray"},{has_singbox,"sing-box"}})
local DEFAULT_VLESS_TYPE = api.get_core("vless_type", {{has_xray,"xray"},{has_singbox,"sing-box"}})
@ -44,7 +43,6 @@ local DEFAULT_HYSTERIA2_TYPE = api.get_core("hysteria2_type", {{has_hysteria2,"h
local core_has = {
["xray"] = has_xray,
["sing-box"] = has_singbox,
["shadowsocks-libev"] = has_ss,
["shadowsocks-rust"] = has_ss_rust,
["hysteria2"] = has_hysteria2
}
@ -460,9 +458,7 @@ end
-- Configure the SS protocol implementation type
local function set_ss_implementation(ss_type, result)
if ss_type == "shadowsocks-libev" and has_ss then
result.type = "SS"
elseif ss_type == "shadowsocks-rust" and has_ss_rust then
if ss_type == "shadowsocks-rust" and has_ss_rust then
result.type = 'SS-Rust'
elseif ss_type == "xray" and has_xray then
result.type = 'Xray'
@ -485,6 +481,7 @@ local function parseClashNode(node, add_mode, group, sub_cfg)
local sub_vmess_type = DEFAULT_VMESS_TYPE
local sub_vless_type = DEFAULT_VLESS_TYPE
local sub_hysteria2_type = DEFAULT_HYSTERIA2_TYPE
local sub_hy_up_mbps, sub_hy_down_mbps = 1000, 1000
if sub_cfg then
if sub_cfg.allowInsecure and sub_cfg.allowInsecure ~= "1" then
sub_allowinsecure = nil
@ -509,6 +506,8 @@ local function parseClashNode(node, add_mode, group, sub_cfg)
if hysteria2_type ~= "global" and core_has[hysteria2_type] then
sub_hysteria2_type = hysteria2_type
end
sub_hy_up_mbps = sub_cfg.hysteria_up_mbps
sub_hy_down_mbps = sub_cfg.hysteria_down_mbps
end
local result = {
timeout = 60,
@ -778,6 +777,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
local sub_vmess_type = DEFAULT_VMESS_TYPE
local sub_vless_type = DEFAULT_VLESS_TYPE
local sub_hysteria2_type = DEFAULT_HYSTERIA2_TYPE
local sub_hy_up_mbps, sub_hy_down_mbps = 1000, 1000
if sub_cfg then
if sub_cfg.allowInsecure and sub_cfg.allowInsecure ~= "1" then
sub_allowinsecure = nil
@ -802,6 +802,8 @@ local function processData(szType, content, add_mode, group, sub_cfg)
if hysteria2_type ~= "global" and core_has[hysteria2_type] then
sub_hysteria2_type = hysteria2_type
end
sub_hy_up_mbps = sub_cfg.hysteria_up_mbps
sub_hy_down_mbps = sub_cfg.hysteria_down_mbps
end
local result = {
timeout = 60,
@ -1113,20 +1115,6 @@ local function processData(szType, content, add_mode, group, sub_cfg)
end
end
if result.type == "SS" then
local aead2022_methods = { "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" }
local aead2022 = false
for k, v in ipairs(aead2022_methods) do
if method:lower() == v:lower() then
aead2022 = true
end
end
if aead2022 then
-- shadowsocks-libev does not support 2022 encryption.
result.error_msg = i18n.translatef("shadowsocks-libev unsupport 2022 encryption.")
end
end
if params.type then
params.type = string.lower(params.type)
if result.type == "sing-box" and params.type == "raw" then
@ -1140,7 +1128,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
else
result.transport = params.type
end
if result.type ~= "SS-Rust" and result.type ~= "SS" then
if result.type ~= "SS-Rust" then
if params.type == 'ws' then
result.ws_host = params.host
result.ws_path = params.path
@ -1647,8 +1635,8 @@ local function processData(szType, content, add_mode, group, sub_cfg)
local insecure = params.allowinsecure or params.allowInsecure or params.insecure
result.tls_allowInsecure = (insecure == "1" or insecure == "0") and insecure or (sub_allowinsecure and "1" or "0")
result.alpn = params.alpn
result.hysteria_up_mbps = params.upmbps
result.hysteria_down_mbps = params.downmbps
result.hysteria_up_mbps = params.upmbps or sub_hy_up_mbps
result.hysteria_down_mbps = params.downmbps or sub_hy_down_mbps
result.hysteria_hop = params.mport
elseif szType == 'hysteria2' or szType == 'hy2' then
@ -1692,6 +1680,8 @@ local function processData(szType, content, add_mode, group, sub_cfg)
result.tls_CertByName = params.vcn
local insecure = params.allowinsecure or params.insecure
result.tls_allowInsecure = (insecure == "1" or insecure == "0") and insecure or (sub_allowinsecure and "1" or "0")
result.hysteria2_up_mbps = params.upmbps or sub_hy_up_mbps
result.hysteria2_down_mbps = params.downmbps or sub_hy_down_mbps
result.hysteria2_hop = params.mport
if params["obfs-password"] or params["obfs_password"] then
result.hysteria2_obfs_type = "salamander"
@ -2180,7 +2170,7 @@ local function update_node(manual)
local list = v["list"]
local sub_cfg = v["sub_cfg"]
local domain_resolver, domain_resolver_dns, domain_resolver_dns_https, domain_strategy
local preproxy_node_group, to_node_group, chain_node_type = "", "", ""
local preproxy_node_group, to_node_group, outbound_iface_group, chain_node_type = "", "", "", ""
-- Subscription Group Chain Agent
local function valid_chain_node(node)
if not node then return "" end
@ -2200,6 +2190,8 @@ local function update_node(manual)
domain_strategy = (sub_cfg.domain_strategy == "UseIPv4" or sub_cfg.domain_strategy == "UseIPv6") and sub_cfg.domain_strategy or nil
preproxy_node_group = (sub_cfg.chain_proxy == "1") and valid_chain_node(sub_cfg.preproxy_node) or ""
to_node_group = (sub_cfg.chain_proxy == "2") and valid_chain_node(sub_cfg.to_node) or ""
outbound_iface_group = (sub_cfg.chain_proxy == "3") and sub_cfg.outbound_iface or ""
chain_node_type = (outbound_iface_group ~= "") and "iface" or chain_node_type
end
for _, vv in ipairs(list) do
local cfgid = uci:section(appname, "nodes", api.gen_short_uuid())
@ -2235,6 +2227,9 @@ local function update_node(manual)
elseif to_node_group ~= "" then
uci:set(appname, cfgid, "chain_proxy", "2")
uci:set(appname, cfgid, "to_node", to_node_group)
elseif outbound_iface_group ~= "" then
uci:set(appname, cfgid, "chain_proxy", "3")
uci:set(appname, cfgid, "outbound_iface", outbound_iface_group)
end
end
end