update 2023-04-17 16:22:41

This commit is contained in:
github-actions[bot] 2023-04-17 16:22:41 +08:00
parent 5d391750c0
commit f0545348c0
56 changed files with 1575 additions and 432 deletions

View File

@ -9,7 +9,7 @@ LUCI_TITLE:=LuCI support for quickstart
LUCI_DEPENDS:=+quickstart +luci-app-store
LUCI_PKGARCH:=all
PKG_VERSION:=0.7.4-1
PKG_VERSION:=0.7.4-2
# PKG_RELEASE MUST be empty for luci.mk
PKG_RELEASE:=

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -4,7 +4,7 @@ include $(TOPDIR)/rules.mk
LUCI_TITLE:=LuCI for UniShare
LUCI_PKGARCH:=all
LUCI_DEPENDS:=+unishare
PKG_VERSION:=1.0.0-3
PKG_VERSION:=1.0.0-4
PKG_RELEASE:=
PKG_MAINTAINER:=jjm2473 <jjm2473@gmail.com>

View File

@ -10,7 +10,9 @@ s.addremove = false
o = s:taboption("general", Flag, "enabled", translate("Enabled"))
o.default = 0
o = s:taboption("general", Flag, "anonymous", translate("Allow Anonymous"))
o = s:taboption("general", Flag, "anonymous", translate("Allow Anonymous"),
translatef("For logged in users, please manage on the '%s' page",
"<a href=\""..luci.dispatcher.build_url("admin", "nas", "unishare", "users").."\" >"..translate("Users").."</a>"))
o.default = 0
o = s:taboption("webdav", Value, "webdav_port", translate("WebDAV Port"))

View File

@ -16,7 +16,8 @@ s = m:section(NamedSection, arg[1], "share", "")
s.addremove = false
s.dynamic = false
path = s:option(Value, "path", translate("Path"))
path = s:option(Value, "path", translate("Path"),
translate("Note: '/mnt' is not suitable as a writable share, because Windows will recognize the wrong capacity"))
path.datatype = "string"
path.rmempty = false
path.validate = function(self, value, section)

View File

@ -6,7 +6,8 @@ s.anonymous = true
s.addremove = true
s.template = "cbi/tblsection"
o = s:option(Value, "username", translate("Username"))
o = s:option(Value, "username", translate("Username"),
translate("Note: Do not use the 'root' user, as Samba forbids 'root' user login by default"))
o.datatype = "string"
o.rmempty = false
o.validate = function(self, value)

View File

@ -13,6 +13,9 @@ msgstr "全局"
msgid "Allow Anonymous"
msgstr "允许匿名用户"
msgid "For logged in users, please manage on the '%s' page"
msgstr "对于登录用户,请在 '%s' 页面进行管理"
msgid "WebDAV Port"
msgstr "WebDAV 端口"
@ -43,6 +46,9 @@ msgstr "登录用户"
msgid "'Everyone' includes anonymous if enabled, 'Logged Users' includes all users configured in '%s' tab"
msgstr "'任何人'包括所有登录用户和匿名用户(如果允许匿名用户),'登录用户'包括所有在'%s'标签页配置的用户"
msgid "Note: '/mnt' is not suitable as a writable share, because Windows will recognize the wrong capacity"
msgstr "注意:'/mnt' 不适合作为可写共享,因为 Windows 会认错容量"
msgid "Name cannot be empty when Path is /"
msgstr "路径是/时,名称不能为空"
@ -54,3 +60,6 @@ msgstr "名称不能包含这些特殊字符'%s'"
msgid "Username must matchs regex '%s'"
msgstr "用户名必须满足正则表达式'%s'"
msgid "Note: Do not use the 'root' user, as Samba forbids 'root' user login by default"
msgstr "注意:不要使用 'root' 用户,因为 Samba 默认禁止 'root' 用户登录"

View File

@ -1,153 +0,0 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-xray
PKG_VERSION:=1.29.0
PKG_RELEASE:=1
PKG_LICENSE:=MPLv2
PKG_LICENSE_FILES:=LICENSE
PKG_MAINTAINER:=yichya <mail@yichya.dev>
PKG_BUILD_PARALLEL:=1
include $(INCLUDE_DIR)/package.mk
define Package/$(PKG_NAME)
SECTION:=Custom
CATEGORY:=Extra packages
TITLE:=LuCI Support for Xray
DEPENDS:=+luci-base +xray-core +dnsmasq +ca-bundle +PACKAGE_firewall4:kmod-nft-tproxy +PACKAGE_firewall:ipset +PACKAGE_firewall:iptables +PACKAGE_firewall:iptables-mod-tproxy
PKGARCH:=all
endef
define Package/$(PKG_NAME)/description
LuCI Support for Xray (Client-side Rendered).
endef
define Package/$(PKG_NAME)/config
menu "luci-app-xray Configuration"
depends on PACKAGE_$(PKG_NAME)
config PACKAGE_XRAY_INCLUDE_CLOUDFLARE_ORIGIN_ROOT_CA
bool "Include Cloudflare Origin Root CA"
default n
config PACKAGE_XRAY_INFINITE_RETRY_ON_STARTUP
bool "Retry infinitely on Xray startup (may solve some startup problems)"
default n
config PACKAGE_XRAY_RLIMIT_NOFILE_LARGE
bool "Increase Max Open Files Limit (recommended)"
default y
config PACKAGE_XRAY_RESTART_DNSMASQ_ON_IFACE_CHANGE
bool "Restart dnsmasq on interface change (select this if using dnsmasq v2.87)"
default n
config PACKAGE_XRAY_IGNORE_TP_SPEC_DEF_GW
bool "Ignore TP_SPEC_DEF_GW (select this if using private IPv4 address)"
default n
choice
prompt "Limit memory use by setting rlimit_data (experimental)"
default PACKAGE_XRAY_RLIMIT_DATA_UNLIMITED
config PACKAGE_XRAY_RLIMIT_DATA_UNLIMITED
bool "Not limited"
config PACKAGE_XRAY_RLIMIT_DATA_SMALL
bool "Small limit (about 50MB)"
config PACKAGE_XRAY_RLIMIT_DATA_LARGE
bool "Large limit (about 321MB)"
endchoice
endmenu
endef
define Build/Compile
endef
define Package/$(PKG_NAME)/postinst
#!/bin/sh
if [[ ! -f $${IPKG_INSTROOT}/usr/share/xray/xray.init.replaced ]]; then
if [[ ! -f $${IPKG_INSTROOT}/etc/init.d/xray ]]; then
echo "echo This file does nothing" > $${IPKG_INSTROOT}/etc/init.d/xray
fi
mv $${IPKG_INSTROOT}/etc/init.d/xray $${IPKG_INSTROOT}/usr/share/xray/xray.init.replaced
mkdir -p $${IPKG_INSTROOT}/etc/config
mv $${IPKG_INSTROOT}/tmp/xray.conf $${IPKG_INSTROOT}/etc/config/xray
fi
rm -f $${IPKG_INSTROOT}/tmp/xray.conf
mkdir -p $${IPKG_INSTROOT}/etc/init.d
mv $${IPKG_INSTROOT}/tmp/xray.init $${IPKG_INSTROOT}/etc/init.d/xray
if [[ -z "$${IPKG_INSTROOT}" ]]; then
if [[ -f /etc/uci-defaults/xray ]]; then
( . /etc/uci-defaults/xray ) && rm -f /etc/uci-defaults/xray
fi
rm -rf /tmp/luci-indexcache* /tmp/luci-modulecache
fi
exit 0
endef
define Package/$(PKG_NAME)/conffiles
/etc/config/xray
endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/tmp
$(INSTALL_BIN) ./root/etc/init.d/xray $(1)/tmp/xray.init
$(INSTALL_DATA) ./root/etc/config/xray $(1)/tmp/xray.conf
$(INSTALL_DIR) $(1)/etc/luci-uploads/xray
$(INSTALL_DIR) $(1)/etc/hotplug.d/iface
$(INSTALL_DIR) $(1)/etc/ssl/certs
ifdef CONFIG_PACKAGE_XRAY_INCLUDE_CLOUDFLARE_ORIGIN_ROOT_CA
$(INSTALL_DATA) ./root/etc/ssl/certs/origin_ca_ecc_root.pem $(1)/etc/ssl/certs/origin_ca_ecc_root.pem
endif
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) ./root/etc/uci-defaults/xray $(1)/etc/uci-defaults/xray
$(INSTALL_DIR) $(1)/www/luci-static/resources/view
$(INSTALL_DATA) ./root/www/luci-static/resources/view/xray.js $(1)/www/luci-static/resources/view/xray.js
$(INSTALL_DIR) $(1)/usr/share/luci/menu.d
$(INSTALL_DATA) ./root/usr/share/luci/menu.d/luci-app-xray.json $(1)/usr/share/luci/menu.d/luci-app-xray.json
$(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d
$(INSTALL_DATA) ./root/usr/share/rpcd/acl.d/luci-app-xray.json $(1)/usr/share/rpcd/acl.d/luci-app-xray.json
$(INSTALL_DIR) $(1)/usr/share/xray
$(LN) /var/run/xray.pid $(1)/usr/share/xray/xray.pid
$(LN) /usr/bin/xray $(1)/usr/share/xray/xray
ifdef CONFIG_PACKAGE_XRAY_IGNORE_TP_SPEC_DEF_GW
$(INSTALL_DATA) ./root/usr/share/xray/ignore_tp_spec_def_gw $(1)/usr/share/xray/ignore_tp_spec_def_gw
endif
ifdef CONFIG_PACKAGE_XRAY_RESTART_DNSMASQ_ON_IFACE_CHANGE
$(INSTALL_DATA) ./root/usr/share/xray/restart_dnsmasq_on_iface_change $(1)/usr/share/xray/restart_dnsmasq_on_iface_change
endif
ifdef CONFIG_PACKAGE_XRAY_INFINITE_RETRY_ON_STARTUP
$(INSTALL_DATA) ./root/usr/share/xray/infinite_retry $(1)/usr/share/xray/infinite_retry
endif
ifdef CONFIG_PACKAGE_XRAY_RLIMIT_NOFILE_LARGE
$(INSTALL_DATA) ./root/usr/share/xray/rlimit_nofile_large $(1)/usr/share/xray/rlimit_nofile
endif
ifdef CONFIG_PACKAGE_XRAY_RLIMIT_DATA_SMALL
$(INSTALL_DATA) ./root/usr/share/xray/rlimit_data_small $(1)/usr/share/xray/rlimit_data
endif
ifdef CONFIG_PACKAGE_XRAY_RLIMIT_DATA_LARGE
$(INSTALL_DATA) ./root/usr/share/xray/rlimit_data_large $(1)/usr/share/xray/rlimit_data
endif
ifdef CONFIG_PACKAGE_firewall
$(INSTALL_BIN) ./root/etc/hotplug.d/iface/01-transparent-proxy-ipset.fw3 $(1)/etc/hotplug.d/iface/01-transparent-proxy-ipset
$(INSTALL_BIN) ./root/usr/share/xray/gen_ipset_rules.lua $(1)/usr/share/xray/gen_ipset_rules.lua
$(INSTALL_BIN) ./root/usr/share/xray/gen_ipset_rules_extra_normal.lua $(1)/usr/share/xray/gen_ipset_rules_extra.lua
$(INSTALL_BIN) ./root/usr/share/xray/firewall_include.lua $(1)/usr/share/xray/firewall_include.lua
$(INSTALL_DATA) ./root/usr/share/xray/init.fw3 $(1)/usr/share/xray/init.firewall
$(INSTALL_BIN) ./root/usr/share/xray/gen_config.lua $(1)/usr/share/xray/gen_config.lua
endif
ifdef CONFIG_PACKAGE_firewall4
$(INSTALL_BIN) ./root/etc/hotplug.d/iface/01-transparent-proxy-ipset.fw4 $(1)/etc/hotplug.d/iface/01-transparent-proxy-ipset
$(INSTALL_DATA) ./root/usr/share/xray/include.nft $(1)/usr/share/xray/include.nft
$(INSTALL_DIR) $(1)/etc/nftables.d
$(LN) /usr/share/xray/include.nft $(1)/etc/nftables.d/99-xray.nft
$(INSTALL_BIN) ./root/usr/share/xray/firewall_include.ut $(1)/usr/share/xray/firewall_include.ut
$(INSTALL_DATA) ./root/usr/share/xray/init.fw4 $(1)/usr/share/xray/init.firewall
$(INSTALL_BIN) ./root/usr/share/xray/gen_config.uc $(1)/usr/share/xray/gen_config.uc
endif
$(INSTALL_DIR) $(1)/usr/libexec/rpcd
$(INSTALL_BIN) ./root/usr/libexec/rpcd/xray $(1)/usr/libexec/rpcd/xray
endef
$(eval $(call BuildPackage,$(PKG_NAME)))

View File

@ -6,11 +6,15 @@ Focus on making the most of Xray (HTTP/HTTPS/Socks/TProxy inbounds, multiple pro
## Warnings
* Since version 2.0.0 this project is split into `fw3` and `fw4` variants and **this breaks compatibility**:
* Configuration files and init scripts are renamed. Manually refill configurations or run `mv /etc/config/xray /etc/config/xray_fw4` (for fw4, similar for fw3) for migration.
* installation method is changed. See `Installation` below for details.
* `fw3` variant is no longer in active development (version 2.0.0 is not tested as well, just merged first). It is strongly recommended to use `fw4` variant.
* About experimental REALITY support
* may change quite frequently so keep in mind about following warnings
* currently only implemented in ucode, which means OpenWrt 22.03 versions (or master branch) and fw4 is required. Support for previous versions (19.07 / 21.02) will be added later.
* server role support **involves breaking changes if you use HTTPS server**: certificate settings are now bound to stream security, so previously uploaded certificate and key files will disappear in LuCI, but this won't prevent Xray from using them. Your previously uploaded file are still there, just select them again in LuCI. If Xray fails to start up and complains about missing certificate files, also try picking them again.
* legacy XTLS support has already been removed in version 1.8.0. This project will also remove legacy XTLS support in the next few updates so please migrate to xtls-rprx-vision or as soon as possible.
* legacy XTLS support has already been removed in version 1.8.0 and is also removed by this project since version 2.0.0.
* Since OpenWrt 22.03 release, the recommended firewall implementation for this project is now **firewall4** with some caveats
* currently this project still works on OpenWrt 19.07 / 21.02 versions. There's a warning about missing `kmod-nft-tproxy` when using these versions, just ignore it. This problem will be fixed later.
* support for versions mentioned above will soon be **deprecated**, which means that most new features won't be implemented for these old versions. Check changelog for details about future changes and availability of various new features.
@ -31,7 +35,12 @@ Focus on making the most of Xray (HTTP/HTTPS/Socks/TProxy inbounds, multiple pro
## Installation
Clone this repository under `package/extra` and find `luci-app-xray` under `Extra Packages`.
Choose one below:
* Add `src-git-full luci-app-xray https://github.com/yichya/luci-app-xray` to `feeds.conf.default` and run `./scripts/feeds update -a; ./scripts/feeds install -a`
* Clone this repository under `package`
Then find `luci-app-xray` under `Extra Packages`.
## Changelog 2023

View File

@ -0,0 +1,66 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-xray-fw3
PKG_VERSION:=2.0.0
PKG_RELEASE:=1
PKG_LICENSE:=MPLv2
PKG_LICENSE_FILES:=LICENSE
PKG_MAINTAINER:=yichya <mail@yichya.dev>
PKG_BUILD_PARALLEL:=1
include $(INCLUDE_DIR)/package.mk
define Package/$(PKG_NAME)
SECTION:=Custom
CATEGORY:=Extra packages
TITLE:=LuCI Support for Xray
DEPENDS:=firewall +ipset +iptables-mod-tproxy +luci-app-xray-shared
PKGARCH:=all
endef
define Package/$(PKG_NAME)/description
LuCI Support for Xray (Client-side Rendered) (fw3 variant).
endef
define Build/Compile
endef
define Package/$(PKG_NAME)/postinst
#!/bin/sh
if [[ -z "$${IPKG_INSTROOT}" ]]; then
if [[ -f /etc/uci-defaults/xray_fw3 ]]; then
( . /etc/uci-defaults/xray_fw3 ) && rm -f /etc/uci-defaults/xray_fw3
fi
rm -rf /tmp/luci-indexcache* /tmp/luci-modulecache
fi
exit 0
endef
define Package/$(PKG_NAME)/conffiles
/etc/config/xray_fw3
endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./root/etc/init.d/xray_fw3 $(1)/etc/init.d/xray_fw3
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_DATA) ./root/etc/config/xray_fw3 $(1)/etc/config/xray_fw3
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) ./root/etc/uci-defaults/xray_fw3 $(1)/etc/uci-defaults/xray_fw3
$(INSTALL_DIR) $(1)/etc/hotplug.d/iface
$(INSTALL_BIN) ./root/etc/hotplug.d/iface/01-transparent-proxy-ipset.fw3 $(1)/etc/hotplug.d/iface/01-transparent-proxy-ipset
$(INSTALL_DIR) $(1)/www/luci-static/resources/view
$(INSTALL_DATA) ./root/www/luci-static/resources/view/xray_fw3.js $(1)/www/luci-static/resources/view/xray.js
$(INSTALL_DIR) $(1)/usr/share/luci/menu.d
$(INSTALL_DATA) ./root/usr/share/luci/menu.d/luci-app-xray.json $(1)/usr/share/luci/menu.d/luci-app-xray.json
$(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d
$(INSTALL_DATA) ./root/usr/share/rpcd/acl.d/luci-app-xray.json $(1)/usr/share/rpcd/acl.d/luci-app-xray.json
$(INSTALL_DIR) $(1)/usr/share/xray
$(INSTALL_BIN) ./root/usr/share/xray/gen_ipset_rules.lua $(1)/usr/share/xray/gen_ipset_rules.lua
$(INSTALL_BIN) ./root/usr/share/xray/gen_ipset_rules_extra_normal.lua $(1)/usr/share/xray/gen_ipset_rules_extra.lua
$(INSTALL_BIN) ./root/usr/share/xray/firewall_include.lua $(1)/usr/share/xray/firewall_include.lua
$(INSTALL_BIN) ./root/usr/share/xray/gen_config.lua $(1)/usr/share/xray/gen_config.lua
endef
$(eval $(call BuildPackage,$(PKG_NAME)))

View File

@ -3,9 +3,39 @@
START=90
STOP=15
USE_PROCD=1
NAME=xray
NAME=xray_fw3
source /usr/share/xray/init.firewall
FIREWALL_INCLUDE="/usr/share/xray/firewall_include.lua"
setup_firewall() {
logger -st xray[$$] -p4 "Setting ipset rules..."
lua /usr/share/xray/gen_ipset_rules.lua | ipset -! restore
/etc/hotplug.d/iface/01-transparent-proxy-ipset
logger -st xray[$$] -p4 "Generating firewall rules..."
/usr/bin/lua ${FIREWALL_INCLUDE} enable > $(uci get firewall.xray.path)
logger -st xray[$$] -p4 "Triggering firewall restart..."
/etc/init.d/firewall restart > /dev/null 2>&1
}
flush_firewall() {
logger -st xray[$$] -p4 "Flushing firewall rules..."
/usr/bin/lua ${FIREWALL_INCLUDE} flush > $(uci get firewall.xray.path)
logger -st xray[$$] -p4 "Triggering firewall restart..."
/etc/init.d/firewall restart > /dev/null 2>&1
logger -st xray[$$] -p4 "Flushing ipset rules..."
for setname in $(ipset -n list | grep "tp_spec"); do
ipset -! destroy $setname
done
/etc/hotplug.d/iface/01-transparent-proxy-ipset
}
impl_gen_config_file() {
/usr/bin/lua /usr/share/xray/gen_config.lua > /var/etc/xray/config.json
}
uci_get_by_type() {
local ret=$(uci get ${NAME}.@$1[0].$2 2>/dev/null)
@ -130,5 +160,5 @@ reload_service() {
}
service_triggers() {
procd_add_reload_trigger "xray"
procd_add_reload_trigger "xray_fw3"
}

View File

@ -0,0 +1,16 @@
#!/bin/sh
uci get xray_fw3.@general[-1] >/dev/null 2>&1 || uci add xray_fw3 general >/dev/null 2>&1
uci commit xray_fw3
uci -q batch <<-EOF >/dev/null
delete ucitrack.@xray_fw3[-1]
add ucitrack xray_fw3
set ucitrack.@xray_fw3[-1].init=xray_fw3
commit ucitrack
delete firewall.xray_fw3
set firewall.xray_fw3=include
set firewall.xray_fw3.type=script
set firewall.xray_fw3.path=/var/etc/xray_fw3.include
set firewall.xray_fw3.reload=1
commit firewall
EOF
exit 0

View File

@ -1,16 +1,16 @@
{
"admin/services/xray": {
"title": "Xray",
"admin/services/xray_fw3": {
"title": "Xray (firewall3)",
"action": {
"type": "view",
"path": "xray"
"path": "xray_fw3"
},
"depends": {
"acl": [
"luci-app-xray"
],
"uci": {
"xray": true
"xray_fw3": true
}
}
}

View File

@ -3,12 +3,12 @@
"description": "Grant access to xray configurations",
"read": {
"uci": [
"xray"
"xray_fw3"
]
},
"write": {
"uci": [
"xray"
"xray_fw3"
]
}
}

View File

@ -55,8 +55,8 @@ COMMIT
COMMIT
EOF]]
local proxy_section = ucursor:get_first("xray", "general")
local proxy = ucursor:get_all("xray", proxy_section)
local proxy_section = ucursor:get_first("xray_fw3", "general")
local proxy = ucursor:get_all("xray_fw3", proxy_section)
print(flush)
if proxy.transparent_proxy_enable ~= "1" then

View File

@ -3,19 +3,19 @@ local ucursor = require "luci.model.uci"
local json = require "luci.jsonc"
local nixiofs = require "nixio.fs"
local proxy_section = ucursor:get_first("xray", "general")
local proxy = ucursor:get_all("xray", proxy_section)
local proxy_section = ucursor:get_first("xray_fw3", "general")
local proxy = ucursor:get_all("xray_fw3", proxy_section)
local tcp_server_section = arg[1] == nil and proxy.main_server or arg[1]
local tcp_server = nil
if tcp_server_section ~= nil and tcp_server_section ~= "disabled" then
tcp_server = ucursor:get_all("xray", tcp_server_section)
tcp_server = ucursor:get_all("xray_fw3", tcp_server_section)
end
local udp_server_section = arg[2] == nil and proxy.tproxy_udp_server or arg[2]
local udp_server = nil
if udp_server_section ~= nil and udp_server_section ~= "disabled" then
udp_server = ucursor:get_all("xray", udp_server_section)
udp_server = ucursor:get_all("xray_fw3", udp_server_section)
end
local geoip_existence = false
@ -394,7 +394,7 @@ local function server_outbound_recursive(t, server, tag)
table.insert(result, 1, f)
end
if dialerProxy ~= nil then
local dialer_proxy_section = ucursor:get_all("xray", dialerProxy)
local dialer_proxy_section = ucursor:get_all("xray_fw3", dialerProxy)
return server_outbound_recursive(result, dialer_proxy_section, "dialer_proxy_" .. tag)
else
return result
@ -474,7 +474,7 @@ end
local function fallbacks()
local f = {}
ucursor:foreach("xray", "fallback", function(s)
ucursor:foreach("xray_fw3", "fallback", function(s)
if s.dest ~= nil then
table.insert(f, {
dest = s.dest,
@ -778,7 +778,7 @@ end
local function manual_tproxy_outbounds()
local result = {}
local i = 0
ucursor:foreach("xray", "manual_tproxy", function(v)
ucursor:foreach("xray_fw3", "manual_tproxy", function(v)
i = i + 1
local tcp_tag = "direct"
local udp_tag = "direct"
@ -788,7 +788,7 @@ local function manual_tproxy_outbounds()
tcp_tag = "tcp_outbound"
else
tcp_tag = string.format("manual_tproxy_force_forward_tcp_outbound_%d", i)
local force_forward_server_tcp = ucursor:get_all("xray", v.force_forward_server_tcp)
local force_forward_server_tcp = ucursor:get_all("xray_fw3", v.force_forward_server_tcp)
for _, f in ipairs(server_outbound(force_forward_server_tcp, tcp_tag)) do
table.insert(result, f)
end
@ -801,7 +801,7 @@ local function manual_tproxy_outbounds()
udp_tag = "udp_outbound"
else
udp_tag = string.format("manual_tproxy_force_forward_udp_outbound_%d", i)
local force_forward_server_udp = ucursor:get_all("xray", v.force_forward_server_udp)
local force_forward_server_udp = ucursor:get_all("xray_fw3", v.force_forward_server_udp)
for _, f in ipairs(server_outbound(force_forward_server_udp, udp_tag)) do
table.insert(result, f)
end
@ -840,7 +840,7 @@ end
local function manual_tproxy_rules()
local result = {}
local i = 0
ucursor:foreach("xray", "manual_tproxy", function(v)
ucursor:foreach("xray_fw3", "manual_tproxy", function(v)
i = i + 1
table.insert(result, {
type = "field",
@ -863,7 +863,7 @@ end
local function bridges()
local result = {}
local i = 0
ucursor:foreach("xray", "bridge", function(v)
ucursor:foreach("xray_fw3", "bridge", function(v)
i = i + 1
table.insert(result, {
tag = string.format("bridge_inbound_%d", i),
@ -876,9 +876,9 @@ end
local function bridge_outbounds()
local result = {}
local i = 0
ucursor:foreach("xray", "bridge", function(v)
ucursor:foreach("xray_fw3", "bridge", function(v)
i = i + 1
local bridge_server = ucursor:get_all("xray", v.upstream)
local bridge_server = ucursor:get_all("xray_fw3", v.upstream)
for _, f in ipairs(server_outbound(bridge_server, string.format("bridge_upstream_outbound_%d", i))) do
table.insert(result, 1, f)
end
@ -896,7 +896,7 @@ end
local function bridge_rules()
local result = {}
local i = 0
ucursor:foreach("xray", "bridge", function(v)
ucursor:foreach("xray_fw3", "bridge", function(v)
i = i + 1
table.insert(result, {
type = "field",

View File

@ -2,8 +2,8 @@
local io = require("io")
local ucursor = require "luci.model.uci"
local proxy_section = ucursor:get_first("xray", "general")
local proxy = ucursor:get_all("xray", proxy_section)
local proxy_section = ucursor:get_first("xray_fw3", "general")
local proxy = ucursor:get_all("xray_fw3", proxy_section)
local gen_ipset_rules_extra = dofile("/usr/share/xray/gen_ipset_rules_extra.lua")
local create_ipset_rules = [[create tp_spec_src_ac hash:mac hashsize 64

View File

@ -24,7 +24,7 @@ function validate_object(id, a) {
}
}
function add_flow_and_stream_security_conf(s, tab_name, depends_field_name, protocol_name, have_xtls, have_tls_flow, client_side, fw4_enabled) {
function add_flow_and_stream_security_conf(s, tab_name, depends_field_name, protocol_name, have_xtls, have_tls_flow, client_side) {
let o = s.taboption(tab_name, form.ListValue, `${protocol_name}_tls`, _(`[${protocol_name}] Stream Security`))
let odep = {}
odep[depends_field_name] = protocol_name
@ -38,7 +38,7 @@ function add_flow_and_stream_security_conf(s, tab_name, depends_field_name, prot
if (have_xtls) {
o.value("xtls", "XTLS")
}
if (have_tls_flow && fw4_enabled) {
if (have_tls_flow) {
o.value("reality", "REALITY (Experimental)")
}
o.depends(odep)
@ -269,7 +269,6 @@ function check_resource_files(load_result) {
let geoip_size = 0;
let geosite_existence = false;
let geosite_size = 0;
let firewall4 = false;
let xray_bin_default = false;
let xray_running = false;
let optional_features = {};
@ -288,9 +287,6 @@ function check_resource_files(load_result) {
geosite_existence = true;
geosite_size = '%.2mB'.format(f.size);
}
if (f.name == "firewall_include.ut") {
firewall4 = true;
}
if (f.name.startsWith("optional_feature_")) {
optional_features[f.name] = true;
}
@ -301,7 +297,6 @@ function check_resource_files(load_result) {
geosite_existence: geosite_existence,
geosite_size: geosite_size,
optional_features: optional_features,
firewall4: firewall4,
xray_bin_default: xray_bin_default,
xray_running: xray_running,
}
@ -310,7 +305,7 @@ function check_resource_files(load_result) {
return view.extend({
load: function () {
return Promise.all([
uci.load("xray"),
uci.load("xray_fw3"),
fs.list("/usr/share/xray"),
network.getHostHints()
])
@ -319,9 +314,8 @@ return view.extend({
render: function (load_result) {
const config_data = load_result[0];
const geoip_direct_code = uci.get_first(config_data, "general", "geoip_direct_code");
const { geoip_existence, geoip_size, geosite_existence, geosite_size, optional_features, firewall4, xray_bin_default, xray_running } = check_resource_files(load_result[1]);
const { geoip_existence, geoip_size, geosite_existence, geosite_size, optional_features, xray_bin_default, xray_running } = check_resource_files(load_result[1]);
const status_text = xray_running ? _("[Xray is running]") : _("[Xray is stopped]");
const fw_text = firewall4 ? _("[fw4]"): _("[fw3]");
let asset_file_status = _('WARNING: at least one of asset files (geoip.dat, geosite.dat) is not found under /usr/share/xray. Xray may not work properly. See <a href="https://github.com/yichya/luci-app-xray">here</a> for help.')
if (geoip_existence) {
@ -330,7 +324,7 @@ return view.extend({
}
}
const m = new form.Map('xray', _('Xray'), status_text + " " + fw_text + " " + asset_file_status);
const m = new form.Map('xray_fw3', _('Xray (firewall3)'), status_text + " " + fw_text + " " + asset_file_status);
var s, o, ss;
@ -408,7 +402,7 @@ return view.extend({
o.value("shadowsocks", "Shadowsocks")
o.rmempty = false
add_flow_and_stream_security_conf(ss, "protocol", "protocol", "trojan", true, false, true, firewall4)
add_flow_and_stream_security_conf(ss, "protocol", "protocol", "trojan", true, false, true)
o = ss.taboption('protocol', form.ListValue, "shadowsocks_security", _("[shadowsocks] Encrypt Method"))
o.depends("protocol", "shadowsocks")
@ -427,7 +421,7 @@ return view.extend({
o.rmempty = false
o.modalonly = true
add_flow_and_stream_security_conf(ss, "protocol", "protocol", "shadowsocks", false, false, true, firewall4)
add_flow_and_stream_security_conf(ss, "protocol", "protocol", "shadowsocks", false, false, true)
o = ss.taboption('protocol', form.ListValue, "vmess_security", _("[vmess] Encrypt Method"))
o.depends("protocol", "vmess")
@ -449,7 +443,7 @@ return view.extend({
o.rmempty = false
o.modalonly = true
add_flow_and_stream_security_conf(ss, "protocol", "protocol", "vmess", false, false, true, firewall4)
add_flow_and_stream_security_conf(ss, "protocol", "protocol", "vmess", false, false, true)
o = ss.taboption('protocol', form.ListValue, "vless_encryption", _("[vless] Encrypt Method"))
o.depends("protocol", "vless")
@ -457,7 +451,7 @@ return view.extend({
o.rmempty = false
o.modalonly = true
add_flow_and_stream_security_conf(ss, "protocol", "protocol", "vless", true, true, true, firewall4)
add_flow_and_stream_security_conf(ss, "protocol", "protocol", "vless", true, true, true)
ss.tab('transport', _('Transport Settings'));
@ -662,16 +656,6 @@ return view.extend({
}
o.modalonly = true
if (firewall4) {
ss.tab('custom', _('Custom Options'));
o = ss.taboption('custom', form.TextValue, 'custom_config', _('Custom Configurations'), _('Configurations here override settings in the previous tabs with the following rules: <ol><li>Object values will be replaced recursively so settings in previous tabs matters.</li><li>Arrays will be replaced entirely instead of being merged.</li><li>Tag <code>tag</code> is ignored. </li></ol>Override rules here may be changed later. Use this only for experimental or pre-release features.'))
o.modalonly = true
o.monospace = true
o.rows = 10
o.validate = validate_object;
}
s.tab('proxy', _('Proxy Settings'));
o = s.taboption('proxy', form.Value, 'tproxy_port_tcp', _('Transparent Proxy Port (TCP)'))
@ -690,14 +674,6 @@ return view.extend({
o.datatype = 'port'
o.default = 1083
if (firewall4) {
o = s.taboption('proxy', form.DynamicList, 'uids_direct', _('Skip Proxy for uids'), _("Processes started by users with these uids won't be forwarded through Xray."))
o.datatype = "integer"
o = s.taboption('proxy', form.DynamicList, 'gids_direct', _('Skip Proxy for gids'), _("Processes started by users in groups with these gids won't be forwarded through Xray."))
o.datatype = "integer"
}
o = s.taboption('proxy', widgets.DeviceSelect, 'lan_ifaces', _("LAN Interface"))
o.noaliases = true
o.rmempty = false
@ -869,9 +845,9 @@ return view.extend({
o.rmempty = false
o.depends("web_server_enable", "1")
add_flow_and_stream_security_conf(s, "xray_server", "web_server_protocol", "vless", true, true, false, firewall4)
add_flow_and_stream_security_conf(s, "xray_server", "web_server_protocol", "vless", true, true, false)
add_flow_and_stream_security_conf(s, "xray_server", "web_server_protocol", "trojan", true, false, false, firewall4)
add_flow_and_stream_security_conf(s, "xray_server", "web_server_protocol", "trojan", true, false, false)
o = s.taboption('xray_server', form.Value, 'web_server_password', _('UserId / Password'), _('Fill user_id for vmess / VLESS, or password for shadowsocks / trojan (also supports <a href="https://github.com/XTLS/Xray-core/issues/158">Xray UUID Mapping</a>)'))
o.depends("web_server_enable", "1")

View File

@ -0,0 +1,67 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-xray-fw4
PKG_VERSION:=2.0.0
PKG_RELEASE:=1
PKG_LICENSE:=MPLv2
PKG_LICENSE_FILES:=LICENSE
PKG_MAINTAINER:=yichya <mail@yichya.dev>
PKG_BUILD_PARALLEL:=1
include $(INCLUDE_DIR)/package.mk
define Package/$(PKG_NAME)
SECTION:=Custom
CATEGORY:=Extra packages
TITLE:=LuCI Support for Xray
DEPENDS:=firewall4 +kmod-nft-tproxy +luci-app-xray-shared
PKGARCH:=all
endef
define Package/$(PKG_NAME)/description
LuCI Support for Xray (Client-side Rendered) (fw4 variant).
endef
define Build/Compile
endef
define Package/$(PKG_NAME)/postinst
#!/bin/sh
if [[ -z "$${IPKG_INSTROOT}" ]]; then
if [[ -f /etc/uci-defaults/xray_fw4 ]]; then
( . /etc/uci-defaults/xray_fw4 ) && rm -f /etc/uci-defaults/xray_fw4
fi
rm -rf /tmp/luci-indexcache* /tmp/luci-modulecache
fi
exit 0
endef
define Package/$(PKG_NAME)/conffiles
/etc/config/xray_fw4
endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./root/etc/init.d/xray_fw4 $(1)/etc/init.d/xray_fw4
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_DATA) ./root/etc/config/xray_fw4 $(1)/etc/config/xray_fw4
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) ./root/etc/uci-defaults/xray_fw4 $(1)/etc/uci-defaults/xray_fw4
$(INSTALL_DIR) $(1)/etc/hotplug.d/iface
$(INSTALL_BIN) ./root/etc/hotplug.d/iface/01-transparent-proxy-ipset.fw4 $(1)/etc/hotplug.d/iface/01-transparent-proxy-ipset
$(INSTALL_DIR) $(1)/etc/nftables.d
$(LN) /usr/share/xray/include.nft $(1)/etc/nftables.d/99-xray.nft
$(INSTALL_DIR) $(1)/www/luci-static/resources/view
$(INSTALL_DATA) ./root/www/luci-static/resources/view/xray_fw4.js $(1)/www/luci-static/resources/view/xray_fw4.js
$(INSTALL_DIR) $(1)/usr/share/luci/menu.d
$(INSTALL_DATA) ./root/usr/share/luci/menu.d/luci-app-xray.json $(1)/usr/share/luci/menu.d/luci-app-xray.json
$(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d
$(INSTALL_DATA) ./root/usr/share/rpcd/acl.d/luci-app-xray.json $(1)/usr/share/rpcd/acl.d/luci-app-xray.json
$(INSTALL_DIR) $(1)/usr/share/xray
$(INSTALL_DATA) ./root/usr/share/xray/include.nft $(1)/usr/share/xray/include.nft
$(INSTALL_BIN) ./root/usr/share/xray/firewall_include.ut $(1)/usr/share/xray/firewall_include.ut
$(INSTALL_BIN) ./root/usr/share/xray/gen_config.uc $(1)/usr/share/xray/gen_config.uc
endef
$(eval $(call BuildPackage,$(PKG_NAME)))

View File

@ -0,0 +1,63 @@
config general
option xray_bin '/usr/bin/xray'
option mark '255'
option tproxy_port_tcp '1080'
option tproxy_port_udp '1081'
option socks_port '1082'
option http_port '1083'
option dns_port '5300'
option dns_count '3'
option fast_dns '114.114.114.114'
option secure_dns '8.8.8.8'
option default_dns '1.1.1.1'
list bypassed_domain_rules 'geosite:cn'
list forwarded_domain_rules 'geosite:geolocation-!cn'
list blocked_domain_rules 'geosite:category-ads'
option transparent_proxy_enable '1'
option wan_bp_list '/dev/null'
option lan_target 'TP_SPEC_WAN_AC'
option lan_ifaces 'br-lan'
list wan_bp_ips '114.114.114.114'
option xray_api '1'
option main_server 'cfg024a8f'
option tproxy_udp_server 'cfg034a8f'
option tproxy_sniffing '1'
option routing_domain_strategy 'AsIs'
option conn_idle '300'
option loglevel 'warning'
option handshake '4'
option uplink_only '2'
option downlink_only '5'
option buffer_size '512'
option direct_bittorrent '1'
config servers
option security 'auto'
option transport 'tcp'
option tcp_guise 'none'
option tls '0'
option tests_enabled 'none'
option protocol 'vless'
option server_port '443'
option password '00000000-0000-0000-0000-000000000000'
option vless_security 'none'
option vless_encryption 'none'
option server 'example.org'
option alias 'VLESS XTLS Splice Example'
option vless_flow 'xtls-rprx-splice'
option vless_tls 'xtls'
option vless_xtls_host 'example.org'
option vless_xtls_insecure '0'
config servers
option password 'supersecret'
option transport 'tcp'
option tcp_guise 'none'
option server 'example.org'
option server_port '443'
option protocol 'trojan'
option alias 'Trojan Example'
option trojan_flow 'none'
option trojan_tls 'tls'
option trojan_tls_host 'example.org'
option trojan_tls_insecure '0'

View File

@ -0,0 +1,166 @@
#!/bin/sh /etc/rc.common
START=90
STOP=15
USE_PROCD=1
NAME=xray_fw4
FIREWALL_INCLUDE="/usr/share/xray/firewall_include.ut"
setup_firewall() {
ip rule add fwmark 251 lookup 251
ip rule add fwmark 252 lookup 252
ip route add local default dev lo table 251
ip route add local default dev lo table 252
logger -st xray[$$] -p4 "Generating firewall4 rules..."
/usr/bin/utpl ${FIREWALL_INCLUDE} > /var/etc/xray/firewall_include.nft
logger -st xray[$$] -p4 "Triggering firewall4 restart..."
/etc/init.d/firewall restart
/etc/hotplug.d/iface/01-transparent-proxy-ipset
}
flush_firewall() {
ip rule del fwmark 251 lookup 251
ip rule del fwmark 252 lookup 252
ip route del local default dev lo table 251
ip route del local default dev lo table 252
logger -st xray[$$] -p4 "Flushing firewall4 rules..."
rm -f /var/etc/xray/firewall_include.nft
logger -st xray[$$] -p4 "Triggering firewall4 restart..."
/etc/init.d/firewall restart
/etc/hotplug.d/iface/01-transparent-proxy-ipset
}
impl_gen_config_file() {
/usr/bin/ucode /usr/share/xray/gen_config.uc > /var/etc/xray/config.json
}
uci_get_by_type() {
local ret=$(uci get ${NAME}.@$1[0].$2 2>/dev/null)
echo ${ret:=$3}
}
log_procd_set_param() {
local type="$1"
shift
logger -st xray[$$] -p4 "Using procd_set_param $type" "$@"
}
start_xray() {
logger -st xray[$$] -p4 "Starting Xray from $1"
procd_open_instance
procd_set_param respawn 1 1 0
procd_set_param command $1
procd_append_param command run
procd_append_param command -confdir
procd_append_param command /var/etc/xray
local rlimit_nofile
if [ -s /usr/share/xray/rlimit_nofile ] ; then
rlimit_nofile="nofile=""$(cat /usr/share/xray/rlimit_nofile)"
fi
local rlimit_data
if [ -s /usr/share/xray/rlimit_data ] ; then
rlimit_data="data=""$(cat /usr/share/xray/rlimit_data)"
fi
# this param passing method is just so fucking weird
if [ -z "${rlimit_nofile}" ] ; then
if [ ! -z "${rlimit_data}" ]; then
log_procd_set_param limits "${rlimit_data}"
procd_set_param limits "${rlimit_data}"
fi
else
if [ -z "${rlimit_data}" ]; then
log_procd_set_param limits "${rlimit_nofile}"
procd_set_param limits "${rlimit_nofile}"
else
log_procd_set_param limits "${rlimit_data}" "${rlimit_nofile}"
procd_set_param limits "${rlimit_data}" "${rlimit_nofile}"
fi
fi
procd_set_param env XRAY_LOCATION_ASSET=/usr/share/xray
procd_set_param stdout 1
procd_set_param stderr 1
procd_set_param file /etc/config/xray
procd_set_param pidfile /var/run/xray.pid
procd_close_instance
}
gen_config_file() {
rm -f /var/etc/xray/*
if [ -s /usr/share/xray/infinite_retry ] ; then
while [ ! -s /var/etc/xray/config.json ] ; do
logger -st xray[$$] -p4 "(Re)generating Xray configuration files..."
impl_gen_config_file
done
else
logger -st xray[$$] -p4 "Generating Xray configuration files..."
impl_gen_config_file
fi
local custom_config=$(uci_get_by_type general custom_config)
[ ! "${#custom_config}" == "0" ] && echo ${custom_config} > /var/etc/xray/config_custom.json
}
setup_dnsmasq() {
local dns_port=$(uci_get_by_type general dns_port)
local dns_count=$(uci_get_by_type general dns_count 0)
echo "# Generated dnsmasq configurations by luci-app-xray" > /tmp/dnsmasq.d/xray.conf
echo "strict-order" >> /tmp/dnsmasq.d/xray.conf
echo "server=/#/127.0.0.1#${dns_port}" >> /tmp/dnsmasq.d/xray.conf
local cur_port
for cur_port in $(seq ${dns_port} $(expr ${dns_port} + ${dns_count})); do
echo "server=127.0.0.1#${cur_port}" >> /tmp/dnsmasq.d/xray.conf
done
logger -st xray[$$] -p4 $(cat /tmp/dnsmasq.d/xray.conf)
/etc/init.d/dnsmasq restart > /dev/null 2>&1
}
flush_dnsmasq() {
rm -f /tmp/dnsmasq.d/xray.conf
/etc/init.d/dnsmasq restart > /dev/null 2>&1
}
create_when_enable() {
[ "$(uci_get_by_type general transparent_proxy_enable)" == "1" ] || return 0
logger -st xray[$$] -p4 "Setting dnsmasq and firewall for transparent proxy..."
setup_dnsmasq
setup_firewall
}
flush_when_disable() {
logger -st xray[$$] -p4 "Resetting dnsmasq and firewall configurations..."
flush_dnsmasq
flush_firewall
}
start_service() {
config_load $NAME
mkdir -p /var/run /var/etc/xray
local xray_bin=$(uci_get_by_type general xray_bin)
command -v ${xray_bin} > /dev/null 2>&1 || return 1
gen_config_file
start_xray ${xray_bin}
create_when_enable || flush_when_disable
}
stop_service() {
flush_when_disable
}
reload_service() {
stop
start
}
service_triggers() {
procd_add_reload_trigger "xray_fw4"
}

View File

@ -0,0 +1,10 @@
#!/bin/sh
uci get xray_fw4.@general[-1] >/dev/null 2>&1 || uci add xray_fw4 general >/dev/null 2>&1
uci commit xray_fw4
uci -q batch <<-EOF >/dev/null
delete ucitrack.@xray_fw4[-1]
add ucitrack xray_fw4
set ucitrack.@xray_fw4[-1].init=xray_fw4
commit ucitrack
EOF
exit 0

View File

@ -0,0 +1,17 @@
{
"admin/services/xray_fw4": {
"title": "Xray (firewall4)",
"action": {
"type": "view",
"path": "xray_fw4"
},
"depends": {
"acl": [
"luci-app-xray"
],
"uci": {
"xray_fw4": true
}
}
}
}

View File

@ -0,0 +1,15 @@
{
"luci-app-xray": {
"description": "Grant access to xray configurations",
"read": {
"uci": [
"xray_fw4"
]
},
"write": {
"uci": [
"xray_fw4"
]
}
}
}

View File

@ -3,8 +3,8 @@
const uci = require("uci");
const fs = require("fs");
const cursor = uci.cursor();
cursor.load("xray");
const config = cursor.get_all("xray");
cursor.load("xray_fw4");
const config = cursor.get_all("xray_fw4");
const general = config[filter(keys(config), k => config[k][".type"] == "general")[0]];
const tp_spec_src_fw = uniq(map(filter(keys(config), k => config[k][".type"] == "lan_hosts" && config[k].bypassed == "0"), k => config[k].macaddr) || []);
const tp_spec_src_bp = uniq(map(filter(keys(config), k => config[k][".type"] == "lan_hosts" && config[k].bypassed == "1"), k => config[k].macaddr) || []);

View File

@ -2,8 +2,8 @@
const uci = require("uci");
const fs = require("fs");
const cursor = uci.cursor();
cursor.load("xray");
const config = cursor.get_all("xray");
cursor.load("xray_fw4");
const config = cursor.get_all("xray_fw4");
const share_dir = fs.lsdir("/usr/share/xray");
const proxy = config[filter(keys(config), k => config[k][".type"] == "general")[0]];
@ -193,19 +193,6 @@ function tls_settings(server, protocol) {
return result;
}
function xtls_settings(server, protocol) {
let result = {
serverName: server[protocol + "_xtls_host"],
allowInsecure: server[protocol + "_xtls_insecure"] != "0"
};
if (server[protocol + "_xtls_alpn"] != null) {
result["alpn"] = server[protocol + "_xtls_alpn"];
}
return result;
}
function reality_settings(server, protocol) {
let result = {
show: server[protocol + "_reality_show"],
@ -222,12 +209,9 @@ function reality_settings(server, protocol) {
function stream_settings(server, protocol, tag) {
const security = server[protocol + "_tls"];
let tlsSettings = null;
let xtlsSettings = null;
let realitySettings = null;
if (security == "tls") {
tlsSettings = tls_settings(server, protocol);
} else if (security == "xtls") {
xtlsSettings = xtls_settings(server, protocol);
} else if (security == "reality") {
realitySettings = reality_settings(server, protocol);
}
@ -248,7 +232,6 @@ function stream_settings(server, protocol, tag) {
},
security: security,
tlsSettings: tlsSettings,
xtlsSettings: xtlsSettings,
realitySettings: realitySettings,
quicSettings: stream_quic(server),
tcpSettings: stream_tcp(server),
@ -317,9 +300,7 @@ function vmess_outbound(server, tag) {
function vless_outbound(server, tag) {
let flow = null;
if (server["vless_tls"] == "xtls") {
flow = server["vless_flow"]
} else if (server["vless_tls"] == "tls") {
if (server["vless_tls"] == "tls") {
flow = server["vless_flow_tls"]
} else if (server["vless_tls"] == "reality") {
flow = server["vless_flow_reality"]
@ -356,13 +337,6 @@ function vless_outbound(server, tag) {
}
function trojan_outbound(server, tag) {
let flow = null;
if (server["trojan_tls"] == "xtls") {
flow = server["trojan_flow"]
}
if (flow == "none") {
flow = null;
}
const stream_settings_object = stream_settings(server, "trojan", tag);
const stream_settings_result = stream_settings_object["stream_settings"];
const dialer_proxy = stream_settings_object["dialer_proxy"];
@ -375,8 +349,7 @@ function trojan_outbound(server, tag) {
{
address: server["server"],
port: int(server["server_port"]),
password: server["password"],
flow: flow,
password: server["password"]
}
]
},
@ -546,28 +519,6 @@ function tls_inbound_settings(protocol_name) {
}
}
function xtls_inbound_settings(protocol_name) {
let wscert = proxy[protocol_name + "_xtls_cert_file"];
if (wscert == null) {
wscert = proxy["web_server_cert_file"]
}
let wskey = proxy[protocol_name + "_xtls_key_file"];
if (wskey == null) {
wskey = proxy["web_server_key_file"]
}
return {
alpn: [
"http/1.1"
],
certificates: [
{
certificateFile: wscert,
keyFile: wskey
}
]
}
}
function reality_inbound_settings(protocol_name) {
return {
show: proxy[protocol_name + "_reality_show"],
@ -583,13 +534,6 @@ function reality_inbound_settings(protocol_name) {
}
function https_trojan_inbound() {
let flow = null;
if (proxy["trojan_tls"] == "xtls") {
flow = proxy["trojan_flow"]
}
if (flow == "none") {
flow = null;
}
return {
port: proxy["web_server_port"] || 443,
protocol: "trojan",
@ -597,8 +541,7 @@ function https_trojan_inbound() {
settings: {
clients: [
{
password: proxy["web_server_password"],
flow: flow
password: proxy["web_server_password"]
}
],
fallbacks: fallbacks()
@ -606,17 +549,14 @@ function https_trojan_inbound() {
streamSettings: {
network: "tcp",
security: proxy["trojan_tls"],
tlsSettings: proxy["trojan_tls"] == "tls" ? tls_inbound_settings("trojan") : null,
xtlsSettings: proxy["trojan_tls"] == "xtls" ? xtls_inbound_settings("trojan") : null
tlsSettings: proxy["trojan_tls"] == "tls" ? tls_inbound_settings("trojan") : null
}
}
}
function https_vless_inbound() {
let flow = null;
if (proxy["vless_tls"] == "xtls") {
flow = proxy["vless_flow"]
} else if (proxy["vless_tls"] == "tls") {
if (proxy["vless_tls"] == "tls") {
flow = proxy["vless_flow_tls"]
} else if (proxy["vless_tls"] == "reality") {
flow = proxy["vless_flow_reality"]
@ -642,7 +582,6 @@ function https_vless_inbound() {
network: "tcp",
security: proxy["vless_tls"],
tlsSettings: proxy["vless_tls"] == "tls" ? tls_inbound_settings("vless") : null,
xtlsSettings: proxy["vless_tls"] == "xtls" ? xtls_inbound_settings("vless") : null,
realitySettings: proxy["vless_tls"] == "reality" ? reality_inbound_settings("vless") : null,
}
}

View File

@ -0,0 +1,924 @@
'use strict';
'require view';
'require uci';
'require form';
'require fs';
'require network';
'require tools.widgets as widgets';
function validate_object(id, a) {
if (a == "") {
return true
}
try {
const t = JSON.parse(a)
if (Array.isArray(t)) {
return "TypeError: Requires an object here, got an array"
}
if (t instanceof Object) {
return true
}
return "TypeError: Requires an object here, got a " + typeof t
} catch (e) {
return e
}
}
function fingerprints(o) {
o.value("chrome", "chrome")
o.value("firefox", "firefox")
o.value("safari", "safari")
o.value("ios", "ios")
o.value("android", "android")
o.value("edge", "edge")
o.value("360", "360")
o.value("qq", "qq")
o.value("random", "random")
o.value("randomized", "randomized")
}
function add_flow_and_stream_security_conf(s, tab_name, depends_field_name, protocol_name, have_tls_flow, client_side) {
let o = s.taboption(tab_name, form.ListValue, `${protocol_name}_tls`, _(`[${protocol_name}] Stream Security`))
let odep = {}
odep[depends_field_name] = protocol_name
if (client_side) {
o.depends(depends_field_name, protocol_name)
o.value("none", "None")
} else {
odep["web_server_enable"] = "1"
}
o.value("tls", "TLS")
if (have_tls_flow) {
o.value("reality", "REALITY (Experimental)")
}
o.depends(odep)
o.rmempty = false
o.modalonly = true
if (have_tls_flow) {
let flow_tls = s.taboption(tab_name, form.ListValue, `${protocol_name}_flow_tls`, _(`[${protocol_name}][tls] Flow`))
let flow_tls_dep = {}
flow_tls_dep[depends_field_name] = protocol_name
flow_tls_dep[`${protocol_name}_tls`] = "tls"
flow_tls.value("none", "none")
flow_tls.value("xtls-rprx-vision", "xtls-rprx-vision")
flow_tls.value("xtls-rprx-vision-udp443", "xtls-rprx-vision-udp443")
if (client_side) {
// wait for some other things
} else {
flow_tls_dep["web_server_enable"] = "1"
}
flow_tls.depends(flow_tls_dep)
flow_tls.rmempty = false
flow_tls.modalonly = true
let flow_reality = s.taboption(tab_name, form.ListValue, `${protocol_name}_flow_reality`, _(`[${protocol_name}][reality] Flow`))
let flow_reality_dep = {}
flow_reality_dep[depends_field_name] = protocol_name
flow_reality_dep[`${protocol_name}_tls`] = "reality"
flow_reality.value("none", "none")
flow_reality.value("xtls-rprx-vision", "xtls-rprx-vision")
flow_reality.value("xtls-rprx-vision-udp443", "xtls-rprx-vision-udp443")
if (client_side) {
// wait for some other things
} else {
flow_reality_dep["web_server_enable"] = "1"
}
flow_reality.depends(flow_reality_dep)
flow_reality.rmempty = false
flow_reality.modalonly = true
o = s.taboption(tab_name, form.Flag, `${protocol_name}_reality_show`, _(`[${protocol_name}][reality] Show`))
o.depends(`${protocol_name}_tls`, "reality")
o.rmempty = true
o.modalonly = true
}
if (client_side) {
o = s.taboption(tab_name, form.Value, `${protocol_name}_tls_host`, _(`[${protocol_name}][tls] Server Name`))
o.depends(`${protocol_name}_tls`, "tls")
o.rmempty = true
o.modalonly = true
o = s.taboption(tab_name, form.Flag, `${protocol_name}_tls_insecure`, _(`[${protocol_name}][tls] Allow Insecure`))
o.depends(`${protocol_name}_tls`, "tls")
o.rmempty = false
o.modalonly = true
o = s.taboption(tab_name, form.Value, `${protocol_name}_tls_fingerprint`, _(`[${protocol_name}][tls] Fingerprint`))
o.depends(`${protocol_name}_tls`, "tls")
o.value("", "(not set)")
fingerprints(o)
o.rmempty = true
o.modalonly = true
o = s.taboption(tab_name, form.DynamicList, `${protocol_name}_tls_alpn`, _(`[${protocol_name}][tls] ALPN`))
o.depends(`${protocol_name}_tls`, "tls")
o.value("h2", "h2")
o.value("http/1.1", "http/1.1")
o.rmempty = true
o.modalonly = true
if (have_tls_flow) {
o = s.taboption(tab_name, form.Value, `${protocol_name}_reality_fingerprint`, _(`[${protocol_name}][reality] Fingerprint`))
o.depends(`${protocol_name}_tls`, "reality")
fingerprints(o)
o.rmempty = false
o.modalonly = true
o = s.taboption(tab_name, form.Value, `${protocol_name}_reality_server_name`, _(`[${protocol_name}][reality] Server Name`))
o.depends(`${protocol_name}_tls`, "reality")
o.rmempty = true
o.modalonly = true
o = s.taboption(tab_name, form.Value, `${protocol_name}_reality_public_key`, _(`[${protocol_name}][reality] Public Key`))
o.depends(`${protocol_name}_tls`, "reality")
o.rmempty = true
o.modalonly = true
o = s.taboption(tab_name, form.Value, `${protocol_name}_reality_short_id`, _(`[${protocol_name}][reality] Short Id`))
o.depends(`${protocol_name}_tls`, "reality")
o.rmempty = true
o.modalonly = true
o = s.taboption(tab_name, form.Value, `${protocol_name}_spider_x`, _(`[${protocol_name}][reality] SpiderX`))
o.depends(`${protocol_name}_tls`, "reality")
o.rmempty = true
o.modalonly = true
}
} else {
let tls_cert_key_dep = {"web_server_enable": "1"}
tls_cert_key_dep[`${protocol_name}_tls`] = "tls"
o = s.taboption(tab_name, form.FileUpload, `${protocol_name}_tls_cert_file`, _(`[${protocol_name}][tls] Certificate File`));
o.root_directory = "/etc/luci-uploads/xray"
o.depends(tls_cert_key_dep)
o = s.taboption(tab_name, form.FileUpload, `${protocol_name}_tls_key_file`, _(`[${protocol_name}][tls] Private Key File`));
o.root_directory = "/etc/luci-uploads/xray"
o.depends(tls_cert_key_dep)
if (have_tls_flow) {
o = s.taboption(tab_name, form.Value, `${protocol_name}_reality_dest`, _(`[${protocol_name}][reality] Dest`))
o.depends(`${protocol_name}_tls`, "reality")
o.datatype = "hostport"
o.rmempty = true
o.modalonly = true
o = s.taboption(tab_name, form.Value, `${protocol_name}_reality_xver`, _(`[${protocol_name}][reality] Xver`))
o.depends(`${protocol_name}_tls`, "reality")
o.datatype = "integer"
o.rmempty = true
o.modalonly = true
o = s.taboption(tab_name, form.DynamicList, `${protocol_name}_reality_server_names`, _(`[${protocol_name}][reality] Server Names`))
o.depends(`${protocol_name}_tls`, "reality")
o.rmempty = true
o.modalonly = true
o = s.taboption(tab_name, form.Value, `${protocol_name}_reality_private_key`, _(`[${protocol_name}][reality] Private Key`))
o.depends(`${protocol_name}_tls`, "reality")
o.rmempty = true
o.modalonly = true
o = s.taboption(tab_name, form.Value, `${protocol_name}_reality_min_client_ver`, _(`[${protocol_name}][reality] Min Client Ver`))
o.depends(`${protocol_name}_tls`, "reality")
o.rmempty = true
o.modalonly = true
o = s.taboption(tab_name, form.Value, `${protocol_name}_reality_max_client_ver`, _(`[${protocol_name}][reality] Max Client Ver`))
o.depends(`${protocol_name}_tls`, "reality")
o.rmempty = true
o.modalonly = true
o = s.taboption(tab_name, form.Value, `${protocol_name}_reality_max_time_diff`, _(`[${protocol_name}][reality] Max Time Diff`))
o.depends(`${protocol_name}_tls`, "reality")
o.datatype = "integer"
o.rmempty = true
o.modalonly = true
o = s.taboption(tab_name, form.DynamicList, `${protocol_name}_reality_short_ids`, _(`[${protocol_name}][reality] Short Ids`))
o.depends(`${protocol_name}_tls`, "reality")
o.rmempty = true
o.modalonly = true
}
}
}
function check_resource_files(load_result) {
let geoip_existence = false;
let geoip_size = 0;
let geosite_existence = false;
let geosite_size = 0;
let xray_bin_default = false;
let xray_running = false;
let optional_features = {};
for (const f of load_result) {
if (f.name == "xray") {
xray_bin_default = true;
}
if (f.name == "xray.pid") {
xray_running = true;
}
if (f.name == "geoip.dat") {
geoip_existence = true;
geoip_size = '%.2mB'.format(f.size);
}
if (f.name == "geosite.dat") {
geosite_existence = true;
geosite_size = '%.2mB'.format(f.size);
}
if (f.name.startsWith("optional_feature_")) {
optional_features[f.name] = true;
}
}
return {
geoip_existence: geoip_existence,
geoip_size: geoip_size,
geosite_existence: geosite_existence,
geosite_size: geosite_size,
optional_features: optional_features,
xray_bin_default: xray_bin_default,
xray_running: xray_running,
}
}
return view.extend({
load: function () {
return Promise.all([
uci.load("xray_fw4"),
fs.list("/usr/share/xray"),
network.getHostHints()
])
},
render: function (load_result) {
const config_data = load_result[0];
const geoip_direct_code = uci.get_first(config_data, "general", "geoip_direct_code");
const { geoip_existence, geoip_size, geosite_existence, geosite_size, optional_features, xray_bin_default, xray_running } = check_resource_files(load_result[1]);
const status_text = xray_running ? _("[Xray is running]") : _("[Xray is stopped]");
let asset_file_status = _('WARNING: at least one of asset files (geoip.dat, geosite.dat) is not found under /usr/share/xray. Xray may not work properly. See <a href="https://github.com/yichya/luci-app-xray">here</a> for help.')
if (geoip_existence) {
if (geosite_existence) {
asset_file_status = _('Asset files check: ') + `geoip.dat ${geoip_size}; geosite.dat ${geosite_size}. ` + _('Report issues or request for features <a href="https://github.com/yichya/luci-app-xray">here</a>.')
}
}
const m = new form.Map('xray_fw4', _('Xray (firewall4)'), status_text + " " + asset_file_status);
var s, o, ss;
s = m.section(form.TypedSection, 'general');
s.addremove = false;
s.anonymous = true;
s.tab('general', _('General Settings'));
o = s.taboption('general', form.Value, 'xray_bin', _('Xray Executable Path'))
o.rmempty = false
if (xray_bin_default) {
o.value("/usr/bin/xray", _("/usr/bin/xray (default, exist)"))
}
o = s.taboption('general', form.ListValue, 'main_server', _('TCP Server'))
o.datatype = "uciname"
o.value("disabled", _("Disabled"))
for (const v of uci.sections(config_data, "servers")) {
o.value(v[".name"], v.alias || v.server + ":" + v.server_port)
}
o = s.taboption('general', form.ListValue, 'tproxy_udp_server', _('UDP Server'))
o.datatype = "uciname"
o.value("disabled", _("Disabled"))
for (const v of uci.sections(config_data, "servers")) {
o.value(v[".name"], v.alias || v.server + ":" + v.server_port)
}
o = s.taboption('general', form.Flag, 'transparent_proxy_enable', _('Enable Transparent Proxy'), _('This enables DNS query forwarding and TProxy for both TCP and UDP connections.'))
o = s.taboption('general', form.Flag, 'tproxy_sniffing', _('Enable Sniffing'), _('If sniffing is enabled, requests will be routed according to domain settings in "DNS Settings" tab.'))
o.depends("transparent_proxy_enable", "1")
o = s.taboption('general', form.Flag, 'route_only', _('Route Only'), _('Use sniffed domain for routing only but still access through IP. Reduces unnecessary DNS requests. See <a href="https://github.com/XTLS/Xray-core/commit/a3023e43ef55d4498b1afbc9a7fe7b385138bb1a">here</a> for help.'))
o.depends({ "transparent_proxy_enable": "1", "tproxy_sniffing": "1" })
o = s.taboption('general', form.Flag, 'direct_bittorrent', _('Bittorrent Direct'), _("If enabled, all bittorrent request won't be forwarded through Xray."))
o.depends({ "transparent_proxy_enable": "1", "tproxy_sniffing": "1" })
o = s.taboption('general', form.SectionValue, "xray_servers", form.GridSection, 'servers', _('Xray Servers'), _("Servers are referenced by index (order in the following list). Deleting servers may result in changes of upstream servers actually used by proxy and bridge."))
ss = o.subsection
ss.sortable = false
ss.anonymous = true
ss.addremove = true
ss.tab('general', _('General Settings'));
o = ss.taboption('general', form.Value, "alias", _("Alias (optional)"))
o.rmempty = true
o = ss.taboption('general', form.Value, 'server', _('Server Hostname'))
o.datatype = 'host'
o = ss.taboption('general', form.ListValue, 'domain_strategy', _('Domain Strategy'))
o.value("UseIP")
o.value("UseIPv4")
o.value("UseIPv6")
o.default = "UseIP"
o.modalonly = true
o = ss.taboption('general', form.Value, 'server_port', _('Server Port'))
o.datatype = 'port'
o.placeholder = '443'
o = ss.taboption('general', form.Value, 'password', _('UserId / Password'), _('Fill user_id for vmess / VLESS, or password for shadowsocks / trojan (also supports <a href="https://github.com/XTLS/Xray-core/issues/158">Xray UUID Mapping</a>)'))
o.modalonly = true
ss.tab('protocol', _('Protocol Settings'));
o = ss.taboption('protocol', form.ListValue, "protocol", _("Protocol"))
o.value("vmess", "VMess")
o.value("vless", "VLESS")
o.value("trojan", "Trojan")
o.value("shadowsocks", "Shadowsocks")
o.rmempty = false
add_flow_and_stream_security_conf(ss, "protocol", "protocol", "trojan", false, true)
o = ss.taboption('protocol', form.ListValue, "shadowsocks_security", _("[shadowsocks] Encrypt Method"))
o.depends("protocol", "shadowsocks")
o.value("none", "none")
o.value("aes-256-gcm", "aes-256-gcm")
o.value("aes-128-gcm", "aes-128-gcm")
o.value("chacha20-poly1305", "chacha20-poly1305")
o.value("2022-blake3-aes-128-gcm", "2022-blake3-aes-128-gcm")
o.value("2022-blake3-aes-256-gcm", "2022-blake3-aes-256-gcm")
o.value("2022-blake3-chacha20-poly1305", "2022-blake3-chacha20-poly1305")
o.rmempty = false
o.modalonly = true
o = ss.taboption('protocol', form.Flag, 'shadowsocks_udp_over_tcp', _('[shadowsocks] UDP over TCP'), _('Only available for shadowsocks-2022 ciphers (2022-*)'))
o.depends("shadowsocks_security", /2022/)
o.rmempty = false
o.modalonly = true
add_flow_and_stream_security_conf(ss, "protocol", "protocol", "shadowsocks", false, true)
o = ss.taboption('protocol', form.ListValue, "vmess_security", _("[vmess] Encrypt Method"))
o.depends("protocol", "vmess")
o.value("none", "none")
o.value("auto", "auto")
o.value("aes-128-gcm", "aes-128-gcm")
o.value("chacha20-poly1305", "chacha20-poly1305")
o.rmempty = false
o.modalonly = true
o = ss.taboption('protocol', form.ListValue, "vmess_alter_id", _("[vmess] AlterId"), _("Deprecated. Make sure you always use VMessAEAD."))
o.depends("protocol", "vmess")
o.value(0, "0 (this enables VMessAEAD)")
o.value(1, "1")
o.value(4, "4")
o.value(16, "16")
o.value(64, "64")
o.value(256, "256")
o.rmempty = false
o.modalonly = true
add_flow_and_stream_security_conf(ss, "protocol", "protocol", "vmess", false, true)
o = ss.taboption('protocol', form.ListValue, "vless_encryption", _("[vless] Encrypt Method"))
o.depends("protocol", "vless")
o.value("none", "none")
o.rmempty = false
o.modalonly = true
add_flow_and_stream_security_conf(ss, "protocol", "protocol", "vless", true, true)
ss.tab('transport', _('Transport Settings'));
o = ss.taboption('transport', form.ListValue, 'transport', _('Transport'))
o.value("tcp", "TCP")
o.value("mkcp", "mKCP")
o.value("ws", "WebSocket")
o.value("h2", "HTTP/2")
o.value("quic", "QUIC")
o.value("grpc", "gRPC")
o.rmempty = false
o = ss.taboption('transport', form.ListValue, "tcp_guise", _("[tcp] Fake Header Type"))
o.depends("transport", "tcp")
o.value("none", _("None"))
o.value("http", "HTTP")
o.rmempty = true
o.modalonly = true
o = ss.taboption('transport', form.DynamicList, "http_host", _("[tcp][fake_http] Host"))
o.depends("tcp_guise", "http")
o.rmempty = false
o.modalonly = true
o = ss.taboption('transport', form.DynamicList, "http_path", _("[tcp][fake_http] Path"))
o.depends("tcp_guise", "http")
o.rmempty = true
o.modalonly = true
o = ss.taboption('transport', form.ListValue, "mkcp_guise", _("[mkcp] Fake Header Type"))
o.depends("transport", "mkcp")
o.value("none", _("None"))
o.value("srtp", _("VideoCall (SRTP)"))
o.value("utp", _("BitTorrent (uTP)"))
o.value("wechat-video", _("WechatVideo"))
o.value("dtls", "DTLS 1.2")
o.value("wireguard", "WireGuard")
o.rmempty = true
o.modalonly = true
o = ss.taboption('transport', form.Value, "mkcp_mtu", _("[mkcp] Maximum Transmission Unit"))
o.datatype = "uinteger"
o.depends("transport", "mkcp")
o.default = 1350
o.rmempty = true
o.modalonly = true
o = ss.taboption('transport', form.Value, "mkcp_tti", _("[mkcp] Transmission Time Interval"))
o.datatype = "uinteger"
o.depends("transport", "mkcp")
o.default = 50
o.rmempty = true
o.modalonly = true
o = ss.taboption('transport', form.Value, "mkcp_uplink_capacity", _("[mkcp] Uplink Capacity"))
o.datatype = "uinteger"
o.depends("transport", "mkcp")
o.default = 5
o.rmempty = true
o.modalonly = true
o = ss.taboption('transport', form.Value, "mkcp_downlink_capacity", _("[mkcp] Downlink Capacity"))
o.datatype = "uinteger"
o.depends("transport", "mkcp")
o.default = 20
o.rmempty = true
o.modalonly = true
o = ss.taboption('transport', form.Value, "mkcp_read_buffer_size", _("[mkcp] Read Buffer Size"))
o.datatype = "uinteger"
o.depends("transport", "mkcp")
o.default = 2
o.rmempty = true
o.modalonly = true
o = ss.taboption('transport', form.Value, "mkcp_write_buffer_size", _("[mkcp] Write Buffer Size"))
o.datatype = "uinteger"
o.depends("transport", "mkcp")
o.default = 2
o.rmempty = true
o.modalonly = true
o = ss.taboption('transport', form.Flag, "mkcp_congestion", _("[mkcp] Congestion Control"))
o.depends("transport", "mkcp")
o.rmempty = true
o.modalonly = true
o = ss.taboption('transport', form.Value, "mkcp_seed", _("[mkcp] Seed"))
o.depends("transport", "mkcp")
o.rmempty = true
o.modalonly = true
o = ss.taboption('transport', form.ListValue, "quic_security", _("[quic] Security"))
o.depends("transport", "quic")
o.value("none", "none")
o.value("aes-128-gcm", "aes-128-gcm")
o.value("chacha20-poly1305", "chacha20-poly1305")
o.rmempty = false
o.modalonly = true
o = ss.taboption('transport', form.Value, "quic_key", _("[quic] Key"))
o.depends("transport", "quic")
o.rmempty = true
o.modalonly = true
o = ss.taboption('transport', form.ListValue, "quic_guise", _("[quic] Fake Header Type"))
o.depends("transport", "quic")
o.value("none", _("None"))
o.value("srtp", _("VideoCall (SRTP)"))
o.value("utp", _("BitTorrent (uTP)"))
o.value("wechat-video", _("WechatVideo"))
o.value("dtls", "DTLS 1.2")
o.value("wireguard", "WireGuard")
o.rmempty = true
o.modalonly = true
o = ss.taboption('transport', form.DynamicList, "h2_host", _("[http2] Host"))
o.depends("transport", "h2")
o.rmempty = true
o.modalonly = true
o = ss.taboption('transport', form.Value, "h2_path", _("[http2] Path"))
o.depends("transport", "h2")
o.rmempty = true
o.modalonly = true
o = ss.taboption('transport', form.Flag, "h2_health_check", _("[h2] Health Check"))
o.depends("transport", "h2")
o.rmempty = true
o.modalonly = true
o = ss.taboption('transport', form.Value, "h2_read_idle_timeout", _("[h2] Read Idle Timeout"))
o.depends({ "transport": "h2", "h2_health_check": "1" })
o.rmempty = true
o.modalonly = true
o.default = 10
o.datatype = 'integer'
o = ss.taboption('transport', form.Value, "h2_health_check_timeout", _("[h2] Health Check Timeout"))
o.depends({ "transport": "h2", "h2_health_check": "1" })
o.rmempty = true
o.modalonly = true
o.default = 20
o.datatype = 'integer'
o = ss.taboption('transport', form.Value, "grpc_service_name", _("[grpc] Service Name"))
o.depends("transport", "grpc")
o.rmempty = true
o.modalonly = true
o = ss.taboption('transport', form.Flag, "grpc_multi_mode", _("[grpc] Multi Mode"))
o.depends("transport", "grpc")
o.rmempty = true
o.modalonly = true
o = ss.taboption('transport', form.Flag, "grpc_health_check", _("[grpc] Health Check"))
o.depends("transport", "grpc")
o.rmempty = true
o.modalonly = true
o = ss.taboption('transport', form.Value, "grpc_idle_timeout", _("[grpc] Idle Timeout"))
o.depends({ "transport": "grpc", "grpc_health_check": "1" })
o.rmempty = true
o.modalonly = true
o.default = 10
o.datatype = 'integer'
o = ss.taboption('transport', form.Value, "grpc_health_check_timeout", _("[grpc] Health Check Timeout"))
o.depends({ "transport": "grpc", "grpc_health_check": "1" })
o.rmempty = true
o.modalonly = true
o.default = 20
o.datatype = 'integer'
o = ss.taboption('transport', form.Flag, "grpc_permit_without_stream", _("[grpc] Permit Without Stream"))
o.depends({ "transport": "grpc", "grpc_health_check": "1" })
o.rmempty = true
o.modalonly = true
o = ss.taboption('transport', form.Value, "grpc_initial_windows_size", _("[grpc] Initial Windows Size"), _("Set to 524288 to avoid Cloudflare sending ENHANCE_YOUR_CALM."))
o.depends("transport", "grpc")
o.rmempty = true
o.modalonly = true
o.default = 0
o.datatype = 'integer'
o = ss.taboption('transport', form.Value, "ws_host", _("[websocket] Host"))
o.depends("transport", "ws")
o.rmempty = true
o.modalonly = true
o = ss.taboption('transport', form.Value, "ws_path", _("[websocket] Path"))
o.depends("transport", "ws")
o.rmempty = true
o.modalonly = true
o = ss.taboption('transport', form.ListValue, 'dialer_proxy', _('Dialer Proxy'), _('Similar to <a href="https://xtls.github.io/config/outbound.html#proxysettingsobject">ProxySettings.Tag</a>'))
o.datatype = "uciname"
o.value("disabled", _("Disabled"))
for (const v of uci.sections(config_data, "servers")) {
o.value(v[".name"], v.alias || v.server + ":" + v.server_port)
}
o.modalonly = true
ss.tab('custom', _('Custom Options'));
o = ss.taboption('custom', form.TextValue, 'custom_config', _('Custom Configurations'), _('Configurations here override settings in the previous tabs with the following rules: <ol><li>Object values will be replaced recursively so settings in previous tabs matters.</li><li>Arrays will be replaced entirely instead of being merged.</li><li>Tag <code>tag</code> is ignored. </li></ol>Override rules here may be changed later. Use this only for experimental or pre-release features.'))
o.modalonly = true
o.monospace = true
o.rows = 10
o.validate = validate_object;
s.tab('proxy', _('Proxy Settings'));
o = s.taboption('proxy', form.Value, 'tproxy_port_tcp', _('Transparent Proxy Port (TCP)'))
o.datatype = 'port'
o.default = 1080
o = s.taboption('proxy', form.Value, 'tproxy_port_udp', _('Transparent Proxy Port (UDP)'))
o.datatype = 'port'
o.default = 1081
o = s.taboption('proxy', form.Value, 'socks_port', _('Socks5 Proxy Port'))
o.datatype = 'port'
o.default = 1082
o = s.taboption('proxy', form.Value, 'http_port', _('HTTP Proxy Port'))
o.datatype = 'port'
o.default = 1083
o = s.taboption('proxy', form.DynamicList, 'uids_direct', _('Skip Proxy for uids'), _("Processes started by users with these uids won't be forwarded through Xray."))
o.datatype = "integer"
o = s.taboption('proxy', form.DynamicList, 'gids_direct', _('Skip Proxy for gids'), _("Processes started by users in groups with these gids won't be forwarded through Xray."))
o.datatype = "integer"
o = s.taboption('proxy', widgets.DeviceSelect, 'lan_ifaces', _("LAN Interface"))
o.noaliases = true
o.rmempty = false
o.nocreate = true
o = s.taboption('proxy', form.SectionValue, "access_control_lan_hosts", form.TableSection, 'lan_hosts', _('LAN Hosts Access Control'), _("Will not enable transparent proxy for these MAC addresses."))
ss = o.subsection;
ss.sortable = false
ss.anonymous = true
ss.addremove = true
o = ss.option(form.Value, "macaddr", _("MAC Address"))
L.sortedKeys(load_result[2].hosts).forEach(function (mac) {
o.value(mac, E([], [mac, ' (', E('strong', [load_result[2].hosts[mac].name || L.toArray(load_result[2].hosts[mac].ipaddrs || load_result[2].hosts[mac].ipv4)[0] || L.toArray(load_result[2].hosts[mac].ip6addrs || load_result[2].hosts[mac].ipv6)[0] || '?']), ')']));
});
o.datatype = "macaddr"
o.rmempty = false
o = ss.option(form.ListValue, "bypassed", _("Access Control Strategy"))
o.value("0", "Always forwarded")
o.value("1", "Always bypassed")
o.rmempty = false
s.tab('dns', _('DNS Settings'));
o = s.taboption('dns', form.Value, 'fast_dns', _('Fast DNS'), _("DNS for resolving outbound domains and following bypassed domains"))
o.datatype = 'or(ip4addr, ip4addrport)'
o.placeholder = "114.114.114.114"
if (geosite_existence) {
o = s.taboption('dns', form.DynamicList, "bypassed_domain_rules", _('Bypassed domain rules'), _('Specify rules like <code>geosite:cn</code> or <code>domain:bilibili.com</code>. See <a href="https://xtls.github.io/config/dns.html#dnsobject">documentation</a> for details.'))
} else {
o = s.taboption('dns', form.DynamicList, 'bypassed_domain_rules', _('Bypassed domain rules'), _('Specify rules like <code>domain:bilibili.com</code> or see <a href="https://xtls.github.io/config/dns.html#dnsobject">documentation</a> for details.<br/> In order to use Geosite rules you need a valid resource file /usr/share/xray/geosite.dat.<br/>Compile your firmware again with data files to use Geosite rules, or <a href="https://github.com/v2fly/domain-list-community">download one</a> and upload it to your router.'))
}
o.rmempty = true
o = s.taboption('dns', form.Value, 'secure_dns', _('Secure DNS'), _("DNS for resolving known polluted domains (specify forwarded domain rules here)"))
o.datatype = 'or(ip4addr, ip4addrport)'
o.placeholder = "1.1.1.1"
if (geosite_existence) {
o = s.taboption('dns', form.DynamicList, "forwarded_domain_rules", _('Forwarded domain rules'), _('Specify rules like <code>geosite:geolocation-!cn</code> or <code>domain:youtube.com</code>. See <a href="https://xtls.github.io/config/dns.html#dnsobject">documentation</a> for details.'))
} else {
o = s.taboption('dns', form.DynamicList, 'forwarded_domain_rules', _('Forwarded domain rules'), _('Specify rules like <code>domain:youtube.com</code> or see <a href="https://xtls.github.io/config/dns.html#dnsobject">documentation</a> for details.<br/> In order to use Geosite rules you need a valid resource file /usr/share/xray/geosite.dat.<br/>Compile your firmware again with data files to use Geosite rules, or <a href="https://github.com/v2fly/domain-list-community">download one</a> and upload it to your router.'))
}
o.rmempty = true
o = s.taboption('dns', form.Value, 'default_dns', _('Default DNS'), _("DNS for resolving other sites (not in the rules above) and DNS records other than A or AAAA (TXT and MX for example)"))
o.datatype = 'or(ip4addr, ip4addrport)'
o.placeholder = "8.8.8.8"
if (geosite_existence) {
o = s.taboption('dns', form.DynamicList, "blocked_domain_rules", _('Blocked domain rules'), _('Specify rules like <code>geosite:category-ads</code> or <code>domain:baidu.com</code>. See <a href="https://xtls.github.io/config/dns.html#dnsobject">documentation</a> for details.'))
} else {
o = s.taboption('dns', form.DynamicList, 'blocked_domain_rules', _('Blocked domain rules'), _('Specify rules like <code>domain:baidu.com</code> or see <a href="https://xtls.github.io/config/dns.html#dnsobject">documentation</a> for details.<br/> In order to use Geosite rules you need a valid resource file /usr/share/xray/geosite.dat.<br/>Compile your firmware again with data files to use Geosite rules, or <a href="https://github.com/v2fly/domain-list-community">download one</a> and upload it to your router.'))
}
o.rmempty = true
o = s.taboption('dns', form.Value, 'dns_port', _('Xray DNS Server Port'), _("Do not use port 53 (dnsmasq), port 5353 (mDNS) or other common ports"))
o.datatype = 'port'
o.default = 5300
o = s.taboption('dns', form.Value, 'dns_count', _('Extra DNS Server Ports'), _('Listen for DNS Requests on multiple ports (all of which serves as dnsmasq upstream servers).<br/>For example if Xray DNS Server Port is 5300 and use 3 extra ports, 5300 - 5303 will be used for DNS requests.<br/>Increasing this value may help reduce the possibility of temporary DNS lookup failures.'))
o.datatype = 'range(0, 50)'
o.default = 0
s.tab('transparent_proxy_rules', _('Transparent Proxy Rules'));
if (geoip_direct_code === "upgrade" || geoip_direct_code === void 0) {
if (geoip_existence) {
o = s.taboption('transparent_proxy_rules', form.DynamicList, 'geoip_direct_code_list', _('GeoIP Direct Code List'), _("Hosts in these GeoIP sets will not be forwarded through Xray. Remove all items to forward all non-private hosts."))
} else {
o = s.taboption('transparent_proxy_rules', form.DynamicList, 'geoip_direct_code_list', _('GeoIP Direct Code List'), _("Resource file /usr/share/xray/geoip.dat not exist. All network traffic will be forwarded. <br/> Compile your firmware again with data files to use this feature, or<br/><a href=\"https://github.com/v2fly/geoip\">download one</a> (maybe disable transparent proxy first) and upload it to your router."))
o.readonly = true
}
} else {
if (geoip_existence) {
o = s.taboption('transparent_proxy_rules', form.Value, 'geoip_direct_code', _('GeoIP Direct Code'), _("Hosts in this GeoIP set will not be forwarded through Xray. <br/> Switching to new format (by selecting 'Unspecified') is recommended for multiple GeoIP options here, <br/> and is required if you want to forward all non-private hosts. This legacy option will be removed later."))
} else {
o = s.taboption('transparent_proxy_rules', form.Value, 'geoip_direct_code', _('GeoIP Direct Code'), _("Resource file /usr/share/xray/geoip.dat not exist. All network traffic will be forwarded. <br/> Compile your firmware again with data files to use this feature, or<br/><a href=\"https://github.com/v2fly/geoip\">download one</a> (maybe disable transparent proxy first) and upload it to your router."))
o.readonly = true
}
}
o.value("cn", "cn")
o.value("telegram", "telegram")
o.datatype = "string"
o = s.taboption('transparent_proxy_rules', form.ListValue, 'routing_domain_strategy', _('Routing Domain Strategy'), _("Domain resolution strategy when matching domain against rules."))
o.value("AsIs", "AsIs")
o.value("IPIfNonMatch", "IPIfNonMatch")
o.value("IPOnDemand", "IPOnDemand")
o.default = "AsIs"
o.rmempty = false
o = s.taboption('transparent_proxy_rules', form.Value, 'mark', _('Socket Mark Number'), _('Avoid proxy loopback problems with local (gateway) traffic'))
o.datatype = 'range(1, 255)'
o.default = 255
o = s.taboption('transparent_proxy_rules', form.DynamicList, "wan_bp_ips", _("Bypassed IP"), _("Requests to these IPs won't be forwarded through Xray."))
o.datatype = "ip4addr"
o.rmempty = true
o = s.taboption('transparent_proxy_rules', form.DynamicList, "wan_fw_ips", _("Forwarded IP"))
o.datatype = "ip4addr"
o.rmempty = true
o = s.taboption('transparent_proxy_rules', form.SectionValue, "access_control_manual_tproxy", form.GridSection, 'manual_tproxy', _('Manual Transparent Proxy'), _('Compared to iptables REDIRECT, Xray could do NAT46 / NAT64 (for example accessing IPv6 only sites). See <a href="https://github.com/v2ray/v2ray-core/issues/2233">FakeDNS</a> for details.'))
ss = o.subsection;
ss.sortable = false
ss.anonymous = true
ss.addremove = true
o = ss.option(form.Value, "source_addr", _("Source Address"))
o.datatype = "ipaddr"
o.rmempty = true
o = ss.option(form.Value, "source_port", _("Source Port"))
o.rmempty = true
o = ss.option(form.Value, "dest_addr", _("Destination Address"))
o.datatype = "host"
o.rmempty = true
o = ss.option(form.Value, "dest_port", _("Destination Port"))
o.datatype = "port"
o.rmempty = true
o = ss.option(form.ListValue, 'domain_strategy', _('Domain Strategy'))
o.value("UseIP")
o.value("UseIPv4")
o.value("UseIPv6")
o.default = "UseIP"
o.modalonly = true
o = ss.option(form.Flag, 'force_forward', _('Force Forward'), _('This destination must be forwarded through an outbound server.'))
o.modalonly = true
o = ss.option(form.ListValue, 'force_forward_server_tcp', _('Force Forward server (TCP)'))
o.depends("force_forward", "1")
o.datatype = "uciname"
for (const v of uci.sections(config_data, "servers")) {
o.value(v[".name"], v.alias || v.server + ":" + v.server_port)
}
o.modalonly = true
o = ss.option(form.ListValue, 'force_forward_server_udp', _('Force Forward server (UDP)'))
o.depends("force_forward", "1")
o.datatype = "uciname"
for (const v of uci.sections(config_data, "servers")) {
o.value(v[".name"], v.alias || v.server + ":" + v.server_port)
}
o.modalonly = true
s.tab('xray_server', _('HTTPS Server'));
o = s.taboption('xray_server', form.Flag, 'web_server_enable', _('Enable Xray HTTPS Server'), _("This will start a HTTPS server which serves both as an inbound for Xray and a reverse proxy web server."));
o = s.taboption('xray_server', form.Value, 'web_server_port', _('Xray HTTPS Server Port'), _("This port needs to be set <code>accept input</code> manually in firewall settings."))
o.datatype = 'port'
o.default = 443
o.depends("web_server_enable", "1")
o = s.taboption('xray_server', form.ListValue, "web_server_protocol", _("Protocol"), _("Only protocols which support fallback are available. Note that REALITY does not support fallback right now."));
o.value("vless", "VLESS")
o.value("trojan", "Trojan")
o.rmempty = false
o.depends("web_server_enable", "1")
add_flow_and_stream_security_conf(s, "xray_server", "web_server_protocol", "vless", true, false)
add_flow_and_stream_security_conf(s, "xray_server", "web_server_protocol", "trojan", false, false)
o = s.taboption('xray_server', form.Value, 'web_server_password', _('UserId / Password'), _('Fill user_id for vmess / VLESS, or password for shadowsocks / trojan (also supports <a href="https://github.com/XTLS/Xray-core/issues/158">Xray UUID Mapping</a>)'))
o.depends("web_server_enable", "1")
o = s.taboption('xray_server', form.Value, 'web_server_address', _('Default Fallback HTTP Server'), _("Only HTTP/1.1 supported here. For HTTP/2 upstream, use Fallback Servers below"))
o.datatype = 'hostport'
o.depends("web_server_enable", "1")
o = s.taboption('xray_server', form.SectionValue, "xray_server_fallback", form.GridSection, 'fallback', _('Fallback Servers'), _("Specify upstream servers here."))
o.depends({"web_server_enable": "1", "web_server_protocol": "trojan"})
o.depends({"web_server_enable": "1", "web_server_protocol": "vless", "vless_tls": "tls"})
o.depends({"web_server_enable": "1", "web_server_protocol": "vless", "vless_tls": "xtls"})
ss = o.subsection;
ss.sortable = false
ss.anonymous = true
ss.addremove = true
o = ss.option(form.Value, "name", _("SNI"))
o.rmempty = true
o = ss.option(form.Value, "alpn", _("ALPN"))
o.rmempty = true
o = ss.option(form.Value, "path", _("Path"))
o.rmempty = true
o = ss.option(form.Value, "xver", _("Xver"))
o.datatype = "uinteger"
o.rmempty = true
o = ss.option(form.Value, "dest", _("Destination Address"))
o.datatype = 'hostport'
o.rmempty = true
s.tab('extra_options', _('Extra Options'))
o = s.taboption('extra_options', form.ListValue, 'loglevel', _('Log Level'), _('Read Xray log in "System Log" or use <code>logread</code> command.'))
o.value("debug")
o.value("info")
o.value("warning")
o.value("error")
o.value("none")
o.default = "warning"
o = s.taboption('extra_options', form.Flag, 'access_log', _('Enable Access Log'), _('Access log will also be written to System Log.'))
o = s.taboption('extra_options', form.Flag, 'dns_log', _('Enable DNS Log'), _('DNS log will also be written to System Log.'))
o = s.taboption('extra_options', form.Flag, 'xray_api', _('Enable Xray API Service'), _('Xray API Service uses port 8080 and GRPC protocol. Also callable via <code>xray api</code> or <code>ubus call xray</code>. See <a href="https://xtls.github.io/document/command.html#xray-api">here</a> for help.'))
o = s.taboption('extra_options', form.Flag, 'stats', _('Enable Statistics'), _('Enable statistics of inbounds / outbounds data. Use Xray API to query values.'))
o = s.taboption('extra_options', form.Flag, 'observatory', _('Enable Observatory'), _('Enable latency measurement for TCP and UDP outbounds. Support for balancers and strategy will be added later.'))
o = s.taboption('extra_options', form.Flag, 'metrics_server_enable', _('Enable Xray Metrics Server'), _("Enable built-in metrics server for pprof and expvar. See <a href='https://github.com/XTLS/Xray-core/pull/1000'>here</a> for details."));
o = s.taboption('extra_options', form.Value, 'metrics_server_port', _('Xray Metrics Server Port'), _("Metrics may be sensitive so think twice before setting it as Default Fallback HTTP Server."))
o.depends("metrics_server_enable", "1")
o.datatype = 'port'
o.placeholder = '18888'
o = s.taboption('extra_options', form.Value, 'handshake', _('Handshake Timeout'), _('Policy: Handshake timeout when connecting to upstream. See <a href="https://xtls.github.io/config/policy.html#levelpolicyobject">here</a> for help.'))
o.datatype = 'uinteger'
o.placeholder = 4
o.default = 4
o = s.taboption('extra_options', form.Value, 'conn_idle', _('Connection Idle Timeout'), _('Policy: Close connection if no data is transferred within given timeout. See <a href="https://xtls.github.io/config/policy.html#levelpolicyobject">here</a> for help.'))
o.datatype = 'uinteger'
o.placeholder = 300
o.default = 300
o = s.taboption('extra_options', form.Value, 'uplink_only', _('Uplink Only Timeout'), _('Policy: How long to wait before closing connection after server closed connection. See <a href="https://xtls.github.io/config/policy.html#levelpolicyobject">here</a> for help.'))
o.datatype = 'uinteger'
o.placeholder = 2
o.default = 2
o = s.taboption('extra_options', form.Value, 'downlink_only', _('Downlink Only Timeout'), _('Policy: How long to wait before closing connection after client closed connection. See <a href="https://xtls.github.io/config/policy.html#levelpolicyobject">here</a> for help.'))
o.datatype = 'uinteger'
o.placeholder = 5
o.default = 5
o = s.taboption('extra_options', form.Value, 'buffer_size', _('Buffer Size'), _('Policy: Internal cache size per connection. See <a href="https://xtls.github.io/config/policy.html#levelpolicyobject">here</a> for help.'))
o.datatype = 'uinteger'
o.placeholder = 512
o.default = 512
o = s.taboption('extra_options', form.SectionValue, "xray_bridge", form.TableSection, 'bridge', _('Bridge'), _('Reverse proxy tool. Currently only client role (bridge) is supported. See <a href="https://xtls.github.io/config/reverse.html#bridgeobject">here</a> for help.'))
ss = o.subsection;
ss.sortable = false
ss.anonymous = true
ss.addremove = true
o = ss.option(form.ListValue, "upstream", _("Upstream"))
o.datatype = "uciname"
for (const v of uci.sections(config_data, "servers")) {
o.value(v[".name"], v.alias || v.server + ":" + v.server_port)
}
o = ss.option(form.Value, "domain", _("Domain"))
o.rmempty = false
o = ss.option(form.Value, "redirect", _("Redirect address"))
o.datatype = "hostport"
o.rmempty = false
// if (Object.keys(optional_features).length > 0) {
// s.tab('optional_features', _('Optional Features'), _("Warning: all settings on this page are experimental, not guaranteed to be stable, and quite likely to be changed very frequently. Use at your own risk."))
// }
s.tab('custom_options', _('Custom Options'))
o = s.taboption('custom_options', form.TextValue, 'custom_config', _('Custom Configurations'), _('Check <code>/var/etc/xray/config.json</code> for tags of generated inbounds and outbounds. See <a href="https://xtls.github.io/config/features/multiple.html">here</a> for help'))
o.monospace = true
o.rows = 10
o.validate = validate_object
return m.render();
}
});

View File

@ -1,16 +0,0 @@
#!/bin/sh
uci get xray.@general[-1] >/dev/null 2>&1 || uci add xray general >/dev/null 2>&1
uci commit xray
uci -q batch <<-EOF >/dev/null
delete ucitrack.@xray[-1]
add ucitrack xray
set ucitrack.@xray[-1].init=xray
commit ucitrack
delete firewall.xray
set firewall.xray=include
set firewall.xray.type=script
set firewall.xray.path=/var/etc/xray.include
set firewall.xray.reload=1
commit firewall
EOF
exit 0

View File

@ -1,31 +0,0 @@
FIREWALL_INCLUDE="/usr/share/xray/firewall_include.lua"
setup_firewall() {
logger -st xray[$$] -p4 "Setting ipset rules..."
lua /usr/share/xray/gen_ipset_rules.lua | ipset -! restore
/etc/hotplug.d/iface/01-transparent-proxy-ipset
logger -st xray[$$] -p4 "Generating firewall rules..."
/usr/bin/lua ${FIREWALL_INCLUDE} enable > $(uci get firewall.xray.path)
logger -st xray[$$] -p4 "Triggering firewall restart..."
/etc/init.d/firewall restart > /dev/null 2>&1
}
flush_firewall() {
logger -st xray[$$] -p4 "Flushing firewall rules..."
/usr/bin/lua ${FIREWALL_INCLUDE} flush > $(uci get firewall.xray.path)
logger -st xray[$$] -p4 "Triggering firewall restart..."
/etc/init.d/firewall restart > /dev/null 2>&1
logger -st xray[$$] -p4 "Flushing ipset rules..."
for setname in $(ipset -n list | grep "tp_spec"); do
ipset -! destroy $setname
done
/etc/hotplug.d/iface/01-transparent-proxy-ipset
}
impl_gen_config_file() {
/usr/bin/lua /usr/share/xray/gen_config.lua > /var/etc/xray/config.json
}

View File

@ -1,33 +0,0 @@
FIREWALL_INCLUDE="/usr/share/xray/firewall_include.ut"
setup_firewall() {
ip rule add fwmark 251 lookup 251
ip rule add fwmark 252 lookup 252
ip route add local default dev lo table 251
ip route add local default dev lo table 252
logger -st xray[$$] -p4 "Generating firewall4 rules..."
/usr/bin/utpl ${FIREWALL_INCLUDE} > /var/etc/xray/firewall_include.nft
logger -st xray[$$] -p4 "Triggering firewall4 restart..."
/etc/init.d/firewall restart
/etc/hotplug.d/iface/01-transparent-proxy-ipset
}
flush_firewall() {
ip rule del fwmark 251 lookup 251
ip rule del fwmark 252 lookup 252
ip route del local default dev lo table 251
ip route del local default dev lo table 252
logger -st xray[$$] -p4 "Flushing firewall4 rules..."
rm -f /var/etc/xray/firewall_include.nft
logger -st xray[$$] -p4 "Triggering firewall4 restart..."
/etc/init.d/firewall restart
/etc/hotplug.d/iface/01-transparent-proxy-ipset
}
impl_gen_config_file() {
/usr/bin/ucode /usr/share/xray/gen_config.uc > /var/etc/xray/config.json
}

View File

@ -0,0 +1,98 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-xray-shared
PKG_VERSION:=2.0.0
PKG_RELEASE:=1
PKG_LICENSE:=MPLv2
PKG_LICENSE_FILES:=LICENSE
PKG_MAINTAINER:=yichya <mail@yichya.dev>
PKG_BUILD_PARALLEL:=1
include $(INCLUDE_DIR)/package.mk
define Package/$(PKG_NAME)
SECTION:=Custom
CATEGORY:=Extra packages
TITLE:=LuCI Support for Xray (Shared Components)
DEPENDS:=+luci-base +xray-core +dnsmasq +ca-bundle
PKGARCH:=all
endef
define Package/$(PKG_NAME)/description
LuCI Support for Xray (Client-side Rendered) (Shared Components).
endef
define Package/$(PKG_NAME)/config
menu "luci-app-xray Configuration"
depends on PACKAGE_$(PKG_NAME)
config PACKAGE_XRAY_INCLUDE_CLOUDFLARE_ORIGIN_ROOT_CA
bool "Include Cloudflare Origin Root CA"
default n
config PACKAGE_XRAY_INFINITE_RETRY_ON_STARTUP
bool "Retry infinitely on Xray startup (may solve some startup problems)"
default n
config PACKAGE_XRAY_RLIMIT_NOFILE_LARGE
bool "Increase Max Open Files Limit (recommended)"
default y
config PACKAGE_XRAY_RESTART_DNSMASQ_ON_IFACE_CHANGE
bool "Restart dnsmasq on interface change (select this if using dnsmasq v2.87)"
default n
config PACKAGE_XRAY_IGNORE_TP_SPEC_DEF_GW
bool "Ignore TP_SPEC_DEF_GW (select this if using private IPv4 address)"
default n
choice
prompt "Limit memory use by setting rlimit_data (experimental)"
default PACKAGE_XRAY_RLIMIT_DATA_UNLIMITED
config PACKAGE_XRAY_RLIMIT_DATA_UNLIMITED
bool "Not limited"
config PACKAGE_XRAY_RLIMIT_DATA_SMALL
bool "Small limit (about 50MB)"
config PACKAGE_XRAY_RLIMIT_DATA_LARGE
bool "Large limit (about 321MB)"
endchoice
endmenu
endef
define Build/Compile
endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/etc/luci-uploads/xray
$(INSTALL_DIR) $(1)/etc/ssl/certs
ifdef CONFIG_PACKAGE_XRAY_INCLUDE_CLOUDFLARE_ORIGIN_ROOT_CA
$(INSTALL_DATA) ./root/etc/ssl/certs/origin_ca_ecc_root.pem $(1)/etc/ssl/certs/origin_ca_ecc_root.pem
endif
$(INSTALL_DIR) $(1)/usr/share/xray
$(LN) /var/run/xray.pid $(1)/usr/share/xray/xray.pid
$(LN) /usr/bin/xray $(1)/usr/share/xray/xray
ifdef CONFIG_PACKAGE_XRAY_IGNORE_TP_SPEC_DEF_GW
$(INSTALL_DATA) ./root/usr/share/xray/ignore_tp_spec_def_gw $(1)/usr/share/xray/ignore_tp_spec_def_gw
endif
ifdef CONFIG_PACKAGE_XRAY_RESTART_DNSMASQ_ON_IFACE_CHANGE
$(INSTALL_DATA) ./root/usr/share/xray/restart_dnsmasq_on_iface_change $(1)/usr/share/xray/restart_dnsmasq_on_iface_change
endif
ifdef CONFIG_PACKAGE_XRAY_INFINITE_RETRY_ON_STARTUP
$(INSTALL_DATA) ./root/usr/share/xray/infinite_retry $(1)/usr/share/xray/infinite_retry
endif
ifdef CONFIG_PACKAGE_XRAY_RLIMIT_NOFILE_LARGE
$(INSTALL_DATA) ./root/usr/share/xray/rlimit_nofile_large $(1)/usr/share/xray/rlimit_nofile
endif
ifdef CONFIG_PACKAGE_XRAY_RLIMIT_DATA_SMALL
$(INSTALL_DATA) ./root/usr/share/xray/rlimit_data_small $(1)/usr/share/xray/rlimit_data
endif
ifdef CONFIG_PACKAGE_XRAY_RLIMIT_DATA_LARGE
$(INSTALL_DATA) ./root/usr/share/xray/rlimit_data_large $(1)/usr/share/xray/rlimit_data
endif
$(INSTALL_DIR) $(1)/usr/libexec/rpcd
$(INSTALL_BIN) ./root/usr/libexec/rpcd/xray $(1)/usr/libexec/rpcd/xray
endef
$(eval $(call BuildPackage,$(PKG_NAME)))

View File

@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
LUCI_TITLE:=Design Theme
LUCI_DEPENDS:=
PKG_VERSION:=5.7.2-20230416
PKG_VERSION:=5.7.4-20230417
include $(TOPDIR)/feeds/luci/luci.mk

View File

@ -42,10 +42,11 @@ luci-theme-design 是一个针对移动端和PC端的沉浸式WebApp体验和优
### 主要特点
- 适配移动端响应式优化适合手机端做为WebApp使用
- 修改和优化了很多插件显示完善的icon图标尽量视觉统一
- 修改和优化了很多插件显示,完善的设备icon图标尽量视觉统一
- 简洁的登录界面底部导航栏类App的沉浸式体验
- 适配深色模式,适配系统自动切换,支持自定义模式
- 适配openwrt 21/22、lede
- 支持插件式配置主题
### 体验WebApp方法

View File

@ -221,14 +221,6 @@
$("header>.container>.brand").css("padding", '0rem')
}
});
/**
* fix legend position
*/
$("legend").each(function () {
var that = $(this);
that.after("<span class='panel-title'>" + that.text() + "</span>");
});
$(".main-right").focus();
$(".main-right").blur();

View File

@ -130,8 +130,8 @@
}
*::-webkit-scrollbar {
width: 4px;
height: 4px;
width: 5px;
height: 5px;
}
*::-webkit-scrollbar-thumb {
background: var(--scrollbarColor) ;
@ -1684,7 +1684,7 @@ fieldset > table > tbody > tr:nth-of-type(odd) {
}
/* fix status overview */
.node-status-overview > .main fieldset:nth-child(4) td:nth-child(2),
.node-status-overview > .main fieldset:nth-child(6) td:nth-child(2),
.node-status-overview table[id="wifi_status_table"] > tbody > tr > td {
white-space: normal;
}
@ -1825,6 +1825,9 @@ div [id*="cbi-wireless"] [id*="-__status"] table td small {
.node-network-wifi .cbi-section-table .cbi-section-table-row td[colspan="8"] {
text-align: center !important;
}
.node-network-wireless #iw-assoclist .cbi-section-table-row td div {
max-width: unset !important;
}
.node-network-wifi table, td, th {
border-top: unset !important;
}

File diff suppressed because one or more lines are too long

View File

@ -16,4 +16,4 @@ showSide=false;}});$(window).resize(function(){if($(window).width()>992){showSid
$("header>.container>.brand").css("padding",'0rem')}else{$("header").css("box-shadow","0 2px 4px rgb(0 0 0 / 8%)")
$("header>.container>.brand").css("padding","0 4.5rem")}
if(showSide){$("header").css("box-shadow","18rem 2px 4px rgb(0 0 0 / 8%)")
$("header>.container>.brand").css("padding",'0rem')}});$("legend").each(function(){var that=$(this);that.after("<span class='panel-title'>"+that.text()+"</span>");});$(".main-right").focus();$(".main-right").blur();$("input").attr("size","0");if(mainNodeName!=undefined){switch(mainNodeName){case "node-status-system_log":case "node-status-kernel_log":$("#syslog").focus(function(){$("#syslog").blur();$(".main-right").focus();$(".main-right").blur();});break;case "node-status-firewall":var button=$(".node-status-firewall > .main fieldset li > a");button.addClass("cbi-button cbi-button-reset a-to-btn");break;case "node-system-reboot":var button=$(".node-system-reboot > .main > .main-right p > a");button.addClass("cbi-button cbi-input-reset a-to-btn");break;}}})(jQuery);
$("header>.container>.brand").css("padding",'0rem')}});$(".main-right").focus();$(".main-right").blur();$("input").attr("size","0");if(mainNodeName!=undefined){switch(mainNodeName){case "node-status-system_log":case "node-status-kernel_log":$("#syslog").focus(function(){$("#syslog").blur();$(".main-right").focus();$(".main-right").blur();});break;case "node-status-firewall":var button=$(".node-status-firewall > .main fieldset li > a");button.addClass("cbi-button cbi-button-reset a-to-btn");break;case "node-system-reboot":var button=$(".node-system-reboot > .main > .main-right p > a");button.addClass("cbi-button cbi-input-reset a-to-btn");break;}}})(jQuery);

View File

@ -50,8 +50,11 @@
</div>
<script>
// thanks for Jo-Philipp Wich <jow@openwrt.org>
var luciLocation = <%= luci.http.write_json(luci.dispatcher.context.path) %>;
// fix legend position
$("legend").each(function () {
var that = $(this);
that.after("<span class='panel-title'>" + that.text() + "</span>");
});
// Fixed openclash plugin causing env(safe-area-inset-bottom) to be 0 under
if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent) && self.location.pathname.indexOf("openclash") != -1) {
var oMeta = document.createElement('meta');
@ -60,6 +63,5 @@
document.querySelector('head').appendChild(oMeta);
}
</script>
<script src="<%=media%>/js/script.js?v=<%= ver.luciversion %>"></script>
</body>
</html>

View File

@ -314,4 +314,10 @@
<a href="<%=pcdata(luci.dispatcher.build_url("admin/system/admin"))%>"><%:Go to password configuration...%></a>
</div>
<%- end -%>
<% if category then subtree("/" .. category .. "/", cattree) end %>
<% if category then subtree("/" .. category .. "/", cattree) end %>
<script>
// thanks for Jo-Philipp Wich <jow@openwrt.org>
var luciLocation = <%= luci.http.write_json(luci.dispatcher.context.path) %>;
</script>
<script src="<%=media%>/js/script.js?v=<%= ver.luciversion %>"></script>

View File

@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=unishare
PKG_VERSION:=1.0.1
PKG_RELEASE:=1
PKG_RELEASE:=2
PKG_MAINTAINER:=jjm2473 <jjm2473@gmail.com>
include $(INCLUDE_DIR)/package.mk

View File

@ -2,40 +2,3 @@ config global
option enabled '0'
option anonymous '1'
option webdav_port '8888'
config user
option username 'admin'
option password 'password'
config user
option username 'jim'
option password 'abcdef'
config share
option path '/mnt'
option name 'mnt'
list rw 'admin'
list proto 'samba'
config share
option path '/root/share'
option name 'public'
list rw 'admin'
list ro 'everyone'
list proto 'samba'
list proto 'webdav'
config share
option path '/root/work'
list rw 'admin'
list rw 'tim'
list ro 'users'
list proto 'samba'
config share
option path '/root/share'
option name 'www'
list ro 'everyone'
list proto 'samba'
list proto 'webdav'