🌴 Sync 2026-07-14 04:31:14

This commit is contained in:
github-actions[bot] 2026-07-14 04:31:14 +08:00
parent f398c537dc
commit 0f3b9d2516
47 changed files with 926 additions and 789 deletions

View File

@ -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

View File

@ -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

View File

@ -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)?

View File

@ -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 <https://github.com/gSpotx2f/luci-app-internet-detector>
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)))

View File

@ -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)

View File

@ -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

View File

@ -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')]
];

View File

@ -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.<br/>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.<br/>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'));

View File

@ -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. <code>%s</code> 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. <code>%s</code> 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 <code>%s</code>, 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({
'<br/>' +
_('This is <strong>DANGEROUS</strong>, your traffic is almost like <strong>PLAIN TEXT</strong>! 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 '<a target="_blank" href="%s" rel="noreferrer noopener">%s</a>'
.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});

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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:= \

View File

@ -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

View File

@ -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"),
"<font color='red'>" ..
translate("Please confirm that your firmware supports FPU.") ..
"</font>")
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

View File

@ -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"))

View File

@ -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")

View File

@ -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隐藏

View File

@ -152,9 +152,10 @@ if load_balancing_options then -- [[ Load balancing Start ]]
o:depends({ [_n("node_add_mode")] = "batch" })
local descrStr = "Example: <code>^A && B && !C && D$</code><br>"
descrStr = descrStr .. "This means the node remark must start with A (^), include B, exclude C (!), and end with D ($).<br>"
descrStr = descrStr .. "Conditions are joined by <code>&&</code>, and their order does not affect the result."
o.description = translate(descrStr) .. string.format("<br><font color='red'>%s</font>",
translate("Keep the match scope small. Too many nodes can impact router performance."))
descrStr = descrStr .. "Conditions are joined by <code>&&</code> (AND), and their order does not affect the result.<br>"
descrStr = descrStr .. "Multiple groups can be separated by <code>||</code> (OR), matching succeeds if any group matches.<br>"
descrStr = descrStr .. "Example: <code>A && B || C && D</code> 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" })

View File

@ -151,9 +151,10 @@ if load_urltest_options then -- [[ URLTest Start ]]
o:depends({ [_n("node_add_mode")] = "batch" })
local descrStr = "Example: <code>^A && B && !C && D$</code><br>"
descrStr = descrStr .. "This means the node remark must start with A (^), include B, exclude C (!), and end with D ($).<br>"
descrStr = descrStr .. "Conditions are joined by <code>&&</code>, and their order does not affect the result."
o.description = translate(descrStr) .. string.format("<br><font color='red'>%s</font>",
translate("Keep the match scope small. Too many nodes can impact router performance."))
descrStr = descrStr .. "Conditions are joined by <code>&&</code> (AND), and their order does not affect the result.<br>"
descrStr = descrStr .. "Multiple groups can be separated by <code>||</code> (OR), matching succeeds if any group matches.<br>"
descrStr = descrStr .. "Example: <code>A && B || C && D</code> 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" })

View File

@ -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)

View File

@ -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

View File

@ -1,7 +1,7 @@
<div id="app_version">
<%
local api = require "luci.passwall.api"
local com = require "luci.passwall.com"
local version = {}
local api = self.api
local com = self.com
-%>
<script type="text/javascript">
@ -194,14 +194,14 @@ local version = {}
<%for _, k in ipairs(com.order) do
local v = com[k]
version[k] = api.get_app_version(k)%>
%>
<div class="cbi-value">
<label class="cbi-value-title"><%=v.name%>
<%:Version%>
</label>
<div class="cbi-value-field">
<!--div class="cbi-value-description"-->
<span><%=version[k] ~="" and version[k] or translate("Null") %></span>
<span><span class="com_version" key="<%=k%>"><%=translate("Null")%></span></span>
<input class="btn cbi-button cbi-button-apply" type="button" id="_<%=k%>-check_btn"
onclick="onBtnClick(this,'<%=k%>');" value="<%:Check update%>" />
<input class="btn cbi-button cbi-button-apply" type="button" id="_<%=k%>-force_btn"
@ -211,3 +211,27 @@ local version = {}
</div>
</div>
<%end%>
<script type="text/javascript">
//<![CDATA[
document.addEventListener("DOMContentLoaded", function () {
let coms = document.getElementsByClassName("com_version");
if (coms.length > 0) {
for (let i = 0; i < coms.length; i++) {
let key = coms[i].getAttribute("key");
coms[i].innerHTML = "<%=translate("Collecting data...")%>";
XHR.get('<%=api.url("version_")%>' + key, null, function(x, result) {
if (x.status == 200 && result.code == 1) {
let data = result.data;
let t = "<%=translate("Null")%>";
if (data && data != "")
t = data;
coms[i].innerHTML = t;
}
});
}
}
});
//]]>
</script>
</div>

View File

@ -532,14 +532,15 @@ msgstr "节点匹配规则"
msgid ""
"Example: <code>^A && B && !C && D$</code><br>"
"This means the node remark must start with A (^), include B, exclude C (!), and end with D ($).<br>"
"Conditions are joined by <code>&&</code>, and their order does not affect the result."
"Conditions are joined by <code>&&</code> (AND), and their order does not affect the result.<br>"
"Multiple groups can be separated by <code>||</code> (OR), matching succeeds if any group matches.<br>"
"Example: <code>A && B || C && D</code> means (A AND B) OR (C AND D)."
msgstr ""
"示例:<code>^A && B && !C && D$</code><br>"
"表示节点备注需同时满足:以 A 开头(^)、包含 B、不包含 C!)、并以 D 结尾($)。<br>"
"多个条件使用 <code>&&</code> 连接,条件顺序不影响结果。"
msgid "Keep the match scope small. Too many nodes can impact router performance."
msgstr "建议尽量缩小匹配范围,节点过多会增加路由器负载。"
"多个条件使用 <code>&&</code>(与)连接,条件顺序不影响结果。<br>"
"多组条件之间可使用 <code>||</code>(或)分隔,任意一组匹配即视为成功。<br>"
"示例:<code>A && B || C && D</code> 表示 (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 开头,然后保存应用后,再手动更新。"

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:= \

View File

@ -152,7 +152,9 @@ if load_balancing_options then -- [[ Load balancing Start ]]
o:depends({ [_n("node_add_mode")] = "batch" })
local descrStr = "Example: <code>^A && B && !C && D$</code><br>"
descrStr = descrStr .. "This means the node remark must start with A (^), include B, exclude C (!), and end with D ($).<br>"
descrStr = descrStr .. "Conditions are joined by <code>&&</code>, and their order does not affect the result."
descrStr = descrStr .. "Conditions are joined by <code>&&</code> (AND), and their order does not affect the result.<br>"
descrStr = descrStr .. "Multiple groups can be separated by <code>||</code> (OR), matching succeeds if any group matches.<br>"
descrStr = descrStr .. "Example: <code>A && B || C && D</code> means (A AND B) OR (C AND D)."
o.description = translate(descrStr)
o = s:option(ListValue, _n("balancingStrategy"), translate("Balancing Strategy"))

View File

@ -154,7 +154,9 @@ if load_urltest_options then -- [[ URLTest Start ]]
o:depends({ [_n("node_add_mode")] = "batch" })
local descrStr = "Example: <code>^A && B && !C && D$</code><br>"
descrStr = descrStr .. "This means the node remark must start with A (^), include B, exclude C (!), and end with D ($).<br>"
descrStr = descrStr .. "Conditions are joined by <code>&&</code>, and their order does not affect the result."
descrStr = descrStr .. "Conditions are joined by <code>&&</code> (AND), and their order does not affect the result.<br>"
descrStr = descrStr .. "Multiple groups can be separated by <code>||</code> (OR), matching succeeds if any group matches.<br>"
descrStr = descrStr .. "Example: <code>A && B || C && D</code> means (A AND B) OR (C AND D)."
o.description = translate(descrStr)
o = s:option(Value, _n("urltest_url"), translate("Probe URL"))

View File

@ -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)

View File

@ -394,11 +394,15 @@ msgstr "قوانین تطبیق گره"
msgid ""
"Example: <code>^A && B && !C && D$</code><br>"
"This means the node remark must start with A (^), include B, exclude C (!), and end with D ($).<br>"
"Conditions are joined by <code>&&</code>, and their order does not affect the result."
"Conditions are joined by <code>&&</code> (AND), and their order does not affect the result.<br>"
"Multiple groups can be separated by <code>||</code> (OR), matching succeeds if any group matches.<br>"
"Example: <code>A && B || C && D</code> means (A AND B) OR (C AND D)."
msgstr ""
"مثال: <code>^A && B && !C && D$</code><br>"
"این بدان معناست که توضیحات گره باید با A شروع شود (^)، شامل B باشد، فاقد C باشد (!)، و با D پایان یابد ($).<br>"
"شرط‌ها با <code>&&</code> به هم متصل می‌شوند و ترتیب آنها تاثیری در نتیجه ندارد."
"شرط‌ها با <code>&&</code> (و) به هم متصل می‌شوند و ترتیب آنها تاثیری در نتیجه ندارد.<br>"
"چندین گروه شرط می‌توانند با <code>||</code> (یا) از هم جدا شوند؛ اگر هر گروهی مطابقت داشته باشد، نتیجه موفقیت‌آمیز است.<br>"
"مثال: <code>A && B || C && D</code> به معنای (A و B) یا (C و D) است."
msgid "Balancing Strategy"

View File

@ -391,11 +391,15 @@ msgstr "Правила отбора узлов"
msgid ""
"Example: <code>^A && B && !C && D$</code><br>"
"This means the node remark must start with A (^), include B, exclude C (!), and end with D ($).<br>"
"Conditions are joined by <code>&&</code>, and their order does not affect the result."
"Conditions are joined by <code>&&</code> (AND), and their order does not affect the result.<br>"
"Multiple groups can be separated by <code>||</code> (OR), matching succeeds if any group matches.<br>"
"Example: <code>A && B || C && D</code> means (A AND B) OR (C AND D)."
msgstr ""
"Пример: <code>^A && B && !C && D$</code><br>"
"Описание узла должно: начинаться с A (^), содержать B, не содержать C (!), заканчиваться на D ($).<br>"
"Условия соединяются оператором <code>&&</code>, порядок условий не влияет на результат."
"Условия соединяются оператором <code>&&</code> (И), порядок условий не влияет на результат.<br>"
"Несколько групп условий можно разделить оператором <code>||</code> (ИЛИ); совпадение любой группы считается успехом.<br>"
"Пример: <code>A && B || C && D</code> означает (A И B) ИЛИ (C И D)."
msgid "Balancing Strategy"
msgstr "Алгоритм балансировки"

View File

@ -391,11 +391,15 @@ msgstr "节点匹配规则"
msgid ""
"Example: <code>^A && B && !C && D$</code><br>"
"This means the node remark must start with A (^), include B, exclude C (!), and end with D ($).<br>"
"Conditions are joined by <code>&&</code>, and their order does not affect the result."
"Conditions are joined by <code>&&</code> (AND), and their order does not affect the result.<br>"
"Multiple groups can be separated by <code>||</code> (OR), matching succeeds if any group matches.<br>"
"Example: <code>A && B || C && D</code> means (A AND B) OR (C AND D)."
msgstr ""
"示例:<code>^A && B && !C && D$</code><br>"
"表示节点备注需同时满足:以 A 开头(^)、包含 B、不包含 C!)、并以 D 结尾($)。<br>"
"多个条件使用 <code>&&</code> 连接,条件顺序不影响结果。"
"多个条件使用 <code>&&</code>(与)连接,条件顺序不影响结果。<br>"
"多组条件之间可使用 <code>||</code>(或)分隔,任意一组匹配即视为成功。<br>"
"示例:<code>A && B || C && D</code> 表示 (A 且 B) 或 (C 且 D)。"
msgid "Balancing Strategy"
msgstr "负载均衡策略"

View File

@ -391,11 +391,15 @@ msgstr "節點匹配規則"
msgid ""
"Example: <code>^A && B && !C && D$</code><br>"
"This means the node remark must start with A (^), include B, exclude C (!), and end with D ($).<br>"
"Conditions are joined by <code>&&</code>, and their order does not affect the result."
"Conditions are joined by <code>&&</code> (AND), and their order does not affect the result.<br>"
"Multiple groups can be separated by <code>||</code> (OR), matching succeeds if any group matches.<br>"
"Example: <code>A && B || C && D</code> means (A AND B) OR (C AND D)."
msgstr ""
"示例:<code>^A && B && !C && D$</code><br>"
"表示節點備註需同時滿足:以 A 開頭(^)、包含 B、不包含 C!)、並以 D 結尾($)。<br>"
"多個條件使用 <code>&&</code> 連接,條件順序不影響結果。"
"多個條件使用 <code>&&</code>(與)連接,條件順序不影響結果。<br>"
"多組條件之間可使用 <code>||</code>(或)分隔,任意一組匹配即視為成功。<br>"
"示例:<code>A && B || C && D</code> 表示 (A 且 B) 或 (C 且 D)。"
msgid "Balancing Strategy"
msgstr "負載均衡策略"

View File

@ -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 -

View File

@ -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 <code>%h</code>.').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 <em>unspecified</em> to remove the interface from the associated zone or fill out the <em>custom</em> field to define a new zone and attach the interface to it.'));

View File

@ -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) <ycarus@zugaina.org>
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)

View File

@ -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"

View File

@ -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 <ptpt52@gmail.com>
PKG_LICENSE:=GPL-2.0

View File

@ -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)?

View File

@ -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 <shevlakov@132lan.ru>