From 0f3b9d25164703cd5bcab1503a0002a03122af79 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 14 Jul 2026 04:31:14 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=8C=B4=20Sync=202026-07-14=2004:31:14?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dae/Makefile | 4 +- daed/Makefile | 4 +- hysteria/Makefile | 4 +- internet-detector/Makefile | 13 +- luci-app-daede/Makefile | 2 +- .../usr/share/luci-app-daede/update-pkg.sh | 23 +- .../htdocs/luci-static/resources/fchomo.js | 6 +- .../luci-static/resources/fchomo/listeners.js | 245 +++++----- .../luci-static/resources/view/fchomo/node.js | 440 +++++++++--------- luci-app-fchomo/po/templates/fchomo.pot | 4 +- luci-app-fchomo/po/zh_Hans/fchomo.po | 8 +- luci-app-fchomo/po/zh_Hant/fchomo.po | 8 +- .../root/usr/share/fchomo/generate_client.uc | 102 ++-- .../root/usr/share/ucode/fchomo.uc | 76 +-- luci-app-passwall/Makefile | 2 +- .../luasrc/controller/passwall.lua | 6 + .../model/cbi/passwall/client/app_update.lua | 14 +- .../passwall/client/node_subscribe_config.lua | 48 +- .../model/cbi/passwall/client/other.lua | 17 +- .../luasrc/model/cbi/passwall/client/rule.lua | 48 +- .../model/cbi/passwall/client/type/ray.lua | 7 +- .../cbi/passwall/client/type/sing-box.lua | 7 +- luci-app-passwall/luasrc/passwall/api.lua | 46 +- .../luasrc/passwall/util_xray.lua | 8 +- .../view/passwall/app_update/app_version.htm | 34 +- luci-app-passwall/po/zh-cn/passwall.po | 37 +- .../root/usr/share/passwall/0_default_config | 13 +- .../root/usr/share/passwall/app.sh | 121 ++--- .../root/usr/share/passwall/iptables.sh | 76 +-- .../root/usr/share/passwall/nftables.sh | 87 ++-- .../root/usr/share/passwall/tasks.sh | 49 +- .../root/usr/share/passwall/utils.sh | 30 +- luci-app-passwall2/Makefile | 2 +- .../model/cbi/passwall2/client/type/ray.lua | 4 +- .../cbi/passwall2/client/type/sing-box.lua | 4 +- luci-app-passwall2/luasrc/passwall2/api.lua | 34 +- luci-app-passwall2/po/fa/passwall2.po | 8 +- luci-app-passwall2/po/ru/passwall2.po | 8 +- luci-app-passwall2/po/zh-cn/passwall2.po | 8 +- luci-app-passwall2/po/zh-tw/passwall2.po | 8 +- .../root/usr/share/passwall2/nftables.sh | 15 +- .../resources/view/network/wireless.js | 13 +- mptcp/Makefile | 2 +- mptcp/files/etc/init.d/mptcp | 6 + natflow/Makefile | 4 +- nps/Makefile | 4 +- torrserver/Makefile | 6 +- 47 files changed, 926 insertions(+), 789 deletions(-) diff --git a/dae/Makefile b/dae/Makefile index 19fba202..5c6274a1 100644 --- a/dae/Makefile +++ b/dae/Makefile @@ -6,9 +6,9 @@ include $(TOPDIR)/rules.mk PKG_NAME:=dae PKG_VERSION:=2026.07.08 -PKG_RELEASE:=15 +PKG_RELEASE:=16 -PKG_SOURCE:=dae-src-2026.07.08-ca25ef2aa396.tar.gz +PKG_SOURCE:=dae-src-2026.07.08-6a60ae809f8b.tar.gz PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/dae-src PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_HASH:=skip diff --git a/daed/Makefile b/daed/Makefile index 36f5724a..a169dfc4 100644 --- a/daed/Makefile +++ b/daed/Makefile @@ -6,9 +6,9 @@ include $(TOPDIR)/rules.mk PKG_NAME:=daed PKG_VERSION:=2026.07.08 -PKG_RELEASE:=21 +PKG_RELEASE:=22 -PKG_SOURCE:=daed-src-2026.07.08-71b818ad193b.tar.gz +PKG_SOURCE:=daed-src-2026.07.08-e83da9ff800e.tar.gz PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/daed-src PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_HASH:=skip diff --git a/hysteria/Makefile b/hysteria/Makefile index af4a152c..f797108a 100644 --- a/hysteria/Makefile +++ b/hysteria/Makefile @@ -5,8 +5,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=hysteria -PKG_VERSION:=2.9.3 -PKG_RELEASE:=11 +PKG_VERSION:=2.10.0 +PKG_RELEASE:=12 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/apernet/hysteria/tar.gz/app/v$(PKG_VERSION)? diff --git a/internet-detector/Makefile b/internet-detector/Makefile index da821eb0..fc19d81c 100644 --- a/internet-detector/Makefile +++ b/internet-detector/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=internet-detector PKG_VERSION:=1.7.3 -PKG_RELEASE:=3 +PKG_RELEASE:=4 PKG_MAINTAINER:=gSpot include $(INCLUDE_DIR)/package.mk @@ -64,4 +64,15 @@ define Package/$(PKG_NAME)/install $(INSTALL_DATA) ./files/usr/lib/lua/internet-detector/modules/mod_regular_script.lua $(1)/usr/lib/lua/internet-detector/modules/mod_regular_script.lua endef +define Package/$(PKG_NAME)/postinst +#!/bin/sh + +ID_CONF="/etc/internet-detector" +SYSUP_CONF="/etc/sysupgrade.conf" + +grep -e "^$${ID_CONF}" "$$SYSUP_CONF" > /dev/null || echo "$$ID_CONF" >> "$$SYSUP_CONF" + +exit 0 +endef + $(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/luci-app-daede/Makefile b/luci-app-daede/Makefile index 01d015a2..a96cee00 100644 --- a/luci-app-daede/Makefile +++ b/luci-app-daede/Makefile @@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-daede PKG_VERSION:=1.14.7 -PKG_RELEASE:=31 +PKG_RELEASE:=32 PKG_MAINTAINER:=kenzok8 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) diff --git a/luci-app-daede/root/usr/share/luci-app-daede/update-pkg.sh b/luci-app-daede/root/usr/share/luci-app-daede/update-pkg.sh index 615bb852..13d8ed19 100755 --- a/luci-app-daede/root/usr/share/luci-app-daede/update-pkg.sh +++ b/luci-app-daede/root/usr/share/luci-app-daede/update-pkg.sh @@ -52,19 +52,26 @@ fi ( flock 9 apk update 2>&1 - # pin exact latest version + --force-broken-world so unrelated broken - # packages can't block this upgrade (cf. clashoo component_update) ver=$(apk list "$PKG" 2>/dev/null | awk -v p="$PKG" '$1 ~ "^" p "-[0-9]" { v=$1; sub("^" p "-", "", v); print v }' | sort -V | tail -1) if [ -n "$ver" ]; then - echo "--- apk add $PKG=$ver ---" - apk add "$PKG=$ver" --force-broken-world 2>&1 + constraint="$PKG=$ver" else - echo "--- apk add $PKG ---" - apk add "$PKG" --force-broken-world 2>&1 + constraint="$PKG" + fi + + echo "--- apk add -s $constraint ---" + if apk add -s "$constraint" 2>&1; then + echo "--- apk add $constraint ---" + apk add "$constraint" 2>&1 + else + echo "result: apk cannot resolve $constraint; no packages were changed" + exit 1 fi ) 9>/tmp/luci-app-daede.apk.lock - # apk's exit code is unreliable (broken-world noise); judge by state instead - if ! apk list --installed 2>/dev/null | grep -q "^${PKG}-"; then + rc=$? + if [ "$rc" != 0 ]; then + : + elif ! apk list --installed 2>/dev/null | grep -q "^${PKG}-"; then echo "result: $PKG is not installed" rc=1 elif apk list -u 2>/dev/null | grep -q "^${PKG}-"; then diff --git a/luci-app-fchomo/htdocs/luci-static/resources/fchomo.js b/luci-app-fchomo/htdocs/luci-static/resources/fchomo.js index 7288d303..1638ce27 100644 --- a/luci-app-fchomo/htdocs/luci-static/resources/fchomo.js +++ b/luci-app-fchomo/htdocs/luci-static/resources/fchomo.js @@ -164,7 +164,7 @@ const inbound_type = [ ['anytls', _('AnyTLS') + ' - ' + _('TCP')], ['tuic', _('TUIC') + ' - ' + _('UDP')], ['hysteria2', _('Hysteria2') + ' - ' + _('UDP')], - ['hysteria2-realm', _('Hysteria2 Realm') + ' - ' + _('TCP/UDP')], + ['hysteria2-realm', _('Hysteria2 Realm Server') + ' - ' + _('TCP/UDP')], ['trusttunnel', _('TrustTunnel') + ' - ' + _('TCP/UDP')], ['tunnel', _('Tunnel') + ' - ' + _('TCP/UDP')] ]; @@ -198,12 +198,12 @@ const outbound_type = [ ['vless', _('VLESS') + ' - ' + _('TCP')], ['trojan', _('Trojan') + ' - ' + _('TCP')], ['anytls', _('AnyTLS') + ' - ' + _('TCP')], + ['tuic', _('TUIC') + ' - ' + _('UDP')], //['hysteria', _('Hysteria') + ' - ' + _('UDP')], ['hysteria2', _('Hysteria2') + ' - ' + _('UDP')], - ['tuic', _('TUIC') + ' - ' + _('UDP')], - ['masque', _('Masque') + ' - ' + _('UDP')], // https://blog.cloudflare.com/post-quantum-warp/ ['trusttunnel', _('TrustTunnel') + ' - ' + _('TCP/UDP')], ['wireguard', _('WireGuard') + ' - ' + _('UDP')], + ['masque', _('Masque') + ' - ' + _('UDP')], // https://blog.cloudflare.com/post-quantum-warp/ ['ssh', _('SSH') + ' - ' + _('TCP')] ]; diff --git a/luci-app-fchomo/htdocs/luci-static/resources/fchomo/listeners.js b/luci-app-fchomo/htdocs/luci-static/resources/fchomo/listeners.js index af030552..698b2587 100644 --- a/luci-app-fchomo/htdocs/luci-static/resources/fchomo/listeners.js +++ b/luci-app-fchomo/htdocs/luci-static/resources/fchomo/listeners.js @@ -171,86 +171,6 @@ function renderListeners(s, uciconfig, isClient) { o.depends({type: /^(tuic)$/, uuid: /.+/}); o.modalonly = true; - /* Hysteria2 fields */ - o = s.taboption('field_general', form.Value, 'hysteria_up_mbps', _('Max upload speed'), - _('In Mbps.')); - o.datatype = 'uinteger'; - o.depends('type', 'hysteria2'); - o.modalonly = true; - - o = s.taboption('field_general', form.Value, 'hysteria_down_mbps', _('Max download speed'), - _('In Mbps.')); - o.datatype = 'uinteger'; - o.depends('type', 'hysteria2'); - o.modalonly = true; - - o = s.taboption('field_general', form.Flag, 'hysteria_ignore_client_bandwidth', _('Ignore client bandwidth'), - _('Tell the client to use the BBR flow control algorithm instead of Hysteria CC.')); - o.default = o.disabled; - o.depends({type: 'hysteria2', hysteria_up_mbps: '', hysteria_down_mbps: ''}); - o.modalonly = true; - - o = s.taboption('field_general', form.ListValue, 'hysteria_obfs_type', _('Obfuscate type')); - o.value('', _('Disable')); - o.value('salamander', _('Salamander')); - o.value('gecko', _('Gecko')); - o.depends('type', 'hysteria2'); - o.modalonly = true; - - o = s.taboption('field_general', hm.GenValue, 'hysteria_obfs_password', _('Obfuscate password'), - _('Enabling obfuscation will make the server incompatible with standard QUIC connections, losing the ability to masquerade with HTTP/3.')); - o.password = true; - o.rmempty = false; - o.depends('type', 'hysteria'); - o.depends({type: 'hysteria2', hysteria_obfs_type: /.+/}); - o.modalonly = true; - - o = s.taboption('field_general', form.Value, 'hysteria_obfs_min_packet_size', _('Obfuscate minimum packet size')); - o.placeholder = '512' - o.depends('hysteria_obfs_type', 'gecko'); - o.modalonly = true; - - o = s.taboption('field_general', form.Value, 'hysteria_obfs_max_packet_size', _('Obfuscate maximum packet size')); - o.placeholder = '1200' - o.depends('hysteria_obfs_type', 'gecko'); - o.modalonly = true; - - o = s.taboption('field_general', form.Value, 'hysteria_masquerade', _('Masquerade'), - _('HTTP3 server behavior when authentication fails.
A 404 page will be returned if empty.')); - o.placeholder = 'file:///var/www or http://127.0.0.1:8080' - o.depends('type', 'hysteria2'); - o.modalonly = true; - - /* Hysteria2 Realmserver fields */ - o = s.taboption('field_general', form.Value, 'hysteria2_realmserver_token', _('Pre-shared key')); - o.placeholder = 'public'; - o.rmempty = false; - o.depends('type', 'hysteria2-realm'); - o.modalonly = true; - - o = s.taboption('field_general', form.Value, 'hysteria2_realmserver_max_realms', _('Max realms')); - o.datatype = 'uinteger'; - o.placeholder = '65536'; - o.depends('type', 'hysteria2-realm'); - o.modalonly = true; - - o = s.taboption('field_general', form.Value, 'hysteria2_realmserver_max_realms_per_ip', _('Max realms per client IP')); - o.datatype = 'uinteger'; - o.placeholder = '4'; - o.depends('type', 'hysteria2-realm'); - o.modalonly = true; - - o = s.taboption('field_general', form.Value, 'hysteria2_realmserver_trusted_proxy_header', _('Trusted proxy header'), - _('Header to read real client IP from (e.g. X-Forwarded-For)')); - o.depends('type', 'hysteria2-realm'); - o.modalonly = true; - - o = s.taboption('field_general', form.Value, 'hysteria2_realmserver_realm_name_pattern', _('Realm name pattern')); - o.default = '^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$'; - o.rmempty = false; - o.depends('type', 'hysteria2-realm'); - o.modalonly = true; - /* Shadowsocks fields */ o = s.taboption('field_general', form.ListValue, 'shadowsocks_chipher', _('Chipher')); o.default = hm.shadowsocks_cipher_methods[1][0]; @@ -470,31 +390,26 @@ function renderListeners(s, uciconfig, isClient) { o.depends('type', 'snell'); o.modalonly = true; - /* Tuic fields */ - o = s.taboption('field_general', hm.GenValue, 'uuid', _('UUID')); + /* VMess / VLESS fields */ + o = s.taboption('field_general', hm.GenValue, 'vmess_uuid', _('UUID')); o.rmempty = false; o.validate = hm.validateUUID; - o.depends('type', 'tuic'); + o.depends({type: /^(vmess|vless)$/}); o.modalonly = true; - o = s.taboption('field_general', form.Value, 'tuic_max_udp_relay_packet_size', _('Max UDP relay packet size')); + o = s.taboption('field_general', form.ListValue, 'vless_flow', _('Flow')); + o.default = hm.vless_flow[0][0]; + hm.vless_flow.forEach((res) => { + o.value.apply(o, res); + }) + o.depends('type', 'vless'); + o.modalonly = true; + + o = s.taboption('field_general', form.Value, 'vmess_alterid', _('Alter ID'), + _('Legacy protocol support (VMess MD5 Authentication) is provided for compatibility purposes only, use of alterId > 1 is not recommended.')); o.datatype = 'uinteger'; - o.default = '1500'; - o.depends('type', 'tuic'); - o.modalonly = true; - - o = s.taboption('field_general', form.Value, 'tuic_max_idle_time', _('Idle timeout'), - _('In seconds.')); - o.default = '15000'; - o.validate = hm.validateTimeDuration; - o.depends('type', 'tuic'); - o.modalonly = true; - - o = s.taboption('field_general', form.Value, 'tuic_authentication_timeout', _('Auth timeout'), - _('In seconds.')); - o.default = '1000'; - o.validate = hm.validateTimeDuration; - o.depends('type', 'tuic'); + o.placeholder = '0'; + o.depends('type', 'vmess'); o.modalonly = true; /* Trojan fields */ @@ -525,26 +440,111 @@ function renderListeners(s, uciconfig, isClient) { o.depends('type', 'anytls'); o.modalonly = true; - /* VMess / VLESS fields */ - o = s.taboption('field_general', hm.GenValue, 'vmess_uuid', _('UUID')); + /* Tuic fields */ + o = s.taboption('field_general', hm.GenValue, 'uuid', _('UUID')); o.rmempty = false; o.validate = hm.validateUUID; - o.depends({type: /^(vmess|vless)$/}); + o.depends('type', 'tuic'); o.modalonly = true; - o = s.taboption('field_general', form.ListValue, 'vless_flow', _('Flow')); - o.default = hm.vless_flow[0][0]; - hm.vless_flow.forEach((res) => { - o.value.apply(o, res); - }) - o.depends('type', 'vless'); - o.modalonly = true; - - o = s.taboption('field_general', form.Value, 'vmess_alterid', _('Alter ID'), - _('Legacy protocol support (VMess MD5 Authentication) is provided for compatibility purposes only, use of alterId > 1 is not recommended.')); + o = s.taboption('field_general', form.Value, 'tuic_max_udp_relay_packet_size', _('Max UDP relay packet size')); o.datatype = 'uinteger'; - o.placeholder = '0'; - o.depends('type', 'vmess'); + o.default = '1500'; + o.depends('type', 'tuic'); + o.modalonly = true; + + o = s.taboption('field_general', form.Value, 'tuic_max_idle_time', _('Idle timeout'), + _('In seconds.')); + o.default = '15000'; + o.validate = hm.validateTimeDuration; + o.depends('type', 'tuic'); + o.modalonly = true; + + o = s.taboption('field_general', form.Value, 'tuic_authentication_timeout', _('Auth timeout'), + _('In seconds.')); + o.default = '1000'; + o.validate = hm.validateTimeDuration; + o.depends('type', 'tuic'); + o.modalonly = true; + + /* Hysteria2 fields */ + o = s.taboption('field_general', form.Value, 'hysteria_up_mbps', _('Max upload speed'), + _('In Mbps.')); + o.datatype = 'uinteger'; + o.depends('type', 'hysteria2'); + o.modalonly = true; + + o = s.taboption('field_general', form.Value, 'hysteria_down_mbps', _('Max download speed'), + _('In Mbps.')); + o.datatype = 'uinteger'; + o.depends('type', 'hysteria2'); + o.modalonly = true; + + o = s.taboption('field_general', form.Flag, 'hysteria_ignore_client_bandwidth', _('Ignore client bandwidth'), + _('Tell the client to use the BBR flow control algorithm instead of Hysteria CC.')); + o.default = o.disabled; + o.depends({type: 'hysteria2', hysteria_up_mbps: '', hysteria_down_mbps: ''}); + o.modalonly = true; + + o = s.taboption('field_general', form.ListValue, 'hysteria_obfs_type', _('Obfuscate type')); + o.value('', _('Disable')); + o.value('salamander', _('Salamander')); + o.value('gecko', _('Gecko')); + o.depends('type', 'hysteria2'); + o.modalonly = true; + + o = s.taboption('field_general', hm.GenValue, 'hysteria_obfs_password', _('Obfuscate password'), + _('Enabling obfuscation will make the server incompatible with standard QUIC connections, losing the ability to masquerade with HTTP/3.')); + o.password = true; + o.rmempty = false; + o.depends('type', 'hysteria'); + o.depends({type: 'hysteria2', hysteria_obfs_type: /.+/}); + o.modalonly = true; + + o = s.taboption('field_general', form.Value, 'hysteria_obfs_min_packet_size', _('Obfuscate minimum packet size')); + o.placeholder = '512' + o.depends('hysteria_obfs_type', 'gecko'); + o.modalonly = true; + + o = s.taboption('field_general', form.Value, 'hysteria_obfs_max_packet_size', _('Obfuscate maximum packet size')); + o.placeholder = '1200' + o.depends('hysteria_obfs_type', 'gecko'); + o.modalonly = true; + + o = s.taboption('field_general', form.Value, 'hysteria_masquerade', _('Masquerade'), + _('HTTP3 server behavior when authentication fails.
A 404 page will be returned if empty.')); + o.placeholder = 'file:///var/www or http://127.0.0.1:8080' + o.depends('type', 'hysteria2'); + o.modalonly = true; + + /* Hysteria2 Realmserver fields */ + o = s.taboption('field_general', form.Value, 'hysteria2_realmserver_token', _('Pre-shared key')); + o.placeholder = 'public'; + o.rmempty = false; + o.depends('type', 'hysteria2-realm'); + o.modalonly = true; + + o = s.taboption('field_general', form.Value, 'hysteria2_realmserver_max_realms', _('Max realms')); + o.datatype = 'uinteger'; + o.placeholder = '65536'; + o.depends('type', 'hysteria2-realm'); + o.modalonly = true; + + o = s.taboption('field_general', form.Value, 'hysteria2_realmserver_max_realms_per_ip', _('Max realms per client IP')); + o.datatype = 'uinteger'; + o.placeholder = '4'; + o.depends('type', 'hysteria2-realm'); + o.modalonly = true; + + o = s.taboption('field_general', form.Value, 'hysteria2_realmserver_trusted_proxy_header', _('Trusted proxy header'), + _('Header to read real client IP from (e.g. X-Forwarded-For)')); + o.depends('type', 'hysteria2-realm'); + o.modalonly = true; + + o = s.taboption('field_general', form.Value, 'hysteria2_realmserver_realm_name_pattern', _('Realm name pattern')); + o.default = '^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$'; + o.rmempty = false; + o.depends('type', 'hysteria2-realm'); o.modalonly = true; /* TrustTunnel fields */ @@ -622,6 +622,7 @@ function renderListeners(s, uciconfig, isClient) { if (isClient) { o = s.taboption('field_general', form.Value, 'routing_mark', _('Routing mark (Fwmark)')); o.datatype = 'uinteger'; + o.modalonly = false; o.editable = true; o = s.taboption('field_general', hm.ListValue, 'rule', _('Sub rule'), @@ -633,6 +634,7 @@ function renderListeners(s, uciconfig, isClient) { ...hm.loadLabelValues(this.config, 'subrule-group') ], section_id); } + o.modalonly = false; o.editable = true; o = s.taboption('field_general', hm.ListValue, 'proxy', _('Proxy group'), @@ -647,6 +649,7 @@ function renderListeners(s, uciconfig, isClient) { ...hm.loadLabelValues(this.config, 'proxy_group') ], section_id); } + o.modalonly = false; o.editable = true; } @@ -947,8 +950,8 @@ function renderListeners(s, uciconfig, isClient) { let def_alpn; switch (type) { - case 'hysteria2': case 'tuic': + case 'hysteria2': def_alpn = ['h3']; break; case 'hysteria2-realm': @@ -1032,7 +1035,7 @@ function renderListeners(s, uciconfig, isClient) { hm.tls_client_auth_types.forEach((res) => { o.value.apply(o, res); }) - o.depends({tls: '1', type: /^(http|socks|mixed|vmess|vless|trojan|anytls|hysteria2|hysteria2-realm|tuic|trusttunnel)$/}); + o.depends({tls: '1', type: /^(http|socks|mixed|vmess|vless|trojan|anytls|tuic|hysteria2|hysteria2-realm|trusttunnel)$/}); o.modalonly = true; o = s.taboption('field_tls', form.Value, 'tls_client_auth_cert_path', _('Client Auth Certificate path') + _(' (mTLS)'), @@ -1041,7 +1044,7 @@ function renderListeners(s, uciconfig, isClient) { o.validate = function(/* ... */) { return hm.validateMTLSClientAuth.call(this, 'tls_client_auth_type', ...arguments); } - o.depends({tls: '1', type: /^(http|socks|mixed|vmess|vless|trojan|anytls|hysteria2|hysteria2-realm|tuic|trusttunnel)$/}); + o.depends({tls: '1', type: /^(http|socks|mixed|vmess|vless|trojan|anytls|tuic|hysteria2|hysteria2-realm|trusttunnel)$/}); o.modalonly = true; o = s.taboption('field_tls', form.Button, '_upload_client_auth_cert', _('Upload certificate') + _(' (mTLS)'), @@ -1090,13 +1093,13 @@ function renderListeners(s, uciconfig, isClient) { return node; } - o.depends({tls: '1', type: /^(http|socks|mixed|vmess|vless|trojan|anytls|hysteria2|hysteria2-realm|tuic|trusttunnel)$/}); + o.depends({tls: '1', type: /^(http|socks|mixed|vmess|vless|trojan|anytls|tuic|hysteria2|hysteria2-realm|trusttunnel)$/}); o.modalonly = true; o = s.taboption('field_tls', hm.CopyValue, 'tls_ech_config', _('ECH config'), _('This ECH parameter needs to be added to the HTTPS record of the domain.')); o.placeholder = 'AEn+DQBFKwAgACABWIHUGj4u+PIggYXcR5JF0gYk3dCRioBW8uJq9H4mKAAIAAEAAQABAANAEnB1YmxpYy50bHMtZWNoLmRldgAA'; - o.depends({tls: '1', type: /^(http|socks|mixed|vmess|vless|trojan|anytls|hysteria2|hysteria2-realm|tuic|trusttunnel)$/}); + o.depends({tls: '1', type: /^(http|socks|mixed|vmess|vless|trojan|anytls|tuic|hysteria2|hysteria2-realm|trusttunnel)$/}); o.modalonly = true; // uTLS fields @@ -1235,7 +1238,7 @@ function renderListeners(s, uciconfig, isClient) { /* Multiplex fields */ o = s.taboption('field_general', form.Flag, 'smux_enabled', _('Multiplex')); o.default = o.disabled; - o.depends({type: /^(shadowsocks|vmess|vless|trojan|tuic|hysteria2|sudoku)$/}); + o.depends({type: /^(shadowsocks|sudoku|vmess|vless|trojan|tuic|hysteria2)$/}); o.modalonly = true; o = s.taboption('field_multiplex', form.Flag, 'smux_padding', _('Enable padding')); diff --git a/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/node.js b/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/node.js index 579485c8..558403d1 100644 --- a/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/node.js +++ b/luci-app-fchomo/htdocs/luci-static/resources/view/fchomo/node.js @@ -130,7 +130,7 @@ const parseProviderYaml = hm.parseYaml.extend({ override_prefix: this.jq(cfg, "override.additional-prefix"), override_suffix: this.jq(cfg, "override.additional-suffix"), override_replace: (this.jq(cfg, "override.proxy-name") || []).map((obj) => JSON.stringify(obj)), // array.string: array.object - // Configuration Items + // Other configuration items override_tfo: this.bool2str(this.jq(cfg, "override.tfo")), // bool override_mptcp: this.bool2str(this.jq(cfg, "override.mptcp")), // bool override_udp: this.bool2str(this.jq(cfg, "override.udp")), // bool @@ -306,7 +306,7 @@ return view.extend({ so = ss.taboption('field_general', form.Value, 'password', _('Password')); so.password = true; so.validate = hm.validateAuthPassword; - so.depends({type: /^(http|socks5|mieru|trojan|anytls|hysteria2|tuic|trusttunnel|ssh)$/}); + so.depends({type: /^(http|socks5|mieru|trojan|anytls|tuic|hysteria2|trusttunnel|ssh)$/}); so.modalonly = true; so = ss.taboption('field_general', hm.TextValue, 'headers', _('HTTP header')); @@ -315,75 +315,6 @@ return view.extend({ so.depends('type', 'http'); so.modalonly = true; - /* Hysteria / Hysteria2 fields */ - so = ss.taboption('field_general', form.DynamicList, 'hysteria_ports', _('Ports pool')); - so.datatype = 'or(port, portrange)'; - so.depends({type: /^(hysteria|hysteria2)$/}); - so.modalonly = true; - - so = ss.taboption('field_general', form.Value, 'hysteria_hop_interval', _('Port hop interval'), - _('In seconds. %s will be used if empty.').format('30')); - so.placeholder = '15 OR 15-30'; - so.depends('type', 'hysteria2'); - so.modalonly = true; - - so = ss.taboption('field_general', form.Value, 'hysteria_up_mbps', _('Max upload speed'), - _('In Mbps.')); - so.datatype = 'uinteger'; - so.depends({type: /^(hysteria|hysteria2)$/}); - so.modalonly = true; - - so = ss.taboption('field_general', form.Value, 'hysteria_down_mbps', _('Max download speed'), - _('In Mbps.')); - so.datatype = 'uinteger'; - so.depends({type: /^(hysteria|hysteria2)$/}); - so.modalonly = true; - - so = ss.taboption('field_general', form.ListValue, 'hysteria_obfs_type', _('Obfuscate type')); - so.value('', _('Disable')); - so.value('salamander', _('Salamander')); - so.value('gecko', _('Gecko')); - so.depends('type', 'hysteria2'); - so.modalonly = true; - - so = ss.taboption('field_general', form.Value, 'hysteria_obfs_password', _('Obfuscate password'), - _('Enabling obfuscation will make the server incompatible with standard QUIC connections, losing the ability to masquerade with HTTP/3.')); - so.password = true; - so.rmempty = false; - so.depends('type', 'hysteria'); - so.depends({type: 'hysteria2', hysteria_obfs_type: /.+/}); - so.modalonly = true; - - so = ss.taboption('field_general', form.Value, 'hysteria_obfs_min_packet_size', _('Obfuscate minimum packet size')); - so.placeholder = '512' - so.depends('hysteria_obfs_type', 'gecko'); - so.modalonly = true; - - so = ss.taboption('field_general', form.Value, 'hysteria_obfs_max_packet_size', _('Obfuscate maximum packet size')); - so.placeholder = '1200' - so.depends('hysteria_obfs_type', 'gecko'); - so.modalonly = true; - - /* SSH fields */ - so = ss.taboption('field_general', form.TextValue, 'ssh_priv_key', _('Priv-key')); - so.depends('type', 'ssh'); - so.modalonly = true; - - so = ss.taboption('field_general', form.Value, 'ssh_priv_key_passphrase', _('Priv-key passphrase')); - so.password = true; - so.depends({type: 'ssh', ssh_priv_key: /.+/}); - so.modalonly = true; - - so = ss.taboption('field_general', form.DynamicList, 'ssh_host_key_algorithms', _('Host-key algorithms')); - so.placeholder = 'rsa'; - so.depends('type', 'ssh'); - so.modalonly = true; - - so = ss.taboption('field_general', form.DynamicList, 'ssh_host_key', _('Host-key')); - so.placeholder = 'ssh-rsa AAAAB3NzaC1yc2EAA...'; - so.depends({type: 'ssh', ssh_host_key_algorithms: /.+/}); - so.modalonly = true; - /* Shadowsocks fields */ so = ss.taboption('field_general', form.ListValue, 'shadowsocks_chipher', _('Chipher')); so.default = hm.shadowsocks_cipher_methods[1][0]; @@ -574,6 +505,100 @@ return view.extend({ so.depends({type: 'snell', snell_version: /^(4|5)$/}); so.modalonly = true; + /* VMess / VLESS fields */ + so = ss.taboption('field_general', form.Value, 'vmess_uuid', _('UUID')); + so.rmempty = false; + so.validate = hm.validateUUID; + so.depends({type: /^(vmess|vless)$/}); + so.modalonly = true; + + so = ss.taboption('field_general', form.ListValue, 'vless_flow', _('Flow')); + so.default = hm.vless_flow[0][0]; + hm.vless_flow.forEach((res) => { + so.value.apply(so, res); + }) + so.depends('type', 'vless'); + so.modalonly = true; + + so = ss.taboption('field_general', form.Value, 'vmess_alterid', _('Alter ID')); + so.datatype = 'uinteger'; + so.default = '0'; + so.depends('type', 'vmess'); + so.modalonly = true; + + so = ss.taboption('field_general', form.ListValue, 'vmess_chipher', _('Chipher')); + so.default = 'auto'; + so.value('auto', _('auto')); + so.value('none', _('none')); + so.value('zero', _('zero')); + so.value('aes-128-gcm', _('aes-128-gcm')); + so.value('chacha20-poly1305', _('chacha20-poly1305')); + so.depends('type', 'vmess'); + so.modalonly = true; + + so = ss.taboption('field_general', form.Flag, 'vmess_global_padding', _('Global padding'), + _('Protocol parameter. Will waste traffic randomly if enabled (enabled by default in v2ray and cannot be disabled).')); + so.default = so.enabled; + so.depends('type', 'vmess'); + so.modalonly = true; + + so = ss.taboption('field_general', form.Flag, 'vmess_authenticated_length', _('Authenticated length'), + _('Protocol parameter. Enable length block encryption.')); + so.default = so.disabled; + so.depends('type', 'vmess'); + so.modalonly = true; + + so = ss.taboption('field_general', form.ListValue, 'vmess_packet_encoding', _('Packet encoding')); + so.value('', _('none')); + so.value('packetaddr', _('packet addr (v2ray-core v5+)')); + so.value('xudp', _('Xudp (Xray-core)')); + so.depends({type: /^(vmess|vless)$/}); + so.modalonly = true; + + /* Trojan fields */ + so = ss.taboption('field_general', form.Flag, 'trojan_ss_enabled', _('Shadowsocks encrypt')); + so.default = so.disabled; + so.depends('type', 'trojan'); + so.modalonly = true; + + so = ss.taboption('field_general', form.ListValue, 'trojan_ss_chipher', _('Shadowsocks chipher')); + so.default = hm.trojan_cipher_methods[0][0]; + hm.trojan_cipher_methods.forEach((res) => { + so.value.apply(so, res); + }) + so.depends({type: 'trojan', trojan_ss_enabled: '1'}); + so.modalonly = true; + + so = ss.taboption('field_general', form.Value, 'trojan_ss_password', _('Shadowsocks password')); + so.password = true; + so.validate = function(section_id, value) { + const encmode = this.section.getOption('trojan_ss_chipher').formvalue(section_id); + return hm.validateShadowsocksPassword.call(this, encmode, section_id, value); + } + so.depends({type: 'trojan', trojan_ss_enabled: '1'}); + so.modalonly = true; + + /* AnyTLS fields */ + so = ss.taboption('field_general', form.Value, 'anytls_idle_session_check_interval', _('Idle session check interval'), + _('In seconds.')); + so.placeholder = '30'; + so.validate = hm.validateTimeDuration; + so.depends('type', 'anytls'); + so.modalonly = true; + + so = ss.taboption('field_general', form.Value, 'anytls_idle_session_timeout', _('Idle session timeout'), + _('In seconds.')); + so.placeholder = '30'; + so.validate = hm.validateTimeDuration; + so.depends('type', 'anytls'); + so.modalonly = true; + + so = ss.taboption('field_general', form.Value, 'anytls_min_idle_session', _('Min of idle sessions to keep')); + so.datatype = 'uinteger'; + so.placeholder = '0'; + so.depends('type', 'anytls'); + so.modalonly = true; + /* TUIC fields */ so = ss.taboption('field_general', form.Value, 'uuid', _('UUID')); so.rmempty = false; @@ -644,165 +669,53 @@ return view.extend({ so.depends('type', 'tuic'); so.modalonly = true; - /* Trojan fields */ - so = ss.taboption('field_general', form.Flag, 'trojan_ss_enabled', _('Shadowsocks encrypt')); - so.default = so.disabled; - so.depends('type', 'trojan'); + /* Hysteria / Hysteria2 fields */ + so = ss.taboption('field_general', form.DynamicList, 'hysteria_ports', _('Ports pool')); + so.datatype = 'or(port, portrange)'; + so.depends({type: /^(hysteria|hysteria2)$/}); so.modalonly = true; - so = ss.taboption('field_general', form.ListValue, 'trojan_ss_chipher', _('Shadowsocks chipher')); - so.default = hm.trojan_cipher_methods[0][0]; - hm.trojan_cipher_methods.forEach((res) => { - so.value.apply(so, res); - }) - so.depends({type: 'trojan', trojan_ss_enabled: '1'}); + so = ss.taboption('field_general', form.Value, 'hysteria_hop_interval', _('Port hop interval'), + _('In seconds. %s will be used if empty.').format('30')); + so.placeholder = '15 OR 15-30'; + so.depends('type', 'hysteria2'); so.modalonly = true; - so = ss.taboption('field_general', form.Value, 'trojan_ss_password', _('Shadowsocks password')); - so.password = true; - so.validate = function(section_id, value) { - const encmode = this.section.getOption('trojan_ss_chipher').formvalue(section_id); - return hm.validateShadowsocksPassword.call(this, encmode, section_id, value); - } - so.depends({type: 'trojan', trojan_ss_enabled: '1'}); - so.modalonly = true; - - /* AnyTLS fields */ - so = ss.taboption('field_general', form.Value, 'anytls_idle_session_check_interval', _('Idle session check interval'), - _('In seconds.')); - so.placeholder = '30'; - so.validate = hm.validateTimeDuration; - so.depends('type', 'anytls'); - so.modalonly = true; - - so = ss.taboption('field_general', form.Value, 'anytls_idle_session_timeout', _('Idle session timeout'), - _('In seconds.')); - so.placeholder = '30'; - so.validate = hm.validateTimeDuration; - so.depends('type', 'anytls'); - so.modalonly = true; - - so = ss.taboption('field_general', form.Value, 'anytls_min_idle_session', _('Min of idle sessions to keep')); + so = ss.taboption('field_general', form.Value, 'hysteria_up_mbps', _('Max upload speed'), + _('In Mbps.')); so.datatype = 'uinteger'; - so.placeholder = '0'; - so.depends('type', 'anytls'); + so.depends({type: /^(hysteria|hysteria2)$/}); so.modalonly = true; - /* VMess / VLESS fields */ - so = ss.taboption('field_general', form.Value, 'vmess_uuid', _('UUID')); - so.rmempty = false; - so.validate = hm.validateUUID; - so.depends({type: /^(vmess|vless)$/}); - so.modalonly = true; - - so = ss.taboption('field_general', form.ListValue, 'vless_flow', _('Flow')); - so.default = hm.vless_flow[0][0]; - hm.vless_flow.forEach((res) => { - so.value.apply(so, res); - }) - so.depends('type', 'vless'); - so.modalonly = true; - - so = ss.taboption('field_general', form.Value, 'vmess_alterid', _('Alter ID')); + so = ss.taboption('field_general', form.Value, 'hysteria_down_mbps', _('Max download speed'), + _('In Mbps.')); so.datatype = 'uinteger'; - so.default = '0'; - so.depends('type', 'vmess'); + so.depends({type: /^(hysteria|hysteria2)$/}); so.modalonly = true; - so = ss.taboption('field_general', form.ListValue, 'vmess_chipher', _('Chipher')); - so.default = 'auto'; - so.value('auto', _('auto')); - so.value('none', _('none')); - so.value('zero', _('zero')); - so.value('aes-128-gcm', _('aes-128-gcm')); - so.value('chacha20-poly1305', _('chacha20-poly1305')); - so.depends('type', 'vmess'); + so = ss.taboption('field_general', form.ListValue, 'hysteria_obfs_type', _('Obfuscate type')); + so.value('', _('Disable')); + so.value('salamander', _('Salamander')); + so.value('gecko', _('Gecko')); + so.depends('type', 'hysteria2'); so.modalonly = true; - so = ss.taboption('field_general', form.Flag, 'vmess_global_padding', _('Global padding'), - _('Protocol parameter. Will waste traffic randomly if enabled (enabled by default in v2ray and cannot be disabled).')); - so.default = so.enabled; - so.depends('type', 'vmess'); - so.modalonly = true; - - so = ss.taboption('field_general', form.Flag, 'vmess_authenticated_length', _('Authenticated length'), - _('Protocol parameter. Enable length block encryption.')); - so.default = so.disabled; - so.depends('type', 'vmess'); - so.modalonly = true; - - so = ss.taboption('field_general', form.ListValue, 'vmess_packet_encoding', _('Packet encoding')); - so.value('', _('none')); - so.value('packetaddr', _('packet addr (v2ray-core v5+)')); - so.value('xudp', _('Xudp (Xray-core)')); - so.depends({type: /^(vmess|vless)$/}); - so.modalonly = true; - - /* Masque fields */ - so = ss.taboption('field_general', form.Value, 'masque_private_key', _('Private key'), - _('Base64 encoded ECDSA private key on the NIST P-256 curve.')); + so = ss.taboption('field_general', form.Value, 'hysteria_obfs_password', _('Obfuscate password'), + _('Enabling obfuscation will make the server incompatible with standard QUIC connections, losing the ability to masquerade with HTTP/3.')); so.password = true; - so.validate = L.bind(hm.validateBase64Key, so, 164); so.rmempty = false; - so.depends('type', 'masque'); + so.depends('type', 'hysteria'); + so.depends({type: 'hysteria2', hysteria_obfs_type: /.+/}); so.modalonly = true; - so = ss.taboption('field_general', form.Value, 'masque_endpoint_public_key', _('Endpoint pubkic key'), - _('Base64 encoded ECDSA public key on the NIST P-256 curve.')); - so.validate = L.bind(hm.validateBase64Key, so, 124); - so.rmempty = false; - so.depends('type', 'masque'); + so = ss.taboption('field_general', form.Value, 'hysteria_obfs_min_packet_size', _('Obfuscate minimum packet size')); + so.placeholder = '512' + so.depends('hysteria_obfs_type', 'gecko'); so.modalonly = true; - so = ss.taboption('field_general', form.Value, 'masque_ip', _('Local address'), - _('The %s address used by local machine in the Cloudflare WARP network.').format('IPv4')); - so.datatype = 'ip4addr(1)'; - so.placeholder = '172.16.0.2'; - so.rmempty = false; - so.depends({type: 'masque', masque_network: /^(|h2)$/}); - so.modalonly = true; - - so = ss.taboption('field_general', form.Value, 'masque_ipv6', _('Local IPv6 address'), - _('The %s address used by local machine in the Cloudflare WARP network.').format('IPv6')); - so.datatype = 'ip6addr(1)'; - so.depends({type: 'masque', masque_network: /^(|h2)$/}); - so.modalonly = true; - - so = ss.taboption('field_general', form.Value, 'masque_mtu', _('MTU')); - so.datatype = 'range(0,9000)'; - so.placeholder = '1280'; - so.depends({type: 'masque', masque_network: /^(|h2)$/}); - so.modalonly = true; - - so = ss.taboption('field_general', form.ListValue, 'masque_network', _('Network')); - so.default = ''; - so.value('', _('h3')); - so.value('h3-l4proxy', _('h3-l4proxy')); - so.value('h2', _('h2')); - so.validate = function(section_id, value) { - const udp = this.section.getUIElement(section_id, 'udp').node.querySelector('input'); - - // Force disabled - if (value === 'h3-l4proxy') { - udp.checked = false; - udp.disabled = true; - } else - udp.removeAttribute('disabled'); - - return true; - } - so.depends('type', 'masque'); - so.modalonly = true; - - so = ss.taboption('field_general', form.Flag, 'masque_remote_dns_resolve', _('Remote DNS resolve'), - _('Force DNS remote resolution.')); - so.default = so.disabled; - so.depends('type', 'masque'); - so.modalonly = true; - - so = ss.taboption('field_general', form.DynamicList, 'masque_dns', _('DNS server')); - so.datatype = 'or(host, hostport)'; - so.depends('masque_remote_dns_resolve', '1'); + so = ss.taboption('field_general', form.Value, 'hysteria_obfs_max_packet_size', _('Obfuscate maximum packet size')); + so.placeholder = '1200' + so.depends('hysteria_obfs_type', 'gecko'); so.modalonly = true; /* TrustTunnel fields */ @@ -888,6 +801,93 @@ return view.extend({ so.depends('wireguard_remote_dns_resolve', '1'); so.modalonly = true; + /* Masque fields */ + so = ss.taboption('field_general', form.Value, 'masque_private_key', _('Private key'), + _('Base64 encoded ECDSA private key on the NIST P-256 curve.')); + so.password = true; + so.validate = L.bind(hm.validateBase64Key, so, 164); + so.rmempty = false; + so.depends('type', 'masque'); + so.modalonly = true; + + so = ss.taboption('field_general', form.Value, 'masque_endpoint_public_key', _('Endpoint pubkic key'), + _('Base64 encoded ECDSA public key on the NIST P-256 curve.')); + so.validate = L.bind(hm.validateBase64Key, so, 124); + so.rmempty = false; + so.depends('type', 'masque'); + so.modalonly = true; + + so = ss.taboption('field_general', form.Value, 'masque_ip', _('Local address'), + _('The %s address used by local machine in the Cloudflare WARP network.').format('IPv4')); + so.datatype = 'ip4addr(1)'; + so.placeholder = '172.16.0.2'; + so.rmempty = false; + so.depends({type: 'masque', masque_network: /^(|h2)$/}); + so.modalonly = true; + + so = ss.taboption('field_general', form.Value, 'masque_ipv6', _('Local IPv6 address'), + _('The %s address used by local machine in the Cloudflare WARP network.').format('IPv6')); + so.datatype = 'ip6addr(1)'; + so.depends({type: 'masque', masque_network: /^(|h2)$/}); + so.modalonly = true; + + so = ss.taboption('field_general', form.Value, 'masque_mtu', _('MTU')); + so.datatype = 'range(0,9000)'; + so.placeholder = '1280'; + so.depends({type: 'masque', masque_network: /^(|h2)$/}); + so.modalonly = true; + + so = ss.taboption('field_general', form.ListValue, 'masque_network', _('Network')); + so.default = ''; + so.value('', _('h3')); + so.value('h3-l4proxy', _('h3-l4proxy')); + so.value('h2', _('h2')); + so.validate = function(section_id, value) { + const udp = this.section.getUIElement(section_id, 'udp').node.querySelector('input'); + + // Force disabled + if (value === 'h3-l4proxy') { + udp.checked = false; + udp.disabled = true; + } else + udp.removeAttribute('disabled'); + + return true; + } + so.depends('type', 'masque'); + so.modalonly = true; + + so = ss.taboption('field_general', form.Flag, 'masque_remote_dns_resolve', _('Remote DNS resolve'), + _('Force DNS remote resolution.')); + so.default = so.disabled; + so.depends('type', 'masque'); + so.modalonly = true; + + so = ss.taboption('field_general', form.DynamicList, 'masque_dns', _('DNS server')); + so.datatype = 'or(host, hostport)'; + so.depends('masque_remote_dns_resolve', '1'); + so.modalonly = true; + + /* SSH fields */ + so = ss.taboption('field_general', form.TextValue, 'ssh_priv_key', _('Priv-key')); + so.depends('type', 'ssh'); + so.modalonly = true; + + so = ss.taboption('field_general', form.Value, 'ssh_priv_key_passphrase', _('Priv-key passphrase')); + so.password = true; + so.depends({type: 'ssh', ssh_priv_key: /.+/}); + so.modalonly = true; + + so = ss.taboption('field_general', form.DynamicList, 'ssh_host_key_algorithms', _('Host-key algorithms')); + so.placeholder = 'rsa'; + so.depends('type', 'ssh'); + so.modalonly = true; + + so = ss.taboption('field_general', form.DynamicList, 'ssh_host_key', _('Host-key')); + so.placeholder = 'ssh-rsa AAAAB3NzaC1yc2EAA...'; + so.depends({type: 'ssh', ssh_host_key_algorithms: /.+/}); + so.modalonly = true; + /* Plugin fields */ so = ss.taboption('field_general', form.ListValue, 'plugin', _('Plugin')); so.value('', _('none')); @@ -975,12 +975,12 @@ return view.extend({ _('The default value is %s, indicating that only the outer connection timeout is used.').format('0')); so.datatype = 'uinteger'; so.placeholder = '30'; - so.depends({type: /^(masque|openvpn)$/}); + so.depends({type: /^(openvpn|masque)$/}); so.modalonly = true; so = ss.taboption('field_general', form.Flag, 'udp', _('UDP')); so.default = so.disabled; - so.depends({type: /^(rematch|direct|socks5|ss|mieru|vmess|vless|trojan|anytls|trusttunnel|masque|wireguard)$/}); + so.depends({type: /^(rematch|direct|socks5|ss|mieru|vmess|vless|trojan|anytls|trusttunnel|wireguard|masque)$/}); so.depends({type: 'snell', snell_version: /^(3|4|5)$/}); so.modalonly = true; @@ -1115,7 +1115,7 @@ return view.extend({ return true; } - so.depends({type: /^(http|socks5|vmess|vless|trojan|anytls|hysteria|hysteria2|tuic|trusttunnel|masque)$/}); + so.depends({type: /^(http|socks5|vmess|vless|trojan|anytls|tuic|hysteria|hysteria2|trusttunnel|masque)$/}); so.modalonly = true; so = ss.taboption('field_tls', form.Flag, 'tls_disable_sni', _('Disable SNI'), @@ -1146,9 +1146,9 @@ return view.extend({ case 'snell': def_alpn = ['h2', 'http/1.1']; // when plugin === 'shadow-tls' break; + case 'tuic': case 'hysteria': case 'hysteria2': - case 'tuic': def_alpn = ['h3']; break; case 'vmess': @@ -1171,7 +1171,7 @@ return view.extend({ return true; } - so.depends({tls: '1', type: /^(vmess|vless|trojan|anytls|hysteria|hysteria2|tuic|trusttunnel)$/}); + so.depends({tls: '1', type: /^(vmess|vless|trojan|anytls|tuic|hysteria|hysteria2|trusttunnel)$/}); so.depends({type: /^(ss|snell)$/, plugin: 'shadow-tls'}); so.modalonly = true; @@ -1193,7 +1193,7 @@ return view.extend({ '
' + _('This is DANGEROUS, your traffic is almost like PLAIN TEXT! Use at your own risk!')); so.default = so.disabled; - so.depends({tls: '1', type: /^(http|socks5|vmess|vless|trojan|anytls|hysteria|hysteria2|tuic|trusttunnel)$/}); + so.depends({tls: '1', type: /^(http|socks5|vmess|vless|trojan|anytls|tuic|hysteria|hysteria2|trusttunnel)$/}); so.modalonly = true; so = ss.taboption('field_tls', form.Value, 'tls_cert_path', _('Certificate path') + _(' (mTLS)'), @@ -1226,7 +1226,7 @@ return view.extend({ so = ss.taboption('field_tls', form.Flag, 'tls_ech', _('Enable ECH')); so.default = so.disabled; - so.depends({tls: '1', type: /^(vmess|vless|trojan|anytls|hysteria|hysteria2|tuic)$/}); + so.depends({tls: '1', type: /^(vmess|vless|trojan|anytls|tuic|hysteria|hysteria2)$/}); so.depends({type: 'ss', plugin: /^(v2ray-plugin|gost-plugin)$/}); so.modalonly = true; @@ -1899,7 +1899,7 @@ return view.extend({ so = ss.taboption('field_override', form.DummyValue, '_config_items', null); so.load = function() { return '%s' - .format('https://wiki.metacubex.one/config/proxy-providers/#_2', _('Configuration Items')); + .format('https://wiki.metacubex.one/config/proxy-providers/#override_1', _('Other configuration items')); } so.rawhtml = true; so.depends({type: 'inline', '!reverse': true}); diff --git a/luci-app-fchomo/po/templates/fchomo.pot b/luci-app-fchomo/po/templates/fchomo.pot index 3ae40dee..6a6f48e5 100644 --- a/luci-app-fchomo/po/templates/fchomo.pot +++ b/luci-app-fchomo/po/templates/fchomo.pot @@ -566,7 +566,7 @@ msgid "Complete" msgstr "" #: htdocs/luci-static/resources/view/fchomo/node.js:1898 -msgid "Configuration Items" +msgid "Other configuration items" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:653 @@ -1442,7 +1442,7 @@ msgid "Hysteria2" msgstr "" #: htdocs/luci-static/resources/fchomo.js:167 -msgid "Hysteria2 Realm" +msgid "Hysteria2 Realm Server" msgstr "" #: htdocs/luci-static/resources/fchomo/listeners.js:121 diff --git a/luci-app-fchomo/po/zh_Hans/fchomo.po b/luci-app-fchomo/po/zh_Hans/fchomo.po index 6b3f4d32..5487edd8 100644 --- a/luci-app-fchomo/po/zh_Hans/fchomo.po +++ b/luci-app-fchomo/po/zh_Hans/fchomo.po @@ -580,8 +580,8 @@ msgid "Complete" msgstr "完成" #: htdocs/luci-static/resources/view/fchomo/node.js:1898 -msgid "Configuration Items" -msgstr "配置项" +msgid "Other configuration items" +msgstr "其他配置项" #: htdocs/luci-static/resources/fchomo/listeners.js:653 #: htdocs/luci-static/resources/view/fchomo/node.js:955 @@ -1468,8 +1468,8 @@ msgid "Hysteria2" msgstr "" #: htdocs/luci-static/resources/fchomo.js:167 -msgid "Hysteria2 Realm" -msgstr "Hysteria2 Realm" +msgid "Hysteria2 Realm Server" +msgstr "Hysteria2 Realm 服务器" #: htdocs/luci-static/resources/fchomo/listeners.js:121 #: htdocs/luci-static/resources/view/fchomo/node.js:235 diff --git a/luci-app-fchomo/po/zh_Hant/fchomo.po b/luci-app-fchomo/po/zh_Hant/fchomo.po index 97a4d829..0ba11e5b 100644 --- a/luci-app-fchomo/po/zh_Hant/fchomo.po +++ b/luci-app-fchomo/po/zh_Hant/fchomo.po @@ -580,8 +580,8 @@ msgid "Complete" msgstr "完成" #: htdocs/luci-static/resources/view/fchomo/node.js:1898 -msgid "Configuration Items" -msgstr "配置項" +msgid "Other configuration items" +msgstr "其他配置項" #: htdocs/luci-static/resources/fchomo/listeners.js:653 #: htdocs/luci-static/resources/view/fchomo/node.js:955 @@ -1468,8 +1468,8 @@ msgid "Hysteria2" msgstr "" #: htdocs/luci-static/resources/fchomo.js:167 -msgid "Hysteria2 Realm" -msgstr "Hysteria2 Realm" +msgid "Hysteria2 Realm Server" +msgstr "Hysteria2 Realm 伺服器" #: htdocs/luci-static/resources/fchomo/listeners.js:121 #: htdocs/luci-static/resources/view/fchomo/node.js:235 diff --git a/luci-app-fchomo/root/usr/share/fchomo/generate_client.uc b/luci-app-fchomo/root/usr/share/fchomo/generate_client.uc index 37bfc9bb..27aeba0a 100644 --- a/luci-app-fchomo/root/usr/share/fchomo/generate_client.uc +++ b/luci-app-fchomo/root/usr/share/fchomo/generate_client.uc @@ -490,7 +490,7 @@ uci.foreach(uciconf, ucinode, (cfg) => { "target-rematch-name": cfg.target_rematch_name, "target-sub-rule": cfg.target_sub_rule, - /* HTTP / SOCKS / Shadowsocks / VMess / VLESS / Trojan / hysteria2 / TUIC / WireGuard / Masque */ + /* HTTP / SOCKS / Shadowsocks / VMess / VLESS / Trojan / TUIC / hysteria2 / WireGuard / Masque */ username: cfg.username, uuid: cfg.vmess_uuid || cfg.uuid, cipher: cfg.vmess_chipher || cfg.shadowsocks_chipher, @@ -502,35 +502,6 @@ uci.foreach(uciconf, ucinode, (cfg) => { "remote-dns-resolve": strToBool(cfg.masque_remote_dns_resolve ?? cfg.wireguard_remote_dns_resolve), dns: cfg.masque_dns || cfg.wireguard_dns, - /* Hysteria / Hysteria2 */ - ports: isEmpty(cfg.hysteria_ports) ? null : join(',', cfg.hysteria_ports), - "hop-interval": strToInt(cfg.hysteria_hop_interval), // @DEBUG ERROR data type *utils.IntRanges[uint16] - up: cfg.hysteria_up_mbps ? cfg.hysteria_up_mbps + ' Mbps' : null, - down: cfg.hysteria_down_mbps ? cfg.hysteria_down_mbps + ' Mbps' : null, - obfs: cfg.hysteria_obfs_type, - "obfs-password": cfg.hysteria_obfs_password, - "obfs-min-packet-size": strToInt(cfg.hysteria_obfs_min_packet_size), - "obfs-max-packet-size": strToInt(cfg.hysteria_obfs_max_packet_size), - "realm-opts": cfg.hysteria2_realm === '1' ? { - enable: true, - "server-url": cfg.hysteria2_realm_server_url, - token: cfg.hysteria2_realm_token, - "realm-id": cfg.hysteria2_realm_id, - "stun-servers": cfg.hysteria2_realm_stun_servers, - // @TLS of server-url - //sni, - //alpn, - //"skip-cert-verify", - //fingerprint, - //certificate, - //"private-key" - } : null, - - /* SSH */ - "private-key-passphrase": cfg.ssh_priv_key_passphrase, - "host-key-algorithms": cfg.ssh_host_key_algorithms, - "host-key": cfg.ssh_host_key, - /* Shadowsocks */ /* Mieru */ @@ -564,17 +535,13 @@ uci.foreach(uciconf, ucinode, (cfg) => { version: cfg.snell_version, reuse: strToBool(cfg.snell_reuse), - /* TUIC */ - ip: cfg.tuic_ip, - "udp-relay-mode": cfg.tuic_udp_relay_mode, - "udp-over-stream": strToBool(cfg.tuic_udp_over_stream), - "udp-over-stream-version": cfg.tuic_udp_over_stream_version, - "max-udp-relay-packet-size": strToInt(cfg.tuic_max_udp_relay_packet_size) || null, - "fast-open": strToBool(cfg.tuic_fast_open), - "reduce-rtt": strToBool(cfg.tuic_reduce_rtt), - "heartbeat-interval": strToInt(cfg.tuic_heartbeat) || null, - "request-timeout": strToInt(cfg.tuic_request_timeout) || null, - "max-open-streams": strToInt(cfg.tuic_max_open_streams) || null, + /* VMess / VLESS */ + flow: cfg.vless_flow, + alterId: strToInt(cfg.vmess_alterid), + "global-padding": cfg.type === 'vmess' ? (cfg.vmess_global_padding === '0' ? false : true) : null, + "authenticated-length": strToBool(cfg.vmess_authenticated_length), + "packet-encoding": cfg.vmess_packet_encoding, + encryption: cfg.vless_encryption === '1' ? cfg.vless_encryption_encryption : null, /* Trojan */ "ss-opts": cfg.trojan_ss_enabled === '1' ? { @@ -588,16 +555,41 @@ uci.foreach(uciconf, ucinode, (cfg) => { "idle-session-timeout": durationToSecond(cfg.anytls_idle_session_timeout), "min-idle-session": strToInt(cfg.anytls_min_idle_session), - /* VMess / VLESS */ - flow: cfg.vless_flow, - alterId: strToInt(cfg.vmess_alterid), - "global-padding": cfg.type === 'vmess' ? (cfg.vmess_global_padding === '0' ? false : true) : null, - "authenticated-length": strToBool(cfg.vmess_authenticated_length), - "packet-encoding": cfg.vmess_packet_encoding, - encryption: cfg.vless_encryption === '1' ? cfg.vless_encryption_encryption : null, + /* TUIC */ + ip: cfg.tuic_ip, + "udp-relay-mode": cfg.tuic_udp_relay_mode, + "udp-over-stream": strToBool(cfg.tuic_udp_over_stream), + "udp-over-stream-version": cfg.tuic_udp_over_stream_version, + "max-udp-relay-packet-size": strToInt(cfg.tuic_max_udp_relay_packet_size) || null, + "fast-open": strToBool(cfg.tuic_fast_open), + "reduce-rtt": strToBool(cfg.tuic_reduce_rtt), + "heartbeat-interval": strToInt(cfg.tuic_heartbeat) || null, + "request-timeout": strToInt(cfg.tuic_request_timeout) || null, + "max-open-streams": strToInt(cfg.tuic_max_open_streams) || null, - /* Masque */ - network: cfg.masque_network || null, + /* Hysteria / Hysteria2 */ + ports: isEmpty(cfg.hysteria_ports) ? null : join(',', cfg.hysteria_ports), + "hop-interval": strToInt(cfg.hysteria_hop_interval), // @DEBUG ERROR data type *utils.IntRanges[uint16] + up: cfg.hysteria_up_mbps ? cfg.hysteria_up_mbps + ' Mbps' : null, + down: cfg.hysteria_down_mbps ? cfg.hysteria_down_mbps + ' Mbps' : null, + obfs: cfg.hysteria_obfs_type, + "obfs-password": cfg.hysteria_obfs_password, + "obfs-min-packet-size": strToInt(cfg.hysteria_obfs_min_packet_size), + "obfs-max-packet-size": strToInt(cfg.hysteria_obfs_max_packet_size), + "realm-opts": cfg.hysteria2_realm === '1' ? { + enable: true, + "server-url": cfg.hysteria2_realm_server_url, + token: cfg.hysteria2_realm_token, + "realm-id": cfg.hysteria2_realm_id, + "stun-servers": cfg.hysteria2_realm_stun_servers, + // @TLS of server-url + //sni, + //alpn, + //"skip-cert-verify", + //fingerprint, + //certificate, + //"private-key" + } : null, /* TrustTunnel */ "health-check": cfg.type === 'trusttunnel' ? (cfg.trusttunnel_health_check === '0' ? false : true) : null, @@ -609,6 +601,14 @@ uci.foreach(uciconf, ucinode, (cfg) => { reserved: cfg.wireguard_reserved, "persistent-keepalive": strToInt(cfg.wireguard_persistent_keepalive), + /* Masque */ + network: cfg.masque_network || null, + + /* SSH */ + "private-key-passphrase": cfg.ssh_priv_key_passphrase, + "host-key-algorithms": cfg.ssh_host_key_algorithms, + "host-key": cfg.ssh_host_key, + /* Plugin fields */ ...(cfg.plugin ? ( cfg.type === 'snell' ? { @@ -820,7 +820,7 @@ uci.foreach(uciconf, uciprov, (cfg) => { "additional-prefix": cfg.override_prefix, "additional-suffix": cfg.override_suffix, "proxy-name": isEmpty(cfg.override_replace) ? null : map(cfg.override_replace, obj => json(obj)), - // Configuration Items + // Other configuration items tfo: strToBool(cfg.override_tfo), mptcp: strToBool(cfg.override_mptcp), udp: (cfg.override_udp === '0') ? null : true, diff --git a/luci-app-fchomo/root/usr/share/ucode/fchomo.uc b/luci-app-fchomo/root/usr/share/ucode/fchomo.uc index 59422183..b74d7963 100644 --- a/luci-app-fchomo/root/usr/share/ucode/fchomo.uc +++ b/luci-app-fchomo/root/usr/share/ucode/fchomo.uc @@ -246,37 +246,6 @@ export function parseListener(cfg, isClient, label) { ...arrToObj([[cfg.uuid, cfg.password]]) } : null), - /* Hysteria2 */ - up: strToInt(cfg.hysteria_up_mbps), - down: strToInt(cfg.hysteria_down_mbps), - "ignore-client-bandwidth": strToBool(cfg.hysteria_ignore_client_bandwidth), - obfs: cfg.hysteria_obfs_type, - "obfs-password": cfg.hysteria_obfs_password, - "obfs-min-packet-size": strToInt(cfg.hysteria_obfs_min_packet_size), - "obfs-max-packet-size": strToInt(cfg.hysteria_obfs_max_packet_size), - masquerade: cfg.hysteria_masquerade, - "realm-opts": cfg.hysteria2_realm === '1' ? { - enable: true, - "server-url": cfg.hysteria2_realm_server_url, - token: cfg.hysteria2_realm_token, - "realm-id": cfg.hysteria2_realm_id, - "stun-servers": cfg.hysteria2_realm_stun_servers, - // @TLS of server-url - //sni, - //alpn, - //"skip-cert-verify", - //fingerprint, - //certificate, - //"private-key" - } : null, - - /* Hysteria2 Realmserver */ - token: cfg.hysteria2_realmserver_token, - "max-realms": strToInt(cfg.hysteria2_realmserver_max_realms), - "max-realms-per-ip": strToInt(cfg.hysteria2_realmserver_max_realms_per_ip), - "trusted-proxy-header": cfg.hysteria2_realmserver_trusted_proxy_header, - "realm-name-pattern": cfg.hysteria2_realmserver_realm_name_pattern, - /* Shadowsocks */ cipher: cfg.shadowsocks_chipher, password: cfg.shadowsocks_password, @@ -308,10 +277,8 @@ export function parseListener(cfg, isClient, label) { psk: cfg.snell_psk, version: cfg.snell_version, - /* Tuic */ - "max-idle-time": durationToSecond(cfg.tuic_max_idle_time), - "authentication-timeout": durationToSecond(cfg.tuic_authentication_timeout), - "max-udp-relay-packet-size": strToInt(cfg.tuic_max_udp_relay_packet_size), + /* VMess / VLESS */ + decryption: cfg.vless_decryption === '1' ? parseVlessEncryption(cfg.vless_encryption_hmpayload, 'server') : null, /* Trojan */ "ss-option": cfg.trojan_ss_enabled === '1' ? { @@ -323,8 +290,43 @@ export function parseListener(cfg, isClient, label) { /* AnyTLS */ "padding-scheme": cfg.anytls_padding_scheme, - /* VMess / VLESS */ - decryption: cfg.vless_decryption === '1' ? parseVlessEncryption(cfg.vless_encryption_hmpayload, 'server') : null, + /* Tuic */ + "max-idle-time": durationToSecond(cfg.tuic_max_idle_time), + "authentication-timeout": durationToSecond(cfg.tuic_authentication_timeout), + "max-udp-relay-packet-size": strToInt(cfg.tuic_max_udp_relay_packet_size), + + /* Hysteria2 */ + up: strToInt(cfg.hysteria_up_mbps), + down: strToInt(cfg.hysteria_down_mbps), + "ignore-client-bandwidth": strToBool(cfg.hysteria_ignore_client_bandwidth), + obfs: cfg.hysteria_obfs_type, + "obfs-password": cfg.hysteria_obfs_password, + "obfs-min-packet-size": strToInt(cfg.hysteria_obfs_min_packet_size), + "obfs-max-packet-size": strToInt(cfg.hysteria_obfs_max_packet_size), + masquerade: cfg.hysteria_masquerade, + "realm-opts": cfg.hysteria2_realm === '1' ? { + enable: true, + "server-url": cfg.hysteria2_realm_server_url, + token: cfg.hysteria2_realm_token, + "realm-id": cfg.hysteria2_realm_id, + "stun-servers": cfg.hysteria2_realm_stun_servers, + // @TLS of server-url + //sni, + //alpn, + //"skip-cert-verify", + //fingerprint, + //certificate, + //"private-key" + } : null, + + /* Hysteria2 Realmserver */ + token: cfg.hysteria2_realmserver_token, + "max-realms": strToInt(cfg.hysteria2_realmserver_max_realms), + "max-realms-per-ip": strToInt(cfg.hysteria2_realmserver_max_realms_per_ip), + "trusted-proxy-header": cfg.hysteria2_realmserver_trusted_proxy_header, + "realm-name-pattern": cfg.hysteria2_realmserver_realm_name_pattern, + + /* TrustTunnel */ /* Tunnel */ target: cfg.tunnel_target, diff --git a/luci-app-passwall/Makefile b/luci-app-passwall/Makefile index 73ba84c6..aef31787 100644 --- a/luci-app-passwall/Makefile +++ b/luci-app-passwall/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall PKG_VERSION:=26.7.1 -PKG_RELEASE:=177 +PKG_RELEASE:=178 PKG_PO_VERSION:=$(PKG_VERSION) PKG_CONFIG_DEPENDS:= \ diff --git a/luci-app-passwall/luasrc/controller/passwall.lua b/luci-app-passwall/luasrc/controller/passwall.lua index 518265f2..012052c1 100644 --- a/luci-app-passwall/luasrc/controller/passwall.lua +++ b/luci-app-passwall/luasrc/controller/passwall.lua @@ -109,6 +109,7 @@ function index() for _, com in ipairs(coms.order) do entry({"admin", "services", appname, "check_" .. com}, call("com_check", com)).leaf = true entry({"admin", "services", appname, "update_" .. com}, call("com_update", com)).leaf = true + entry({"admin", "services", appname, "version_" .. com}, call("com_version", com)).leaf = true end --[[Backup]] @@ -881,6 +882,11 @@ function com_update(comname) http_write_json(json) end +function com_version(comname) + local version = api.get_app_version(comname) + http_write_json_ok(version) +end + function read_rulelist() local rule_type = http.formvalue("type") local rule_path diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/app_update.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/app_update.lua index 9106571e..5f573a9e 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/app_update.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/app_update.lua @@ -1,22 +1,24 @@ local api = require "luci.passwall.api" +local com = require "luci.passwall.com" local appname = "passwall" m = Map(appname) api.set_apply_on_parse(m) -- [[ App Settings ]]-- -s = m:section(TypedSection, "global_app", translate("App Update"), - "" .. - translate("Please confirm that your firmware supports FPU.") .. - "") +s = m:section(TypedSection, "global_app", translate("App Update")) s.anonymous = true -s:append(Template(appname .. "/app_update/app_version")) + +local app_version = Template(appname .. "/app_update/app_version") +app_version.api = api +app_version.config = m.config +app_version.com = com +s:append(app_version) o = s:option(Flag, "github_proxy", translate("GitHub Proxy"), translate("Use gh-proxy instead of proxy nodes for component updates.")) o.default = 0 local k, v -local com = require "luci.passwall.com" for _, k in ipairs(com.order) do v = com[k] if k ~= "chinadns-ng" then diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe_config.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe_config.lua index 66dad750..e3d2c44c 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe_config.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/node_subscribe_config.lua @@ -229,13 +229,8 @@ end o = s:option(Flag, "boot_update", translate("Update Once on Boot"), translate("Updates the subscription the first time PassWall runs automatically after each system boot.")) o.default = 0 ----- Enable auto update subscribe -o = s:option(Flag, "auto_update", translate("Enable auto update subscribe")) -o.default = 0 -o.rmempty = false - ----- Week Update -o = s:option(ListValue, "week_update", translate("Update Mode")) +o = s:option(ListValue, "update_week_mode", translate("Auto Update Mode")) +o:value("", translate("Disable")) o:value(8, translate("Loop Mode")) o:value(7, translate("Every day")) o:value(1, translate("Every Monday")) @@ -245,29 +240,30 @@ o:value(4, translate("Every Thursday")) o:value(5, translate("Every Friday")) o:value(6, translate("Every Saturday")) o:value(0, translate("Every Sunday")) -o.default = 7 -o:depends("auto_update", true) -o.rmempty = true ----- Time Update -o = s:option(ListValue, "time_update", translate("Update Time(every day)")) -for t = 0, 23 do o:value(t, t .. ":00") end -o.default = 0 -o:depends("week_update", "0") -o:depends("week_update", "1") -o:depends("week_update", "2") -o:depends("week_update", "3") -o:depends("week_update", "4") -o:depends("week_update", "5") -o:depends("week_update", "6") -o:depends("week_update", "7") -o.rmempty = true +o = s:option(Value, "update_time_mode", translate("Update Time")) +for t = 0, 23 do o:value(t .. ":00") end +o.default = "0:00" +o.validate = function(self, value) + local b = api.is_timehhmm(value) + if b then + return value + end + return nil +end +o:depends("update_week_mode", "0") +o:depends("update_week_mode", "1") +o:depends("update_week_mode", "2") +o:depends("update_week_mode", "3") +o:depends("update_week_mode", "4") +o:depends("update_week_mode", "5") +o:depends("update_week_mode", "6") +o:depends("update_week_mode", "7") ----- Interval Update -o = s:option(ListValue, "interval_update", translate("Update Interval(hour)")) +o = s:option(ListValue, "update_interval_mode", translate("Update Interval(hour)")) for t = 1, 24 do o:value(t, t .. " " .. translate("hour")) end o.default = 2 -o:depends("week_update", "8") +o:depends("update_week_mode", "8") o.rmempty = true o = s:option(ListValue, "access_mode", translate("Subscribe URL Access Method")) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua index 9201d76c..2f53c6ae 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/other.lua @@ -29,7 +29,9 @@ o.rmempty = true for index, value in ipairs({"stop", "start", "restart"}) do o = s:option(ListValue, value .. "_week_mode", translate(value .. " automatically mode")) o:value("", translate("Disable")) - o:value(8, translate("Loop Mode")) + if value == "restart" then + o:value(8, translate("Loop Mode")) + end o:value(7, translate("Every day")) o:value(1, translate("Every Monday")) o:value(2, translate("Every Tuesday")) @@ -38,9 +40,16 @@ for index, value in ipairs({"stop", "start", "restart"}) do o:value(5, translate("Every Friday")) o:value(6, translate("Every Saturday")) o:value(0, translate("Every Sunday")) - o = s:option(ListValue, value .. "_time_mode", translate(value .. " Time(Every day)")) - for t = 0, 23 do o:value(t, t .. ":00") end - o.default = 0 + o = s:option(Value, value .. "_time_mode", translate(value .. " Time")) + for t = 0, 23 do o:value(t .. ":00") end + o.default = "0:00" + o.validate = function(self, value) + local b = api.is_timehhmm(value) + if b then + return value + end + return nil + end o:depends(value .. "_week_mode", "0") o:depends(value .. "_week_mode", "1") o:depends(value .. "_week_mode", "2") diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/rule.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/rule.lua index fa5d6d87..c6e12ed8 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/rule.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/rule.lua @@ -97,13 +97,8 @@ if has_xray or has_singbox then end end ----- Auto Update -o = s:option(Flag, "auto_update", translate("Enable auto update rules")) -o.default = 0 -o.rmempty = false - ----- Week Update -o = s:option(ListValue, "week_update", translate("Update Mode")) +o = s:option(ListValue, "update_week_mode", translate("Auto Update Mode")) +o:value("", translate("Disable")) o:value(8, translate("Loop Mode")) o:value(7, translate("Every day")) o:value(1, translate("Every Monday")) @@ -113,29 +108,30 @@ o:value(4, translate("Every Thursday")) o:value(5, translate("Every Friday")) o:value(6, translate("Every Saturday")) o:value(0, translate("Every Sunday")) -o.default = 7 -o:depends("auto_update", true) -o.rmempty = true ----- Time Update -o = s:option(ListValue, "time_update", translate("Update Time(every day)")) -for t = 0, 23 do o:value(t, t .. ":00") end -o.default = 0 -o:depends("week_update", "0") -o:depends("week_update", "1") -o:depends("week_update", "2") -o:depends("week_update", "3") -o:depends("week_update", "4") -o:depends("week_update", "5") -o:depends("week_update", "6") -o:depends("week_update", "7") -o.rmempty = true +o = s:option(Value, "update_time_mode", translate("Update Time")) +for t = 0, 23 do o:value(t .. ":00") end +o.default = "0:00" +o.validate = function(self, value) + local b = api.is_timehhmm(value) + if b then + return value + end + return nil +end +o:depends("update_week_mode", "0") +o:depends("update_week_mode", "1") +o:depends("update_week_mode", "2") +o:depends("update_week_mode", "3") +o:depends("update_week_mode", "4") +o:depends("update_week_mode", "5") +o:depends("update_week_mode", "6") +o:depends("update_week_mode", "7") ----- Interval Update -o = s:option(ListValue, "interval_update", translate("Update Interval(hour)")) +o = s:option(ListValue, "update_interval_mode", translate("Update Interval(hour)")) for t = 1, 24 do o:value(t, t .. " " .. translate("hour")) end o.default = 2 -o:depends("week_update", "8") +o:depends("update_week_mode", "8") o.rmempty = true ---- 更新选项,始终被js隐藏 diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua index 2e6c2ab3..853e642b 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua @@ -152,9 +152,10 @@ if load_balancing_options then -- [[ Load balancing Start ]] o:depends({ [_n("node_add_mode")] = "batch" }) local descrStr = "Example: ^A && B && !C && D$
" descrStr = descrStr .. "This means the node remark must start with A (^), include B, exclude C (!), and end with D ($).
" - descrStr = descrStr .. "Conditions are joined by &&, and their order does not affect the result." - o.description = translate(descrStr) .. string.format("
%s", - translate("Keep the match scope small. Too many nodes can impact router performance.")) + descrStr = descrStr .. "Conditions are joined by && (AND), and their order does not affect the result.
" + descrStr = descrStr .. "Multiple groups can be separated by || (OR), matching succeeds if any group matches.
" + descrStr = descrStr .. "Example: A && B || C && D means (A AND B) OR (C AND D)." + o.description = translate(descrStr) o = s:option(ListValue, _n("balancingStrategy"), translate("Balancing Strategy")) o:depends({ [_n("protocol")] = "_balancing" }) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua index 5284791c..439cfb71 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua @@ -151,9 +151,10 @@ if load_urltest_options then -- [[ URLTest Start ]] o:depends({ [_n("node_add_mode")] = "batch" }) local descrStr = "Example: ^A && B && !C && D$
" descrStr = descrStr .. "This means the node remark must start with A (^), include B, exclude C (!), and end with D ($).
" - descrStr = descrStr .. "Conditions are joined by &&, and their order does not affect the result." - o.description = translate(descrStr) .. string.format("
%s", - translate("Keep the match scope small. Too many nodes can impact router performance.")) + descrStr = descrStr .. "Conditions are joined by && (AND), and their order does not affect the result.
" + descrStr = descrStr .. "Multiple groups can be separated by || (OR), matching succeeds if any group matches.
" + descrStr = descrStr .. "Example: A && B || C && D means (A AND B) OR (C AND D)." + o.description = translate(descrStr) o = s:option(Value, _n("urltest_url"), translate("Probe URL")) o:depends({ [_n("protocol")] = "_urltest" }) diff --git a/luci-app-passwall/luasrc/passwall/api.lua b/luci-app-passwall/luasrc/passwall/api.lua index 0d3d616e..7a2ebdc4 100644 --- a/luci-app-passwall/luasrc/passwall/api.lua +++ b/luci-app-passwall/luasrc/passwall/api.lua @@ -348,6 +348,18 @@ function strToTable(str) return loadstring("return " .. str)() end +function is_timehhmm(timeStr) + local hour, minute = string.match(timeStr, "^(%d?%d):(%d%d)$") + if hour and minute then + hour = tonumber(hour) + minute = tonumber(minute) + if hour >= 0 and hour <= 23 and minute >= 0 and minute <= 59 then + return true + end + end + return false +end + function is_normal_node(e) if e and e.type and e.protocol and (e.protocol == "_balancing" or e.protocol == "_shunt" or e.protocol == "_iface" or e.protocol == "_urltest") then return false @@ -1522,11 +1534,22 @@ end function match_node_rule(name, rule) if not name then return false end if not rule or rule == "" then return true end + -- split rule by || into OR groups + local function split_or(expr) + local t = {} + for part in (expr .. "||"):gmatch("(.-)%|%|") do + part = trim(part) + if part ~= "" then + table.insert(t, part) + end + end + return t + end -- split rule by && local function split_and(expr) local t = {} - for part in expr:gmatch("[^&]+") do - part = part:gsub("^%s+", ""):gsub("%s+$", "") + for part in (expr .. "&&"):gmatch("(.-)%&%&") do + part = trim(part) if part ~= "" then table.insert(t, part) end @@ -1557,13 +1580,22 @@ function match_node_rule(name, rule) -- contains return str:find(cond, 1, true) ~= nil end - -- AND logic - for _, cond in ipairs(split_and(rule)) do - if not match_cond(name, cond) then - return false + -- check if all conditions in AND group match + local function match_and_group(str, group_expr) + for _, cond in ipairs(split_and(group_expr)) do + if not match_cond(str, cond) then + return false + end + end + return true + end + -- OR logic: return true if any group matches + for _, group in ipairs(split_or(rule)) do + if match_and_group(name, group) then + return true end end - return true + return false end function get_core(field, candidates) diff --git a/luci-app-passwall/luasrc/passwall/util_xray.lua b/luci-app-passwall/luasrc/passwall/util_xray.lua index 8063196a..cc320701 100644 --- a/luci-app-passwall/luasrc/passwall/util_xray.lua +++ b/luci-app-passwall/luasrc/passwall/util_xray.lua @@ -900,10 +900,10 @@ function gen_config(var) fragment_table = { type = "fragment", settings = { - packets = xray_settings.fragment_packets, - lengths = #lengths > 0 and lengths or nil, - delays = #delays > 0 and delays or nil, - maxSplit = xray_settings.fragment_maxSplit + packets = xray_settings.fragment_packets or "tlshello", + lengths = #lengths > 0 and lengths or {"3-5","6-8","10-20"}, + delays = #delays > 0 and delays or {"10-20"}, + maxSplit = xray_settings.fragment_maxSplit or "3-6" } } end diff --git a/luci-app-passwall/luasrc/view/passwall/app_update/app_version.htm b/luci-app-passwall/luasrc/view/passwall/app_update/app_version.htm index cda606e7..54f34859 100644 --- a/luci-app-passwall/luasrc/view/passwall/app_update/app_version.htm +++ b/luci-app-passwall/luasrc/view/passwall/app_update/app_version.htm @@ -1,7 +1,7 @@ +
<% -local api = require "luci.passwall.api" -local com = require "luci.passwall.com" -local version = {} +local api = self.api +local com = self.com -%> +
diff --git a/luci-app-passwall/po/zh-cn/passwall.po b/luci-app-passwall/po/zh-cn/passwall.po index c71c6761..6189be51 100644 --- a/luci-app-passwall/po/zh-cn/passwall.po +++ b/luci-app-passwall/po/zh-cn/passwall.po @@ -532,14 +532,15 @@ msgstr "节点匹配规则" msgid "" "Example: ^A && B && !C && D$
" "This means the node remark must start with A (^), include B, exclude C (!), and end with D ($).
" -"Conditions are joined by &&, and their order does not affect the result." +"Conditions are joined by && (AND), and their order does not affect the result.
" +"Multiple groups can be separated by || (OR), matching succeeds if any group matches.
" +"Example: A && B || C && D means (A AND B) OR (C AND D)." msgstr "" "示例:^A && B && !C && D$
" "表示节点备注需同时满足:以 A 开头(^)、包含 B、不包含 C(!)、并以 D 结尾($)。
" -"多个条件使用 && 连接,条件顺序不影响结果。" - -msgid "Keep the match scope small. Too many nodes can impact router performance." -msgstr "建议尽量缩小匹配范围,节点过多会增加路由器负载。" +"多个条件使用 &&(与)连接,条件顺序不影响结果。
" +"多组条件之间可使用 ||(或)分隔,任意一组匹配即视为成功。
" +"示例:A && B || C && D 表示 (A 且 B) 或 (C 且 D)。" msgid "Balancing Strategy" msgstr "负载均衡策略" @@ -823,8 +824,8 @@ msgstr "单位:分钟" msgid "stop automatically mode" msgstr "定时关闭模式" -msgid "stop Time(Every day)" -msgstr "关闭时间(每天)" +msgid "stop Time" +msgstr "关闭时间" msgid "stop Interval(Hour)" msgstr "关闭间隔(小时)" @@ -832,8 +833,8 @@ msgstr "关闭间隔(小时)" msgid "start automatically mode" msgstr "定时开启模式" -msgid "start Time(Every day)" -msgstr "开启时间(每天)" +msgid "start Time" +msgstr "开启时间" msgid "start Interval(Hour)" msgstr "开启间隔(小时)" @@ -841,8 +842,8 @@ msgstr "开启间隔(小时)" msgid "restart automatically mode" msgstr "定时重启模式" -msgid "restart Time(Every day)" -msgstr "重启时间(每天)" +msgid "restart Time" +msgstr "重启时间" msgid "restart Interval(Hour)" msgstr "重启间隔(小时)" @@ -1057,17 +1058,14 @@ msgstr "中国域名列表(Chnlist)更新URL" msgid "Rule status" msgstr "规则版本" -msgid "Enable auto update rules" -msgstr "开启自动更新规则" - -msgid "Update Time(every day)" -msgstr "更新时间(每天)" +msgid "Update Time" +msgstr "更新时间" msgid "Update Interval(hour)" msgstr "更新间隔(小时)" -msgid "Update Mode" -msgstr "更新模式" +msgid "Auto Update Mode" +msgstr "自动更新模式" msgid "Loop Mode" msgstr "循环" @@ -1177,9 +1175,6 @@ msgstr "移动中" msgid "App Update" msgstr "组件更新" -msgid "Please confirm that your firmware supports FPU." -msgstr "请确认你的固件支持 FPU。" - msgid "if you want to run from memory, change the path, /tmp beginning then save the application and update it manually." msgstr "如果你希望从内存中运行,请更改路径,/tmp 开头,然后保存应用后,再手动更新。" diff --git a/luci-app-passwall/root/usr/share/passwall/0_default_config b/luci-app-passwall/root/usr/share/passwall/0_default_config index a3668069..a0c018ce 100644 --- a/luci-app-passwall/root/usr/share/passwall/0_default_config +++ b/luci-app-passwall/root/usr/share/passwall/0_default_config @@ -55,17 +55,12 @@ config global_other option show_node_info '0' config global_rules - option auto_update '1' option chnlist_update '1' option chnroute_update '1' option chnroute6_update '1' option gfwlist_update '1' - option geosite_update '1' - option geoip_update '1' - option enable_geoview '1' - option geo2rule '1' - option week_update '7' - option time_update '4' + option geosite_update '0' + option geoip_update '0' list gfwlist_url 'https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/gfw.txt' list chnroute_url 'https://ispip.clang.cn/all_cn.txt' list chnroute_url 'https://cdn.jsdelivr.net/gh/gaoyifan/china-operator-ip@ip-lists/china.txt' @@ -74,8 +69,8 @@ config global_rules list chnlist_url 'https://cdn.jsdelivr.net/gh/felixonmars/dnsmasq-china-list/accelerated-domains.china.conf' list chnlist_url 'https://cdn.jsdelivr.net/gh/felixonmars/dnsmasq-china-list/apple.china.conf' option v2ray_location_asset '/usr/share/v2ray/' - option geoip_url 'https://cdn.jsdelivr.net/gh/Loyalsoldier/geoip@release/geoip.dat' - option geosite_url 'https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat' + option geoip_url 'https://github.com/Loyalsoldier/geoip/releases/latest/download/geoip.dat' + option geosite_url 'https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat' config global_app option geoview_file '/usr/bin/geoview' diff --git a/luci-app-passwall/root/usr/share/passwall/app.sh b/luci-app-passwall/root/usr/share/passwall/app.sh index 4e8e67f1..d8a083ca 100755 --- a/luci-app-passwall/root/usr/share/passwall/app.sh +++ b/luci-app-passwall/root/usr/share/passwall/app.sh @@ -74,7 +74,7 @@ check_run_environment() { run_ipt2socks() { local flag proto tcp_tproxy local_port socks_address socks_port socks_username socks_password log_file local _extra_param="" - eval_set_val $@ + eval_set_val "$@" [ -n "$log_file" ] || log_file="/dev/null" socks_address=$(get_host_ip "ipv4" ${socks_address}) [ -n "$socks_username" ] && [ -n "$socks_password" ] && _extra_param="${_extra_param} -a $socks_username -k $socks_password" @@ -100,7 +100,7 @@ run_singbox() { local flag type node tcp_redir_port tcp_proxy_way udp_redir_port socks_address socks_port socks_username socks_password http_address http_port http_username http_password local dns_listen_port direct_dns_query_strategy direct_dns_port direct_dns_udp_server direct_dns_tcp_server remote_dns_protocol remote_dns_udp_server remote_dns_tcp_server remote_dns_doh remote_dns_client_ip remote_fakedns remote_dns_query_strategy dns_cache dns_socks_address dns_socks_port local loglevel log_file config_file server_host server_port no_run - eval_set_val $@ + eval_set_val "$@" [ -z "$type" ] && { type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z') [ "$type" != "sing-box" ] && [ -n "$SINGBOX_BIN" ] && type="sing-box" @@ -198,7 +198,7 @@ run_xray() { local flag type node tcp_redir_port tcp_proxy_way udp_redir_port socks_address socks_port socks_username socks_password http_address http_port http_username http_password local dns_listen_port direct_dns_query_strategy direct_dns_port direct_dns_udp_server direct_dns_tcp_server remote_dns_protocol remote_dns_udp_server remote_dns_tcp_server remote_dns_doh remote_dns_client_ip remote_fakedns remote_dns_query_strategy dns_cache dns_socks_address dns_socks_port local loglevel log_file config_file server_host server_port no_run - eval_set_val $@ + eval_set_val "$@" [ -z "$type" ] && { type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z') [ "$type" != "xray" ] && [ -n "$XRAY_BIN" ] && type="xray" @@ -287,7 +287,7 @@ run_xray() { run_dns2socks() { local flag socks socks_address socks_port socks_username socks_password listen_address listen_port dns cache log_file local _extra_param="" - eval_set_val $@ + eval_set_val "$@" [ -n "$flag" ] && flag="_${flag}" [ -n "$log_file" ] || log_file="/dev/null" dns=$(get_first_dns dns 53 | sed 's/#/:/g') @@ -305,11 +305,11 @@ run_dns2socks() { run_chinadns_ng() { local _flag _listen_port _dns_local _dns_trust _no_ipv6_trust _use_direct_list _use_proxy_list _gfwlist _chnlist _default_mode _default_tag _no_logic_log _tcp_node _remote_fakedns _filter_https local _extra_param="" - eval_set_val $@ + eval_set_val "$@" local _CONF_FILE=$TMP_ACL_PATH/$_flag/chinadns_ng.conf local _LOG_FILE="/dev/null" - [ "$(config_t_get global log_chinadns_ng "0")" == "1" ] && _LOG_FILE=$TMP_ACL_PATH/$_flag/chinadns_ng.log + [ "$(config_t_get global log_chinadns_ng "0")" = "1" ] && _LOG_FILE=$TMP_ACL_PATH/$_flag/chinadns_ng.log _extra_param="-FLAG ${_flag} -TCP_NODE ${_tcp_node} -LISTEN_PORT ${_listen_port} -DNS_LOCAL ${_dns_local} -DNS_TRUST ${_dns_trust}" _extra_param="${_extra_param} -USE_DIRECT_LIST ${_use_direct_list} -USE_PROXY_LIST ${_use_proxy_list} -USE_BLOCK_LIST ${_use_block_list}" @@ -323,7 +323,7 @@ run_chinadns_ng() { run_socks() { local flag node bind socks_port config_file http_port http_config_file relay_port log_file no_run - eval_set_val $@ + eval_set_val "$@" [ -n "$config_file" ] && [ -z "$(echo ${config_file} | grep $TMP_PATH)" ] && config_file=$TMP_PATH/$config_file [ -n "$http_port" ] || http_port=0 [ -n "$http_config_file" ] && [ -z "$(echo ${http_config_file} | grep $TMP_PATH)" ] && http_config_file=$TMP_PATH/$http_config_file @@ -367,14 +367,14 @@ run_socks() { error_msg="某种原因,此 Socks 服务的相关配置已失联,启动中止!" fi - if [ "$type" == "sing-box" ] || [ "$type" == "xray" ]; then + if [ "$type" = "sing-box" ] || [ "$type" = "xray" ]; then local protocol=$(config_n_get $node protocol) - if [ "$protocol" == "_balancing" ] || [ "$protocol" == "_shunt" ] || [ "$protocol" == "_iface" ] || [ "$protocol" == "_urltest" ]; then + if [ "$protocol" = "_balancing" ] || [ "$protocol" = "_shunt" ] || [ "$protocol" = "_iface" ] || [ "$protocol" = "_urltest" ]; then unset error_msg fi fi - if [ -n "${error_msg}" ] && ([ -n "$(config_n_get $node hysteria_hop)" ] || [ -n "$(config_n_get $node hysteria2_hop)" ] || [ "$(config_n_get $node hysteria2_realms)" = "1" ]); then + if [ -n "${error_msg}" ] && { [ -n "$(config_n_get $node hysteria_hop)" ] || [ -n "$(config_n_get $node hysteria2_hop)" ] || [ "$(config_n_get $node hysteria2_realms)" = "1" ]; }; then unset error_msg fi @@ -527,7 +527,7 @@ run_socks() { run_redir() { local node proto bind local_port config_file log_file - eval_set_val $@ + eval_set_val "$@" local tcp_node_socks_flag tcp_node_http_flag [ -n "$config_file" ] && [ -z "$(echo ${config_file} | grep $TMP_PATH)" ] && config_file=${GLOBAL_ACL_PATH}/${config_file} if [ -n "$log_file" ] && [ -z "$(echo ${log_file} | grep $TMP_PATH)" ]; then @@ -644,7 +644,7 @@ run_redir() { tcp_node_socks_port=$(get_new_port $(config_t_get global tcp_node_socks_port 1070)) tcp_node_http_port=$(config_t_get global tcp_node_http_port 0) [ "$tcp_node_http_port" != "0" ] && tcp_node_http=1 - if [ $PROXY_IPV6 == "1" ]; then + if [ $PROXY_IPV6 = "1" ]; then echolog "开启实验性IPv6透明代理(TProxy),请确认您的节点及类型支持IPv6!" fi @@ -725,7 +725,7 @@ run_redir() { DNSMASQ_FILTER_PROXY_IPV6=0 local _remote_dns_client_ip=$(config_t_get global remote_dns_client_ip) [ -n "${_remote_dns_client_ip}" ] && _args="${_args} remote_dns_client_ip=${_remote_dns_client_ip}" - [ "${DNS_CACHE}" == "0" ] && _args="${_args} dns_cache=0" + [ "${DNS_CACHE}" = "0" ] && _args="${_args} dns_cache=0" resolve_dns_port=${NEXT_DNS_LISTEN_PORT} _args="${_args} dns_listen_port=${resolve_dns_port}" @@ -811,7 +811,7 @@ run_redir() { DNSMASQ_FILTER_PROXY_IPV6=0 local _remote_dns_client_ip=$(config_t_get global remote_dns_client_ip) [ -n "${_remote_dns_client_ip}" ] && _args="${_args} remote_dns_client_ip=${_remote_dns_client_ip}" - [ "${DNS_CACHE}" == "0" ] && _args="${_args} dns_cache=0" + [ "${DNS_CACHE}" = "0" ] && _args="${_args} dns_cache=0" resolve_dns_port=${NEXT_DNS_LISTEN_PORT} _args="${_args} dns_listen_port=${resolve_dns_port}" @@ -984,7 +984,7 @@ start_socks() { echolog "分析 Socks 服务的节点配置..." for id in $ids; do local enabled=$(config_n_get $id enabled 0) - [ "$enabled" == "0" ] && continue + [ "$enabled" = "0" ] && continue local node=$(config_n_get $id node) [ -z "$node" ] && continue local bind_local=$(config_n_get $id bind_local 0) @@ -994,7 +994,7 @@ start_socks() { local config_file="SOCKS_${id}.json" local log_file="SOCKS_${id}.log" local log=$(config_n_get $id log 1) - [ "$log" == "0" ] && log_file="" + [ "$log" = "0" ] && log_file="" local http_port=$(config_n_get $id http_port 0) local http_config_file="HTTP2SOCKS_${id}.json" local enable_autoswitch=$(config_n_get $id enable_autoswitch 0) @@ -1012,7 +1012,7 @@ start_socks() { socks_node_switch() { local flag new_node - eval_set_val $@ + eval_set_val "$@" [ -n "$flag" ] && [ -n "$new_node" ] && { local prefix pf filename # 结束 SS 插件进程 @@ -1037,7 +1037,7 @@ socks_node_switch() { local config_file="SOCKS_${flag}.json" local log_file="SOCKS_${flag}.log" local log=$(config_n_get $flag log 1) - [ "$log" == "0" ] && log_file="" + [ "$log" = "0" ] && log_file="" local http_port=$(config_n_get $flag http_port 0) local http_config_file="HTTP2SOCKS_${flag}.json" LOG_FILE="/dev/null" @@ -1045,7 +1045,7 @@ socks_node_switch() { set_cache_var "socks_${flag}" "$new_node" local ENABLED_DEFAULT_ACL=$(get_cache_var "ENABLED_DEFAULT_ACL") local ENABLED_ACLS=$(get_cache_var "ENABLED_ACLS") - [ "$ENABLED_DEFAULT_ACL" != "1" -a "$ENABLED_ACLS" != "1" ] && return + [ "$ENABLED_DEFAULT_ACL" != "1" ] && [ "$ENABLED_ACLS" != "1" ] && return local USE_TABLES=$(get_cache_var "USE_TABLES") [ -n "$USE_TABLES" ] && source $APP_PATH/${USE_TABLES}.sh filter_direct_node_list } @@ -1086,19 +1086,29 @@ start_crontab() { build_time() { local w="$1" - local h="$2" - local expr="0 $h * * $w" - [ "$w" = "7" ] && expr="0 $h * * *" + local t="$2" + local h m + if echo "$t" | grep -q ':'; then + h="${t%%:*}" + m="${t##*:}" + else + h="$t" + m=0 + fi + h=$(printf '%d' "$h") + m=$(printf '%d' "$m") + local expr="$m $h * * $w" + [ "$w" = "7" ] && expr="$m $h * * *" echo "$expr" } add_service_cron() { local week="$1" - local hour="$2" + local time="$2" local action="$3" local logmsg="$4" [ -z "$week" ] && return - local svr_t=$(build_time "$week" "$hour") + local svr_t=$(build_time "$week" "$time") if [ "$week" = "8" ]; then update_loop=1 else @@ -1115,12 +1125,11 @@ start_crontab() { add_service_cron "$(config_t_get global_delay restart_week_mode)" "$(config_t_get global_delay restart_time_mode)" "restart" "配置定时任务:自动重启服务。" # ===== rule update ===== - local autoupdate=$(config_t_get global_rules auto_update) - local weekupdate=$(config_t_get global_rules week_update) - local dayupdate=$(config_t_get global_rules time_update) - if [ "$autoupdate" = "1" ]; then - local rule_t=$(build_time "$weekupdate" "$dayupdate") - if [ "$weekupdate" = "8" ]; then + local rules_update_week_mode=$(config_t_get global_rules update_week_mode) + local rules_update_time_mode=$(config_t_get global_rules update_time_mode) + if [ -n "$rules_update_week_mode" ]; then + local rule_t=$(build_time "$rules_update_week_mode" "$rules_update_time_mode") + if [ "$rules_update_week_mode" = "8" ]; then update_loop=1 else echo "$rule_t lua $APP_PATH/rule_update.lua log all cron > /dev/null 2>&1 &" >>/etc/crontabs/root @@ -1131,25 +1140,25 @@ start_crontab() { # ===== subscribe ===== local TMP_SUB_PATH=$TMP_PATH/sub_crontabs mkdir -p "$TMP_SUB_PATH" - local item cfgid remark week_update time_update + local item cfgid remark sub_update_week_mode sub_update_time_mode for item in $(uci show ${CONFIG} | grep "=subscribe_list" | cut -d '.' -sf 2 | cut -d '=' -sf 1); do - if [ "$(config_n_get "$item" auto_update 0)" = "1" ]; then + sub_update_week_mode=$(config_n_get $item update_week_mode) + if [ -n "$sub_update_week_mode" ]; then cfgid=$(uci show ${CONFIG}.$item | head -n 1 | cut -d '.' -sf 2 | cut -d '=' -sf 1) remark=$(config_n_get "$item" remark) - week_update=$(config_n_get "$item" week_update) - time_update=$(config_n_get "$item" time_update) - echo "$cfgid" >> "$TMP_SUB_PATH/${week_update}_${time_update}" + sub_update_time_mode=$(config_n_get $item update_time_mode) + echo "$cfgid" >> "$TMP_SUB_PATH/${sub_update_week_mode}_${sub_update_time_mode}" echolog "配置定时任务:自动更新【$remark】订阅。" fi done if [ -d "$TMP_SUB_PATH" ]; then local name cfgids for name in $(ls "$TMP_SUB_PATH"); do - week_update=${name%_*} - time_update=${name#*_} + sub_update_week_mode=${name%_*} + sub_update_time_mode=${name#*_} cfgids=$(tr '\n' ',' < "$TMP_SUB_PATH/$name" | sed 's/,$//') - local sub_t=$(build_time "$week_update" "$time_update") - if [ "$week_update" = "8" ]; then + local sub_t=$(build_time "$sub_update_week_mode" "$sub_update_time_mode") + if [ "$sub_update_week_mode" = "8" ]; then update_loop=1 else echo "$sub_t lua $APP_PATH/subscribe.lua start $cfgids cron > /dev/null 2>&1 &" >>/etc/crontabs/root @@ -1253,7 +1262,7 @@ start_dns() { local log_file=$TMP_PATH/DNS.log local log_file=/dev/null local _args="type=$DNS_MODE config_file=$config_file log_file=$log_file" - [ "${DNS_CACHE}" == "0" ] && _args="${_args} dns_cache=0" + [ "${DNS_CACHE}" = "0" ] && _args="${_args} dns_cache=0" _args="${_args} direct_dns_query_strategy=${DIRECT_DNS_QUERY_STRATEGY}" _args="${_args} remote_dns_query_strategy=${REMOTE_DNS_QUERY_STRATEGY}" DNSMASQ_FILTER_PROXY_IPV6=0 @@ -1292,7 +1301,7 @@ start_dns() { local log_file=$TMP_PATH/DNS.log local log_file=/dev/null local _args="type=$DNS_MODE config_file=$config_file log_file=$log_file" - [ "${DNS_CACHE}" == "0" ] && _args="${_args} dns_cache=0" + [ "${DNS_CACHE}" = "0" ] && _args="${_args} dns_cache=0" _args="${_args} direct_dns_query_strategy=${DIRECT_DNS_QUERY_STRATEGY}" _args="${_args} remote_dns_query_strategy=${REMOTE_DNS_QUERY_STRATEGY}" DNSMASQ_FILTER_PROXY_IPV6=0 @@ -1363,7 +1372,7 @@ start_dns() { rm -rf $TMP_PATH2/dnsmasq_default* local group_domestic=$(config_t_get global group_domestic) local smartdns_remote_dns=$(config_t_get global smartdns_remote_dns) - if [ -n "${smartdns_remote_dns}" -a "${smartdns_remote_dns}" != "nil" ]; then + if [ -n "${smartdns_remote_dns}" ] && [ "${smartdns_remote_dns}" != "nil" ]; then smartdns_remote_dns=$(echo ${smartdns_remote_dns} | tr -s ' ' '|') else smartdns_remote_dns="tcp://1.1.1.1" @@ -1430,13 +1439,13 @@ start_dns() { [ "$USE_DEFAULT_DNS" = "remote" ] && { dnsmasq_version=$(dnsmasq -v | grep -i "Dnsmasq version " | awk '{print $3}') - [ "$(expr $dnsmasq_version \>= 2.87)" == 0 ] && echolog "Dnsmasq版本低于2.87,有可能无法正常使用!!!" + [ "$(check_ver "$dnsmasq_version" "2.87")" = "1" ] && echolog "Dnsmasq版本低于2.87,有可能无法正常使用!!!" } local DNSMASQ_TUN_DNS=$(get_first_dns TUN_DNS 53) local RUN_NEW_DNSMASQ=1 RUN_NEW_DNSMASQ=${DNS_REDIRECT} - if [ "${RUN_NEW_DNSMASQ}" == "0" ]; then + if [ "${RUN_NEW_DNSMASQ}" = "0" ]; then #The old logic will be removed in the future. #Run a copy dnsmasq instance, DNS hijack that don't need a proxy devices. [ "1" = "0" ] && { @@ -1542,7 +1551,7 @@ acl_app() { local acl_path=${TMP_ACL_PATH}/$sid mkdir -p ${acl_path} - [ -n "${source_list}" ] && echo -e "${source_list}" | sed '/^$/d' > ${acl_path}/source_list + [ -n "${source_list}" ] && printf "%b\n" "${source_list}" | sed '/^$/d' > ${acl_path}/source_list use_global_config=${use_global_config:-0} [ "${use_global_config}" = "1" ] && { @@ -1627,7 +1636,7 @@ acl_app() { _dns_port=$dns_port if [ "$dns_mode" = "dns2socks" ]; then run_dns2socks flag=acl_${sid} socks_address=127.0.0.1 socks_port=$socks_port listen_address=0.0.0.0 listen_port=${_dns_port} dns=$remote_dns cache=1 - elif [ "$dns_mode" = "sing-box" -o "$dns_mode" = "xray" ]; then + elif [ "$dns_mode" = "sing-box" ] || [ "$dns_mode" = "xray" ]; then config_file=$TMP_ACL_PATH/${tcp_node}_SOCKS_${socks_port}_DNS.json remote_dns_doh=${remote_dns_doh:-https://1.1.1.1/dns-query} local type=${dns_mode} @@ -1853,8 +1862,8 @@ start() { nftflag=0 USE_TABLES="" check_run_environment - if [ "$ENABLED_DEFAULT_ACL" == 1 ] || [ "$ENABLED_ACLS" == 1 ]; then - [ "$(uci -q get dhcp.@dnsmasq[0].dns_redirect)" == "1" ] && { + if [ "$ENABLED_DEFAULT_ACL" = 1 ] || [ "$ENABLED_ACLS" = 1 ]; then + [ "$(uci -q get dhcp.@dnsmasq[0].dns_redirect)" = "1" ] && { uci -q set ${CONFIG}.@global[0].dnsmasq_dns_redirect='1' uci -q commit ${CONFIG} uci -q set dhcp.@dnsmasq[0].dns_redirect='0' @@ -1862,7 +1871,7 @@ start() { lua $APP_PATH/helper_dnsmasq.lua restart -LOG 0 } fi - [ "$ENABLED_DEFAULT_ACL" == 1 ] && { + [ "$ENABLED_DEFAULT_ACL" = 1 ] && { mkdir -p ${GLOBAL_ACL_PATH} start_redir TCP start_redir UDP @@ -1870,11 +1879,11 @@ start() { } [ -n "$USE_TABLES" ] && source $APP_PATH/${USE_TABLES}.sh start set_cache_var "USE_TABLES" "$USE_TABLES" - if [ "$ENABLED_DEFAULT_ACL" == 1 ] || [ "$ENABLED_ACLS" == 1 ]; then + if [ "$ENABLED_DEFAULT_ACL" = 1 ] || [ "$ENABLED_ACLS" = 1 ]; then bridge_nf_ipt=$(sysctl -e -n net.bridge.bridge-nf-call-iptables) set_cache_var "bak_bridge_nf_ipt" "$bridge_nf_ipt" sysctl -w net.bridge.bridge-nf-call-iptables=0 >/dev/null 2>&1 - [ "$PROXY_IPV6" == "1" ] && { + [ "$PROXY_IPV6" = "1" ] && { bridge_nf_ip6t=$(sysctl -e -n net.bridge.bridge-nf-call-ip6tables) set_cache_var "bak_bridge_nf_ip6t" "$bridge_nf_ip6t" sysctl -w net.bridge.bridge-nf-call-ip6tables=0 >/dev/null 2>&1 @@ -1981,7 +1990,7 @@ get_config() { } ENABLED_ACLS=$(config_t_get global acl_enable 0) [ "$ENABLED_ACLS" = 1 ] && { - [ "$(uci show ${CONFIG} | grep "@acl_rule" | grep "enabled='1'" | wc -l)" == 0 ] && ENABLED_ACLS=0 + [ "$(uci show ${CONFIG} | grep "@acl_rule" | grep "enabled='1'" | wc -l)" = 0 ] && ENABLED_ACLS=0 } set_cache_var ENABLED_DEFAULT_ACL $ENABLED_DEFAULT_ACL set_cache_var ENABLED_ACLS $ENABLED_ACLS @@ -2004,7 +2013,7 @@ get_config() { [ "${TCP_PROXY_MODE}" != "disable" ] && TCP_PROXY_MODE="proxy" [ "${UDP_PROXY_MODE}" != "disable" ] && UDP_PROXY_MODE="proxy" LOCALHOST_PROXY=$(config_t_get global localhost_proxy 1) - [ "${LOCALHOST_PROXY}" == 1 ] && { + [ "${LOCALHOST_PROXY}" = 1 ] && { LOCALHOST_TCP_PROXY_MODE=$TCP_PROXY_MODE LOCALHOST_UDP_PROXY_MODE=$UDP_PROXY_MODE } @@ -2075,13 +2084,13 @@ arg1=$1 shift case $arg1 in run_socks) - run_socks $@ + run_socks "$@" ;; socks_node_switch) - socks_node_switch $@ + socks_node_switch "$@" ;; start) - start $@ + start "$@" ;; stop) stop diff --git a/luci-app-passwall/root/usr/share/passwall/iptables.sh b/luci-app-passwall/root/usr/share/passwall/iptables.sh index e34b2b99..53a2a42c 100755 --- a/luci-app-passwall/root/usr/share/passwall/iptables.sh +++ b/luci-app-passwall/root/usr/share/passwall/iptables.sh @@ -38,8 +38,8 @@ ipt_n="$ipt -t nat -w" ipt_m="$ipt -t mangle -w" ip6t_n="$ip6t -t nat -w" ip6t_m="$ip6t -t mangle -w" -[ -z "$ip6t" -o -z "$(lsmod | grep 'ip6table_nat')" ] && ip6t_n="eval #$ip6t_n" -[ -z "$ip6t" -o -z "$(lsmod | grep 'ip6table_mangle')" ] && ip6t_m="eval #$ip6t_m" +[ -z "$ip6t" ] || [ -z "$(lsmod | grep 'ip6table_nat')" ] && ip6t_n="eval #$ip6t_n" +[ -z "$ip6t" ] || [ -z "$(lsmod | grep 'ip6table_mangle')" ] && ip6t_m="eval #$ip6t_m" FWI=$(uci -q get firewall.passwall.path 2>/dev/null) FAKE_IP="198.18.0.0/15" FAKE_IP_6="fc00::/18" @@ -47,7 +47,7 @@ FAKE_IP_6="fc00::/18" factor() { if [ -z "$1" ] || [ -z "$2" ]; then echo "" - elif [ "$1" == "1:65535" ]; then + elif [ "$1" = "1:65535" ]; then echo "" else echo "$2 $1" @@ -168,7 +168,7 @@ REDIRECT() { local s="-j REDIRECT" [ -n "$1" ] && { local s="$s --to-ports $1" - [ "$2" == "TPROXY" ] && { + [ "$2" = "TPROXY" ] && { local mark="-m mark --mark ${FWMARK}" s="${mark} -j TPROXY --on-port $1" } @@ -195,11 +195,11 @@ get_jump_ipt() { } load_acl() { - ([ "$ENABLED_ACLS" == 1 ] || ([ "$ENABLED_DEFAULT_ACL" == 1 ] && [ "$CLIENT_PROXY" == 1 ])) && echolog " - 访问控制:" - [ "$ENABLED_ACLS" == 1 ] && { + { [ "$ENABLED_ACLS" = "1" ] || { [ "$ENABLED_DEFAULT_ACL" = "1" ] && [ "$CLIENT_PROXY" = "1" ]; }; } && echolog " - 访问控制:" + [ "$ENABLED_ACLS" = 1 ] && { acl_app for sid in $(ls -F ${TMP_ACL_PATH} | grep '/$' | awk -F '/' '{print $1}' | grep -v 'default'); do - eval $(uci -q show "${CONFIG}.${sid}" | cut -d'.' -sf 3-) + eval "$(uci -q show "${CONFIG}.${sid}" | cut -d'.' -sf 3-)" tcp_no_redir_ports=${tcp_no_redir_ports:-default} udp_no_redir_ports=${udp_no_redir_ports:-default} @@ -379,7 +379,7 @@ load_acl() { ipset -! create $gfw6_set_name nethash family inet6 maxelem 1048576 timeout 172800 } } - [ "${use_shunt_tcp}" = "1" -o "${use_shunt_udp}" = "1" ] && { + [ "${use_shunt_tcp}" = "1" ] || [ "${use_shunt_udp}" = "1" ] && { [ "${use_global_config}" = "0" ] && { shunt_set_name="psw_${sid}_shunt" shunt6_set_name="psw_${sid}_shunt6" @@ -403,16 +403,16 @@ load_acl() { [ -z "$(get_cache_var "ACL_${sid}_tcp_default")" ] && echolog " - ${msg}使用与全局配置不相同节点,已将DNS强制重定向到专用 DNS 服务器。" fi - [ -n "$tcp_port" -o -n "$udp_port" ] && { + [ -n "$tcp_port" ] || [ -n "$udp_port" ] && { [ "${use_block_list}" = "1" ] && $ipt_m -A PSW $(comment "$remarks") ${_ipt_source} $(dst $IPSET_BLOCK) -j DROP [ "${use_direct_list}" = "1" ] && $ipt_tmp -A PSW $(comment "$remarks") ${_ipt_source} $(dst $IPSET_WHITE) -j RETURN - [ "$PROXY_IPV6" == "1" ] && [ "$_ipv4" != "1" ] && { + [ "$PROXY_IPV6" = "1" ] && [ "$_ipv4" != "1" ] && { [ "${use_block_list}" = "1" ] && $ip6t_m -A PSW $(comment "$remarks") ${_ipt_source} $(dst $IPSET_BLOCK6) -j DROP 2>/dev/null [ "${use_direct_list}" = "1" ] && $ip6t_m -A PSW $(comment "$remarks") ${_ipt_source} $(dst $IPSET_WHITE6) -j RETURN 2>/dev/null } [ "$tcp_proxy_drop_ports" != "disable" ] && { - [ "$PROXY_IPV6" == "1" ] && [ "$_ipv4" != "1" ] && { + [ "$PROXY_IPV6" = "1" ] && [ "$_ipv4" != "1" ] && { [ "${use_fakedns}" = "1" ] && add_port_rules "$ip6t_m -A PSW $(comment "$remarks") -p tcp ${_ipt_source}" $tcp_proxy_drop_ports "-d $FAKE_IP_6 -j DROP" 2>/dev/null [ "${use_proxy_list}" = "1" ] && add_port_rules "$ip6t_m -A PSW $(comment "$remarks") -p tcp ${_ipt_source}" $tcp_proxy_drop_ports "$(dst $black6_set_name) -j DROP" 2>/dev/null [ "${use_gfw_list}" = "1" ] && add_port_rules "$ip6t_m -A PSW $(comment "$remarks") -p tcp ${_ipt_source}" $tcp_proxy_drop_ports "$(dst $gfw6_set_name) -j DROP" 2>/dev/null @@ -430,7 +430,7 @@ load_acl() { } [ "$udp_proxy_drop_ports" != "disable" ] && { - [ "$PROXY_IPV6" == "1" ] && [ "$_ipv4" != "1" ] && { + [ "$PROXY_IPV6" = "1" ] && [ "$_ipv4" != "1" ] && { [ "${use_fakedns}" = "1" ] && add_port_rules "$ip6t_m -A PSW $(comment "$remarks") -p udp ${_ipt_source}" $udp_proxy_drop_ports "-d $FAKE_IP_6 -j DROP" 2>/dev/null [ "${use_proxy_list}" = "1" ] && add_port_rules "$ip6t_m -A PSW $(comment "$remarks") -p udp ${_ipt_source}" $udp_proxy_drop_ports "$(dst $black6_set_name) -j DROP" 2>/dev/null [ "${use_gfw_list}" = "1" ] && add_port_rules "$ip6t_m -A PSW $(comment "$remarks") -p udp ${_ipt_source}" $udp_proxy_drop_ports "$(dst $gfw6_set_name) -j DROP" 2>/dev/null @@ -469,7 +469,7 @@ load_acl() { [ "${tcp_proxy_mode}" != "disable" ] && $ipt_n -A PSW $(comment "$remarks") -p icmp ${_ipt_source} $(REDIRECT) } - [ "$accept_icmpv6" = "1" ] && [ "$PROXY_IPV6" == "1" ] && [ "$_ipv4" != "1" ] && { + [ "$accept_icmpv6" = "1" ] && [ "$PROXY_IPV6" = "1" ] && [ "$_ipv4" != "1" ] && { [ "${use_fakedns}" = "1" ] && $ip6t_n -A PSW $(comment "$remarks") -p ipv6-icmp ${_ipt_source} -d $FAKE_IP_6 $(REDIRECT) 2>/dev/null [ "${use_proxy_list}" = "1" ] && $ip6t_n -A PSW $(comment "$remarks") -p ipv6-icmp ${_ipt_source} $(dst $black6_set_name) $(REDIRECT) 2>/dev/null [ "${use_gfw_list}" = "1" ] && $ip6t_n -A PSW $(comment "$remarks") -p ipv6-icmp ${_ipt_source} $(dst $gfw6_set_name) $(REDIRECT) 2>/dev/null @@ -486,7 +486,7 @@ load_acl() { [ "${tcp_proxy_mode}" != "disable" ] && add_port_rules "$ipt_tmp -A PSW $(comment "$remarks") -p tcp ${_ipt_source}" $tcp_redir_ports "${ipt_j}" [ -n "${is_tproxy}" ] && $ipt_m -A PSW $(comment "$remarks") -p tcp ${_ipt_source} $(REDIRECT $tcp_port TPROXY) - [ "$PROXY_IPV6" == "1" ] && [ "$_ipv4" != "1" ] && { + [ "$PROXY_IPV6" = "1" ] && [ "$_ipv4" != "1" ] && { [ "${use_fakedns}" = "1" ] && $ip6t_m -A PSW $(comment "$remarks") -p tcp ${_ipt_source} -d $FAKE_IP_6 -j PSW_RULE 2>/dev/null [ "${use_proxy_list}" = "1" ] && add_port_rules "$ip6t_m -A PSW $(comment "$remarks") -p tcp ${_ipt_source}" $tcp_redir_ports "$(dst $black6_set_name) -j PSW_RULE" 2>/dev/null [ "${use_gfw_list}" = "1" ] && add_port_rules "$ip6t_m -A PSW $(comment "$remarks") -p tcp ${_ipt_source}" $tcp_redir_ports "$(dst $gfw6_set_name) -j PSW_RULE" 2>/dev/null @@ -517,7 +517,7 @@ load_acl() { [ "${udp_proxy_mode}" != "disable" ] && add_port_rules "$ipt_m -A PSW $(comment "$remarks") -p udp ${_ipt_source}" $udp_redir_ports "-j PSW_RULE" $ipt_m -A PSW $(comment "$remarks") -p udp ${_ipt_source} $(REDIRECT $udp_port TPROXY) - [ "$PROXY_IPV6" == "1" ] && [ "$_ipv4" != "1" ] && { + [ "$PROXY_IPV6" = "1" ] && [ "$_ipv4" != "1" ] && { [ "${use_fakedns}" = "1" ] && $ip6t_m -A PSW $(comment "$remarks") -p udp ${_ipt_source} -d $FAKE_IP_6 -j PSW_RULE 2>/dev/null [ "${use_proxy_list}" = "1" ] && add_port_rules "$ip6t_m -A PSW $(comment "$remarks") -p udp ${_ipt_source}" $udp_redir_ports "$(dst $black6_set_name) -j PSW_RULE" 2>/dev/null [ "${use_gfw_list}" = "1" ] && add_port_rules "$ip6t_m -A PSW $(comment "$remarks") -p udp ${_ipt_source}" $udp_redir_ports "$(dst $gfw6_set_name) -j PSW_RULE" 2>/dev/null @@ -540,7 +540,7 @@ load_acl() { done } - [ "$ENABLED_DEFAULT_ACL" == 1 ] && [ "$CLIENT_PROXY" == 1 ] && { + [ "$ENABLED_DEFAULT_ACL" = 1 ] && [ "$CLIENT_PROXY" = 1 ] && { msg="【默认】," local ipt_tmp=$ipt_n [ -n "${is_tproxy}" ] && ipt_tmp=$ipt_m @@ -586,22 +586,22 @@ load_acl() { $ip6t_n -A PSW_DNS $(comment "默认") -p tcp --dport 53 -j REDIRECT --to-ports ${DNS_REDIRECT} 2>/dev/null fi - [ -n "${TCP_PROXY_MODE}" -o -n "${UDP_PROXY_MODE}" ] && { + [ -n "${TCP_PROXY_MODE}" ] || [ -n "${UDP_PROXY_MODE}" ] && { [ "${USE_BLOCK_LIST}" = "1" ] && $ipt_m -A PSW $(comment "默认") $(dst $IPSET_BLOCK) -j DROP [ "${USE_DIRECT_LIST}" = "1" ] && $ipt_tmp -A PSW $(comment "默认") $(dst $IPSET_WHITE) -j RETURN - [ "$PROXY_IPV6" == "1" ] && { + [ "$PROXY_IPV6" = "1" ] && { [ "${USE_BLOCK_LIST}" = "1" ] && $ip6t_m -A PSW $(comment "默认") $(dst $IPSET_BLOCK6) -j DROP 2>/dev/null [ "${USE_DIRECT_LIST}" = "1" ] && $ip6t_m -A PSW $(comment "默认") $(dst $IPSET_WHITE6) -j RETURN 2>/dev/null } [ "$TCP_PROXY_DROP_PORTS" != "disable" ] && { - [ "$PROXY_IPV6" == "1" ] && { + [ "$PROXY_IPV6" = "1" ] && { [ "${USE_FAKEDNS}" = "1" ] && add_port_rules "$ip6t_m -A PSW $(comment "默认") -p tcp" $TCP_PROXY_DROP_PORTS "-d $FAKE_IP_6 -j DROP" [ "${USE_PROXY_LIST}" = "1" ] && add_port_rules "$ip6t_m -A PSW $(comment "默认") -p tcp" $TCP_PROXY_DROP_PORTS "$(dst $IPSET_BLACK6) -j DROP" [ "${USE_GFW_LIST}" = "1" ] && add_port_rules "$ip6t_m -A PSW $(comment "默认") -p tcp" $TCP_PROXY_DROP_PORTS "$(dst $IPSET_GFW6) -j DROP" [ "${CHN_LIST}" != "0" ] && add_port_rules "$ip6t_m -A PSW $(comment "默认") -p tcp" $TCP_PROXY_DROP_PORTS "$(dst $IPSET_CHN6) $(get_jump_ipt ${CHN_LIST} "-j DROP")" - [ "${USE_SHUNT_TCP}" = "1" ] && $ip6t_m -A PSW $(comment "默认") -p tcp $TCP_PROXY_DROP_PORTS "$(dst $IPSET_SHUNT6) -j DROP" - [ "${TCP_PROXY_MODE}" != "disable" ] && $ip6t_m -A PSW $(comment "默认") -p tcp $TCP_PROXY_DROP_PORTS "-j DROP" + [ "${USE_SHUNT_TCP}" = "1" ] && add_port_rules "$ip6t_m -A PSW $(comment "默认") -p tcp" $TCP_PROXY_DROP_PORTS "$(dst $IPSET_SHUNT6) -j DROP" + [ "${TCP_PROXY_MODE}" != "disable" ] && add_port_rules "$ip6t_m -A PSW $(comment "默认") -p tcp" $TCP_PROXY_DROP_PORTS "-j DROP" } [ "${USE_FAKEDNS}" = "1" ] && add_port_rules "$ipt_m -A PSW $(comment "默认") -p tcp" $TCP_PROXY_DROP_PORTS "-d $FAKE_IP -j DROP" [ "${USE_PROXY_LIST}" = "1" ] && add_port_rules "$ipt_m -A PSW $(comment "默认") -p tcp" $TCP_PROXY_DROP_PORTS "$(dst $IPSET_BLACK) -j DROP" @@ -613,12 +613,12 @@ load_acl() { } [ "$UDP_PROXY_DROP_PORTS" != "disable" ] && { - [ "$PROXY_IPV6" == "1" ] && { + [ "$PROXY_IPV6" = "1" ] && { [ "${USE_FAKEDNS}" = "1" ] && add_port_rules "$ip6t_m -A PSW $(comment "默认") -p udp" $UDP_PROXY_DROP_PORTS "-d $FAKE_IP_6 -j DROP" [ "${USE_PROXY_LIST}" = "1" ] && add_port_rules "$ip6t_m -A PSW $(comment "默认") -p udp" $UDP_PROXY_DROP_PORTS "$(dst $IPSET_BLACK6) -j DROP" [ "${USE_GFW_LIST}" = "1" ] && add_port_rules "$ip6t_m -A PSW $(comment "默认") -p udp" $UDP_PROXY_DROP_PORTS "$(dst $IPSET_GFW6) -j DROP" [ "${CHN_LIST}" != "0" ] && add_port_rules "$ip6t_m -A PSW $(comment "默认") -p udp" $UDP_PROXY_DROP_PORTS "$(dst $IPSET_CHN6) $(get_jump_ipt ${CHN_LIST} "-j DROP")" - [ "${USE_SHUNT_TCP}" = "1" ] && add_port_rules "$ip6t_m -A PSW $(comment "默认") -p udp" $UDP_PROXY_DROP_PORTS "$(dst $IPSET_SHUNT6) -j DROP" + [ "${USE_SHUNT_UDP}" = "1" ] && add_port_rules "$ip6t_m -A PSW $(comment "默认") -p udp" $UDP_PROXY_DROP_PORTS "$(dst $IPSET_SHUNT6) -j DROP" [ "${UDP_PROXY_MODE}" != "disable" ] && add_port_rules "$ip6t_m -A PSW $(comment "默认") -p udp" $UDP_PROXY_DROP_PORTS "-j DROP" } [ "${USE_FAKEDNS}" = "1" ] && add_port_rules "$ipt_m -A PSW $(comment "默认") -p udp" $UDP_PROXY_DROP_PORTS "-d $FAKE_IP -j DROP" @@ -656,7 +656,7 @@ load_acl() { [ "${TCP_PROXY_MODE}" != "disable" ] && $ipt_n -A PSW $(comment "默认") -p icmp $(REDIRECT) } - [ "$accept_icmpv6" = "1" ] && [ "$PROXY_IPV6" == "1" ] && { + [ "$accept_icmpv6" = "1" ] && [ "$PROXY_IPV6" = "1" ] && { [ "${USE_FAKEDNS}" = "1" ] && $ip6t_n -A PSW $(comment "默认") -p ipv6-icmp -d $FAKE_IP_6 $(REDIRECT) [ "${USE_PROXY_LIST}" = "1" ] && $ip6t_n -A PSW $(comment "默认") -p ipv6-icmp $(dst $IPSET_BLACK6) $(REDIRECT) [ "${USE_GFW_LIST}" = "1" ] && $ip6t_n -A PSW $(comment "默认") -p ipv6-icmp $(dst $IPSET_GFW6) $(REDIRECT) @@ -673,7 +673,7 @@ load_acl() { [ "${TCP_PROXY_MODE}" != "disable" ] && add_port_rules "$ipt_tmp -A PSW $(comment "默认") -p tcp" $TCP_REDIR_PORTS "${ipt_j}" [ -n "${is_tproxy}" ]&& $ipt_tmp -A PSW $(comment "默认") -p tcp $(REDIRECT $TCP_REDIR_PORT TPROXY) - [ "$PROXY_IPV6" == "1" ] && { + [ "$PROXY_IPV6" = "1" ] && { [ "${USE_FAKEDNS}" = "1" ] && $ip6t_m -A PSW $(comment "默认") -p tcp -d $FAKE_IP_6 -j PSW_RULE [ "${USE_PROXY_LIST}" = "1" ] && add_port_rules "$ip6t_m -A PSW $(comment "默认") -p tcp" $TCP_REDIR_PORTS "$(dst $IPSET_BLACK6) -j PSW_RULE" [ "${USE_GFW_LIST}" = "1" ] && add_port_rules "$ip6t_m -A PSW $(comment "默认") -p tcp" $TCP_REDIR_PORTS "$(dst $IPSET_GFW6) -j PSW_RULE" @@ -692,7 +692,7 @@ load_acl() { # 加载UDP默认代理模式 if [ -n "${UDP_PROXY_MODE}" ]; then - [ -n "$UDP_NODE" -o "$TCP_UDP" = "1" ] && { + [ -n "$UDP_NODE" ] || [ "$TCP_UDP" = "1" ] && { if is_socks_wrap "$UDP_NODE"; then msg2="${msg}使用 UDP 节点[Socks 配置($(config_n_get ${UDP_NODE#Socks_} port) 端口)](TPROXY:${UDP_REDIR_PORT})" else @@ -707,7 +707,7 @@ load_acl() { [ "${UDP_PROXY_MODE}" != "disable" ] && add_port_rules "$ipt_m -A PSW $(comment "默认") -p udp" $UDP_REDIR_PORTS "-j PSW_RULE" $ipt_m -A PSW $(comment "默认") -p udp $(REDIRECT $UDP_REDIR_PORT TPROXY) - [ "$PROXY_IPV6" == "1" ] && { + [ "$PROXY_IPV6" = "1" ] && { [ "${USE_FAKEDNS}" = "1" ] && $ip6t_m -A PSW $(comment "默认") -p udp -d $FAKE_IP_6 -j PSW_RULE [ "${USE_PROXY_LIST}" = "1" ] && add_port_rules "$ip6t_m -A PSW $(comment "默认") -p udp" $UDP_REDIR_PORTS "$(dst $IPSET_BLACK6) -j PSW_RULE" [ "${USE_GFW_LIST}" = "1" ] && add_port_rules "$ip6t_m -A PSW $(comment "默认") -p udp" $UDP_REDIR_PORTS "$(dst $IPSET_GFW6) -j PSW_RULE" @@ -782,7 +782,7 @@ filter_node() { local port=$(config_n_get "$node" port) local hop=$(config_n_get "$node" hysteria2_hop) [ -n "$hop" ] && port="${port:+$port,}$hop" - [ -z "$address" -o -z "$port" ] && return 1 + [ -z "$address" ] || [ -z "$port" ] && return 1 filter_server_port "$address" "$port" "$stream" } @@ -1145,7 +1145,7 @@ add_firewall_rule() { [ "$TCP_UDP" = "1" ] && [ -z "$UDP_NODE" ] && UDP_NODE=$TCP_NODE - [ "$ENABLED_DEFAULT_ACL" == 1 ] && { + [ "$ENABLED_DEFAULT_ACL" = 1 ] && { local ipt_tmp=$ipt_n if [ -n "${is_tproxy}" ]; then ipt_tmp=$ipt_m @@ -1186,7 +1186,7 @@ add_firewall_rule() { } fi - [ -n "${LOCALHOST_TCP_PROXY_MODE}" -o -n "${LOCALHOST_UDP_PROXY_MODE}" ] && { + [ -n "${LOCALHOST_TCP_PROXY_MODE}" ] || [ -n "${LOCALHOST_UDP_PROXY_MODE}" ] && { [ "$TCP_PROXY_DROP_PORTS" != "disable" ] && { [ "${USE_FAKEDNS}" = "1" ] && add_port_rules "$ipt_m -A PSW_OUTPUT -p tcp" $TCP_PROXY_DROP_PORTS "-d $FAKE_IP -j DROP" [ "${USE_PROXY_LIST}" = "1" ] && add_port_rules "$ipt_m -A PSW_OUTPUT -p tcp" $TCP_PROXY_DROP_PORTS "$(dst $IPSET_BLACK) -j DROP" @@ -1273,7 +1273,7 @@ add_firewall_rule() { insert_rule_before "$ipt_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW) -p tcp -j PSW_OUTPUT" } - [ "$PROXY_IPV6" == "1" ] && { + [ "$PROXY_IPV6" = "1" ] && { [ -n "${LOCALHOST_TCP_PROXY_MODE}" ] && { [ "${USE_FAKEDNS}" = "1" ] && $ip6t_m -A PSW_OUTPUT -p tcp -d $FAKE_IP_6 -j PSW_RULE [ "${USE_PROXY_LIST}" = "1" ] && add_port_rules "$ip6t_m -A PSW_OUTPUT -p tcp" $TCP_REDIR_PORTS "$(dst $IPSET_BLACK6) -j PSW_RULE" @@ -1289,12 +1289,12 @@ add_firewall_rule() { fi # 加载路由器自身代理 UDP - if [ -n "$UDP_NODE" -o "$TCP_UDP" = "1" ]; then + if [ -n "$UDP_NODE" ] || [ "$TCP_UDP" = "1" ]; then _proxy_udp_access() { [ -n "${2}" ] || return 0 if echo "${2}" | grep -q -v ':'; then ipset -q test $IPSET_LAN ${2} - [ $? == 0 ] && { + [ $? = 0 ] && { echolog " - 上游 DNS 服务器 ${2} 已在直接访问的列表中,不强制向 UDP 代理转发对该服务器 UDP/${3} 端口的访问" return 0 } @@ -1303,7 +1303,7 @@ add_firewall_rule() { echolog " - [$?]将上游 DNS 服务器 ${2}:${3} 加入到路由器自身代理的 UDP 转发链" else ipset -q test $IPSET_LAN6 ${2} - [ $? == 0 ] && { + [ $? = 0 ] && { echolog " - 上游 DNS 服务器 ${2} 已在直接访问的列表中,不强制向 UDP 代理转发对该服务器 UDP/${3} 端口的访问" return 0 } @@ -1325,7 +1325,7 @@ add_firewall_rule() { $ipt_m -A PSW $(comment "本机") -p udp -i lo -j RETURN insert_rule_before "$ipt_m" "OUTPUT" "mwan3" "$(comment mangle-OUTPUT-PSW) -p udp -j PSW_OUTPUT" - [ "$PROXY_IPV6" == "1" ] && { + [ "$PROXY_IPV6" = "1" ] && { [ -n "$LOCALHOST_UDP_PROXY_MODE" ] && { [ "${USE_FAKEDNS}" = "1" ] && $ip6t_m -A PSW_OUTPUT -p udp -d $FAKE_IP_6 -j PSW_RULE [ "${USE_PROXY_LIST}" = "1" ] && add_port_rules "$ip6t_m -A PSW_OUTPUT -p udp" $UDP_REDIR_PORTS "$(dst $IPSET_BLACK6) -j PSW_RULE" @@ -1425,7 +1425,7 @@ gen_include() { flush_include extract_rules() { local _ipt="${ipt}" - [ "$1" == "6" ] && _ipt="${ip6t}" + [ "$1" = "6" ] && _ipt="${ip6t}" [ -z "${_ipt}" ] && return echo "*$2" @@ -1497,7 +1497,7 @@ get_ip6t_bin() { } start() { - [ "$ENABLED_DEFAULT_ACL" == 0 -a "$ENABLED_ACLS" == 0 ] && return + [ "$ENABLED_DEFAULT_ACL" = 0 ] && [ "$ENABLED_ACLS" = 0 ] && return add_firewall_rule gen_include } @@ -1505,7 +1505,7 @@ start() { stop() { [ -z "$(command -v echolog)" ] && . "$UTILS_PATH" del_firewall_rule - [ $(config_t_get global flush_set_on_reboot "0") = "1" -o $(config_t_get global flush_set "0") = "1" ] && { + [ $(config_t_get global flush_set_on_reboot "0") = "1" ] || [ $(config_t_get global flush_set "0") = "1" ] && { uci -q delete ${CONFIG}.@global[0].flush_set uci -q commit ${CONFIG} flush_ipset diff --git a/luci-app-passwall/root/usr/share/passwall/nftables.sh b/luci-app-passwall/root/usr/share/passwall/nftables.sh index 9186ce53..51d47b8b 100755 --- a/luci-app-passwall/root/usr/share/passwall/nftables.sh +++ b/luci-app-passwall/root/usr/share/passwall/nftables.sh @@ -121,13 +121,13 @@ REDIRECT() { local s="counter redirect" [ -n "$1" ] && { local s="$s to :$1" - [ "$2" == "TPROXY" ] && { + [ "$2" = "TPROXY" ] && { s="counter meta mark ${FWMARK} tproxy to :$1" } - [ "$2" == "TPROXY4" ] && { + [ "$2" = "TPROXY4" ] && { s="counter meta mark ${FWMARK} tproxy ip to :$1" } - [ "$2" == "TPROXY6" ] && { + [ "$2" = "TPROXY6" ] && { s="counter meta mark ${FWMARK} tproxy ip6 to :$1" } } @@ -175,25 +175,28 @@ insert_nftset() { *) suffix=" timeout $timeout_argument" ;; esac { - if [ $# -gt 0 ]; then + if [ $# -gt 0 ] && [ $# -le 1000 ]; then printf "%s\n" "$@" + elif [ $# -gt 1000 ]; then + printf "%s\n" "$*" else cat fi | awk -v s="$suffix" -v n="$nftset_name" -v t="$NFTABLE_NAME" ' BEGIN { RS = "[ \t\n\r]+" + ORS = "" } $0 != "" { - if (first == 0) { - printf "add element %s %s { \n", t, n; + if (!first) { + printf "add element %s %s { \n", t, n first = 1; } else { - printf ",\n"; + print ",\n" } - printf "%s%s", $0, s; + print $0 s } END { - if (first == 1) printf "\n }\n"; + if (first) print "\n }\n" } ' } | nft -f - @@ -211,7 +214,7 @@ gen_nftset() { local gc_interval_time="1h" if ! nft list set $NFTABLE_NAME $nftset_name >/dev/null 2>&1; then - if [ "$timeout_argument_set" == "0" ]; then + if [ "$timeout_argument_set" = "0" ]; then nft "add set $NFTABLE_NAME $nftset_name { type $ip_type; flags interval, timeout; auto-merge; }" else nft "add set $NFTABLE_NAME $nftset_name { type $ip_type; flags interval, timeout; timeout $timeout_argument_set; gc-interval $gc_interval_time; auto-merge; }" @@ -236,11 +239,11 @@ get_jump_nft() { } load_acl() { - ([ "$ENABLED_ACLS" == 1 ] || ([ "$ENABLED_DEFAULT_ACL" == 1 ] && [ "$CLIENT_PROXY" == 1 ])) && echolog " - 访问控制:" - [ "$ENABLED_ACLS" == 1 ] && { + { [ "$ENABLED_ACLS" = "1" ] || { [ "$ENABLED_DEFAULT_ACL" = "1" ] && [ "$CLIENT_PROXY" = "1" ]; }; } && echolog " - 访问控制:" + [ "$ENABLED_ACLS" = 1 ] && { acl_app for sid in $(ls -F ${TMP_ACL_PATH} | grep '/$' | awk -F '/' '{print $1}' | grep -v 'default'); do - eval $(uci -q show "${CONFIG}.${sid}" | cut -d'.' -sf 3-) + eval "$(uci -q show "${CONFIG}.${sid}" | cut -d'.' -sf 3-)" tcp_no_redir_ports=${tcp_no_redir_ports:-default} udp_no_redir_ports=${udp_no_redir_ports:-default} @@ -409,7 +412,7 @@ load_acl() { gen_nftset $gfw6_set_name ipv6_addr "2d" 0 } } - [ "${use_shunt_tcp}" = "1" -o "${use_shunt_udp}" = "1" ] && { + [ "${use_shunt_tcp}" = "1" ] || [ "${use_shunt_udp}" = "1" ] && { [ "${use_global_config}" = "0" ] && { shunt_set_name="psw_${sid}_shunt" shunt6_set_name="psw_${sid}_shunt6" @@ -433,18 +436,18 @@ load_acl() { [ -z "$(get_cache_var "ACL_${sid}_tcp_default")" ] && echolog " - ${msg}使用与全局配置不相同节点,已将DNS强制重定向到专用 DNS 服务器。" fi - [ -n "$tcp_port" -o -n "$udp_port" ] && { + [ -n "$tcp_port" ] || [ -n "$udp_port" ] && { [ "${use_block_list}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE ${_ipt_source} ip daddr @$NFTSET_BLOCK counter drop comment \"$remarks\"" [ "${use_block_list}" = "1" ] && [ -z "${is_tproxy}" ] && nft "add rule $NFTABLE_NAME PSW_NAT ${_ipt_source} ip daddr @$NFTSET_BLOCK counter drop comment \"$remarks\"" [ "${use_direct_list}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE ${_ipt_source} ip daddr @$NFTSET_WHITE counter return comment \"$remarks\"" [ "${use_direct_list}" = "1" ] && [ -z "${is_tproxy}" ] && nft "add rule $NFTABLE_NAME PSW_NAT ${_ipt_source} ip daddr @$NFTSET_WHITE counter return comment \"$remarks\"" - [ "$PROXY_IPV6" == "1" ] && [ "$_ipv4" != "1" ] && { + [ "$PROXY_IPV6" = "1" ] && [ "$_ipv4" != "1" ] && { [ "${use_block_list}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 ${_ipt_source} ip6 daddr @$NFTSET_BLOCK6 counter drop comment \"$remarks\"" [ "${use_direct_list}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 ${_ipt_source} ip6 daddr @$NFTSET_WHITE6 counter return comment \"$remarks\"" } [ "$tcp_proxy_drop_ports" != "disable" ] && { - [ "$PROXY_IPV6" == "1" ] && [ "$_ipv4" != "1" ] && { + [ "$PROXY_IPV6" = "1" ] && [ "$_ipv4" != "1" ] && { [ "${use_fakedns}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto tcp ${_ipt_source} $(factor $tcp_proxy_drop_ports "tcp dport") ip6 daddr $FAKE_IP_6 counter drop comment \"$remarks\"" 2>/dev/null [ "${use_proxy_list}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto tcp ${_ipt_source} $(factor $tcp_proxy_drop_ports "tcp dport") ip6 daddr @$black6_set_name counter drop comment \"$remarks\"" 2>/dev/null [ "${use_gfw_list}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto tcp ${_ipt_source} $(factor $tcp_proxy_drop_ports "tcp dport") ip6 daddr @$gfw6_set_name counter drop comment \"$remarks\"" 2>/dev/null @@ -462,7 +465,7 @@ load_acl() { } [ "$udp_proxy_drop_ports" != "disable" ] && { - [ "$PROXY_IPV6" == "1" ] && [ "$_ipv4" != "1" ] && { + [ "$PROXY_IPV6" = "1" ] && [ "$_ipv4" != "1" ] && { [ "${use_fakedns}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto udp ${_ipt_source} $(factor $udp_proxy_drop_ports "udp dport") ip6 daddr $FAKE_IP_6 counter drop comment \"$remarks\"" 2>/dev/null [ "${use_proxy_list}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto udp ${_ipt_source} $(factor $udp_proxy_drop_ports "udp dport") ip6 daddr @$black6_set_name counter drop comment \"$remarks\"" 2>/dev/null [ "${use_gfw_list}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto udp ${_ipt_source} $(factor $udp_proxy_drop_ports "udp dport") ip6 daddr @$gfw6_set_name counter drop comment \"$remarks\"" 2>/dev/null @@ -504,7 +507,7 @@ load_acl() { nft "add rule $NFTABLE_NAME PSW_ICMP_REDIRECT ip protocol icmp ${_ipt_source} return comment \"$remarks\"" } - [ "$accept_icmpv6" = "1" ] && [ "$PROXY_IPV6" == "1" ] && [ "$_ipv4" != "1" ] && { + [ "$accept_icmpv6" = "1" ] && [ "$PROXY_IPV6" = "1" ] && [ "$_ipv4" != "1" ] && { [ "${use_direct_list}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_ICMP_REDIRECT meta l4proto icmpv6 ${_ipt_source} ip6 daddr @$NFTSET_WHITE6 counter return comment \"$remarks\"" 2>/dev/null [ "${use_fakedns}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_ICMP_REDIRECT meta l4proto icmpv6 ${_ipt_source} ip6 daddr $FAKE_IP_6 $(REDIRECT) comment \"$remarks\"" 2>/dev/null [ "${use_proxy_list}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_ICMP_REDIRECT meta l4proto icmpv6 ${_ipt_source} ip6 daddr @$black6_set_name $(REDIRECT) comment \"$remarks\"" 2>/dev/null @@ -523,7 +526,7 @@ load_acl() { [ "${tcp_proxy_mode}" != "disable" ] && nft "add rule $NFTABLE_NAME $nft_chain ip protocol tcp ${_ipt_source} $(factor $tcp_redir_ports "tcp dport") ${nft_j} comment \"$remarks\"" [ -n "${is_tproxy}" ] && nft "add rule $NFTABLE_NAME $nft_chain ip protocol tcp ${_ipt_source} $(REDIRECT $tcp_port TPROXY4) comment \"$remarks\"" - [ "$PROXY_IPV6" == "1" ] && [ "$_ipv4" != "1" ] && { + [ "$PROXY_IPV6" = "1" ] && [ "$_ipv4" != "1" ] && { [ "${use_fakedns}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto tcp ${_ipt_source} ip6 daddr $FAKE_IP_6 counter jump PSW_RULE comment \"$remarks\"" [ "${use_proxy_list}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto tcp ${_ipt_source} $(factor $tcp_redir_ports "tcp dport") ip6 daddr @$black6_set_name counter jump PSW_RULE comment \"$remarks\"" 2>/dev/null [ "${use_gfw_list}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto tcp ${_ipt_source} $(factor $tcp_redir_ports "tcp dport") ip6 daddr @$gfw6_set_name counter jump PSW_RULE comment \"$remarks\"" 2>/dev/null @@ -554,7 +557,7 @@ load_acl() { [ "${udp_proxy_mode}" != "disable" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol udp ${_ipt_source} $(factor $udp_redir_ports "udp dport") counter jump PSW_RULE comment \"$remarks\"" nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol udp ${_ipt_source} $(REDIRECT $udp_port TPROXY4) comment \"$remarks\"" - [ "$PROXY_IPV6" == "1" ] && [ "$_ipv4" != "1" ] && { + [ "$PROXY_IPV6" = "1" ] && [ "$_ipv4" != "1" ] && { [ "${use_fakedns}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto udp ${_ipt_source} ip6 daddr $FAKE_IP_6 counter jump PSW_RULE comment \"$remarks\"" [ "${use_proxy_list}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto udp ${_ipt_source} $(factor $udp_redir_ports "udp dport") ip6 daddr @$black6_set_name counter jump PSW_RULE comment \"$remarks\"" 2>/dev/null [ "${use_gfw_list}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto udp ${_ipt_source} $(factor $udp_redir_ports "udp dport") ip6 daddr @$gfw6_set_name counter jump PSW_RULE comment \"$remarks\"" 2>/dev/null @@ -577,7 +580,7 @@ load_acl() { done } - [ "$ENABLED_DEFAULT_ACL" == 1 ] && [ "$CLIENT_PROXY" == 1 ] && { + [ "$ENABLED_DEFAULT_ACL" = 1 ] && [ "$CLIENT_PROXY" = 1 ] && { msg="【默认】," [ "$TCP_NO_REDIR_PORTS" != "disable" ] && { nft "add rule $NFTABLE_NAME $nft_prerouting_chain ip protocol tcp $(factor $TCP_NO_REDIR_PORTS "tcp dport") counter return comment \"默认\"" @@ -620,18 +623,18 @@ load_acl() { nft "add rule $NFTABLE_NAME PSW_DNS meta l4proto tcp tcp dport 53 counter redirect to :${DNS_REDIRECT} comment \"默认\"" fi - [ -n "${TCP_PROXY_MODE}" -o -n "${UDP_PROXY_MODE}" ] && { + [ -n "${TCP_PROXY_MODE}" ] || [ -n "${UDP_PROXY_MODE}" ] && { [ "${USE_BLOCK_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE ip daddr @$NFTSET_BLOCK counter drop comment \"默认\"" [ "${USE_BLOCK_LIST}" = "1" ] && [ -z "${is_tproxy}" ] && nft "add rule $NFTABLE_NAME PSW_NAT ip daddr @$NFTSET_BLOCK counter drop comment \"默认\"" [ "${USE_DIRECT_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE ip daddr @$NFTSET_WHITE counter return comment \"默认\"" [ "${USE_DIRECT_LIST}" = "1" ] && [ -z "${is_tproxy}" ] && nft "add rule $NFTABLE_NAME PSW_NAT ip daddr @$NFTSET_WHITE counter return comment \"默认\"" - [ "$PROXY_IPV6" == "1" ] && { + [ "$PROXY_IPV6" = "1" ] && { [ "${USE_BLOCK_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 ip6 daddr @$NFTSET_BLOCK6 counter drop comment \"默认\"" [ "${USE_DIRECT_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 ip6 daddr @$NFTSET_WHITE6 counter return comment \"默认\"" } [ "$TCP_PROXY_DROP_PORTS" != "disable" ] && { - [ "$PROXY_IPV6" == "1" ] && { + [ "$PROXY_IPV6" = "1" ] && { [ "${USE_FAKEDNS}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto tcp $(factor $TCP_PROXY_DROP_PORTS "tcp dport") ip6 daddr $FAKE_IP_6 counter drop comment \"默认\"" [ "${USE_PROXY_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto tcp $(factor $TCP_PROXY_DROP_PORTS "tcp dport") ip6 daddr @$NFTSET_BLACK6 counter drop comment \"默认\"" [ "${USE_GFW_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto tcp $(factor $TCP_PROXY_DROP_PORTS "tcp dport") ip6 daddr @$NFTSET_GFW6 counter drop comment \"默认\"" @@ -650,7 +653,7 @@ load_acl() { } [ "$UDP_PROXY_DROP_PORTS" != "disable" ] && { - [ "$PROXY_IPV6" == "1" ] && { + [ "$PROXY_IPV6" = "1" ] && { [ "${USE_FAKEDNS}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto udp $(factor $UDP_PROXY_DROP_PORTS "udp dport") ip6 daddr $FAKE_IP_6 counter drop comment \"默认\"" [ "${USE_PROXY_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto udp $(factor $UDP_PROXY_DROP_PORTS "udp dport") ip6 daddr @$NFTSET_BLACK6 counter drop comment \"默认\"" [ "${USE_GFW_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto udp $(factor $UDP_PROXY_DROP_PORTS "udp dport") ip6 daddr @$NFTSET_GFW6 counter drop comment \"默认\"" @@ -697,7 +700,7 @@ load_acl() { nft "add rule $NFTABLE_NAME PSW_ICMP_REDIRECT ip protocol icmp return comment \"默认\"" } - [ "$accept_icmpv6" = "1" ] && [ "$PROXY_IPV6" == "1" ] && { + [ "$accept_icmpv6" = "1" ] && [ "$PROXY_IPV6" = "1" ] && { [ "${USE_DIRECT_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_ICMP_REDIRECT ip6 daddr @$NFTSET_WHITE6 counter return comment \"默认\"" [ "${USE_FAKEDNS}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_ICMP_REDIRECT meta l4proto icmpv6 ip6 daddr $FAKE_IP_6 $(REDIRECT) comment \"默认\"" [ "${USE_PROXY_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_ICMP_REDIRECT meta l4proto icmpv6 ip6 daddr @$NFTSET_BLACK6 $(REDIRECT) comment \"默认\"" @@ -717,7 +720,7 @@ load_acl() { [ -n "${is_tproxy}" ] && nft "add rule $NFTABLE_NAME $nft_chain ip protocol tcp $(REDIRECT $TCP_REDIR_PORT TPROXY4) comment \"默认\"" nft "add rule $NFTABLE_NAME $nft_chain ip protocol tcp counter return comment \"默认\"" - [ "$PROXY_IPV6" == "1" ] && { + [ "$PROXY_IPV6" = "1" ] && { [ "${USE_FAKEDNS}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto tcp ip6 daddr $FAKE_IP_6 counter jump PSW_RULE comment \"默认\"" [ "${USE_PROXY_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto tcp $(factor $TCP_REDIR_PORTS "tcp dport") ip6 daddr @$NFTSET_BLACK6 counter jump PSW_RULE comment \"默认\"" [ "${USE_GFW_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto tcp $(factor $TCP_REDIR_PORTS "tcp dport") ip6 daddr @$NFTSET_GFW6 counter jump PSW_RULE comment \"默认\"" @@ -734,7 +737,7 @@ load_acl() { # 加载UDP默认代理模式 if [ -n "${UDP_PROXY_MODE}" ]; then - [ -n "$UDP_NODE" -o "$TCP_UDP" = "1" ] && { + [ -n "$UDP_NODE" ] || [ "$TCP_UDP" = "1" ] && { if is_socks_wrap "$UDP_NODE"; then msg2="${msg}使用 UDP 节点[Socks 配置($(config_n_get ${UDP_NODE#Socks_} port) 端口)](TPROXY:${UDP_REDIR_PORT})" else @@ -750,7 +753,7 @@ load_acl() { nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol udp $(REDIRECT $UDP_REDIR_PORT TPROXY4) comment \"默认\"" nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol udp counter return comment \"默认\"" - [ "$PROXY_IPV6" == "1" ] && { + [ "$PROXY_IPV6" = "1" ] && { [ "${USE_FAKEDNS}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto udp ip6 daddr $FAKE_IP_6 counter jump PSW_RULE comment \"默认\"" [ "${USE_PROXY_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto udp $(factor $UDP_REDIR_PORTS "udp dport") ip6 daddr @$NFTSET_BLACK6 counter jump PSW_RULE comment \"默认\"" [ "${USE_GFW_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 meta l4proto udp $(factor $UDP_REDIR_PORTS "udp dport") ip6 daddr @$NFTSET_GFW6 counter jump PSW_RULE comment \"默认\"" @@ -823,7 +826,7 @@ filter_node() { local port=$(config_n_get "$node" port) local hop=$(config_n_get "$node" hysteria2_hop) [ -n "$hop" ] && port="${port:+$port,}$hop" - [ -z "$address" -o -z "$port" ] && return 1 + [ -z "$address" ] || [ -z "$port" ] && return 1 filter_server_port "$address" "$port" "$stream" } @@ -1201,7 +1204,7 @@ add_firewall_rule() { } # jump chains - [ "$PROXY_IPV6" == "1" ] && { + [ "$PROXY_IPV6" = "1" ] && { nft "add rule $NFTABLE_NAME mangle_prerouting meta nfproto {ipv6} counter jump PSW_MANGLE_V6" nft "add rule $NFTABLE_NAME mangle_output meta nfproto {ipv6} counter jump PSW_OUTPUT_MANGLE_V6 comment \"PSW_OUTPUT_MANGLE\"" @@ -1213,7 +1216,7 @@ add_firewall_rule() { [ "$TCP_UDP" = "1" ] && [ -z "$UDP_NODE" ] && UDP_NODE=$TCP_NODE - [ "$ENABLED_DEFAULT_ACL" == 1 ] && { + [ "$ENABLED_DEFAULT_ACL" = 1 ] && { msg="【路由器本机】," [ "$TCP_NO_REDIR_PORTS" != "disable" ] && { @@ -1247,7 +1250,7 @@ add_firewall_rule() { } fi - [ -n "${LOCALHOST_TCP_PROXY_MODE}" -o -n "${LOCALHOST_UDP_PROXY_MODE}" ] && { + [ -n "${LOCALHOST_TCP_PROXY_MODE}" ] || [ -n "${LOCALHOST_UDP_PROXY_MODE}" ] && { [ "$TCP_PROXY_DROP_PORTS" != "disable" ] && { [ "${USE_FAKEDNS}" = "1" ] && nft add rule $NFTABLE_NAME $nft_output_chain ip protocol tcp ip daddr $FAKE_IP $(factor $TCP_PROXY_DROP_PORTS "tcp dport") counter drop [ "${USE_PROXY_LIST}" = "1" ] && nft add rule $NFTABLE_NAME $nft_output_chain ip protocol tcp ip daddr @$NFTSET_BLACK $(factor $TCP_PROXY_DROP_PORTS "tcp dport") counter drop @@ -1297,7 +1300,7 @@ add_firewall_rule() { echolog " - [$?]将上游 DNS 服务器 [${2}]:${3} 加入到路由器自身代理的 TCP 转发链,请确保您的节点支持IPv6,并开启IPv6透明代理!" fi } - [ "$TCP_PROXY_DNS" == 1 ] && hosts_foreach REMOTE_DNS _proxy_tcp_access 53 + [ "$TCP_PROXY_DNS" = 1 ] && hosts_foreach REMOTE_DNS _proxy_tcp_access 53 [ "$accept_icmp" = "1" ] && { [ "${USE_FAKEDNS}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_ICMP_REDIRECT oif lo ip protocol icmp ip daddr $FAKE_IP counter redirect" @@ -1340,7 +1343,7 @@ add_firewall_rule() { [ -n "${is_tproxy}" ] && nft "add rule $NFTABLE_NAME mangle_output ip protocol tcp counter jump PSW_OUTPUT_MANGLE comment \"PSW_OUTPUT_MANGLE\"" [ -z "${is_tproxy}" ] && nft "add rule $NFTABLE_NAME nat_output ip protocol tcp counter jump PSW_OUTPUT_NAT" - [ "$PROXY_IPV6" == "1" ] && { + [ "$PROXY_IPV6" = "1" ] && { [ -n "${LOCALHOST_TCP_PROXY_MODE}" ] && { [ "${USE_FAKEDNS}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 meta l4proto tcp ip6 daddr $FAKE_IP_6 counter jump PSW_RULE" [ "${USE_PROXY_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 meta l4proto tcp ip6 daddr @$NFTSET_BLACK6 $(factor $TCP_REDIR_PORTS "tcp dport") counter jump PSW_RULE" @@ -1355,12 +1358,12 @@ add_firewall_rule() { fi # 加载路由器自身代理 UDP - if [ -n "$UDP_NODE" -o "$TCP_UDP" = "1" ]; then + if [ -n "$UDP_NODE" ] || [ "$TCP_UDP" = "1" ]; then _proxy_udp_access() { [ -n "${2}" ] || return 0 if echo "${2}" | grep -q -v ':'; then nft "get element $NFTABLE_NAME $NFTSET_LAN {${2}}" &>/dev/null - [ $? == 0 ] && { + [ $? = 0 ] && { echolog " - 上游 DNS 服务器 ${2} 已在直接访问的列表中,不强制向 UDP 代理转发对该服务器 UDP/${3} 端口的访问" return 0 } @@ -1369,7 +1372,7 @@ add_firewall_rule() { echolog " - [$?]将上游 DNS 服务器 ${2}:${3} 加入到路由器自身代理的 UDP 转发链" else nft "get element $NFTABLE_NAME $NFTSET_LAN6 {${2}}" &>/dev/null - [ $? == 0 ] && { + [ $? = 0 ] && { echolog " - 上游 DNS 服务器 ${2} 已在直接访问的列表中,不强制向 UDP 代理转发对该服务器 UDP/${3} 端口的访问" return 0 } @@ -1391,7 +1394,7 @@ add_firewall_rule() { nft "add rule $NFTABLE_NAME PSW_MANGLE ip protocol udp iif lo counter return comment \"本机\"" nft "add rule $NFTABLE_NAME mangle_output ip protocol udp counter jump PSW_OUTPUT_MANGLE comment \"PSW_OUTPUT_MANGLE\"" - [ "$PROXY_IPV6" == "1" ] && { + [ "$PROXY_IPV6" = "1" ] && { [ -n "${LOCALHOST_UDP_PROXY_MODE}" ] && { [ "${USE_FAKEDNS}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 meta l4proto udp ip6 daddr $FAKE_IP_6 counter jump PSW_RULE" [ "${USE_PROXY_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 meta l4proto udp ip6 daddr @$NFTSET_BLACK6 $(factor $UDP_REDIR_PORTS "udp dport") counter jump PSW_RULE" @@ -1512,7 +1515,7 @@ gen_include() { } start() { - [ "$ENABLED_DEFAULT_ACL" == 0 -a "$ENABLED_ACLS" == 0 ] && return + [ "$ENABLED_DEFAULT_ACL" = 0 ] && [ "$ENABLED_ACLS" = 0 ] && return add_firewall_rule gen_include } @@ -1520,7 +1523,7 @@ start() { stop() { [ -z "$(command -v echolog)" ] && . "$UTILS_PATH" del_firewall_rule - [ $(config_t_get global flush_set_on_reboot "0") = "1" -o $(config_t_get global flush_set "0") = "1" ] && { + [ $(config_t_get global flush_set_on_reboot "0") = "1" ] || [ $(config_t_get global flush_set "0") = "1" ] && { uci -q delete ${CONFIG}.@global[0].flush_set uci -q commit ${CONFIG} #flush_table diff --git a/luci-app-passwall/root/usr/share/passwall/tasks.sh b/luci-app-passwall/root/usr/share/passwall/tasks.sh index 564caee4..25d2320e 100755 --- a/luci-app-passwall/root/usr/share/passwall/tasks.sh +++ b/luci-app-passwall/root/usr/share/passwall/tasks.sh @@ -18,24 +18,6 @@ do if [ "$CFG_UPDATE_INT" -ne 0 ]; then - stop_week_mode=$(config_t_get global_delay stop_week_mode) - stop_interval_mode=$(config_t_get global_delay stop_interval_mode) - stop_interval_mode=$(expr "$stop_interval_mode" \* 60) - if [ -n "$stop_week_mode" ]; then - [ "$stop_week_mode" = "8" ] && { - [ "$(expr "$CFG_UPDATE_INT" % "$stop_interval_mode")" -eq 0 ] && { /etc/init.d/$CONFIG stop > /dev/null 2>&1 & } - } - fi - - start_week_mode=$(config_t_get global_delay start_week_mode) - start_interval_mode=$(config_t_get global_delay start_interval_mode) - start_interval_mode=$(expr "$start_interval_mode" \* 60) - if [ -n "$start_week_mode" ]; then - [ "$start_week_mode" = "8" ] && { - [ "$(expr "$CFG_UPDATE_INT" % "$start_interval_mode")" -eq 0 ] && { /etc/init.d/$CONFIG start > /dev/null 2>&1 & } - } - fi - restart_week_mode=$(config_t_get global_delay restart_week_mode) restart_interval_mode=$(config_t_get global_delay restart_interval_mode) restart_interval_mode=$(expr "$restart_interval_mode" \* 60) @@ -45,36 +27,35 @@ do } fi - autoupdate=$(config_t_get global_rules auto_update) - weekupdate=$(config_t_get global_rules week_update) - hourupdate=$(config_t_get global_rules interval_update) - hourupdate=$(expr "$hourupdate" \* 60) - if [ "$autoupdate" = "1" ]; then - [ "$weekupdate" = "8" ] && { - [ "$(expr "$CFG_UPDATE_INT" % "$hourupdate")" -eq 0 ] && { lua $APP_PATH/rule_update.lua log all cron > /dev/null 2>&1 & } + rules_update_week_mode=$(config_t_get global_rules update_week_mode) + rules_update_interval_mode=$(config_t_get global_rules update_interval_mode) + rules_update_interval_mode=$(expr "$rules_update_interval_mode" \* 60) + if [ -n "$rules_update_week_mode" ]; then + [ "$rules_update_week_mode" = "8" ] && { + [ "$(expr "$CFG_UPDATE_INT" % "$rules_update_interval_mode")" -eq 0 ] && { lua $APP_PATH/rule_update.lua log all cron > /dev/null 2>&1 & } } fi TMP_SUB_PATH=$TMP_PATH/sub_tasks mkdir -p $TMP_SUB_PATH for item in $(uci show ${CONFIG} | grep "=subscribe_list" | cut -d '.' -sf 2 | cut -d '=' -sf 1); do - if [ "$(config_n_get $item auto_update 0)" = "1" ]; then + sub_update_week_mode=$(config_n_get $item update_week_mode) + if [ -n "$sub_update_week_mode" ]; then cfgid=$(uci show ${CONFIG}.$item | head -n 1 | cut -d '.' -sf 2 | cut -d '=' -sf 1) remark=$(config_n_get $item remark) - week_update=$(config_n_get $item week_update) - hour_update=$(config_n_get $item interval_update) - echo "$cfgid" >> $TMP_SUB_PATH/${week_update}_${hour_update} + sub_update_interval_mode=$(config_n_get $item update_interval_mode) + echo "$cfgid" >> $TMP_SUB_PATH/${sub_update_week_mode}_${sub_update_interval_mode} fi done [ -d "${TMP_SUB_PATH}" ] && { for name in $(ls ${TMP_SUB_PATH}); do - week_update=$(echo $name | awk -F '_' '{print $1}') - hour_update=$(echo $name | awk -F '_' '{print $2}') - hour_update=$(expr "$hour_update" \* 60) + sub_update_week_mode=${name%_*} + sub_update_interval_mode=${name#*_} + sub_update_interval_mode=$(expr "$sub_update_interval_mode" \* 60) cfgids=$(echo -n $(cat ${TMP_SUB_PATH}/${name}) | sed 's# #,#g') - [ "$week_update" = "8" ] && { - [ "$(expr "$CFG_UPDATE_INT" % "$hour_update")" -eq 0 ] && { lua $APP_PATH/subscribe.lua start $cfgids cron > /dev/null 2>&1 & } + [ "$sub_update_week_mode" = "8" ] && { + [ "$(expr "$CFG_UPDATE_INT" % "$sub_update_interval_mode")" -eq 0 ] && { lua $APP_PATH/subscribe.lua start $cfgids cron > /dev/null 2>&1 & } } done diff --git a/luci-app-passwall/root/usr/share/passwall/utils.sh b/luci-app-passwall/root/usr/share/passwall/utils.sh index e2847193..e9b5aeba 100755 --- a/luci-app-passwall/root/usr/share/passwall/utils.sh +++ b/luci-app-passwall/root/usr/share/passwall/utils.sh @@ -89,7 +89,7 @@ get_host_ip() { [ -z "$count" ] && count=3 local isip="" local ip="" - if [ "$1" == "ipv6" ]; then + if [ "$1" = "ipv6" ]; then isip=$(echo $host | grep -E "([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4}") if [ -n "$isip" ]; then ip=$(echo "$host" | tr -d '[]') @@ -100,7 +100,7 @@ get_host_ip() { fi [ -z "$isip" ] && { local t=4 - [ "$1" == "ipv6" ] && t=6 + [ "$1" = "ipv6" ] && t=6 local vpsrip=$(resolveip -$t -t $count $host | awk 'NR==1{print}') ip=$vpsrip } @@ -113,7 +113,7 @@ get_node_host_ip() { [ -n "$address" ] && { local use_ipv6=$(config_n_get $1 use_ipv6) local network_type="ipv4" - [ "$use_ipv6" == "1" ] && network_type="ipv6" + [ "$use_ipv6" = "1" ] && network_type="ipv6" ip=$(get_host_ip $network_type $address) } echo $ip @@ -220,7 +220,7 @@ get_first_dns() { echo "${2}#${3}" return 1 } - eval "hosts_foreach \"${__hosts_val}\" __first \"$@\"" + hosts_foreach "${__hosts_val}" __first "$@" } get_last_dns() { @@ -231,8 +231,8 @@ get_last_dns() { __last="${2}#${3}" __first=${__first:-${__last}} } - eval "hosts_foreach \"${__hosts_val}\" __every \"$@\"" - [ "${__first}" == "${__last}" ] || echo "${__last}" + hosts_foreach "${__hosts_val}" __first "$@" + [ "${__first}" = "${__last}" ] || echo "${__last}" } normalize_dns() { @@ -319,7 +319,7 @@ get_new_port() { fi fi fi - [ "$port" -lt $min_port -o "$port" -gt $max_port ] && port=$default_start_port + [ "$port" -lt $min_port ] || [ "$port" -gt $max_port ] && port=$default_start_port local start_port="$port" while :; do if [ "$(check_port_exists "$port" "$protocol")" = 0 ]; then @@ -346,9 +346,11 @@ check_ver() { local version1="$1" local version2="$2" local i v1 v1_1 v1_2 v1_3 v2 v2_1 v2_2 v2_3 - IFS='.'; set -- $version1; v1_1=${1:-0}; v1_2=${2:-0}; v1_3=${3:-0} - IFS='.'; set -- $version2; v2_1=${1:-0}; v2_2=${2:-0}; v2_3=${3:-0} - IFS= + local old_ifs="$IFS" + IFS='.' + set -- $version1; v1_1=${1:-0}; v1_2=${2:-0}; v1_3=${3:-0} + set -- $version2; v2_1=${1:-0}; v2_2=${2:-0}; v2_3=${3:-0} + IFS="$old_ifs" for i in 1 2 3; do eval v1=\$v1_$i eval v2=\$v2_$i @@ -481,8 +483,10 @@ ln_run() { if [ -z "$persist_log_path" ] && [ "$sys_log" != "1" ]; then ${file_func:-echolog " - ${ln_name}"} "$@" >${output} 2>&1 & else - [ "${output: -1, -7}" == "TCP.log" ] && local protocol="TCP" - [ "${output: -1, -7}" == "UDP.log" ] && local protocol="UDP" + case "$output" in + *TCP.log) local protocol="TCP" ;; + *UDP.log) local protocol="UDP" ;; + esac if [ -n "${persist_log_path}" ]; then mkdir -p ${persist_log_path} local log_file=${persist_log_path}/passwall_${protocol}_${ln_name}_$(date '+%F').log @@ -490,7 +494,7 @@ ln_run() { ${file_func:-echolog " - ${ln_name}"} "$@" >> ${log_file} 2>&1 & sys_log=0 fi - if [ "${sys_log}" == "1" ]; then + if [ "${sys_log}" = "1" ]; then echolog "记录 ${ln_name}_${protocol} 到系统日志" ${file_func:-echolog " - ${ln_name}"} "$@" 2>&1 | logger -t PASSWALL_${protocol}_${ln_name} & fi diff --git a/luci-app-passwall2/Makefile b/luci-app-passwall2/Makefile index 32455abe..9df331b5 100644 --- a/luci-app-passwall2/Makefile +++ b/luci-app-passwall2/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall2 PKG_VERSION:=26.7.12 -PKG_RELEASE:=60 +PKG_RELEASE:=61 PKG_PO_VERSION:=$(PKG_VERSION) PKG_CONFIG_DEPENDS:= \ diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua index d92660c4..9fc3f6eb 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua @@ -152,7 +152,9 @@ if load_balancing_options then -- [[ Load balancing Start ]] o:depends({ [_n("node_add_mode")] = "batch" }) local descrStr = "Example: ^A && B && !C && D$
" descrStr = descrStr .. "This means the node remark must start with A (^), include B, exclude C (!), and end with D ($).
" - descrStr = descrStr .. "Conditions are joined by &&, and their order does not affect the result." + descrStr = descrStr .. "Conditions are joined by && (AND), and their order does not affect the result.
" + descrStr = descrStr .. "Multiple groups can be separated by || (OR), matching succeeds if any group matches.
" + descrStr = descrStr .. "Example: A && B || C && D means (A AND B) OR (C AND D)." o.description = translate(descrStr) o = s:option(ListValue, _n("balancingStrategy"), translate("Balancing Strategy")) diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/sing-box.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/sing-box.lua index e1023ae8..8dde7edd 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/sing-box.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/sing-box.lua @@ -154,7 +154,9 @@ if load_urltest_options then -- [[ URLTest Start ]] o:depends({ [_n("node_add_mode")] = "batch" }) local descrStr = "Example: ^A && B && !C && D$
" descrStr = descrStr .. "This means the node remark must start with A (^), include B, exclude C (!), and end with D ($).
" - descrStr = descrStr .. "Conditions are joined by &&, and their order does not affect the result." + descrStr = descrStr .. "Conditions are joined by && (AND), and their order does not affect the result.
" + descrStr = descrStr .. "Multiple groups can be separated by || (OR), matching succeeds if any group matches.
" + descrStr = descrStr .. "Example: A && B || C && D means (A AND B) OR (C AND D)." o.description = translate(descrStr) o = s:option(Value, _n("urltest_url"), translate("Probe URL")) diff --git a/luci-app-passwall2/luasrc/passwall2/api.lua b/luci-app-passwall2/luasrc/passwall2/api.lua index 561b7555..7da2d87a 100644 --- a/luci-app-passwall2/luasrc/passwall2/api.lua +++ b/luci-app-passwall2/luasrc/passwall2/api.lua @@ -1521,11 +1521,22 @@ end function match_node_rule(name, rule) if not name then return false end if not rule or rule == "" then return true end + -- split rule by || into OR groups + local function split_or(expr) + local t = {} + for part in (expr .. "||"):gmatch("(.-)%|%|") do + part = trim(part) + if part ~= "" then + table.insert(t, part) + end + end + return t + end -- split rule by && local function split_and(expr) local t = {} - for part in expr:gmatch("[^&]+") do - part = part:gsub("^%s+", ""):gsub("%s+$", "") + for part in (expr .. "&&"):gmatch("(.-)%&%&") do + part = trim(part) if part ~= "" then table.insert(t, part) end @@ -1556,13 +1567,22 @@ function match_node_rule(name, rule) -- contains return str:find(cond, 1, true) ~= nil end - -- AND logic - for _, cond in ipairs(split_and(rule)) do - if not match_cond(name, cond) then - return false + -- check if all conditions in AND group match + local function match_and_group(str, group_expr) + for _, cond in ipairs(split_and(group_expr)) do + if not match_cond(str, cond) then + return false + end + end + return true + end + -- OR logic: return true if any group matches + for _, group in ipairs(split_or(rule)) do + if match_and_group(name, group) then + return true end end - return true + return false end function get_core(field, candidates) diff --git a/luci-app-passwall2/po/fa/passwall2.po b/luci-app-passwall2/po/fa/passwall2.po index f464183a..3c185094 100644 --- a/luci-app-passwall2/po/fa/passwall2.po +++ b/luci-app-passwall2/po/fa/passwall2.po @@ -394,11 +394,15 @@ msgstr "قوانین تطبیق گره" msgid "" "Example: ^A && B && !C && D$
" "This means the node remark must start with A (^), include B, exclude C (!), and end with D ($).
" -"Conditions are joined by &&, and their order does not affect the result." +"Conditions are joined by && (AND), and their order does not affect the result.
" +"Multiple groups can be separated by || (OR), matching succeeds if any group matches.
" +"Example: A && B || C && D means (A AND B) OR (C AND D)." msgstr "" "مثال: ^A && B && !C && D$
" "این بدان معناست که توضیحات گره باید با A شروع شود (^)، شامل B باشد، فاقد C باشد (!)، و با D پایان یابد ($).
" -"شرط‌ها با && به هم متصل می‌شوند و ترتیب آنها تاثیری در نتیجه ندارد." +"شرط‌ها با && (و) به هم متصل می‌شوند و ترتیب آنها تاثیری در نتیجه ندارد.
" +"چندین گروه شرط می‌توانند با || (یا) از هم جدا شوند؛ اگر هر گروهی مطابقت داشته باشد، نتیجه موفقیت‌آمیز است.
" +"مثال: A && B || C && D به معنای (A و B) یا (C و D) است." msgid "Balancing Strategy" diff --git a/luci-app-passwall2/po/ru/passwall2.po b/luci-app-passwall2/po/ru/passwall2.po index 1465593f..4bea8828 100644 --- a/luci-app-passwall2/po/ru/passwall2.po +++ b/luci-app-passwall2/po/ru/passwall2.po @@ -391,11 +391,15 @@ msgstr "Правила отбора узлов" msgid "" "Example: ^A && B && !C && D$
" "This means the node remark must start with A (^), include B, exclude C (!), and end with D ($).
" -"Conditions are joined by &&, and their order does not affect the result." +"Conditions are joined by && (AND), and their order does not affect the result.
" +"Multiple groups can be separated by || (OR), matching succeeds if any group matches.
" +"Example: A && B || C && D means (A AND B) OR (C AND D)." msgstr "" "Пример: ^A && B && !C && D$
" "Описание узла должно: начинаться с A (^), содержать B, не содержать C (!), заканчиваться на D ($).
" -"Условия соединяются оператором &&, порядок условий не влияет на результат." +"Условия соединяются оператором && (И), порядок условий не влияет на результат.
" +"Несколько групп условий можно разделить оператором || (ИЛИ); совпадение любой группы считается успехом.
" +"Пример: A && B || C && D означает (A И B) ИЛИ (C И D)." msgid "Balancing Strategy" msgstr "Алгоритм балансировки" diff --git a/luci-app-passwall2/po/zh-cn/passwall2.po b/luci-app-passwall2/po/zh-cn/passwall2.po index 4949ab1d..da052b98 100644 --- a/luci-app-passwall2/po/zh-cn/passwall2.po +++ b/luci-app-passwall2/po/zh-cn/passwall2.po @@ -391,11 +391,15 @@ msgstr "节点匹配规则" msgid "" "Example: ^A && B && !C && D$
" "This means the node remark must start with A (^), include B, exclude C (!), and end with D ($).
" -"Conditions are joined by &&, and their order does not affect the result." +"Conditions are joined by && (AND), and their order does not affect the result.
" +"Multiple groups can be separated by || (OR), matching succeeds if any group matches.
" +"Example: A && B || C && D means (A AND B) OR (C AND D)." msgstr "" "示例:^A && B && !C && D$
" "表示节点备注需同时满足:以 A 开头(^)、包含 B、不包含 C(!)、并以 D 结尾($)。
" -"多个条件使用 && 连接,条件顺序不影响结果。" +"多个条件使用 &&(与)连接,条件顺序不影响结果。
" +"多组条件之间可使用 ||(或)分隔,任意一组匹配即视为成功。
" +"示例:A && B || C && D 表示 (A 且 B) 或 (C 且 D)。" msgid "Balancing Strategy" msgstr "负载均衡策略" diff --git a/luci-app-passwall2/po/zh-tw/passwall2.po b/luci-app-passwall2/po/zh-tw/passwall2.po index c82781b9..9245e80e 100644 --- a/luci-app-passwall2/po/zh-tw/passwall2.po +++ b/luci-app-passwall2/po/zh-tw/passwall2.po @@ -391,11 +391,15 @@ msgstr "節點匹配規則" msgid "" "Example: ^A && B && !C && D$
" "This means the node remark must start with A (^), include B, exclude C (!), and end with D ($).
" -"Conditions are joined by &&, and their order does not affect the result." +"Conditions are joined by && (AND), and their order does not affect the result.
" +"Multiple groups can be separated by || (OR), matching succeeds if any group matches.
" +"Example: A && B || C && D means (A AND B) OR (C AND D)." msgstr "" "示例:^A && B && !C && D$
" "表示節點備註需同時滿足:以 A 開頭(^)、包含 B、不包含 C(!)、並以 D 結尾($)。
" -"多個條件使用 && 連接,條件順序不影響結果。" +"多個條件使用 &&(與)連接,條件順序不影響結果。
" +"多組條件之間可使用 ||(或)分隔,任意一組匹配即視為成功。
" +"示例:A && B || C && D 表示 (A 且 B) 或 (C 且 D)。" msgid "Balancing Strategy" msgstr "負載均衡策略" diff --git a/luci-app-passwall2/root/usr/share/passwall2/nftables.sh b/luci-app-passwall2/root/usr/share/passwall2/nftables.sh index c12ccd59..ab272b81 100755 --- a/luci-app-passwall2/root/usr/share/passwall2/nftables.sh +++ b/luci-app-passwall2/root/usr/share/passwall2/nftables.sh @@ -160,25 +160,28 @@ insert_nftset() { *) suffix=" timeout $timeout_argument" ;; esac { - if [ $# -gt 0 ]; then + if [ $# -gt 0 ] && [ $# -le 1000 ]; then printf "%s\n" "$@" + elif [ $# -gt 1000 ]; then + printf "%s\n" "$*" else cat fi | awk -v s="$suffix" -v n="$nftset_name" -v t="$NFTABLE_NAME" ' BEGIN { RS = "[ \t\n\r]+" + ORS = "" } $0 != "" { - if (first == 0) { - printf "add element %s %s { \n", t, n; + if (!first) { + printf "add element %s %s { \n", t, n first = 1; } else { - printf ",\n"; + print ",\n" } - printf "%s%s", $0, s; + print $0 s } END { - if (first == 1) printf "\n }\n"; + if (first) print "\n }\n" } ' } | nft -f - diff --git a/luci-mod-network/htdocs/luci-static/resources/view/network/wireless.js b/luci-mod-network/htdocs/luci-static/resources/view/network/wireless.js index 345bfad5..8e21bba5 100644 --- a/luci-mod-network/htdocs/luci-static/resources/view/network/wireless.js +++ b/luci-mod-network/htdocs/luci-static/resources/view/network/wireless.js @@ -4456,6 +4456,16 @@ return view.extend({ uci.set('network', nameval, 'device', staDevice); } + else if (hwtype == 'qcawifi' || hwtype == 'qcawificfg80211') { + const radioName = radioDev.getName(); + const radioMatch = radioName.match(/^wifi(\d+)$/); + const radioVifs = uci.sections('wireless', 'wifi-iface') + .filter(section => section.device == radioName); + const vifIndex = radioVifs.findIndex(section => section['.name'] == section_id); + + if (radioMatch && vifIndex >= 0) + uci.set('network', nameval, 'device', 'ath%s%s'.format(radioMatch[1], vifIndex || '')); + } firewall.deleteNetwork(net.getName()); @@ -4540,7 +4550,8 @@ return view.extend({ if (bss.ssid != null) { bssid = s2.option(form.Flag, 'bssid', _('Lock to BSSID'), _('Instead of joining any network with a matching SSID, only connect to the BSSID %h.').format(bss.bssid)); - bssid.default = (uci.get('wireless', radioDev.getName(), 'type') == 'mt_dbdc') ? '1' : '0'; + const radioType = uci.get('wireless', radioDev.getName(), 'type'); + bssid.default = ['mt_dbdc', 'qcawifi', 'qcawificfg80211'].includes(radioType) ? '1' : '0'; } zone = s2.option(widgets.ZoneSelect, 'zone', _('Create / Assign firewall-zone'), _('Choose the firewall zone you want to assign to this interface. Select unspecified to remove the interface from the associated zone or fill out the custom field to define a new zone and attach the interface to it.')); diff --git a/mptcp/Makefile b/mptcp/Makefile index 3573471a..1828317a 100644 --- a/mptcp/Makefile +++ b/mptcp/Makefile @@ -10,7 +10,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=mptcp PKG_VERSION:=6.1 -PKG_RELEASE:=6 +PKG_RELEASE:=7 PKG_MAINTAINER:=Ycarus (Yannick Chabanois) PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) diff --git a/mptcp/files/etc/init.d/mptcp b/mptcp/files/etc/init.d/mptcp index 65952921..27b0692c 100755 --- a/mptcp/files/etc/init.d/mptcp +++ b/mptcp/files/etc/init.d/mptcp @@ -202,6 +202,12 @@ interface_multipath_settings() { uci -q set openmptcprouter.${config}.multipath="$mode" } [ "$mode" != "off" ] && { + # LRO, TSO and UFO break MPTCP packets scheduling, always disable them on multipath interfaces + [ -n "$iface" ] && { + for offload in lro tso ufo; do + ethtool -K $iface $offload off >/dev/null 2>&1 + done + } [ -n "$mptcpintf" ] && mptcpintf="$mptcpintf $iface" [ -z "$mptcpintf" ] && mptcpintf="$iface" [ -z "$mptcpmintf" ] && mptcpmintf="$config" diff --git a/natflow/Makefile b/natflow/Makefile index eccad148..f8968ba8 100644 --- a/natflow/Makefile +++ b/natflow/Makefile @@ -10,12 +10,12 @@ include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=natflow PKG_VERSION:=20260531 -PKG_RELEASE:=45 +PKG_RELEASE:=46 PKG_SOURCE:=$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=https://github.com/ptpt52/natflow.git PKG_SOURCE_PROTO:=git -PKG_SOURCE_VERSION:=0a3d1131b6a5094959f6441ef435b2b3b6fa4819 +PKG_SOURCE_VERSION:=5bf4ff4efbdab184c5c2f4e27bf0604726589bd3 PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_MAINTAINER:=Chen Minqiang PKG_LICENSE:=GPL-2.0 diff --git a/nps/Makefile b/nps/Makefile index 5635bc69..5f44a7b8 100644 --- a/nps/Makefile +++ b/nps/Makefile @@ -5,8 +5,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=nps -PKG_VERSION:=0.26.35 -PKG_RELEASE:=10 +PKG_VERSION:=0.26.36 +PKG_RELEASE:=11 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/yisier/nps/tar.gz/v$(PKG_VERSION)? diff --git a/torrserver/Makefile b/torrserver/Makefile index 92398459..0dad7cd6 100644 --- a/torrserver/Makefile +++ b/torrserver/Makefile @@ -8,12 +8,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=torrserver -PKG_VERSION:=MatriX.142 -PKG_RELEASE:=13 +PKG_VERSION:=MatriX.142.1 +PKG_RELEASE:=14 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/YouROK/TorrServer.git -PKG_SOURCE_VERSION:=f0585eb7dfc92e0e5fdcb17a7e7eead212201e7d +PKG_SOURCE_VERSION:=fa0e1ecb701e78826e3226e582a6ba0e76718a61 PKG_MIRROR_HASH:=skip PKG_MAINTAINER:=Konstantine Shevlakov