mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-31 05:05:13 +08:00
🌈 Sync 2026-05-19 02:35:14
This commit is contained in:
1 parent
595807ea37
commit
ca5e918f4b
81 files changed
+12000
-3190
No files matched your search
@@ -1,131 +0,0 @@
|
||||
#
|
||||
# Copyright (C) 2010-2016 OpenWrt.org
|
||||
# Copyright (C) 2009-2016 Thomas Heil <heil@terminal-consulting.de>
|
||||
# Copyright (C) 2018 Christian Lachner <gladiac@gmail.com>
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=haproxy
|
||||
PKG_VERSION:=3.2.19
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://www.haproxy.org/download/3.2/src
|
||||
PKG_HASH:=skip
|
||||
|
||||
PKG_MAINTAINER:=Thomas Heil <heil@terminal-consulting.de>, \
|
||||
Christian Lachner <gladiac@gmail.com>
|
||||
PKG_LICENSE:=GPL-2.0-only
|
||||
PKG_LICENSE_FILES:=LICENSE
|
||||
PKG_CPE_ID:=cpe:/a:haproxy:haproxy
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/haproxy/Default
|
||||
SUBMENU:=Web Servers/Proxies
|
||||
SECTION:=net
|
||||
CATEGORY:=Network
|
||||
TITLE:=TCP/HTTP Load Balancer
|
||||
URL:=https://www.haproxy.org/
|
||||
DEPENDS:= +USE_GLIBC:libcrypt-compat +libpcre2 +libltdl +zlib +libpthread +liblua5.4 +libatomic
|
||||
endef
|
||||
|
||||
define Package/haproxy/Default/description
|
||||
Open source Reliable, High Performance TCP/HTTP Load Balancer.
|
||||
endef
|
||||
|
||||
define Package/haproxy
|
||||
$(call Package/haproxy/Default)
|
||||
TITLE+=with SSL support
|
||||
DEPENDS+= +libopenssl +libncurses +libreadline
|
||||
VARIANT:=ssl
|
||||
endef
|
||||
|
||||
define Package/haproxy/description
|
||||
$(call Package/haproxy/Default/description)
|
||||
This package is built with SSL and LUA support.
|
||||
endef
|
||||
|
||||
define Package/haproxy-nossl
|
||||
$(call Package/haproxy/Default)
|
||||
TITLE+=without SSL support
|
||||
VARIANT:=nossl
|
||||
CONFLICTS:=haproxy
|
||||
endef
|
||||
|
||||
define Package/haproxy-nossl/description
|
||||
$(call Package/haproxy/Default/description)
|
||||
This package is built without SSL support.
|
||||
endef
|
||||
|
||||
TARGET=linux-musl
|
||||
ENABLE_LUA:=y
|
||||
|
||||
ifeq ($(CONFIG_USE_GLIBC),y)
|
||||
TARGET=linux-glibc
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_VARIANT),ssl)
|
||||
ADDON+=USE_OPENSSL=1
|
||||
ADDON+=ADDLIB="-lcrypto -lm"
|
||||
ADDON+=USE_QUIC=1
|
||||
endif
|
||||
|
||||
define Build/Compile
|
||||
$(MAKE) TARGET=$(TARGET) -C $(PKG_BUILD_DIR) \
|
||||
DESTDIR="$(PKG_INSTALL_DIR)" \
|
||||
CC="$(TARGET_CC)" \
|
||||
PCREDIR="$(STAGING_DIR)/usr/" \
|
||||
USE_LUA=1 LUA_LIB_NAME="lua5.4" LUA_INC="$(STAGING_DIR)/usr/include/lua5.4" LUA_LIB="$(STAGING_DIR)/usr/lib" \
|
||||
USE_ZLIB=1 USE_PCRE2=1 USE_PCRE2_JIT=1 USE_LIBATOMIC=1 USE_PROMEX=1 \
|
||||
VERSION="$(PKG_VERSION)" SUBVERS="-$(PKG_RELEASE)" \
|
||||
VERDATE="$(shell date -d @$(SOURCE_DATE_EPOCH) '+%Y/%m/%d')" IGNOREGIT=1 \
|
||||
$(ADDON) \
|
||||
CFLAGS="$(TARGET_CFLAGS) -fno-strict-aliasing -Wdeclaration-after-statement -Wno-unused-label -Wno-sign-compare -Wno-unused-parameter -Wno-clobbered -Wno-missing-field-initializers -Wno-cast-function-type -Wno-address-of-packed-member -Wtype-limits -Wshift-negative-value -Wshift-overflow=2 -Wduplicated-cond -Wnull-dereference -fwrapv -fasynchronous-unwind-tables -Wno-null-dereference" \
|
||||
LD="$(TARGET_CC)" \
|
||||
LDFLAGS="$(TARGET_LDFLAGS)"
|
||||
|
||||
$(MAKE_VARS) $(MAKE) -C $(PKG_BUILD_DIR) \
|
||||
DESTDIR="$(PKG_INSTALL_DIR)" \
|
||||
LD="$(TARGET_CC)" \
|
||||
LDFLAGS="$(TARGET_LDFLAGS)" \
|
||||
$(MAKE_FLAGS) \
|
||||
install
|
||||
|
||||
$(MAKE_VARS) $(MAKE) -C $(PKG_BUILD_DIR) \
|
||||
DESTDIR="$(PKG_INSTALL_DIR)" \
|
||||
CC="$(TARGET_CC)" \
|
||||
CFLAGS="$(TARGET_CFLAGS) -Wno-address-of-packed-member" \
|
||||
LDFLAGS="$(TARGET_LDFLAGS)" \
|
||||
admin/halog/halog
|
||||
endef
|
||||
|
||||
define Package/haproxy/install
|
||||
$(INSTALL_DIR) $(1)/usr/sbin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/haproxy $(1)/usr/sbin/
|
||||
endef
|
||||
|
||||
Package/haproxy-nossl/install = $(Package/haproxy/install)
|
||||
|
||||
define Package/halog
|
||||
$(call Package/haproxy)
|
||||
TITLE+=halog
|
||||
DEPENDS:=haproxy
|
||||
endef
|
||||
|
||||
define Package/halog/description
|
||||
HAProxy Log Analyzer
|
||||
endef
|
||||
|
||||
define Package/halog/install
|
||||
$(INSTALL_DIR) $(1)/usr/bin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/admin/halog/halog $(1)/usr/bin/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,haproxy))
|
||||
$(eval $(call BuildPackage,halog))
|
||||
$(eval $(call BuildPackage,haproxy-nossl))
|
||||
@@ -16,8 +16,8 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-amlogic
|
||||
PKG_VERSION:=3.1.313
|
||||
PKG_RELEASE:=11
|
||||
PKG_VERSION:=3.1.315
|
||||
PKG_RELEASE:=12
|
||||
|
||||
PKG_LICENSE:=GPL-2.0 License
|
||||
PKG_MAINTAINER:=ophub <https://github.com/ophub/luci-app-amlogic>
|
||||
|
||||
@@ -162,6 +162,7 @@ const inbound_type = [
|
||||
['anytls', _('AnyTLS') + ' - ' + _('TCP')],
|
||||
['tuic', _('TUIC') + ' - ' + _('UDP')],
|
||||
['hysteria2', _('Hysteria2') + ' - ' + _('UDP')],
|
||||
['hysteria2-realm', _('Hysteria2 Realm') + ' - ' + _('TCP/UDP')],
|
||||
['trusttunnel', _('TrustTunnel') + ' - ' + _('TCP/UDP')],
|
||||
['tunnel', _('Tunnel') + ' - ' + _('TCP/UDP')]
|
||||
];
|
||||
|
||||
@@ -118,6 +118,7 @@ function renderListeners(s, uciconfig, isClient) {
|
||||
|
||||
s.tab('field_general', _('General fields'));
|
||||
s.tab('field_vless_encryption', _('Vless Encryption fields'));
|
||||
s.tab('field_hysteria2_realm', _('Hysteria2 Realm fields'));
|
||||
s.tab('field_tls', _('TLS fields'));
|
||||
s.tab('field_transport', _('Transport fields'));
|
||||
s.tab('field_multiplex', _('Multiplex fields'));
|
||||
@@ -209,6 +210,36 @@ function renderListeners(s, uciconfig, isClient) {
|
||||
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];
|
||||
@@ -498,11 +529,18 @@ function renderListeners(s, uciconfig, isClient) {
|
||||
/* Plugin fields */
|
||||
o = s.taboption('field_general', form.ListValue, 'plugin', _('Plugin'));
|
||||
o.value('', _('none'));
|
||||
o.value('obfs', _('obfs-simple'));
|
||||
o.value('shadow-tls', _('shadow-tls'));
|
||||
//o.value('kcp-tun', _('kcp-tun'));
|
||||
o.depends('type', 'shadowsocks');
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_general', form.ListValue, 'plugin_opts_obfsmode', _('Plugin: ') + _('Obfs Mode'));
|
||||
o.value('http', _('HTTP'));
|
||||
o.value('tls', _('TLS'));
|
||||
o.depends('plugin', 'obfs');
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_general', form.Value, 'plugin_opts_handshake_dest', _('Plugin: ') + _('Handshake target that supports TLS 1.3'));
|
||||
o.datatype = 'hostport';
|
||||
o.placeholder = 'cloud.tencent.com:443';
|
||||
@@ -782,6 +820,40 @@ function renderListeners(s, uciconfig, isClient) {
|
||||
o.depends('vless_decryption', '1');
|
||||
o.modalonly = true;
|
||||
|
||||
// @xhttp-config其他的配置
|
||||
|
||||
/* Hysteria2 Realm fields */
|
||||
o = s.taboption('field_general', form.Flag, 'hysteria2_realm', _('Realm'));
|
||||
o.default = o.disabled;
|
||||
o.depends('type', 'hysteria2');
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_hysteria2_realm', form.Value, 'hysteria2_realm_server_url', _('Rendezvous server'));
|
||||
o.placeholder = 'https://realm.hy2.io';
|
||||
o.rmempty = false;
|
||||
o.depends('hysteria2_realm', '1');
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_hysteria2_realm', form.Value, 'hysteria2_realm_token', _('Pre-shared key of rendezvous server'));
|
||||
o.placeholder = 'public';
|
||||
o.depends('hysteria2_realm', '1');
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_hysteria2_realm', form.Value, 'hysteria2_realm_id', _('Realm ID'));
|
||||
o.placeholder = 'my-cabin-1f3a8c2e9b';
|
||||
o.rmempty = false;
|
||||
o.depends('hysteria2_realm', '1');
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_hysteria2_realm', form.DynamicList, 'hysteria2_realm_stun_servers', _('STUN servers'));
|
||||
o.datatype = 'hostport';
|
||||
o.default = ['stun.nextcloud.com:3478','stun.sip.us:3478','global.stun.twilio.com:3478'];
|
||||
o.rmempty = false;
|
||||
o.depends('hysteria2_realm', '1');
|
||||
o.modalonly = true;
|
||||
|
||||
// @ 下面支持填写针对server-url的TLS配置(sni, skip-cert-verify, fingerprint, certificate, private-key, alpn)
|
||||
|
||||
/* TLS fields */
|
||||
o = s.taboption('field_general', form.Flag, 'tls', _('TLS'));
|
||||
o.default = o.disabled;
|
||||
@@ -795,12 +867,29 @@ function renderListeners(s, uciconfig, isClient) {
|
||||
if (['trojan', 'anytls', 'tuic', 'hysteria2', 'trusttunnel'].includes(type)) {
|
||||
tls.checked = true;
|
||||
tls.disabled = true;
|
||||
if (['tuic', 'hysteria2'].includes(type) && !`${tls_alpn.getValue()}`)
|
||||
tls_alpn.setValue('h3');
|
||||
} else {
|
||||
tls.removeAttribute('disabled');
|
||||
}
|
||||
|
||||
// Default alpn
|
||||
if (!`${tls_alpn.getValue()}`) {
|
||||
let def_alpn;
|
||||
|
||||
switch (type) {
|
||||
case 'hysteria2':
|
||||
case 'tuic':
|
||||
def_alpn = ['h3'];
|
||||
break;
|
||||
case 'hysteria2-realm':
|
||||
def_alpn = ['h2', 'http/1.1'];
|
||||
break;
|
||||
default:
|
||||
def_alpn = [];
|
||||
}
|
||||
|
||||
tls_alpn.setValue(def_alpn);
|
||||
}
|
||||
|
||||
// Force disabled
|
||||
if (['trusttunnel'].includes(type)) {
|
||||
tls_alpn.node.querySelector('input').disabled = true;
|
||||
@@ -817,7 +906,7 @@ function renderListeners(s, uciconfig, isClient) {
|
||||
|
||||
return true;
|
||||
}
|
||||
o.depends({type: /^(http|socks|mixed|vmess|vless|trojan|anytls|tuic|hysteria2|trusttunnel)$/});
|
||||
o.depends({type: /^(http|socks|mixed|vmess|vless|trojan|anytls|tuic|hysteria2|hysteria2-realm|trusttunnel)$/});
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_tls', form.DynamicList, 'tls_alpn', _('TLS ALPN'),
|
||||
@@ -860,7 +949,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|tuic|trusttunnel)$/});
|
||||
o.depends({tls: '1', type: /^(http|socks|mixed|vmess|vless|trojan|anytls|hysteria2|hysteria2-realm|tuic|trusttunnel)$/});
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_tls', form.Value, 'tls_client_auth_cert_path', _('Client Auth Certificate path') + _(' (mTLS)'),
|
||||
@@ -869,7 +958,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|tuic|trusttunnel)$/});
|
||||
o.depends({tls: '1', type: /^(http|socks|mixed|vmess|vless|trojan|anytls|hysteria2|hysteria2-realm|tuic|trusttunnel)$/});
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_tls', form.Button, '_upload_client_auth_cert', _('Upload certificate') + _(' (mTLS)'),
|
||||
@@ -918,13 +1007,13 @@ function renderListeners(s, uciconfig, isClient) {
|
||||
|
||||
return node;
|
||||
}
|
||||
o.depends({tls: '1', type: /^(http|socks|mixed|vmess|vless|trojan|anytls|hysteria2|tuic|trusttunnel)$/});
|
||||
o.depends({tls: '1', type: /^(http|socks|mixed|vmess|vless|trojan|anytls|hysteria2|hysteria2-realm|tuic|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|tuic|trusttunnel)$/});
|
||||
o.depends({tls: '1', type: /^(http|socks|mixed|vmess|vless|trojan|anytls|hysteria2|hysteria2-realm|tuic|trusttunnel)$/});
|
||||
o.modalonly = true;
|
||||
|
||||
// uTLS fields
|
||||
|
||||
@@ -221,6 +221,7 @@ return view.extend({
|
||||
|
||||
ss.tab('field_general', _('General fields'));
|
||||
ss.tab('field_vless_encryption', _('Vless Encryption fields'));
|
||||
ss.tab('field_hysteria2_realm', _('Hysteria2 Realm fields'));
|
||||
ss.tab('field_tls', _('TLS fields'));
|
||||
ss.tab('field_transport', _('Transport fields'));
|
||||
ss.tab('field_multiplex', _('Multiplex fields'));
|
||||
@@ -956,6 +957,40 @@ return view.extend({
|
||||
so.depends('vless_encryption', '1');
|
||||
so.modalonly = true;
|
||||
|
||||
// @ 下面支持填写针对download-settings的上下行分离配置
|
||||
|
||||
/* Hysteria2 Realm fields */
|
||||
so = ss.taboption('field_general', form.Flag, 'hysteria2_realm', _('Realm'));
|
||||
so.default = so.disabled;
|
||||
so.depends('type', 'hysteria2');
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_hysteria2_realm', form.Value, 'hysteria2_realm_server_url', _('Rendezvous server'));
|
||||
so.placeholder = 'https://realm.hy2.io';
|
||||
so.rmempty = false;
|
||||
so.depends('hysteria2_realm', '1');
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_hysteria2_realm', form.Value, 'hysteria2_realm_token', _('Pre-shared key of rendezvous server'));
|
||||
so.placeholder = 'public';
|
||||
so.depends('hysteria2_realm', '1');
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_hysteria2_realm', form.Value, 'hysteria2_realm_id', _('Realm ID'));
|
||||
so.placeholder = 'my-cabin-1f3a8c2e9b';
|
||||
so.rmempty = false;
|
||||
so.depends('hysteria2_realm', '1');
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_hysteria2_realm', form.DynamicList, 'hysteria2_realm_stun_servers', _('STUN servers'));
|
||||
so.datatype = 'hostport';
|
||||
so.default = ['stun.nextcloud.com:3478','stun.sip.us:3478','global.stun.twilio.com:3478'];
|
||||
so.rmempty = false;
|
||||
so.depends('hysteria2_realm', '1');
|
||||
so.modalonly = true;
|
||||
|
||||
// @ 下面支持填写针对server-url的TLS配置(sni, skip-cert-verify, fingerprint, certificate, private-key, alpn)
|
||||
|
||||
/* TLS fields */
|
||||
so = ss.taboption('field_general', form.Flag, 'tls', _('TLS'));
|
||||
so.default = so.disabled;
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -511,6 +511,20 @@ uci.foreach(uciconf, ucinode, (cfg) => {
|
||||
down: cfg.hysteria_down_mbps ? cfg.hysteria_down_mbps + ' Mbps' : null,
|
||||
obfs: cfg.hysteria_obfs_type,
|
||||
"obfs-password": cfg.hysteria_obfs_password,
|
||||
"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,
|
||||
@@ -680,6 +694,7 @@ uci.foreach(uciconf, ucinode, (cfg) => {
|
||||
"h-max-request-times": cfg.transport_xhttp_xmux_max_request_times,
|
||||
"h-max-reusable-secs": cfg.transport_xhttp_xmux_max_reusable_secs,
|
||||
"h-keep-alive-period": strToInt(cfg.transport_xhttp_xmux_keep_alive_period)
|
||||
// @download-settings
|
||||
} : null
|
||||
} : null
|
||||
} : {}),
|
||||
|
||||
@@ -251,6 +251,27 @@ export function parseListener(cfg, isClient, label) {
|
||||
obfs: cfg.hysteria_obfs_type,
|
||||
"obfs-password": cfg.hysteria_obfs_password,
|
||||
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,
|
||||
@@ -302,6 +323,11 @@ export function parseListener(cfg, isClient, label) {
|
||||
|
||||
/* Plugin fields */
|
||||
...(cfg.plugin ? {
|
||||
// obfs-simple
|
||||
"simple-obfs": cfg.plugin === 'obfs' ? {
|
||||
enable: true,
|
||||
mode: cfg.plugin_opts_obfsmode
|
||||
} : null,
|
||||
// shadow-tls
|
||||
"shadow-tls": cfg.plugin === 'shadow-tls' ? {
|
||||
enable: true,
|
||||
@@ -357,6 +383,7 @@ export function parseListener(cfg, isClient, label) {
|
||||
"sc-max-buffered-posts": strToInt(cfg.transport_xhttp_sc_max_buffered_posts) || null,
|
||||
"sc-stream-up-server-secs": cfg.transport_xhttp_sc_stream_up_server_secs,
|
||||
"sc-max-each-post-bytes": strToInt(cfg.transport_xhttp_sc_max_each_post_bytes) || null,
|
||||
// @其他的配置
|
||||
} : null
|
||||
} : {})
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ include $(TOPDIR)/rules.mk
|
||||
LUCI_TITLE:=Information dashboard for 3G/LTE dongle
|
||||
LUCI_DEPENDS:=+modeminfo
|
||||
PKG_LICENSE:=GPLv3
|
||||
PKG_VERSION:=0.4.6
|
||||
PKG_RELEASE:=2
|
||||
PKG_VERSION:=0.4.7
|
||||
PKG_RELEASE:=3
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
'use strict';
|
||||
'require ui';
|
||||
'require poll';
|
||||
'require fs';
|
||||
'require uci';
|
||||
|
||||
function getSignalColor(percent) {
|
||||
if (percent === null || percent === undefined || percent < 5) {
|
||||
return '#000000';
|
||||
}
|
||||
|
||||
let p = percent;
|
||||
|
||||
if (p >= 80) return '#00cc00';
|
||||
|
||||
if (p >= 67) {
|
||||
const ratio = (p - 50) / 30;
|
||||
const r = Math.floor(255 * (1 - ratio));
|
||||
const g = 255;
|
||||
return `rgb(${r}, ${g}, 0)`;
|
||||
}
|
||||
|
||||
if (p >= 35) {
|
||||
const ratio = (p - 25) / 25;
|
||||
const r = 255;
|
||||
const g = Math.floor(165 + (90 * ratio));
|
||||
return `rgb(${r}, ${g}, 0)`;
|
||||
}
|
||||
|
||||
const ratio = (p - 5) / 20;
|
||||
const r = 255;
|
||||
const g = Math.floor(165 * ratio);
|
||||
return `rgb(${r}, ${g}, 0)`;
|
||||
}
|
||||
|
||||
|
||||
function getSignalState(percent) {
|
||||
const p = percent || 0;
|
||||
if (p < 10) return 'error';
|
||||
if (p < 25) return 'warning';
|
||||
if (p < 50) return 'warning';
|
||||
return 'active';
|
||||
}
|
||||
|
||||
function isUciIndexTwo() {
|
||||
return L.resolveDefault(fs.exec_direct('/sbin/uci', ['get', 'modeminfo.@general[0].index']), '')
|
||||
.then(function(value) {
|
||||
return value.trim() === '2';
|
||||
})
|
||||
.catch(function() {
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function updateIndicator() {
|
||||
|
||||
|
||||
|
||||
isUciIndexTwo().then(function(ok) {
|
||||
if (!ok) {
|
||||
ui.hideIndicator('modem-status');
|
||||
return;
|
||||
}
|
||||
|
||||
if (window.location.pathname.includes('/cgi-bin/luci/admin/modem/main')) {
|
||||
ui.hideIndicator('modem-status');
|
||||
return;
|
||||
}
|
||||
L.resolveDefault(fs.exec_direct('/usr/bin/modeminfo'), '{"modem":[]}')
|
||||
.then(function(res) {
|
||||
var data = JSON.parse(res);
|
||||
if (!data.modem || !data.modem.length) {
|
||||
ui.hideIndicator('modem-status');
|
||||
return;
|
||||
}
|
||||
|
||||
var parts = data.modem.map(function(modem) {
|
||||
var percent = parseInt(modem.csq_per);
|
||||
var cops = modem.cops || '';
|
||||
var mode = modem.mode + (parseInt(modem.lteca) > 0 ? '+' : '');
|
||||
return { mode: mode, cops: cops, percent: percent };
|
||||
});
|
||||
|
||||
var minPercent = Math.min.apply(null, parts.map(function(p) { return p.percent; }));
|
||||
var state = getSignalState(minPercent);
|
||||
|
||||
var status = parts.map(function(p) {
|
||||
return p.mode + ' ' + p.cops;
|
||||
}).join(' | ');
|
||||
|
||||
ui.showIndicator('modem-status', status, null, state);
|
||||
|
||||
var indicator = document.querySelector('[data-indicator="modem-status"]');
|
||||
if (indicator) {
|
||||
var html = parts.map(function(p) {
|
||||
var color = getSignalColor(p.percent);
|
||||
return '<span style="color:' + color + '; -webkit-text-stroke: 0.5px black; text-stroke: 0.5px black;">●</span> ' + p.mode + ' ' + p.cops;
|
||||
}).join(' | ');
|
||||
indicator.innerHTML = html;
|
||||
}
|
||||
})
|
||||
.catch(function() {
|
||||
ui.hideIndicator('modem-status');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
setTimeout(function() {
|
||||
updateIndicator();
|
||||
poll.add(updateIndicator, 10);
|
||||
}, 500);
|
||||
|
||||
return L.Class.extend({
|
||||
__name__: 'ModemIndicator'
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
'use strict';
|
||||
'require modem-indicator';
|
||||
|
||||
return L.Class.extend({
|
||||
__name__: 'preload.modem-indicator'
|
||||
});
|
||||
@@ -60,7 +60,7 @@ var qdesc = _('Select qmi port.');
|
||||
var lacdec = _('Show LAC and CID in decimal.');
|
||||
var mmdesc = _('Get device hardware name via mmcli utility if aviable.');
|
||||
var qmidesc = _('Set qmi mode.');
|
||||
var idesc = _('Short info on Overview page');
|
||||
var idesc = _('Show short info.<br />Overview: show info on main page \"Cellular Network\" section<br />MenuBar: show info on menubar all pages<br />NOTICE: Don\'t add too many modems in menubar, it may break the theme display.');
|
||||
var portplace = _('Please select a port');
|
||||
|
||||
return view.extend({
|
||||
@@ -88,8 +88,12 @@ return view.extend({
|
||||
s = m.section(form.TypedSection, 'general', _('General option'), null);
|
||||
s.anonymous = true;
|
||||
|
||||
o = s.option(form.Flag, 'index', _('Index page'), idesc);
|
||||
s.anonymous = true;
|
||||
o = s.option(form.ListValue, 'index', _('Short info'), idesc);
|
||||
o.widget="radio";
|
||||
o.value(0,_('none'));
|
||||
o.value(1,_('overview'));
|
||||
o.value(2,_('menubar'));
|
||||
o.default = '0';
|
||||
o.rmempty = true;
|
||||
|
||||
o = s.option(form.Flag, 'decimail', _('Show decimal'), lacdec);
|
||||
|
||||
+14
-5
@@ -19,7 +19,11 @@ return baseclass.extend({
|
||||
title: _('Cellular network'),
|
||||
|
||||
load: async function() {
|
||||
uci.load('modeminfo');
|
||||
await uci.load('modeminfo');
|
||||
var index = uci.sections('modeminfo', 'general');
|
||||
if (!index || !index[0] || index[0].index !== "1") {
|
||||
return null;
|
||||
};
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeout = setTimeout(() => {
|
||||
@@ -43,10 +47,15 @@ return baseclass.extend({
|
||||
|
||||
render: function(data){
|
||||
if (!data || data.trim() === '') {
|
||||
return E('div', {
|
||||
'class': 'cbi-section',
|
||||
'style': 'color: #999; text-align: center;'
|
||||
}, _('Wait devices information'));
|
||||
var index = uci.sections('modeminfo', 'general');
|
||||
if (!index || !index[0] || index[0].index !== "1") {
|
||||
return null;
|
||||
} else {
|
||||
return E('div', {
|
||||
'class': 'cbi-section',
|
||||
'style': 'color: #999; text-align: center;'
|
||||
}, _('Wait devices information'));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
@@ -132,11 +132,23 @@ msgstr "Только QMI"
|
||||
msgid "QMI over MBIM"
|
||||
msgstr "QMI через MBIM"
|
||||
|
||||
msgid "Index page"
|
||||
msgstr "На главную"
|
||||
msgid "Short info"
|
||||
msgstr "Краткая информация"
|
||||
|
||||
msgid "Short info on Overview page"
|
||||
msgstr "Краткая информация о сети на главной странице"
|
||||
msgid "Show short info.<br />Overview: show info on main page \"Cellular Network\" section<br />MenuBar: show info on menubar all pages<br />NOTICE: Don\'t add too many modems in menubar, it may break the theme display."
|
||||
msgstr "Показвать краткую информацию<br />На главной: показывать главной странице раздел \"Сотовая сеть\"<br />Меню: показывать в строке меню на всех страницах<br />ВНИМАНИЕ: не добавляйте слишком много устройств в строку меню, это может сломать отображение."
|
||||
|
||||
msgid "none"
|
||||
msgstr "не отображать"
|
||||
|
||||
msgid "overview"
|
||||
msgid "на главной"
|
||||
|
||||
msgid "menubar"
|
||||
msgstr "в строке меню"
|
||||
|
||||
msgid "Wait devices information"
|
||||
msgstr "Ожидаются данные устройств"
|
||||
|
||||
msgid "sec"
|
||||
msgstr "сек"
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
},
|
||||
"file": {
|
||||
"/usr/bin/modeminfo": [ "exec" ],
|
||||
"/usr/share/modeminfo/scripts/rmtmp": [ "exec" ]
|
||||
"/usr/share/modeminfo/scripts/rmtmp": [ "exec" ],
|
||||
"/sbin/uci": [ "exec" ]
|
||||
},
|
||||
"uci": [ "modeminfo" ]
|
||||
},
|
||||
|
||||
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-passwall
|
||||
PKG_VERSION:=26.5.11
|
||||
PKG_RELEASE:=126
|
||||
PKG_RELEASE:=127
|
||||
PKG_PO_VERSION:=$(PKG_VERSION)
|
||||
|
||||
PKG_CONFIG_DEPENDS:= \
|
||||
@@ -18,8 +18,6 @@ PKG_CONFIG_DEPENDS:= \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Server \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client \
|
||||
@@ -43,9 +41,6 @@ LUCI_DEPENDS:=+coreutils +coreutils-base64 +coreutils-nohup +curl \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Haproxy:haproxy \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Hysteria:hysteria \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy:naiveproxy \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client:shadowsocks-libev-ss-local \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client:shadowsocks-libev-ss-redir \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Server:shadowsocks-libev-ss-server \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client:shadowsocks-rust-sslocal \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Server:shadowsocks-rust-ssserver \
|
||||
+PACKAGE_$(PKG_NAME)_INCLUDE_ShadowsocksR_Libev_Client:shadowsocksr-libev-ssr-local \
|
||||
@@ -106,14 +101,6 @@ config PACKAGE_$(PKG_NAME)_INCLUDE_NaiveProxy
|
||||
select PACKAGE_naiveproxy
|
||||
default n
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Client
|
||||
bool "Include Shadowsocks Libev Client"
|
||||
default y
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Libev_Server
|
||||
bool "Include Shadowsocks Libev Server"
|
||||
default y if aarch64||arm||i386||x86_64
|
||||
|
||||
config PACKAGE_$(PKG_NAME)_INCLUDE_Shadowsocks_Rust_Client
|
||||
bool "Include Shadowsocks Rust Client"
|
||||
depends on !i386
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
local api = require "luci.passwall.api"
|
||||
local uci = api.uci
|
||||
local appname = "passwall"
|
||||
local has_ss = api.is_finded("ss-redir")
|
||||
local has_ss_rust = api.is_finded("sslocal")
|
||||
local has_singbox = api.finded_com("sing-box")
|
||||
local has_xray = api.finded_com("xray")
|
||||
@@ -12,10 +11,6 @@ local vmess_type = {}
|
||||
local vless_type = {}
|
||||
local hysteria2_type = {}
|
||||
local xray_version = api.get_app_version("xray")
|
||||
if has_ss then
|
||||
local s = "shadowsocks-libev"
|
||||
table.insert(ss_type, s)
|
||||
end
|
||||
if has_ss_rust then
|
||||
local s = "shadowsocks-rust"
|
||||
table.insert(ss_type, s)
|
||||
|
||||
@@ -16,7 +16,6 @@ end
|
||||
|
||||
m:append(Template(appname .. "/cbi/nodes_listvalue_com"))
|
||||
|
||||
local has_ss = api.is_finded("ss-redir")
|
||||
local has_ss_rust = api.is_finded("sslocal")
|
||||
local has_singbox = api.finded_com("sing-box")
|
||||
local has_xray = api.finded_com("xray")
|
||||
@@ -27,10 +26,6 @@ local vmess_type = {}
|
||||
local vless_type = {}
|
||||
local hysteria2_type = {}
|
||||
local xray_version = api.get_app_version("xray")
|
||||
if has_ss then
|
||||
local s = "shadowsocks-libev"
|
||||
table.insert(ss_type, s)
|
||||
end
|
||||
if has_ss_rust then
|
||||
local s = "shadowsocks-rust"
|
||||
table.insert(ss_type, s)
|
||||
|
||||
@@ -262,6 +262,13 @@ if load_balancing_options then -- [[ Load balancing Start ]]
|
||||
o.default = "2"
|
||||
o.placeholder = "2"
|
||||
o.description = translate("The load balancer selects the optimal number of nodes, and traffic is randomly distributed among them.")
|
||||
|
||||
o = s:option(Value, _n("tolerance"), translate("Failure Tolerance (%)"))
|
||||
o:depends({ [_n("balancingStrategy")] = "leastLoad" })
|
||||
o.datatype = "uinteger"
|
||||
o.default = "10"
|
||||
o.placeholder = "10"
|
||||
o.description = translate("The maximum acceptable speed test failure rate. For example, 1 means allowing a 1% failure rate.")
|
||||
end -- [[ 负载均衡 End ]]
|
||||
|
||||
if load_iface_options then -- [[ 自定义接口 Start ]]
|
||||
|
||||
@@ -43,6 +43,8 @@ local security_list = { "none", "auto", "aes-128-gcm", "chacha20-poly1305", "zer
|
||||
|
||||
local singbox_tags = luci.sys.exec(singbox_bin .. " version | grep 'Tags:' | awk '{print $2}'")
|
||||
|
||||
local singbox_version = api.get_app_version("sing-box"):match("[^v]+")
|
||||
|
||||
o = s:option(ListValue, _n("protocol"), translate("Protocol"))
|
||||
o:value("socks", "Socks")
|
||||
o:value("http", "HTTP")
|
||||
@@ -351,13 +353,28 @@ end
|
||||
if singbox_tags:find("with_quic") then
|
||||
o = s:option(Value, _n("hysteria2_hop"), translate("Port hopping range"))
|
||||
o.description = translate("Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,).")
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false })
|
||||
|
||||
o = s:option(Value, _n("hysteria2_hop_interval"), translate("Hop Interval(second)"), translate("Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5."))
|
||||
o.datatype = "or(uinteger,portrange)"
|
||||
o.placeholder = "30"
|
||||
o.default = "30"
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false })
|
||||
|
||||
o = s:option(Flag, _n("hysteria2_realms"), translate("Realms"))
|
||||
o.default = "0"
|
||||
if api.compare_versions(singbox_version, ">=", "1.14.0") then
|
||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||
else
|
||||
o:depends({ [_n("protocol")] = "__hide"})
|
||||
end
|
||||
|
||||
o = s:option(Value, _n("hysteria2_realm_url"), translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name")
|
||||
o:depends({ [_n("hysteria2_realms")] = "1" })
|
||||
|
||||
o = s:option(DynamicList, _n("hysteria2_realm_stun"), translate("Realm STUN"))
|
||||
o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" }
|
||||
o:depends({ [_n("hysteria2_realms")] = "1" })
|
||||
|
||||
o = s:option(Value, _n("hysteria2_auth_password"), translate("Auth Password"))
|
||||
o.password = true
|
||||
@@ -479,7 +496,7 @@ o.default = "0"
|
||||
o:depends({ [_n("tls")] = true, [_n("flow")] = "", [_n("reality")] = false })
|
||||
o:depends({ [_n("protocol")] = "tuic" })
|
||||
o:depends({ [_n("protocol")] = "hysteria" })
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false })
|
||||
o:depends({ [_n("protocol")] = "naive" })
|
||||
|
||||
o = s:option(TextValue, _n("ech_config"), translate("ECH Config"))
|
||||
@@ -787,10 +804,14 @@ local protocols = s.fields[_n("protocol")].keylist
|
||||
if #protocols > 0 then
|
||||
for i, v in ipairs(protocols) do
|
||||
if not v:find("^_") then
|
||||
s.fields[_n("address")]:depends({ [_n("protocol")] = v })
|
||||
s.fields[_n("port")]:depends({ [_n("protocol")] = v })
|
||||
s.fields[_n("domain_resolver")]:depends({ [_n("protocol")] = v })
|
||||
s.fields[_n("domain_strategy")]:depends({ [_n("protocol")] = v })
|
||||
local depends_condition = { [_n("protocol")] = v }
|
||||
if v == "hysteria2" then
|
||||
depends_condition[_n("hysteria2_realms")] = false
|
||||
end
|
||||
s.fields[_n("address")]:depends(depends_condition)
|
||||
s.fields[_n("port")]:depends(depends_condition)
|
||||
s.fields[_n("domain_resolver")]:depends(depends_condition)
|
||||
s.fields[_n("domain_strategy")]:depends(depends_condition)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -805,6 +826,7 @@ if not load_shunt_options then
|
||||
o:value("1", translate("Preproxy Node"))
|
||||
end
|
||||
o:value("2", translate("Landing Node"))
|
||||
o:depends({ [_n("hysteria2_realms")] = false })
|
||||
|
||||
o1 = s:option(ListValue, _n("preproxy_node"), translate("Preproxy Node"), translate("Only support a layer of proxy."))
|
||||
o1:depends({ [_n("chain_proxy")] = "1" })
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
local m, s = ...
|
||||
|
||||
if not api.is_finded("ss-local") and not api.is_finded("ss-redir") then
|
||||
return
|
||||
end
|
||||
|
||||
type_name = "SS"
|
||||
|
||||
-- [[ Shadowsocks Libev ]]
|
||||
|
||||
s.fields["type"]:value(type_name, "Shadowsocks Libev")
|
||||
|
||||
if s.val["type"] ~= type_name then
|
||||
return
|
||||
end
|
||||
|
||||
local option_prefix = "ss_"
|
||||
|
||||
local function _n(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
local ss_encrypt_method_list = {
|
||||
"rc4-md5", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr",
|
||||
"aes-192-ctr", "aes-256-ctr", "bf-cfb", "salsa20", "chacha20", "chacha20-ietf",
|
||||
"aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305",
|
||||
"xchacha20-ietf-poly1305"
|
||||
}
|
||||
|
||||
o = s:option(ListValue, _n("del_protocol")) --始终隐藏,用于删除 protocol
|
||||
o:depends({ [_n("__hide")] = "1" })
|
||||
o.rewrite_option = "protocol"
|
||||
|
||||
o = s:option(Value, _n("address"), translate("Address (Support Domain Name)"))
|
||||
|
||||
o = s:option(Value, _n("port"), translate("Port"))
|
||||
o.datatype = "port"
|
||||
|
||||
o = s:option(Value, _n("password"), translate("Password"))
|
||||
o.password = true
|
||||
|
||||
o = s:option(Value, _n("method"), translate("Encrypt Method"))
|
||||
for a, t in ipairs(ss_encrypt_method_list) do o:value(t) end
|
||||
|
||||
o = s:option(Value, _n("timeout"), translate("Connection Timeout"))
|
||||
o.datatype = "uinteger"
|
||||
o.default = 300
|
||||
|
||||
o = s:option(Flag, _n("tcp_fast_open"), "TCP " .. translate("Fast Open"), translate("Need node support required"))
|
||||
o.default = 0
|
||||
|
||||
o = s:option(Flag, _n("plugin_enabled"), translate("plugin"))
|
||||
o.default = 0
|
||||
|
||||
o = s:option(ListValue, _n("plugin"), "SIP003 " .. translate("plugin"))
|
||||
o.default = "none"
|
||||
o:value("none", translate("none"))
|
||||
if api.is_finded("xray-plugin") then o:value("xray-plugin") end
|
||||
if api.is_finded("v2ray-plugin") then o:value("v2ray-plugin") end
|
||||
if api.is_finded("obfs-local") then o:value("obfs-local") end
|
||||
o:depends({ [_n("plugin_enabled")] = true })
|
||||
|
||||
o = s:option(Value, _n("plugin_opts"), translate("opts"))
|
||||
o:depends({ [_n("plugin_enabled")] = true })
|
||||
|
||||
api.luci_types(arg[1], m, s, type_name, option_prefix)
|
||||
@@ -24,6 +24,7 @@ o = s:option(Flag, _n("custom"), translate("Use Custom Config"))
|
||||
|
||||
o = s:option(Value, _n("port"), translate("Listen Port"))
|
||||
o.datatype = "port"
|
||||
o.rmempty = false
|
||||
o:depends({ [_n("custom")] = false })
|
||||
|
||||
o = s:option(Flag, _n("realms"), translate("Realms"))
|
||||
|
||||
@@ -55,6 +55,7 @@ o:depends({ [_n("custom")] = false })
|
||||
|
||||
o = s:option(Value, _n("port"), translate("Listen Port"))
|
||||
o.datatype = "port"
|
||||
o.rmempty = false
|
||||
o:depends({ [_n("custom")] = false })
|
||||
|
||||
o = s:option(Flag, _n("auth"), translate("Auth"))
|
||||
@@ -154,6 +155,17 @@ if singbox_tags:find("with_quic") then
|
||||
end
|
||||
|
||||
if singbox_tags:find("with_quic") then
|
||||
o = s:option(Flag, _n("hysteria2_realms"), translate("Realms"))
|
||||
o.default = "0"
|
||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||
|
||||
o = s:option(Value, _n("hysteria2_realm_url"), translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name")
|
||||
o:depends({ [_n("hysteria2_realms")] = "1" })
|
||||
|
||||
o = s:option(DynamicList, _n("hysteria2_realm_stun"), translate("Realm STUN"))
|
||||
o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" }
|
||||
o:depends({ [_n("hysteria2_realms")] = "1" })
|
||||
|
||||
o = s:option(Value, _n("hysteria2_auth_password"), translate("Auth Password"))
|
||||
o.password = true
|
||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||
@@ -321,7 +333,7 @@ o:depends({ [_n("tls")] = true, [_n("flow")] = "", [_n("reality")] = false })
|
||||
o:depends({ [_n("protocol")] = "naive" })
|
||||
o:depends({ [_n("protocol")] = "hysteria" })
|
||||
o:depends({ [_n("protocol")] = "tuic" })
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false })
|
||||
|
||||
o = s:option(TextValue, _n("ech_key"), translate("ECH Key"))
|
||||
o.default = ""
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
local m, s = ...
|
||||
|
||||
local api = require "luci.passwall.api"
|
||||
|
||||
if not api.is_finded("ss-server") then
|
||||
return
|
||||
end
|
||||
|
||||
local type_name = "SS"
|
||||
|
||||
local option_prefix = "ss_"
|
||||
|
||||
local function _n(name)
|
||||
return option_prefix .. name
|
||||
end
|
||||
|
||||
local ss_encrypt_method_list = {
|
||||
"rc4-md5", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr",
|
||||
"aes-192-ctr", "aes-256-ctr", "bf-cfb", "camellia-128-cfb",
|
||||
"camellia-192-cfb", "camellia-256-cfb", "salsa20", "chacha20",
|
||||
"chacha20-ietf", -- aead
|
||||
"aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305",
|
||||
"xchacha20-ietf-poly1305"
|
||||
}
|
||||
|
||||
-- [[ Shadowsocks ]]
|
||||
|
||||
s.fields["type"]:value(type_name, translate("Shadowsocks"))
|
||||
|
||||
o = s:option(Flag, _n("custom"), translate("Use Custom Config"))
|
||||
|
||||
o = s:option(Value, _n("port"), translate("Listen Port"))
|
||||
o.datatype = "port"
|
||||
o:depends({ [_n("custom")] = false })
|
||||
|
||||
o = s:option(Value, _n("password"), translate("Password"))
|
||||
o.password = true
|
||||
o:depends({ [_n("custom")] = false })
|
||||
|
||||
o = s:option(ListValue, _n("method"), translate("Encrypt Method"))
|
||||
for a, t in ipairs(ss_encrypt_method_list) do o:value(t) end
|
||||
o:depends({ [_n("custom")] = false })
|
||||
|
||||
o = s:option(Value, _n("timeout"), translate("Connection Timeout"))
|
||||
o.datatype = "uinteger"
|
||||
o.default = 300
|
||||
o:depends({ [_n("custom")] = false })
|
||||
|
||||
o = s:option(Flag, _n("tcp_fast_open"), "TCP " .. translate("Fast Open"))
|
||||
o.default = "0"
|
||||
o:depends({ [_n("custom")] = false })
|
||||
|
||||
o = s:option(TextValue, _n("custom_config"), translate("Custom Config"))
|
||||
o.rows = 10
|
||||
o.wrap = "off"
|
||||
o:depends({ [_n("custom")] = true })
|
||||
o.validate = function(self, value, t)
|
||||
if value and api.jsonc.parse(value) then
|
||||
return value
|
||||
else
|
||||
return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!")
|
||||
end
|
||||
end
|
||||
o.custom_cfgvalue = function(self, section, value)
|
||||
local config_str = m:get(section, "config_str")
|
||||
if config_str then
|
||||
return api.base64Decode(config_str)
|
||||
end
|
||||
end
|
||||
o.custom_write = function(self, section, value)
|
||||
m:set(section, "config_str", api.base64Encode(value) or "")
|
||||
end
|
||||
|
||||
o = s:option(Flag, _n("log"), translate("Log"))
|
||||
o.default = "1"
|
||||
o.rmempty = false
|
||||
|
||||
api.luci_types(arg[1], m, s, type_name, option_prefix)
|
||||
@@ -472,9 +472,10 @@ function get_valid_nodes()
|
||||
end
|
||||
end
|
||||
local port = e.port or e.hysteria_hop or e.hysteria2_hop
|
||||
if (port and e.address) or e.hysteria2_realms then
|
||||
local is_realm = (e.type == "Hysteria2" or e.protocol == 'hysteria2') and e.hysteria2_realms or nil
|
||||
if (port and e.address) or is_realm then
|
||||
local address = e.address
|
||||
if is_ip(address) or datatypes.hostname(address) or e.hysteria2_realms then
|
||||
if is_ip(address) or datatypes.hostname(address) or is_realm then
|
||||
if (e.type == "sing-box" or e.type == "Xray") and e.protocol then
|
||||
local protocol = e.protocol
|
||||
if protocol == "vmess" then
|
||||
@@ -501,10 +502,11 @@ function get_valid_nodes()
|
||||
type_name = type_name .. " " .. protocol
|
||||
end
|
||||
if is_ipv6(address) then address = get_ipv6_full(address) end
|
||||
type_name = is_realm and type_name .. " Realm" or type_name
|
||||
e["remark"] = trim("%s:[%s]" % {type_name, e.remarks})
|
||||
if show_node_info == "1" then
|
||||
port = (port or ""):gsub(":", "-")
|
||||
if not e.hysteria2_realms then
|
||||
if not is_realm then
|
||||
e["remark"] = trim("%s:[%s] %s:%s" % {type_name, e.remarks, address, port})
|
||||
end
|
||||
end
|
||||
@@ -596,6 +598,9 @@ function get_node_remarks(n)
|
||||
end
|
||||
type_name = type_name .. " " .. protocol
|
||||
end
|
||||
if (n.type == "Hysteria2" or n.protocol == 'hysteria2') and n.hysteria2_realms then
|
||||
type_name = type_name .. " Realm"
|
||||
end
|
||||
remarks = trim("%s:[%s]" % {type_name, n.remarks})
|
||||
end
|
||||
end
|
||||
@@ -1595,3 +1600,29 @@ function vps_domain_exclude(domain)
|
||||
if map[domain] then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
function parse_realm_uri(uri)
|
||||
if type(uri) ~= "string" then return nil end
|
||||
-- realm://token@server/realm_id?query
|
||||
local token, server_url, realm_id, query = trim(uri):match("^realm://([^@]+)@([^/]+)/([^?]*)%??(.*)$")
|
||||
if not token or not server_url or not realm_id then return nil end
|
||||
realm_id = realm_id:gsub("/+$", "")
|
||||
local realm = {
|
||||
token = token,
|
||||
server_url = server_url,
|
||||
realm_id = realm_id
|
||||
}
|
||||
-- 解析 query 中的 stun=
|
||||
if query and query ~= "" then
|
||||
local stun_servers = {}
|
||||
for key, value in query:gmatch("([^&=?]+)=([^&]+)") do
|
||||
if key == "stun" and value ~= "" then
|
||||
stun_servers[#stun_servers + 1] = value
|
||||
end
|
||||
end
|
||||
if #stun_servers > 0 then
|
||||
realm.stun_servers = stun_servers
|
||||
end
|
||||
end
|
||||
return realm
|
||||
end
|
||||
@@ -132,7 +132,7 @@ local function start()
|
||||
end
|
||||
end
|
||||
bin = ln_run("/usr/bin/microsocks", "microsocks_" .. id, string.format("-i :: -p %s %s", port, auth), log_path)
|
||||
elseif type == "SS" or type == "SSR" then
|
||||
elseif type == "SSR" then
|
||||
if user.custom == "1" and user.config_str then
|
||||
config = jsonc.parse(api.base64Decode(user.config_str))
|
||||
else
|
||||
|
||||
@@ -67,11 +67,7 @@ function gen_config(var)
|
||||
server_host = api.get_ipv6_full(server_host)
|
||||
end
|
||||
|
||||
local server = server_host .. (server_port and ":" .. server_port or "")
|
||||
|
||||
if node.hysteria2_hop then
|
||||
server = server .. (server_port and "," or ":") .. string.gsub(node.hysteria2_hop, ":", "-")
|
||||
end
|
||||
local server = server_host .. ":" .. ((server_port or "") .. "," .. (node.hysteria2_hop or "")):gsub("^[%s,]+", ""):gsub("[%s,]+$", ""):gsub(":", "-")
|
||||
|
||||
local config = {
|
||||
server = (function()
|
||||
|
||||
@@ -80,11 +80,7 @@ function gen_config(var)
|
||||
tcp_tproxy = var["tcp_tproxy"] and true or nil
|
||||
}
|
||||
|
||||
if node.type == "SS" then
|
||||
config.plugin = plugin_file or nil
|
||||
config.plugin_opts = (plugin_file) and node.plugin_opts or nil
|
||||
config.mode = mode
|
||||
elseif node.type == "SSR" then
|
||||
if node.type == "SSR" then
|
||||
config.protocol = node.protocol
|
||||
config.protocol_param = node.protocol_param
|
||||
config.obfs = node.obfs
|
||||
|
||||
@@ -103,8 +103,8 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
local run_socks_instance = true
|
||||
if proxy_table ~= nil and type(proxy_table) == "table" then
|
||||
proxy_tag = proxy_table.tag or nil
|
||||
fragment = (proxy_table.fragment and node.protocol ~= "naive") and true or nil
|
||||
record_fragment = (proxy_table.record_fragment and node.protocol ~= "naive") and true or nil
|
||||
fragment = (proxy_table.fragment and node.protocol ~= "naive" and not node.hysteria2_realms) and true or nil
|
||||
record_fragment = (proxy_table.record_fragment and node.protocol ~= "naive" and not node.hysteria2_realms) and true or nil
|
||||
run_socks_instance = proxy_table.run_socks_instance
|
||||
end
|
||||
|
||||
@@ -472,6 +472,7 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
table.insert(server_ports, range)
|
||||
end
|
||||
end
|
||||
result.server_port = nil
|
||||
end
|
||||
protocol_table = {
|
||||
server_ports = next(server_ports) and server_ports or nil,
|
||||
@@ -528,6 +529,10 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
table.insert(server_ports, range)
|
||||
end
|
||||
end
|
||||
result.server_port = nil
|
||||
end
|
||||
if node.hysteria2_realms then
|
||||
server_ports = {}
|
||||
end
|
||||
local interval, interval_max
|
||||
if next(server_ports) then
|
||||
@@ -571,7 +576,18 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
return (t and t >= 2 and t <= 60) and t or nil
|
||||
end)(node.hysteria2_keep_alive_period),
|
||||
disable_path_mtu_discovery = version_ge_1_14_0 and (tonumber(node.hysteria2_disable_mtu_discovery) == 1) or nil,
|
||||
tls = tls
|
||||
tls = tls,
|
||||
realm = node.hysteria2_realms and (function()
|
||||
result.server = nil
|
||||
result.server_port = nil
|
||||
local realm = api.parse_realm_uri(node.hysteria2_realm_url)
|
||||
if realm then
|
||||
realm.server_url = realm.server_url and "https://" .. realm.server_url or nil
|
||||
realm.stun_servers = realm.stun_servers or node.hysteria2_realm_stun
|
||||
return realm
|
||||
end
|
||||
return nil
|
||||
end)() or nil
|
||||
}
|
||||
end
|
||||
|
||||
@@ -908,7 +924,17 @@ function gen_config_server(node)
|
||||
}
|
||||
},
|
||||
ignore_client_bandwidth = (node.hysteria2_ignore_client_bandwidth == "1") and true or false,
|
||||
tls = tls
|
||||
tls = tls,
|
||||
realm = node.hysteria2_realms and (function()
|
||||
local realm = api.parse_realm_uri(node.hysteria2_realm_url)
|
||||
if realm then
|
||||
realm.server_url = realm.server_url and "https://" .. realm.server_url or nil
|
||||
realm.stun_servers = realm.stun_servers or node.hysteria2_realm_stun
|
||||
realm.stun_domain_resolver = "direct"
|
||||
return realm
|
||||
end
|
||||
return nil
|
||||
end)() or nil
|
||||
}
|
||||
end
|
||||
|
||||
@@ -2088,7 +2114,7 @@ function gen_config(var)
|
||||
if not value.detour and value.server then
|
||||
value.detour = "direct"
|
||||
end
|
||||
if value.server and not api.datatypes.hostname(value.server) then
|
||||
if (value.server and not api.datatypes.hostname(value.server)) and not value.realm then
|
||||
value.domain_resolver = nil
|
||||
end
|
||||
for k, v in pairs(config.outbounds[index]) do
|
||||
|
||||
@@ -1072,7 +1072,13 @@ function gen_config(var)
|
||||
type = _node.balancingStrategy,
|
||||
settings = {
|
||||
expected = _node.expected and tonumber(_node.expected) and tonumber(_node.expected) or 2,
|
||||
maxRTT = "1s"
|
||||
maxRTT = "1s",
|
||||
tolerance = (function(t)
|
||||
t = tonumber(t) or 0
|
||||
if t < 1 then return nil end
|
||||
if t > 100 then t = 100 end
|
||||
return t / 100
|
||||
end)(_node.tolerance)
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -4,13 +4,12 @@ local api = require "luci.passwall.api"
|
||||
local appname = api.appname
|
||||
local map = self.map
|
||||
|
||||
local has_ss = api.is_finded("ss-redir")
|
||||
local has_ss_rust = api.is_finded("sslocal")
|
||||
local has_singbox = api.finded_com("sing-box")
|
||||
local has_xray = api.finded_com("xray")
|
||||
local has_hysteria2 = api.finded_com("hysteria")
|
||||
|
||||
local ss_type = api.get_core("ss_type", {{has_ss,"shadowsocks-libev"},{has_ss_rust,"shadowsocks-rust"},{has_singbox,"sing-box"},{has_xray,"xray"}})
|
||||
local ss_type = api.get_core("ss_type", {{has_ss_rust,"shadowsocks-rust"},{has_singbox,"sing-box"},{has_xray,"xray"}})
|
||||
local trojan_type = api.get_core("trojan_type", {{has_singbox,"sing-box"},{has_xray,"xray"}})
|
||||
local vmess_type = api.get_core("vmess_type", {{has_xray,"xray"},{has_singbox,"sing-box"}})
|
||||
local vless_type = api.get_core("vless_type", {{has_xray,"xray"},{has_singbox,"sing-box"}})
|
||||
@@ -165,10 +164,7 @@ local current_node = map:get(section)
|
||||
|
||||
var dom_prefix = null
|
||||
var protocol = ""
|
||||
if (v_type === "SS") {
|
||||
dom_prefix = "ss_"
|
||||
protocol = "ss"
|
||||
} else if (v_type === "SS-Rust") {
|
||||
if (v_type === "SS-Rust") {
|
||||
dom_prefix = "ssrust_"
|
||||
protocol = "ss"
|
||||
} else if (v_type === "SSR") {
|
||||
@@ -196,7 +192,7 @@ local current_node = map:get(section)
|
||||
}
|
||||
}
|
||||
var url = null;
|
||||
if (v_type === "SS" || v_type === "SS-Rust" || ((v_type === "sing-box" || v_type === "Xray") && opt.get(dom_prefix + "protocol").value === "shadowsocks")) {
|
||||
if (v_type === "SS-Rust" || ((v_type === "sing-box" || v_type === "Xray") && opt.get(dom_prefix + "protocol").value === "shadowsocks")) {
|
||||
protocol = "ss"
|
||||
var v_port = opt.get(dom_prefix + "port");
|
||||
var v_method = opt.get(dom_prefix + "method") || opt.get(dom_prefix + "ss_method");
|
||||
@@ -1000,17 +996,9 @@ local current_node = map:get(section)
|
||||
dom_prefix = "singbox_"
|
||||
opt.set('type', "sing-box");
|
||||
opt.set(dom_prefix + 'protocol', "shadowsocks");
|
||||
} else if (ss_type == "shadowsocks-rust") {
|
||||
} else {
|
||||
dom_prefix = "ssrust_"
|
||||
opt.set('type', "SS-Rust");
|
||||
} else {
|
||||
if (["2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"].includes(method)) {
|
||||
dom_prefix = "ssrust_"
|
||||
opt.set('type', "SS-Rust");
|
||||
} else {
|
||||
dom_prefix = "ss_"
|
||||
opt.set('type', "SS");
|
||||
}
|
||||
}
|
||||
|
||||
const _method = (method || "none").toLowerCase();
|
||||
|
||||
@@ -910,7 +910,11 @@ table td, .table .td {
|
||||
} else {
|
||||
port_s = o["hysteria_hop"] || o["hysteria2_hop"];
|
||||
}
|
||||
str += type + ":" + remarks;
|
||||
if ((o.type === "Hysteria2" || o.protocol === 'hysteria2') && o.hysteria2_realms) {
|
||||
str += type + " Realm:" + remarks;
|
||||
} else {
|
||||
str += type + ":" + remarks;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
@@ -952,7 +956,7 @@ table td, .table .td {
|
||||
var newDom = node_template.cloneNode(true);
|
||||
newDom.classList.add("cbi-rowstyle-" + (i % 2 + 1));
|
||||
var innerHTML = newDom.innerHTML;
|
||||
if (auto_detection_time != "icmp" && o["address"] && o["port"]) {
|
||||
if (auto_detection_time != "icmp" && o["address"]) {
|
||||
innerHTML = innerHTML.split("{{ping}}").join('<span class="ping"><a href="javascript:void(0)" onclick="javascript:ping_node(\'{{id}}\', this, \'icmp\')"><%:Test%></a></span>');
|
||||
} else {
|
||||
innerHTML = innerHTML.split("{{ping}}").join('<span class="ping_value" cbiid="{{id}}"><a href="javascript:void(0)" style="color:inherit">---</a></span>');
|
||||
@@ -962,7 +966,8 @@ table td, .table .td {
|
||||
} else {
|
||||
innerHTML = innerHTML.split("{{tcping}}").join('<span class="tcping_value" cbiid="{{id}}"><a href="javascript:void(0)" style="color:inherit">---</a></span>');
|
||||
}
|
||||
if (o["protocol"] && o["protocol"] === '_shunt') {
|
||||
let is_realm = (o.type === "Hysteria2" || o.protocol === 'hysteria2') && o.hysteria2_realms || false;
|
||||
if (o["protocol"] === '_shunt' || is_realm) {
|
||||
innerHTML = innerHTML.split("{{url_test}}").join('<span class="ping" cbiid="{{id}}">---</span>');
|
||||
} else {
|
||||
innerHTML = innerHTML.split("{{url_test}}").join('<span class="ping"><a href="javascript:void(0)" onclick="javascript:urltest_node(\'{{id}}\', this)" title="<%:TLS handshake test, latency for reference only%>"><%:Test%></a></span>');
|
||||
@@ -971,11 +976,13 @@ table td, .table .td {
|
||||
innerHTML = innerHTML.split("{{group}}").join(o["group"] || "");
|
||||
let node_remarks = get_remarks_name(o);
|
||||
if (show_node_info == "1") {
|
||||
if (o["address"] && o["port"]) {
|
||||
let _port = o["port"] || o["hysteria_hop"] || o["hysteria2_hop"];
|
||||
if (_port) _port = _port.replace(/:/g, '-');
|
||||
if (o["address"] && _port) {
|
||||
let _address = o["address"]
|
||||
if (o["full_address"])
|
||||
_address = o["full_address"]
|
||||
node_remarks += "<br>" + _address + ":" + o["port"]
|
||||
node_remarks += "<br>" + _address + ":" + _port
|
||||
}
|
||||
}
|
||||
innerHTML = innerHTML.split("{{remarks}}").join(node_remarks);
|
||||
|
||||
@@ -577,6 +577,12 @@ msgstr "优选节点数量"
|
||||
msgid "The load balancer selects the optimal number of nodes, and traffic is randomly distributed among them."
|
||||
msgstr "负载均衡器选出最优节点的个数,流量将在这几个节点中随机分配。"
|
||||
|
||||
msgid "Failure Tolerance (%)"
|
||||
msgstr "测速失败率容忍度(%)"
|
||||
|
||||
msgid "The maximum acceptable speed test failure rate. For example, 1 means allowing a 1% failure rate."
|
||||
msgstr "最多可接受的测速失败率,例如 1 表示允许 1% 的测速失败率。"
|
||||
|
||||
msgid "Shunt"
|
||||
msgstr "分流"
|
||||
|
||||
|
||||
@@ -374,7 +374,7 @@ run_socks() {
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "${error_msg}" ] && [ "$(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
|
||||
|
||||
@@ -463,17 +463,6 @@ run_socks() {
|
||||
lua $UTIL_SS gen_config "$(json_dump)" > $config_file
|
||||
[ -n "$no_run" ] || ln_run "$(first_type ssr-local)" "ssr-local" $log_file -c "$config_file" -v -u
|
||||
;;
|
||||
ss)
|
||||
[ -n "$no_run" ] || {
|
||||
local plugin_sh="${config_file%.json}_plugin.sh"
|
||||
json_add_string "plugin_sh" "$plugin_sh"
|
||||
}
|
||||
json_add_string "local_addr" "$bind"
|
||||
json_add_string "local_port" "$socks_port"
|
||||
json_add_string "mode" "tcp_and_udp"
|
||||
lua $UTIL_SS gen_config "$(json_dump)" > $config_file
|
||||
[ -n "$no_run" ] || ln_run "$(first_type ss-local)" "ss-local" $log_file -c "$config_file" -v
|
||||
;;
|
||||
ss-rust)
|
||||
[ "$http_port" != "0" ] && {
|
||||
http_flag=1
|
||||
@@ -632,15 +621,6 @@ run_redir() {
|
||||
lua $UTIL_SS gen_config "$(json_dump)" > $config_file
|
||||
ln_run "$(first_type ssr-redir)" "ssr-redir" $log_file -c "$config_file" -v -U
|
||||
;;
|
||||
ss)
|
||||
local plugin_sh="${config_file%.json}_plugin.sh"
|
||||
json_add_string "plugin_sh" "$plugin_sh"
|
||||
json_add_string "local_addr" "0.0.0.0"
|
||||
json_add_string "local_port" "$local_port"
|
||||
json_add_string "mode" "udp_only"
|
||||
lua $UTIL_SS gen_config "$(json_dump)" > $config_file
|
||||
ln_run "$(first_type ss-redir)" "ss-redir" $log_file -c "$config_file" -v
|
||||
;;
|
||||
ss-rust)
|
||||
local plugin_sh="${config_file%.json}_plugin.sh"
|
||||
json_add_string "plugin_sh" "$plugin_sh"
|
||||
@@ -889,23 +869,6 @@ run_redir() {
|
||||
lua $UTIL_SS gen_config "$(json_dump)" > $config_file
|
||||
ln_run "$(first_type ssr-redir)" "ssr-redir" $log_file -c "$config_file" -v ${_extra_param}
|
||||
;;
|
||||
ss)
|
||||
[ "${TCP_PROXY_WAY}" = "tproxy" ] && json_add_string "tcp_tproxy" "true"
|
||||
if [ "$TCP_UDP" = "1" ]; then
|
||||
config_file="${config_file//TCP/TCP_UDP}"
|
||||
UDP_REDIR_PORT=$TCP_REDIR_PORT
|
||||
unset UDP_NODE
|
||||
json_add_string "mode" "tcp_and_udp"
|
||||
else
|
||||
json_add_string "mode" "tcp_only"
|
||||
fi
|
||||
local plugin_sh="${config_file%.json}_plugin.sh"
|
||||
json_add_string "plugin_sh" "$plugin_sh"
|
||||
json_add_string "local_addr" "0.0.0.0"
|
||||
json_add_string "local_port" "$local_port"
|
||||
lua $UTIL_SS gen_config "$(json_dump)" > $config_file
|
||||
ln_run "$(first_type ss-redir)" "ss-redir" $log_file -c "$config_file" -v
|
||||
;;
|
||||
ss-rust)
|
||||
json_add_string "local_tcp_redir_port" "$local_port"
|
||||
[ "${TCP_PROXY_WAY}" = "tproxy" ] && json_add_string "tcp_tproxy" "true"
|
||||
@@ -2049,8 +2012,8 @@ get_config() {
|
||||
FILTER_PROXY_IPV6=$(config_t_get global filter_proxy_ipv6 0)
|
||||
DNS_REDIRECT=$(config_t_get global dns_redirect 1)
|
||||
|
||||
REDIRECT_LIST="socks ss ss-rust ssr sing-box xray naiveproxy hysteria2"
|
||||
TPROXY_LIST="socks ss ss-rust ssr sing-box xray hysteria2"
|
||||
REDIRECT_LIST="socks ss-rust ssr sing-box xray naiveproxy hysteria2"
|
||||
TPROXY_LIST="socks ss-rust ssr sing-box xray hysteria2"
|
||||
|
||||
NEXT_DNS_LISTEN_PORT=15353
|
||||
TUN_DNS="127.0.0.1#${NEXT_DNS_LISTEN_PORT}"
|
||||
|
||||
@@ -24,7 +24,6 @@ local UrlDecode = api.UrlDecode
|
||||
local uci = api.uci
|
||||
local fs = api.fs
|
||||
|
||||
local has_ss = api.is_finded("ss-redir")
|
||||
local has_ss_rust = api.is_finded("sslocal")
|
||||
local has_ssr = api.is_finded("ssr-local") and api.is_finded("ssr-redir")
|
||||
local has_singbox = api.finded_com("sing-box")
|
||||
@@ -35,7 +34,7 @@ local DEFAULT_FILTER_KEYWORD_MODE = uci:get(appname, "@global_subscribe[0]", "fi
|
||||
local DEFAULT_FILTER_KEYWORD_DISCARD_LIST = uci:get(appname, "@global_subscribe[0]", "filter_discard_list") or {}
|
||||
local DEFAULT_FILTER_KEYWORD_KEEP_LIST = uci:get(appname, "@global_subscribe[0]", "filter_keep_list") or {}
|
||||
-- 取节点使用core类型(节点订阅页面未设置时,自动取默认)
|
||||
local DEFAULT_SS_TYPE = api.get_core("ss_type", {{has_ss,"shadowsocks-libev"},{has_ss_rust,"shadowsocks-rust"},{has_singbox,"sing-box"},{has_xray,"xray"}})
|
||||
local DEFAULT_SS_TYPE = api.get_core("ss_type", {{has_ss_rust,"shadowsocks-rust"},{has_singbox,"sing-box"},{has_xray,"xray"}})
|
||||
local DEFAULT_TROJAN_TYPE = api.get_core("trojan_type", {{has_singbox,"sing-box"},{has_xray,"xray"}})
|
||||
local DEFAULT_VMESS_TYPE = api.get_core("vmess_type", {{has_xray,"xray"},{has_singbox,"sing-box"}})
|
||||
local DEFAULT_VLESS_TYPE = api.get_core("vless_type", {{has_xray,"xray"},{has_singbox,"sing-box"}})
|
||||
@@ -43,7 +42,6 @@ local DEFAULT_HYSTERIA2_TYPE = api.get_core("hysteria2_type", {{has_hysteria2,"h
|
||||
local core_has = {
|
||||
["xray"] = has_xray,
|
||||
["sing-box"] = has_singbox,
|
||||
["shadowsocks-libev"] = has_ss,
|
||||
["shadowsocks-rust"] = has_ss_rust,
|
||||
["hysteria2"] = has_hysteria2
|
||||
}
|
||||
@@ -482,9 +480,7 @@ end
|
||||
|
||||
-- 设置 ss 协议实现类型
|
||||
local function set_ss_implementation(ss_type, result)
|
||||
if ss_type == "shadowsocks-libev" and has_ss then
|
||||
result.type = "SS"
|
||||
elseif ss_type == "shadowsocks-rust" and has_ss_rust then
|
||||
if ss_type == "shadowsocks-rust" and has_ss_rust then
|
||||
result.type = 'SS-Rust'
|
||||
elseif ss_type == "xray" and has_xray then
|
||||
result.type = 'Xray'
|
||||
@@ -835,20 +831,6 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
||||
end
|
||||
end
|
||||
|
||||
if result.type == "SS" then
|
||||
local aead2022_methods = { "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" }
|
||||
local aead2022 = false
|
||||
for k, v in ipairs(aead2022_methods) do
|
||||
if method:lower() == v:lower() then
|
||||
aead2022 = true
|
||||
end
|
||||
end
|
||||
if aead2022 then
|
||||
-- shadowsocks-libev 不支持2022加密
|
||||
result.error_msg = "shadowsocks-libev 不支持2022加密。"
|
||||
end
|
||||
end
|
||||
|
||||
if params.type then
|
||||
params.type = string.lower(params.type)
|
||||
if result.type == "sing-box" and params.type == "raw" then
|
||||
@@ -862,7 +844,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
||||
else
|
||||
result.transport = params.type
|
||||
end
|
||||
if result.type ~= "SS-Rust" and result.type ~= "SS" then
|
||||
if result.type ~= "SS-Rust" then
|
||||
if params.type == 'ws' then
|
||||
result.ws_host = params.host
|
||||
result.ws_path = params.path
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-passwall2
|
||||
PKG_VERSION:=26.5.1
|
||||
PKG_RELEASE:=43
|
||||
PKG_VERSION:=26.5.18
|
||||
PKG_RELEASE:=44
|
||||
PKG_PO_VERSION:=$(PKG_VERSION)
|
||||
|
||||
PKG_CONFIG_DEPENDS:= \
|
||||
|
||||
@@ -52,7 +52,7 @@ function index()
|
||||
entry({"admin", "services", appname, "socks_config"}, cbi(appname .. "/client/socks_config")).leaf = true
|
||||
entry({"admin", "services", appname, "acl"}, cbi(appname .. "/client/acl"), _("Access control"), 98).leaf = true
|
||||
entry({"admin", "services", appname, "acl_config"}, cbi(appname .. "/client/acl_config")).leaf = true
|
||||
entry({"admin", "services", appname, "log"}, form(appname .. "/client/log"), _("Watch Logs"), 999).leaf = true
|
||||
entry({"admin", "services", appname, "log"}, form(appname .. "/client/log"), _("Runtime Logs"), 999).leaf = true
|
||||
|
||||
--[[ Server ]]
|
||||
entry({"admin", "services", appname, "server"}, cbi(appname .. "/server/index"), _("Server-Side"), 99).leaf = true
|
||||
@@ -508,13 +508,17 @@ function delete_select_nodes()
|
||||
if t["node"] == w then
|
||||
uci:delete(appname, t[".name"])
|
||||
end
|
||||
local changed = false
|
||||
local auto_switch_node_list = uci:get(appname, t[".name"], "autoswitch_backup_node") or {}
|
||||
for i = #auto_switch_node_list, 1, -1 do
|
||||
if w == auto_switch_node_list[i] then
|
||||
table.remove(auto_switch_node_list, i)
|
||||
changed = true
|
||||
end
|
||||
end
|
||||
uci:set_list(appname, t[".name"], "autoswitch_backup_node", auto_switch_node_list)
|
||||
if changed then
|
||||
uci:set_list(appname, t[".name"], "autoswitch_backup_node", auto_switch_node_list)
|
||||
end
|
||||
end)
|
||||
uci:foreach(appname, "haproxy_config", function(t)
|
||||
if t["lbss"] == w then
|
||||
|
||||
@@ -21,27 +21,50 @@ local function _n(name)
|
||||
end
|
||||
|
||||
o = s:option(Value, _n("address"), translate("Address (Support Domain Name)"))
|
||||
o:depends({ [_n("realms")] = false })
|
||||
|
||||
o = s:option(Value, _n("port"), translate("Port"))
|
||||
o.datatype = "port"
|
||||
o:depends({ [_n("realms")] = false })
|
||||
|
||||
o = s:option(Value, _n("hop"), translate("Port hopping range"))
|
||||
o.description = translate("Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,).")
|
||||
o.rewrite_option = o.option
|
||||
o:depends({ [_n("realms")] = false })
|
||||
|
||||
o = s:option(Value, _n("hop_interval"), translate("Hop Interval(second)"), translate("Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5."))
|
||||
o.datatype = "or(uinteger,portrange)"
|
||||
o.placeholder = "30"
|
||||
o.default = "30"
|
||||
o.rewrite_option = o.option
|
||||
o:depends({ [_n("realms")] = false })
|
||||
|
||||
o = s:option(Value, _n("obfs"), translate("Obfs Password"))
|
||||
o = s:option(Flag, _n("realms"), translate("Realms"))
|
||||
o.default = "0"
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Value, _n("realm_url"), translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name")
|
||||
o.rewrite_option = o.option
|
||||
o:depends({ [_n("realms")] = "1" })
|
||||
|
||||
o = s:option(DynamicList, _n("realm_stun"), translate("Realm STUN"))
|
||||
o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" }
|
||||
o.rewrite_option = o.option
|
||||
o:depends({ [_n("realms")] = "1" })
|
||||
|
||||
o = s:option(Value, _n("auth_password"), translate("Auth Password"))
|
||||
o.password = true
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(ListValue, _n("obfs_type"), translate("Obfs Type"))
|
||||
o:value("", translate("Disable"))
|
||||
o:value("salamander")
|
||||
o.rewrite_option = o.option
|
||||
|
||||
o = s:option(Value, _n("obfs_password"), translate("Obfs Password"))
|
||||
o.rewrite_option = o.option
|
||||
o:depends({ [_n("obfs_type")] = "salamander" })
|
||||
|
||||
o = s:option(Flag, _n("fast_open"), translate("Fast Open"))
|
||||
o.default = "0"
|
||||
|
||||
|
||||
@@ -164,28 +164,66 @@ if load_balancing_options then -- [[ Load balancing Start ]]
|
||||
|
||||
-- Fallback Node
|
||||
o = s:option(ListValue, _n("fallback_node"), translate("Fallback Node"))
|
||||
o.group = {"",""}
|
||||
o:value("", translate("Close(Not use)"))
|
||||
o:value("_direct", translate("Direct Connection"))
|
||||
o:depends({ [_n("protocol")] = "_balancing" })
|
||||
o.template = appname .. "/cbi/nodes_listvalue"
|
||||
o.group = {""}
|
||||
local function check_fallback_chain(fb)
|
||||
for k, v in pairs(fallback_list) do
|
||||
if v.fallback == fb then
|
||||
fallback_list[k] = nil
|
||||
check_fallback_chain(v.id)
|
||||
-- Maximum number of fallback nesting layers
|
||||
local MAX_FALLBACK_DEPTH = 3
|
||||
-- Check if a loop will form.
|
||||
local function will_loop(start_id, target_id, depth)
|
||||
depth = depth or 0
|
||||
-- Recursion stops after the maximum depth is exceeded.
|
||||
if depth >= MAX_FALLBACK_DEPTH then
|
||||
return false
|
||||
end
|
||||
for _, v in ipairs(fallback_list) do
|
||||
if v.id == target_id then
|
||||
local fb = v.fallback
|
||||
-- No fallback
|
||||
if not fb or fb == "" or fb == "_direct" then
|
||||
return false
|
||||
end
|
||||
-- Loopback detected
|
||||
if fb == start_id then
|
||||
return true
|
||||
end
|
||||
-- Continue recursive checking
|
||||
return will_loop(start_id, fb, depth + 1)
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
-- Check the fallback chain and remove the balancer node that would form a closed loop.
|
||||
if is_balancer then
|
||||
check_fallback_chain(arg[1])
|
||||
-- Get fallback chain depth
|
||||
local function get_fallback_depth(id, depth)
|
||||
depth = depth or 0
|
||||
if depth >= MAX_FALLBACK_DEPTH then
|
||||
return depth
|
||||
end
|
||||
for _, v in ipairs(fallback_list) do
|
||||
if v.id == id then
|
||||
local fb = v.fallback
|
||||
if not fb or fb == "" or fb == "_direct" then
|
||||
return depth
|
||||
end
|
||||
return get_fallback_depth(fb, depth + 1)
|
||||
end
|
||||
end
|
||||
return depth
|
||||
end
|
||||
for i, v in ipairs(fallback_list) do
|
||||
o:value(v.id, v.remark)
|
||||
o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
|
||||
for _, v in ipairs(fallback_list) do
|
||||
local depth = get_fallback_depth(v.id)
|
||||
-- Once the maximum number of nested doll layers is exceeded, further selection of the balancer is not allowed.
|
||||
if depth < MAX_FALLBACK_DEPTH
|
||||
and not will_loop(arg[1], v.id)
|
||||
then
|
||||
o:value(v.id, v.remark)
|
||||
o.group[#o.group + 1] = (v.group and v.group ~= "") and v.group or translate("default")
|
||||
end
|
||||
end
|
||||
for k1, v1 in pairs(node_list) do
|
||||
if k1 == "socks_list" or k1 == "normal_list" then
|
||||
if k1 == "socks_list" or k1 == "normal_list" or k1 == "urltest_list" then
|
||||
for i, v in ipairs(v1) do
|
||||
o:value(v.id, v.remark)
|
||||
o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default")
|
||||
@@ -221,6 +259,13 @@ if load_balancing_options then -- [[ Load balancing Start ]]
|
||||
o.default = "2"
|
||||
o.placeholder = "2"
|
||||
o.description = translate("The load balancer selects the optimal number of nodes, and traffic is randomly distributed among them.")
|
||||
|
||||
o = s:option(Value, _n("tolerance"), translate("Failure Tolerance (%)"))
|
||||
o:depends({ [_n("balancingStrategy")] = "leastLoad" })
|
||||
o.datatype = "uinteger"
|
||||
o.default = "10"
|
||||
o.placeholder = "10"
|
||||
o.description = translate("The maximum acceptable speed test failure rate. For example, 1 means allowing a 1% failure rate.")
|
||||
end -- [[ Load balancing End ]]
|
||||
|
||||
if load_iface_options then -- [[ Custom Interface Start ]]
|
||||
@@ -299,11 +344,9 @@ o.placeholder = "30"
|
||||
o.default = "30"
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
|
||||
o = s:option(Value, _n("hysteria2_up_mbps"), translate("Max upload Mbps"))
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
|
||||
o = s:option(Value, _n("hysteria2_down_mbps"), translate("Max download Mbps"))
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
o = s:option(Value, _n("hysteria2_auth_password"), translate("Auth Password"))
|
||||
o.password = true
|
||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||
|
||||
o = s:option(ListValue, _n("hysteria2_obfs_type"), translate("Obfs Type"))
|
||||
o:value("", translate("Disable"))
|
||||
@@ -313,9 +356,11 @@ o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
o = s:option(Value, _n("hysteria2_obfs_password"), translate("Obfs Password"))
|
||||
o:depends({ [_n("hysteria2_obfs_type")] = "salamander" })
|
||||
|
||||
o = s:option(Value, _n("hysteria2_auth_password"), translate("Auth Password"))
|
||||
o.password = true
|
||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||
o = s:option(Value, _n("hysteria2_up_mbps"), translate("Max upload Mbps"))
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
|
||||
o = s:option(Value, _n("hysteria2_down_mbps"), translate("Max download Mbps"))
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
|
||||
o = s:option(Value, _n("hysteria2_idle_timeout"), translate("Idle Timeout"), translate("Example:") .. "30s (4s~120s)")
|
||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||
|
||||
@@ -43,6 +43,8 @@ local security_list = { "none", "auto", "aes-128-gcm", "chacha20-poly1305", "zer
|
||||
|
||||
local singbox_tags = luci.sys.exec(singbox_bin .. " version | grep 'Tags:' | awk '{print $2}'")
|
||||
|
||||
local singbox_version = api.get_app_version("sing-box"):match("[^v]+")
|
||||
|
||||
o = s:option(ListValue, _n("protocol"), translate("Protocol"))
|
||||
o:value("socks", "Socks")
|
||||
o:value("http", "HTTP")
|
||||
@@ -388,19 +390,32 @@ end
|
||||
if singbox_tags:find("with_quic") then
|
||||
o = s:option(Value, _n("hysteria2_hop"), translate("Port hopping range"))
|
||||
o.description = translate("Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,).")
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false })
|
||||
|
||||
o = s:option(Value, _n("hysteria2_hop_interval"), translate("Hop Interval(Second)"), translate("Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5."))
|
||||
o = s:option(Value, _n("hysteria2_hop_interval"), translate("Hop Interval(second)"), translate("Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5."))
|
||||
o.datatype = "or(uinteger,portrange)"
|
||||
o.placeholder = "30"
|
||||
o.default = "30"
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false })
|
||||
|
||||
o = s:option(Value, _n("hysteria2_up_mbps"), translate("Max upload Mbps"))
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
o = s:option(Flag, _n("hysteria2_realms"), translate("Realms"))
|
||||
o.default = "0"
|
||||
if api.compare_versions(singbox_version, ">=", "1.14.0") then
|
||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||
else
|
||||
o:depends({ [_n("protocol")] = "__hide"})
|
||||
end
|
||||
|
||||
o = s:option(Value, _n("hysteria2_down_mbps"), translate("Max download Mbps"))
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
o = s:option(Value, _n("hysteria2_realm_url"), translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name")
|
||||
o:depends({ [_n("hysteria2_realms")] = "1" })
|
||||
|
||||
o = s:option(DynamicList, _n("hysteria2_realm_stun"), translate("Realm STUN"))
|
||||
o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" }
|
||||
o:depends({ [_n("hysteria2_realms")] = "1" })
|
||||
|
||||
o = s:option(Value, _n("hysteria2_auth_password"), translate("Auth Password"))
|
||||
o.password = true
|
||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||
|
||||
o = s:option(ListValue, _n("hysteria2_obfs_type"), translate("Obfs Type"))
|
||||
o:value("", translate("Disable"))
|
||||
@@ -410,8 +425,20 @@ if singbox_tags:find("with_quic") then
|
||||
o = s:option(Value, _n("hysteria2_obfs_password"), translate("Obfs Password"))
|
||||
o:depends({ [_n("hysteria2_obfs_type")] = "salamander" })
|
||||
|
||||
o = s:option(Value, _n("hysteria2_auth_password"), translate("Auth Password"))
|
||||
o.password = true
|
||||
o = s:option(Value, _n("hysteria2_up_mbps"), translate("Max upload Mbps"))
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
|
||||
o = s:option(Value, _n("hysteria2_down_mbps"), translate("Max download Mbps"))
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
|
||||
o = s:option(Value, _n("hysteria2_idle_timeout"), translate("Idle Timeout"), translate("Example:") .. "30s (4s~120s)")
|
||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||
|
||||
o = s:option(Value, _n("hysteria2_keep_alive_period"), translate("QUIC KeepAlive interval"), translate("Example:") .. "10s (2s~60s)")
|
||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||
|
||||
o = s:option(Flag, _n("hysteria2_disable_mtu_discovery"), translate("Disable MTU detection"))
|
||||
o.default = "0"
|
||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||
end
|
||||
|
||||
@@ -506,7 +533,7 @@ o.default = "0"
|
||||
o:depends({ [_n("tls")] = true, [_n("flow")] = "", [_n("reality")] = false })
|
||||
o:depends({ [_n("protocol")] = "tuic" })
|
||||
o:depends({ [_n("protocol")] = "hysteria" })
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false })
|
||||
o:depends({ [_n("protocol")] = "naive" })
|
||||
|
||||
o = s:option(TextValue, _n("ech_config"), translate("ECH Config"))
|
||||
@@ -818,10 +845,14 @@ local protocols = s.fields[_n("protocol")].keylist
|
||||
if #protocols > 0 then
|
||||
for i, v in ipairs(protocols) do
|
||||
if not v:find("^_") then
|
||||
s.fields[_n("address")]:depends({ [_n("protocol")] = v })
|
||||
s.fields[_n("port")]:depends({ [_n("protocol")] = v })
|
||||
s.fields[_n("domain_resolver")]:depends({ [_n("protocol")] = v })
|
||||
s.fields[_n("domain_strategy")]:depends({ [_n("protocol")] = v })
|
||||
local depends_condition = { [_n("protocol")] = v }
|
||||
if v == "hysteria2" then
|
||||
depends_condition[_n("hysteria2_realms")] = false
|
||||
end
|
||||
s.fields[_n("address")]:depends(depends_condition)
|
||||
s.fields[_n("port")]:depends(depends_condition)
|
||||
s.fields[_n("domain_resolver")]:depends(depends_condition)
|
||||
s.fields[_n("domain_strategy")]:depends(depends_condition)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -834,16 +865,21 @@ if not load_shunt_options then
|
||||
if not (load_iface_options or load_urltest_options) then
|
||||
-- Special node cannot be use pre-proxy.
|
||||
o:value("1", translate("Preproxy Node"))
|
||||
o:value("3", translate("Outbound Interface"))
|
||||
end
|
||||
o:value("2", translate("Landing Node"))
|
||||
|
||||
o1 = s:option(ListValue, _n("preproxy_node"), translate("Preproxy Node"), translate("Only support a layer of proxy."))
|
||||
o1:depends({ [_n("chain_proxy")] = "1" })
|
||||
o1:depends({ [_n("chain_proxy")] = "1", [_n("hysteria2_realms")] = false })
|
||||
o1.template = appname .. "/cbi/nodes_listvalue"
|
||||
o1.group = {}
|
||||
|
||||
o3 = s:option(Value, _n("outbound_iface"), translate("Outbound Interface"))
|
||||
o3.default = "eth1"
|
||||
o3:depends({ [_n("chain_proxy")] = "3" })
|
||||
|
||||
o2 = s:option(ListValue, _n("to_node"), translate("Landing Node"), translate("Only support a layer of proxy."))
|
||||
o2:depends({ [_n("chain_proxy")] = "2" })
|
||||
o2:depends({ [_n("chain_proxy")] = "2", [_n("hysteria2_realms")] = false })
|
||||
o2.template = appname .. "/cbi/nodes_listvalue"
|
||||
o2.group = {}
|
||||
|
||||
|
||||
@@ -22,17 +22,38 @@ o = s:option(Flag, _n("custom"), translate("Use Custom Config"))
|
||||
|
||||
o = s:option(Value, _n("port"), translate("Listen Port"))
|
||||
o.datatype = "port"
|
||||
o.rmempty = false
|
||||
o:depends({ [_n("custom")] = false })
|
||||
|
||||
o = s:option(Value, _n("obfs"), translate("Obfs Password"))
|
||||
o = s:option(Flag, _n("realms"), translate("Realms"))
|
||||
o.default = "0"
|
||||
o.rewrite_option = o.option
|
||||
o:depends({ [_n("custom")] = false })
|
||||
|
||||
o = s:option(Value, _n("realm_url"), translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name")
|
||||
o.rewrite_option = o.option
|
||||
o:depends({ [_n("realms")] = "1" })
|
||||
|
||||
o = s:option(DynamicList, _n("realm_stun"), translate("Realm STUN"))
|
||||
o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" }
|
||||
o.rewrite_option = o.option
|
||||
o:depends({ [_n("realms")] = "1" })
|
||||
|
||||
o = s:option(Value, _n("auth_password"), translate("Auth Password"))
|
||||
o.password = true
|
||||
o.rewrite_option = o.option
|
||||
o:depends({ [_n("custom")] = false })
|
||||
|
||||
o = s:option(ListValue, _n("obfs_type"), translate("Obfs Type"))
|
||||
o:value("", translate("Disable"))
|
||||
o:value("salamander")
|
||||
o.rewrite_option = o.option
|
||||
o:depends({ [_n("custom")] = false })
|
||||
|
||||
o = s:option(Value, _n("obfs_password"), translate("Obfs Password"))
|
||||
o.rewrite_option = o.option
|
||||
o:depends({ [_n("obfs_type")] = "salamander" })
|
||||
|
||||
o = s:option(Flag, _n("udp"), translate("UDP"))
|
||||
o.default = "1"
|
||||
o.rewrite_option = o.option
|
||||
|
||||
@@ -129,6 +129,14 @@ o = s:option(Value, _n("hysteria2_auth_password"), translate("Auth Password"))
|
||||
o.password = true
|
||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||
|
||||
o = s:option(ListValue, _n("hysteria2_obfs_type"), translate("Obfs Type"))
|
||||
o:value("", translate("Disable"))
|
||||
o:value("salamander")
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
|
||||
o = s:option(Value, _n("hysteria2_obfs_password"), translate("Obfs Password"))
|
||||
o:depends({ [_n("hysteria2_obfs_type")] = "salamander" })
|
||||
|
||||
o = s:option(Flag, _n("hysteria2_ignore_client_bandwidth"), translate("Client BBR Flow Control"))
|
||||
o.default = 0
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
@@ -139,14 +147,6 @@ o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_ignore_client_bandwid
|
||||
o = s:option(Value, _n("hysteria2_down_mbps"), translate("Max download Mbps"))
|
||||
o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_ignore_client_bandwidth")] = false })
|
||||
|
||||
o = s:option(ListValue, _n("hysteria2_obfs_type"), translate("Obfs Type"))
|
||||
o:value("", translate("Disable"))
|
||||
o:value("salamander")
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
|
||||
o = s:option(Value, _n("hysteria2_obfs_password"), translate("Obfs Password"))
|
||||
o:depends({ [_n("hysteria2_obfs_type")] = "salamander" })
|
||||
|
||||
---- [[ TLS ]]
|
||||
o = s:option(Flag, _n("tls"), translate("TLS"))
|
||||
o.default = 0
|
||||
|
||||
@@ -58,6 +58,7 @@ o:depends({ [_n("custom")] = false })
|
||||
|
||||
o = s:option(Value, _n("port"), translate("Listen Port"))
|
||||
o.datatype = "port"
|
||||
o.rmempty = false
|
||||
o:depends({ [_n("custom")] = false })
|
||||
|
||||
o = s:option(Flag, _n("auth"), translate("Auth"))
|
||||
@@ -157,10 +158,29 @@ if singbox_tags:find("with_quic") then
|
||||
end
|
||||
|
||||
if singbox_tags:find("with_quic") then
|
||||
o = s:option(Flag, _n("hysteria2_realms"), translate("Realms"))
|
||||
o.default = "0"
|
||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||
|
||||
o = s:option(Value, _n("hysteria2_realm_url"), translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name")
|
||||
o:depends({ [_n("hysteria2_realms")] = "1" })
|
||||
|
||||
o = s:option(DynamicList, _n("hysteria2_realm_stun"), translate("Realm STUN"))
|
||||
o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" }
|
||||
o:depends({ [_n("hysteria2_realms")] = "1" })
|
||||
|
||||
o = s:option(Value, _n("hysteria2_auth_password"), translate("Auth Password"))
|
||||
o.password = true
|
||||
o:depends({ [_n("protocol")] = "hysteria2"})
|
||||
|
||||
o = s:option(ListValue, _n("hysteria2_obfs_type"), translate("Obfs Type"))
|
||||
o:value("", translate("Disable"))
|
||||
o:value("salamander")
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
|
||||
o = s:option(Value, _n("hysteria2_obfs_password"), translate("Obfs Password"))
|
||||
o:depends({ [_n("hysteria2_obfs_type")] = "salamander" })
|
||||
|
||||
o = s:option(Flag, _n("hysteria2_ignore_client_bandwidth"), translate("Client BBR Flow Control"), translate("Commands the client to use the BBR flow control algorithm"))
|
||||
o.default = 0
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
@@ -170,14 +190,6 @@ if singbox_tags:find("with_quic") then
|
||||
|
||||
o = s:option(Value, _n("hysteria2_down_mbps"), translate("Max download Mbps"))
|
||||
o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_ignore_client_bandwidth")] = false })
|
||||
|
||||
o = s:option(ListValue, _n("hysteria2_obfs_type"), translate("Obfs Type"))
|
||||
o:value("", translate("Disable"))
|
||||
o:value("salamander")
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
|
||||
o = s:option(Value, _n("hysteria2_obfs_password"), translate("Obfs Password"))
|
||||
o:depends({ [_n("hysteria2_obfs_type")] = "salamander" })
|
||||
end
|
||||
|
||||
o = s:option(ListValue, _n("d_protocol"), translate("Destination protocol"))
|
||||
@@ -324,7 +336,7 @@ o:depends({ [_n("tls")] = true, [_n("flow")] = "", [_n("reality")] = false })
|
||||
o:depends({ [_n("protocol")] = "naive" })
|
||||
o:depends({ [_n("protocol")] = "hysteria" })
|
||||
o:depends({ [_n("protocol")] = "tuic" })
|
||||
o:depends({ [_n("protocol")] = "hysteria2" })
|
||||
o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false })
|
||||
|
||||
o = s:option(TextValue, _n("ech_key"), translate("ECH Key"))
|
||||
o.default = ""
|
||||
|
||||
@@ -31,7 +31,11 @@ local type_table = {}
|
||||
for filename in fs.dir(types_dir) do
|
||||
table.insert(type_table, filename)
|
||||
end
|
||||
table.sort(type_table)
|
||||
table.sort(type_table, function(a, b)
|
||||
if a == "socks.lua" then return true end
|
||||
if b == "socks.lua" then return false end
|
||||
return a < b
|
||||
end)
|
||||
|
||||
for index, value in ipairs(type_table) do
|
||||
local p_func = loadfile(types_dir .. value)
|
||||
|
||||
@@ -377,11 +377,13 @@ function is_special_node(e)
|
||||
end
|
||||
|
||||
function is_ip(val)
|
||||
val = trim(val):lower()
|
||||
local str = val:match("%[(.-)%]") or val
|
||||
return datatypes.ipaddr(str) or false
|
||||
end
|
||||
|
||||
function is_ipv6(val)
|
||||
val = trim(val):lower()
|
||||
local str = val:match("%[(.-)%]") or val
|
||||
return datatypes.ip6addr(str) or false
|
||||
end
|
||||
@@ -497,9 +499,10 @@ function get_valid_nodes()
|
||||
end
|
||||
end
|
||||
local port = e.port or e.hysteria_hop or e.hysteria2_hop
|
||||
if port and e.address then
|
||||
local is_realm = (e.type == "Hysteria2" or e.protocol == 'hysteria2') and e.hysteria2_realms or nil
|
||||
if (port and e.address) or is_realm then
|
||||
local address = e.address
|
||||
if is_ip(address) or datatypes.hostname(address) then
|
||||
if is_ip(address) or datatypes.hostname(address) or is_realm then
|
||||
if (e.type == "sing-box" or e.type == "Xray") and e.protocol then
|
||||
local protocol = e.protocol
|
||||
if protocol == "vmess" then
|
||||
@@ -526,10 +529,13 @@ function get_valid_nodes()
|
||||
type_name = type_name .. " " .. protocol
|
||||
end
|
||||
if is_ipv6(address) then address = get_ipv6_full(address) end
|
||||
type_name = is_realm and type_name .. " Realm" or type_name
|
||||
e["remark"] = trim("%s:[%s]" % {type_name, e.remarks})
|
||||
if show_node_info == "1" then
|
||||
port = port:gsub(":", "-")
|
||||
e["remark"] = trim("%s:[%s] %s:%s" % {type_name, e.remarks, address, port})
|
||||
port = (port or ""):gsub(":", "-")
|
||||
if not is_realm then
|
||||
e["remark"] = trim("%s:[%s] %s:%s" % {type_name, e.remarks, address, port})
|
||||
end
|
||||
end
|
||||
e.node_type = "normal"
|
||||
if not e.group or e.group == "" then
|
||||
@@ -619,6 +625,9 @@ function get_node_remarks(n)
|
||||
end
|
||||
type_name = type_name .. " " .. protocol
|
||||
end
|
||||
if (n.type == "Hysteria2" or n.protocol == 'hysteria2') and n.hysteria2_realms then
|
||||
type_name = type_name .. " Realm"
|
||||
end
|
||||
remarks = trim("%s:[%s]" % {type_name, n.remarks})
|
||||
end
|
||||
end
|
||||
@@ -1204,7 +1213,7 @@ function to_move(app_name,file)
|
||||
}
|
||||
end
|
||||
|
||||
local flag = sys.call('pgrep -af "passwall2/.*'.. app_name ..'" >/dev/null')
|
||||
local flag = sys.call('busybox pgrep -af "passwall2/.*'.. app_name ..'" >/dev/null')
|
||||
if flag == 0 then
|
||||
sys.call("/etc/init.d/passwall2 stop")
|
||||
end
|
||||
@@ -1588,3 +1597,29 @@ function get_dnsmasq_server_domain()
|
||||
end
|
||||
return dnsmasq_server_t
|
||||
end
|
||||
|
||||
function parse_realm_uri(uri)
|
||||
if type(uri) ~= "string" then return nil end
|
||||
-- realm://token@server/realm_id?query
|
||||
local token, server_url, realm_id, query = trim(uri):match("^realm://([^@]+)@([^/]+)/([^?]*)%??(.*)$")
|
||||
if not token or not server_url or not realm_id then return nil end
|
||||
realm_id = realm_id:gsub("/+$", "")
|
||||
local realm = {
|
||||
token = token,
|
||||
server_url = server_url,
|
||||
realm_id = realm_id
|
||||
}
|
||||
-- 解析 query 中的 stun=
|
||||
if query and query ~= "" then
|
||||
local stun_servers = {}
|
||||
for key, value in query:gmatch("([^&=?]+)=([^&]+)") do
|
||||
if key == "stun" and value ~= "" then
|
||||
stun_servers[#stun_servers + 1] = value
|
||||
end
|
||||
end
|
||||
if #stun_servers > 0 then
|
||||
realm.stun_servers = stun_servers
|
||||
end
|
||||
end
|
||||
return realm
|
||||
end
|
||||
@@ -5,15 +5,24 @@ local jsonc = api.jsonc
|
||||
|
||||
function gen_config_server(node)
|
||||
local config = {
|
||||
listen = ":" .. node.port,
|
||||
listen = (function()
|
||||
if node.hysteria2_realms and node.hysteria2_realm_url then
|
||||
local url = node.hysteria2_realm_url:gsub("/+$", "")
|
||||
if node.port then
|
||||
url = url .. (url:find("?") and "&lport=" or "?lport=") .. node.port
|
||||
end
|
||||
return url
|
||||
end
|
||||
return ":" .. (node.port or "0")
|
||||
end)(),
|
||||
tls = {
|
||||
cert = node.tls_certificateFile,
|
||||
key = node.tls_keyFile,
|
||||
},
|
||||
obfs = (node.hysteria2_obfs) and {
|
||||
obfs = (node.hysteria2_obfs_type and node.hysteria2_obfs_password) and {
|
||||
type = "salamander",
|
||||
salamander = {
|
||||
password = node.hysteria2_obfs
|
||||
password = node.hysteria2_obfs_password
|
||||
}
|
||||
} or nil,
|
||||
auth = {
|
||||
@@ -26,6 +35,9 @@ function gen_config_server(node)
|
||||
} or nil,
|
||||
ignoreClientBandwidth = (node.hysteria2_ignoreClientBandwidth == "1") and true or false,
|
||||
disableUDP = (node.hysteria2_udp == "0") and true or false,
|
||||
realm = (node.hysteria2_realms and node.hysteria2_realm_stun) and {
|
||||
stunServers = node.hysteria2_realm_stun
|
||||
} or nil
|
||||
}
|
||||
return config
|
||||
end
|
||||
@@ -51,14 +63,19 @@ function gen_config(var)
|
||||
if api.is_ipv6(server_host) then
|
||||
server_host = api.get_ipv6_full(server_host)
|
||||
end
|
||||
local server = server_host .. ":" .. server_port
|
||||
|
||||
if (node.hysteria2_hop) then
|
||||
server = server .. "," .. string.gsub(node.hysteria2_hop, ":", "-")
|
||||
end
|
||||
local server = server_host .. ":" .. ((server_port or "") .. "," .. (node.hysteria2_hop or "")):gsub("^[%s,]+", ""):gsub("[%s,]+$", ""):gsub(":", "-")
|
||||
|
||||
local config = {
|
||||
server = server,
|
||||
server = (function()
|
||||
if node.hysteria2_realms and node.hysteria2_realm_url then
|
||||
return node.hysteria2_realm_url:gsub("/+$", "")
|
||||
end
|
||||
return server
|
||||
end)(),
|
||||
realm = (node.hysteria2_realms and node.hysteria2_realm_stun) and {
|
||||
stunServers = node.hysteria2_realm_stun
|
||||
} or nil,
|
||||
transport = {
|
||||
type = "udp",
|
||||
udp = node.hysteria2_hop and (function()
|
||||
@@ -83,10 +100,10 @@ function gen_config(var)
|
||||
return udp
|
||||
end)() or nil
|
||||
},
|
||||
obfs = (node.hysteria2_obfs) and {
|
||||
obfs = (node.hysteria2_obfs_type and node.hysteria2_obfs_password) and {
|
||||
type = "salamander",
|
||||
salamander = {
|
||||
password = node.hysteria2_obfs
|
||||
password = node.hysteria2_obfs_password
|
||||
}
|
||||
} or nil,
|
||||
auth = node.hysteria2_auth_password,
|
||||
|
||||
@@ -134,8 +134,8 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
local run_socks_instance = true
|
||||
if proxy_table ~= nil and type(proxy_table) == "table" then
|
||||
proxy_tag = proxy_table.tag or nil
|
||||
fragment = proxy_table.fragment or nil
|
||||
record_fragment = proxy_table.record_fragment or nil
|
||||
fragment = (proxy_table.fragment and node.protocol ~= "naive" and not node.hysteria2_realms) and true or nil
|
||||
record_fragment = (proxy_table.record_fragment and node.protocol ~= "naive" and not node.hysteria2_realms) and true or nil
|
||||
run_socks_instance = proxy_table.run_socks_instance
|
||||
end
|
||||
|
||||
@@ -250,7 +250,7 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
enabled = true,
|
||||
disable_sni = (node.tls_disable_sni == "1") and true or false, -- Do not send the server name in ClientHello.
|
||||
server_name = node.tls_serverName, -- Used to verify the hostname on the returned certificate, unless the settings are insecure. It is also included in ClientHello to support virtual hosts, unless it is an IP address.
|
||||
insecure = (node.tls_allowInsecure == "1") and true or false, -- Accepts any server certificate.
|
||||
insecure = node.tls_allowInsecure == "1" or (node.tls_pinSHA256 and node.tls_pinSHA256 ~= ""), -- Accepts any server certificate. (Also compatible with xray's pinnedPeerCertSha256)
|
||||
alpn = alpn, -- A list of supported application layer protocols, arranged in order of priority. If both peers support ALPN, the protocol selected will be one of these protocols; otherwise, the connection will fail.
|
||||
--max_version = "1.3",
|
||||
fragment = fragment,
|
||||
@@ -506,6 +506,7 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
table.insert(server_ports, range)
|
||||
end
|
||||
end
|
||||
result.server_port = nil
|
||||
end
|
||||
protocol_table = {
|
||||
server_ports = next(server_ports) and server_ports or nil,
|
||||
@@ -519,9 +520,9 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
obfs = node.hysteria_obfs,
|
||||
auth = (node.hysteria_auth_type == "base64") and node.hysteria_auth_password or nil,
|
||||
auth_str = (node.hysteria_auth_type == "string") and node.hysteria_auth_password or nil,
|
||||
recv_window_conn = tonumber(node.hysteria_recv_window_conn),
|
||||
recv_window = tonumber(node.hysteria_recv_window),
|
||||
disable_mtu_discovery = (node.hysteria_disable_mtu_discovery == "1") and true or false,
|
||||
recv_window_conn = tonumber(node.hysteria_recv_window_conn), --1.14 将变更为 stream_receive_window
|
||||
recv_window = tonumber(node.hysteria_recv_window), --1.14 将变更为 connection_receive_window
|
||||
disable_mtu_discovery = (node.hysteria_disable_mtu_discovery == "1") and true or false, --1.14 将变更为 disable_path_mtu_discovery
|
||||
tls = tls
|
||||
}
|
||||
end
|
||||
@@ -545,13 +546,12 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
heartbeat = (tonumber(node.tuic_heartbeat) or 3) .. "s",
|
||||
tls = tls
|
||||
}
|
||||
if node.tuic_alpn and node.tuic_alpn ~= "default" then
|
||||
local alpn = {}
|
||||
string.gsub(node.tuic_alpn, '[^,]+', function(w)
|
||||
table.insert(alpn, w)
|
||||
end)
|
||||
if #alpn > 0 then protocol_table.tls.alpn = alpn end
|
||||
end
|
||||
node.tuic_alpn = (node.tuic_alpn and node.tuic_alpn ~= "default") and node.tuic_alpn or "h3"
|
||||
local alpn = {}
|
||||
string.gsub(node.tuic_alpn, '[^,]+', function(w)
|
||||
table.insert(alpn, w)
|
||||
end)
|
||||
if #alpn > 0 then protocol_table.tls.alpn = alpn end
|
||||
end
|
||||
|
||||
if node.protocol == "hysteria2" then
|
||||
@@ -563,6 +563,10 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
table.insert(server_ports, range)
|
||||
end
|
||||
end
|
||||
result.server_port = nil
|
||||
end
|
||||
if node.hysteria2_realms then
|
||||
server_ports = {}
|
||||
end
|
||||
local interval, interval_max
|
||||
if next(server_ports) then
|
||||
@@ -595,7 +599,29 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
password = node.hysteria2_obfs_password
|
||||
} or nil,
|
||||
password = node.hysteria2_auth_password or nil,
|
||||
tls = tls
|
||||
idle_timeout = (function(t)
|
||||
if not version_ge_1_14_0 then return nil end
|
||||
t = tonumber(tostring(t or "30"):match("^%d+"))
|
||||
return (t and t >= 4 and t <= 120) and t or 30
|
||||
end)(node.hysteria2_idle_timeout),
|
||||
keep_alive_period = (function(t)
|
||||
if not version_ge_1_14_0 then return nil end
|
||||
t = tonumber(tostring(t or "0"):match("^%d+"))
|
||||
return (t and t >= 2 and t <= 60) and t or nil
|
||||
end)(node.hysteria2_keep_alive_period),
|
||||
disable_path_mtu_discovery = version_ge_1_14_0 and (tonumber(node.hysteria2_disable_mtu_discovery) == 1) or nil,
|
||||
tls = tls,
|
||||
realm = node.hysteria2_realms and (function()
|
||||
result.server = nil
|
||||
result.server_port = nil
|
||||
local realm = api.parse_realm_uri(node.hysteria2_realm_url)
|
||||
if realm then
|
||||
realm.server_url = realm.server_url and "https://" .. realm.server_url or nil
|
||||
realm.stun_servers = realm.stun_servers or node.hysteria2_realm_stun
|
||||
return realm
|
||||
end
|
||||
return nil
|
||||
end)() or nil
|
||||
}
|
||||
end
|
||||
|
||||
@@ -881,10 +907,10 @@ function gen_config_server(node)
|
||||
auth_str = (node.hysteria_auth_type == "string") and node.hysteria_auth_password or nil,
|
||||
}
|
||||
},
|
||||
recv_window_conn = node.hysteria_recv_window_conn and tonumber(node.hysteria_recv_window_conn) or nil,
|
||||
recv_window_client = node.hysteria_recv_window_client and tonumber(node.hysteria_recv_window_client) or nil,
|
||||
max_conn_client = node.hysteria_max_conn_client and tonumber(node.hysteria_max_conn_client) or nil,
|
||||
disable_mtu_discovery = (node.hysteria_disable_mtu_discovery == "1") and true or false,
|
||||
recv_window_conn = node.hysteria_recv_window_conn and tonumber(node.hysteria_recv_window_conn) or nil, --1.14 to stream_receive_window
|
||||
recv_window_client = node.hysteria_recv_window_client and tonumber(node.hysteria_recv_window_client) or nil, --1.14 to connection_receive_window
|
||||
max_conn_client = node.hysteria_max_conn_client and tonumber(node.hysteria_max_conn_client) or nil, --1.14 to max_concurrent_streams
|
||||
disable_mtu_discovery = (node.hysteria_disable_mtu_discovery == "1") and true or false, --1.14 to disable_path_mtu_discover
|
||||
tls = tls
|
||||
}
|
||||
end
|
||||
@@ -928,7 +954,17 @@ function gen_config_server(node)
|
||||
}
|
||||
},
|
||||
ignore_client_bandwidth = (node.hysteria2_ignore_client_bandwidth == "1") and true or false,
|
||||
tls = tls
|
||||
tls = tls,
|
||||
realm = node.hysteria2_realms and (function()
|
||||
local realm = api.parse_realm_uri(node.hysteria2_realm_url)
|
||||
if realm then
|
||||
realm.server_url = realm.server_url and "https://" .. realm.server_url or nil
|
||||
realm.stun_servers = realm.stun_servers or node.hysteria2_realm_stun
|
||||
realm.stun_domain_resolver = "direct"
|
||||
return realm
|
||||
end
|
||||
return nil
|
||||
end)() or nil
|
||||
}
|
||||
end
|
||||
|
||||
@@ -1312,7 +1348,6 @@ function gen_config(var)
|
||||
else
|
||||
ut_nodes = _node.urltest_node
|
||||
end
|
||||
if #ut_nodes == 0 then return nil end
|
||||
local valid_nodes = {}
|
||||
for i = 1, #(ut_nodes or {}) do
|
||||
local ut_node_id = ut_nodes[i]
|
||||
@@ -1444,6 +1479,10 @@ function gen_config(var)
|
||||
end
|
||||
end
|
||||
end
|
||||
if node.chain_proxy == "3" and node.outbound_iface then
|
||||
outbound.detour = nil
|
||||
outbound.bind_interface = node.outbound_iface
|
||||
end
|
||||
return default_outTag, last_insert_outbound
|
||||
end
|
||||
|
||||
@@ -1775,6 +1814,10 @@ function gen_config(var)
|
||||
tag = "local"
|
||||
})
|
||||
|
||||
route.default_domain_resolver = {
|
||||
server = "local"
|
||||
}
|
||||
|
||||
if direct_dns_udp_server then
|
||||
table.insert(dns.servers, {
|
||||
tag = "direct",
|
||||
@@ -2051,7 +2094,7 @@ function gen_config(var)
|
||||
string.gsub(direct_ipset, '[^' .. "," .. ']+', function(w)
|
||||
sys.call("ipset -q -F " .. w)
|
||||
end)
|
||||
local ipset_prefix_name = "passwall2_" .. node_id .. "_"
|
||||
local ipset_prefix_name = "psw2_" .. node_id .. "_"
|
||||
local ipset_list = sys.exec("ipset list | grep 'Name: ' | grep '" .. ipset_prefix_name .. "' | awk '{print $2}'")
|
||||
string.gsub(ipset_list, '[^' .. "\r\n" .. ']+', function(w)
|
||||
sys.call("ipset -q -F " .. w)
|
||||
@@ -2070,7 +2113,7 @@ function gen_config(var)
|
||||
end)
|
||||
local family = "inet"
|
||||
local table_name = "passwall2"
|
||||
local nftset_prefix_name = "passwall2_" .. node_id .. "_"
|
||||
local nftset_prefix_name = "psw2_" .. node_id .. "_"
|
||||
local nftset_list = sys.exec("nft -a list sets | grep -E '" .. nftset_prefix_name .. "' | awk -F 'set ' '{print $2}' | awk '{print $1}'")
|
||||
string.gsub(nftset_list, '[^' .. "\r\n" .. ']+', function(w)
|
||||
sys.call(string.format("nft flush set %s %s %s 2>/dev/null", family, table_name, w))
|
||||
@@ -2126,19 +2169,15 @@ function gen_config(var)
|
||||
type = "direct",
|
||||
tag = "direct",
|
||||
routing_mark = 255,
|
||||
domain_resolver = {
|
||||
server = "local",
|
||||
strategy = "prefer_ipv6"
|
||||
}
|
||||
})
|
||||
for index, value in ipairs(config.outbounds) do
|
||||
if not value["_flag_proxy_tag"] and not value.detour and value["_id"] and value.server and value.server_port and not no_run then
|
||||
sys.call(string.format("echo '%s' >> %s", value["_id"], api.TMP_PATH .. "/direct_node_list"))
|
||||
end
|
||||
if not value.detour and value.server then
|
||||
if not value.detour and not value.bind_interface and value.server then
|
||||
value.detour = "direct"
|
||||
end
|
||||
if value.server and not api.datatypes.hostname(value.server) then
|
||||
if (value.server and not api.datatypes.hostname(value.server)) and not value.realm then
|
||||
value.domain_resolver = nil
|
||||
end
|
||||
for k, v in pairs(config.outbounds[index]) do
|
||||
@@ -2290,10 +2329,6 @@ function gen_front_dns_config(var)
|
||||
type = "direct",
|
||||
tag = "direct",
|
||||
routing_mark = 255,
|
||||
domain_resolver = {
|
||||
server = "direct",
|
||||
strategy = direct_strategy
|
||||
}
|
||||
})
|
||||
|
||||
local direct_dns_shunt = uci:get(appname, "@global[0]", "direct_dns_shunt") or ""
|
||||
@@ -2363,6 +2398,10 @@ function gen_front_dns_config(var)
|
||||
domain = node_domain
|
||||
})
|
||||
end
|
||||
route.default_domain_resolver = {
|
||||
server = "direct",
|
||||
strategy = direct_strategy
|
||||
}
|
||||
end
|
||||
|
||||
if default_dns_udp_server then
|
||||
|
||||
@@ -794,6 +794,9 @@ function gen_config_server(node)
|
||||
config.outbounds[index][k] = nil
|
||||
end
|
||||
end
|
||||
if value.protocol == "freedom" and api.compare_versions(xray_version, "<", "26.5.3") then -- Todo is to remove it
|
||||
value.settings = nil
|
||||
end
|
||||
end
|
||||
|
||||
return config
|
||||
@@ -1049,10 +1052,10 @@ function gen_config(var)
|
||||
if #valid_nodes == 0 then return nil end
|
||||
|
||||
-- fallback node
|
||||
local fallback_node_tag = nil
|
||||
local fallback_node_id = _node.fallback_node
|
||||
if not fallback_node_id or fallback_node_id == "" then fallback_node_id = nil end
|
||||
if fallback_node_id then
|
||||
fallback_node_id = (fallback_node_id and fallback_node_id ~= "") and fallback_node_id or nil
|
||||
local fallback_node_tag = (fallback_node_id == "_direct") and "direct" or "blackhole"
|
||||
if fallback_node_id and fallback_node_id ~= "_direct" then
|
||||
local is_new_node = true
|
||||
for _, outbound in ipairs(outbounds) do
|
||||
if string.sub(outbound.tag, 1, #fallback_node_id) == fallback_node_id then
|
||||
@@ -1082,7 +1085,13 @@ function gen_config(var)
|
||||
type = _node.balancingStrategy,
|
||||
settings = {
|
||||
expected = _node.expected and tonumber(_node.expected) and tonumber(_node.expected) or 2,
|
||||
maxRTT = "1s"
|
||||
maxRTT = "1s",
|
||||
tolerance = (function(t)
|
||||
t = tonumber(t) or 0
|
||||
if t < 1 then return nil end
|
||||
if t > 100 then t = 100 end
|
||||
return t / 100
|
||||
end)(_node.tolerance)
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1264,9 +1273,9 @@ function gen_config(var)
|
||||
interface = node.iface
|
||||
}
|
||||
},
|
||||
settings = {
|
||||
settings = (api.compare_versions(xray_version, ">", "26.4.25")) and { -- Todo: Remove version check
|
||||
finalRules = {{ action = "allow" }}
|
||||
}
|
||||
} or nil
|
||||
}
|
||||
sys.call(string.format("mkdir -p %s && touch %s/%s", api.TMP_IFACE_PATH, api.TMP_IFACE_PATH, node.iface))
|
||||
end
|
||||
@@ -1763,15 +1772,22 @@ function gen_config(var)
|
||||
end
|
||||
end
|
||||
end
|
||||
local dns_block_mode = "host"
|
||||
dns_block_mode = ""
|
||||
if dns_block_mode == "host" and dns_outboundTag == "blackhole" then
|
||||
for d_i, d_k in ipairs(value.domain) do
|
||||
dns.hosts[d_k] = "0.0.0.0"
|
||||
local dns_block = true -- If you do not want the blackhole rule to use DNS routing, please change it to `nil` or do not assign a value.
|
||||
if dns_outboundTag == "blackhole" then
|
||||
if dns_block then
|
||||
local dns_block_mode = "Hosts" -- use the Hosts mode to block.
|
||||
if dns_block_mode == "Hosts" then
|
||||
for d_i, d_k in ipairs(value.domain) do
|
||||
dns.hosts[d_k] = "0.0.0.0"
|
||||
end
|
||||
dns_server = nil
|
||||
end
|
||||
else
|
||||
dns_server = nil
|
||||
end
|
||||
dns_server = nil
|
||||
end
|
||||
if dns_server then
|
||||
dns_server.finalQuery = true
|
||||
dns_server.domains = value.domain
|
||||
if value.shunt_rule_name then
|
||||
dns_server.tag = "dns-in-" .. value.shunt_rule_name
|
||||
@@ -1806,7 +1822,7 @@ function gen_config(var)
|
||||
string.gsub(direct_ipset, '[^' .. "," .. ']+', function(w)
|
||||
sys.call("ipset -q -F " .. w)
|
||||
end)
|
||||
local ipset_prefix_name = "passwall2_" .. node_id .. "_"
|
||||
local ipset_prefix_name = "psw2_" .. node_id .. "_"
|
||||
local ipset_list = sys.exec("ipset list | grep 'Name: ' | grep '" .. ipset_prefix_name .. "' | awk '{print $2}'")
|
||||
string.gsub(ipset_list, '[^' .. "\r\n" .. ']+', function(w)
|
||||
sys.call("ipset -q -F " .. w)
|
||||
@@ -1825,7 +1841,7 @@ function gen_config(var)
|
||||
end)
|
||||
local family = "inet"
|
||||
local table_name = "passwall2"
|
||||
local nftset_prefix_name = "passwall2_" .. node_id .. "_"
|
||||
local nftset_prefix_name = "psw2_" .. node_id .. "_"
|
||||
local nftset_list = sys.exec("nft -a list sets | grep -E '" .. nftset_prefix_name .. "' | awk -F 'set ' '{print $2}' | awk '{print $1}'")
|
||||
string.gsub(nftset_list, '[^' .. "\r\n" .. ']+', function(w)
|
||||
sys.call(string.format("nft flush set %s %s %s 2>/dev/null", family, table_name, w))
|
||||
@@ -2080,7 +2096,12 @@ function gen_proto_config(var)
|
||||
end
|
||||
|
||||
table.insert(outbounds, {
|
||||
protocol = "freedom", tag = "direct", settings = {finalRules = {{ action = "allow" }}}, sockopt = {mark = 255}
|
||||
protocol = "freedom",
|
||||
tag = "direct",
|
||||
settings = (api.compare_versions(xray_version, ">", "26.4.25")) and { -- Todo: Remove version check
|
||||
finalRules = {{ action = "allow" }}
|
||||
} or nil,
|
||||
sockopt = {mark = 255}
|
||||
})
|
||||
|
||||
local config = {
|
||||
|
||||
@@ -35,21 +35,47 @@ local appname = api.appname
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
var shunt_list = JSON.parse('<%=self.shunt_list%>');
|
||||
const shunt_list = JSON.parse('<%=self.shunt_list%>');
|
||||
|
||||
function go() {
|
||||
var _status = document.getElementsByClassName('_status');
|
||||
for (var i = 0; i < _status.length; i++) {
|
||||
var id = _status[i].getAttribute("socks_id");
|
||||
function to_edit_node(btn) {
|
||||
if (!btn) return;
|
||||
const idReg = /^cbid\..*\..*node$/;
|
||||
let hidden_select = null;
|
||||
const container = btn.closest('#cbi-<%=appname%>-global') || btn.closest('#cbi-<%=appname%>-socks');
|
||||
if (!container) return null;
|
||||
const selects = container.querySelectorAll('select[id^="cbid."][id*="."][id$="node"]');
|
||||
for (const sel of selects) {
|
||||
if ( idReg.test(sel.id) && getComputedStyle(sel).display === "none" && (sel.compareDocumentPosition(btn) & Node.DOCUMENT_POSITION_FOLLOWING)) {
|
||||
hidden_select = sel;
|
||||
}
|
||||
}
|
||||
if (!hidden_select) return;
|
||||
let node_select_value = hidden_select?.options[0]?.value;
|
||||
if (!node_select_value || node_select_value.indexOf("_default") === 0 || node_select_value.indexOf("_direct") === 0 || node_select_value.indexOf("_blackhole") === 0) {
|
||||
return;
|
||||
}
|
||||
let to_url = '<%=api.url("node_config")%>/' + node_select_value;
|
||||
if (node_select_value.indexOf("Socks_") === 0) {
|
||||
to_url = '<%=api.url("socks_config")%>/' + node_select_value.substring("Socks_".length);
|
||||
}
|
||||
location.href = to_url;
|
||||
}
|
||||
|
||||
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
||||
async function go() {
|
||||
const _status = document.getElementsByClassName('_status');
|
||||
for (let i = 0; i < _status.length; i++) {
|
||||
const id = _status[i].getAttribute("socks_id");
|
||||
XHR.get('<%=api.url("socks_status")%>', {
|
||||
index: i,
|
||||
id: id
|
||||
},
|
||||
function(x, result) {
|
||||
var index = result.index;
|
||||
var div = '';
|
||||
var div1 = '<font style="font-weight:bold;" color="green">✓</font> ';
|
||||
var div2 = '<font style="font-weight:bold;" color="red">X</font> ';
|
||||
const index = result.index;
|
||||
let div = '';
|
||||
const div1 = '<font style="font-weight:bold;" color="green">✓</font> ';
|
||||
const div2 = '<font style="font-weight:bold;" color="red">X</font> ';
|
||||
|
||||
if (result.socks_status) {
|
||||
div += div1;
|
||||
@@ -68,82 +94,111 @@ local appname = api.appname
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
var global_id = null;
|
||||
var global = document.getElementById("cbi-<%=appname%>-global");
|
||||
let global_id = null;
|
||||
const global = document.getElementById("cbi-<%=appname%>-global");
|
||||
if (global) {
|
||||
var node = global.getElementsByClassName("cbi-section-node")[0];
|
||||
var node_id = node.getAttribute("id");
|
||||
global_id = node_id;
|
||||
var all_node = node.querySelectorAll("[id]");
|
||||
var reg1 = /^cbid\..*node\.main$/;
|
||||
// Add an "Edit" placeholder to the routing rule node in advance to ensure left alignment of the node list.
|
||||
document.querySelectorAll('.td[data-widget="nodes_listvalue"][data-name="_node"] > div').forEach(container => {
|
||||
if (!container.querySelector('.shunt-node-placeholder')) {
|
||||
const placeholder = document.createElement('div');
|
||||
placeholder.className = 'shunt-node-placeholder';
|
||||
placeholder.style.cssText = 'display:inline-flex; width:40px; flex-shrink:0;';
|
||||
container.appendChild(placeholder);
|
||||
}
|
||||
});
|
||||
|
||||
for (var i = 0; i < all_node.length; i++) {
|
||||
var el = all_node[i];
|
||||
await delay(100);
|
||||
|
||||
const node = global.getElementsByClassName("cbi-section-node")[0];
|
||||
const node_id = node.getAttribute("id");
|
||||
global_id = node_id;
|
||||
const all_node = node.querySelectorAll("[id]");
|
||||
const reg1 = /^cbid\..*node\.main$/;
|
||||
//const reg1 = /^cbid\..*\.(node)\.main$/;
|
||||
|
||||
for (let i = 0; i < all_node.length; i++) {
|
||||
const el = all_node[i];
|
||||
if (!reg1.test(el.id)) continue;
|
||||
|
||||
var node_select = el;
|
||||
const node_select = el;
|
||||
if (!node_select) continue;
|
||||
var cbid = el.id.replace(/\.main$/, "");
|
||||
var hidden_select = document.getElementById(cbid);
|
||||
var node_select_value = hidden_select ? hidden_select.options[0].value : "";
|
||||
const cbid = el.id.replace(/\.main$/, "");
|
||||
const hidden_select = document.getElementById(cbid);
|
||||
const node_select_value = hidden_select?.options[0]?.value;
|
||||
if (!node_select_value || node_select_value.indexOf("_default") === 0 || node_select_value.indexOf("_direct") === 0 || node_select_value.indexOf("_blackhole") === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var to_url = '<%=api.url("node_config")%>/' + node_select_value;
|
||||
if (node_select_value.indexOf("Socks_") === 0) {
|
||||
to_url = '<%=api.url("socks_config")%>/' + node_select_value.substring("Socks_".length);
|
||||
}
|
||||
var html = '<a href="#" onclick="location.href=\'' + to_url + '\'"><%:Edit%></a>';
|
||||
let html = '<a href="#" onclick="return to_edit_node(this);"><%:Edit%></a>';
|
||||
|
||||
var m = cbid.match(/\.node$/);
|
||||
const m = cbid.match(/\.node$/);
|
||||
if (m) {
|
||||
html += '<a href="#" onclick="window.open(\'' + '<%=api.url("get_redir_log")%>?id=default&name=' + 'global' + '\', \'_blank\')"><%:Log%></a>';
|
||||
}
|
||||
|
||||
node_select.insertAdjacentHTML("beforeend",
|
||||
'<div class="node-actions" style="display:inline-flex; align-items:center; gap:4px; flex-wrap:wrap; margin-left:4px;">'
|
||||
+ html + '</div>'
|
||||
);
|
||||
html = '<div class="node-actions" style="display:inline-flex; align-items:center; gap:4px; flex-wrap:wrap; margin-left:4px;">' + html + '</div>'
|
||||
|
||||
const placeholder = node_select.parentElement.querySelector('.shunt-node-placeholder');
|
||||
if (placeholder) {
|
||||
placeholder.innerHTML = html;
|
||||
} else {
|
||||
node_select.insertAdjacentHTML("beforeend", html);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var socks = document.getElementById("cbi-<%=appname%>-socks");
|
||||
const socks = document.getElementById("cbi-<%=appname%>-socks");
|
||||
if (socks) {
|
||||
var socks_enabled_dom = document.getElementById(global_id + "-socks_enabled");
|
||||
socks_enabled_dom.parentNode.removeChild(socks_enabled_dom);
|
||||
var descr = socks.getElementsByClassName("cbi-section-descr")[0];
|
||||
descr.outerHTML = socks_enabled_dom.outerHTML;
|
||||
rows = socks.getElementsByClassName("cbi-section-table-row");
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
const socks_enabled_dom = document.getElementById(global_id + "-socks_enabled");
|
||||
const descr = socks.getElementsByClassName("cbi-section-descr")[0];
|
||||
descr.replaceWith(socks_enabled_dom);
|
||||
const rows = socks.getElementsByClassName("cbi-section-table-row");
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
try {
|
||||
var row = rows[i];
|
||||
var id = row.id;
|
||||
const row = rows[i];
|
||||
const id = row.id;
|
||||
if (!id) continue;
|
||||
var dom_id = id + "-node";
|
||||
var cbid = dom_id.replace("cbi-", "cbid-").replace(new RegExp("-", 'g'), ".");
|
||||
let dom_id = id + "-node";
|
||||
const cbid = dom_id.replace("cbi-", "cbid-").replace(new RegExp("-", 'g'), ".");
|
||||
dom_id = cbid + ".main";
|
||||
var node_select = document.getElementById(dom_id);
|
||||
const node_select = document.getElementById(dom_id);
|
||||
if (!node_select) continue;
|
||||
|
||||
var hidden_select = document.getElementById(cbid);;
|
||||
var node_select_value = hidden_select ? hidden_select.options[0].value : "";
|
||||
if (node_select_value && node_select_value != "") {
|
||||
var to_url = '<%=api.url("node_config")%>/' + node_select_value;
|
||||
var html = '<a href="#" onclick="location.href=\'' + to_url + '\'"><%:Edit%></a>';
|
||||
html += '<a href="#" onclick="window.open(\'' + '<%=api.url("get_socks_log")%>?name=' + id.replace("cbi-<%=appname%>-", "") + '\', \'_blank\')"><%:Log%></a>';
|
||||
let html = '<a href="#" onclick="return to_edit_node(this);"><%:Edit%></a>';
|
||||
html += '<a href="#" onclick="window.open(\'' + '<%=api.url("get_socks_log")%>?name=' + id.replace("cbi-<%=appname%>-", "") + '\', \'_blank\')"><%:Log%></a>';
|
||||
|
||||
node_select.insertAdjacentHTML("afterend",
|
||||
'<div class="node-actions" style="display:inline-flex; align-items:center; gap:4px; flex-wrap:wrap; margin-left:4px;">'
|
||||
+ html + '</div>'
|
||||
);
|
||||
}
|
||||
node_select.insertAdjacentHTML("afterend",
|
||||
'<div class="node-actions" style="display:inline-flex; align-items:center; gap:4px; flex-wrap:wrap; margin-left:4px;">'
|
||||
+ html + '</div>'
|
||||
);
|
||||
} catch(err) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(function () {
|
||||
let lastCount = 0;
|
||||
let stableTimes = 0;
|
||||
const STABLE_THRESHOLD = 5;
|
||||
function waitStable() {
|
||||
const list = document.querySelectorAll('[id^="cbid.<%=appname%>."][id$="node.main"]');
|
||||
const count = list.length;
|
||||
if (count === lastCount && count > 0) {
|
||||
stableTimes++;
|
||||
} else {
|
||||
stableTimes = 0;
|
||||
lastCount = count;
|
||||
}
|
||||
if (stableTimes >= STABLE_THRESHOLD) {
|
||||
go();
|
||||
return;
|
||||
}
|
||||
requestAnimationFrame(waitStable);
|
||||
}
|
||||
waitStable();
|
||||
})();
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => setTimeout(() => {
|
||||
const hiddenSelect = document.getElementById("cbid.<%=appname%>.<%=self.global_cfgid%>.node");
|
||||
let o_val = hiddenSelect.value
|
||||
@@ -184,8 +239,6 @@ local appname = api.appname
|
||||
shunt_taboption.appendChild(shunt_option_list);
|
||||
}
|
||||
}
|
||||
go();
|
||||
}, 100));
|
||||
//setTimeout("go()", 1000);
|
||||
//]]>
|
||||
</script>
|
||||
@@ -602,10 +602,10 @@ local current_node = map:get(section)
|
||||
|
||||
if (v_type === "Hysteria2") {
|
||||
v_password = opt.get("hysteria2_auth_password");
|
||||
var dom_obfs = opt.get("hysteria2_obfs");
|
||||
var dom_obfs = opt.get("hysteria2_obfs_password");
|
||||
if (dom_obfs && dom_obfs.value != "") {
|
||||
params += "&obfs=" + "salamander";
|
||||
params += opt.query("obfs-password", "hysteria2_obfs");
|
||||
params += opt.query("obfs-password", "hysteria2_obfs_password");
|
||||
}
|
||||
params += opt.query("mport", "hysteria2_hop");
|
||||
} else {
|
||||
@@ -1621,7 +1621,8 @@ local current_node = map:get(section)
|
||||
dom_prefix = "hysteria2_"
|
||||
opt.set(dom_prefix + 'auth_password', decodeURIComponent(password));
|
||||
if (queryParam["obfs-password"] || queryParam["obfs_password"]) {
|
||||
opt.set(dom_prefix + 'obfs', queryParam["obfs-password"] || queryParam["obfs_password"]);
|
||||
opt.set(dom_prefix + 'obfs_type', "salamander");
|
||||
opt.set(dom_prefix + 'obfs_password', queryParam["obfs-password"] || queryParam["obfs_password"]);
|
||||
}
|
||||
opt.set(dom_prefix + 'hop', queryParam.mport || "");
|
||||
}
|
||||
@@ -1678,7 +1679,7 @@ local current_node = map:get(section)
|
||||
}
|
||||
opt.set(dom_prefix + 'tuic_congestion_control', queryParam.congestion_control || 'cubic');
|
||||
opt.set(dom_prefix + 'tuic_udp_relay_mode', queryParam.udp_relay_mode || 'native');
|
||||
opt.set(dom_prefix + 'tuic_alpn', queryParam.alpn || 'default');
|
||||
opt.set(dom_prefix + 'tuic_alpn', queryParam.alpn || 'h3');
|
||||
opt.set(dom_prefix + 'tls_serverName', queryParam.sni || '');
|
||||
opt.set(dom_prefix + 'tls_disable_sni', queryParam.disable_sni === "1");
|
||||
opt.set(
|
||||
|
||||
@@ -875,6 +875,8 @@ table td, .table .td {
|
||||
p = "URLTest";
|
||||
} else if (protocol == "_shunt") {
|
||||
p = "<%:Shunt%>";
|
||||
} else if (protocol == "_iface") {
|
||||
p = "<%:Interface%>";
|
||||
} else if (protocol == "vmess") {
|
||||
p = "VMess";
|
||||
} else if (protocol == "vless") {
|
||||
@@ -911,7 +913,11 @@ table td, .table .td {
|
||||
} else {
|
||||
port_s = o["hysteria_hop"] || o["hysteria2_hop"];
|
||||
}
|
||||
str += type + ":" + remarks;
|
||||
if ((o.type === "Hysteria2" || o.protocol === 'hysteria2') && o.hysteria2_realms) {
|
||||
str += type + " Realm:" + remarks;
|
||||
} else {
|
||||
str += type + ":" + remarks;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
@@ -953,7 +959,7 @@ table td, .table .td {
|
||||
var newDom = node_template.cloneNode(true);
|
||||
newDom.classList.add("cbi-rowstyle-" + (i % 2 + 1));
|
||||
var innerHTML = newDom.innerHTML;
|
||||
if (auto_detection_time != "icmp" && o["address"] && o["port"]) {
|
||||
if (auto_detection_time != "icmp" && o["address"]) {
|
||||
innerHTML = innerHTML.split("{{ping}}").join('<span class="ping"><a href="javascript:void(0)" onclick="javascript:ping_node(\'{{id}}\', this, \'icmp\')"><%:Test%></a></span>');
|
||||
} else {
|
||||
innerHTML = innerHTML.split("{{ping}}").join('<span class="ping_value" cbiid="{{id}}"><a href="javascript:void(0)" style="color:inherit">---</a></span>');
|
||||
@@ -972,11 +978,13 @@ table td, .table .td {
|
||||
innerHTML = innerHTML.split("{{group}}").join(o["group"] || "");
|
||||
let node_remarks = get_remarks_name(o);
|
||||
if (show_node_info == "1") {
|
||||
if (o["address"] && o["port"]) {
|
||||
let _port = o["port"] || o["hysteria_hop"] || o["hysteria2_hop"];
|
||||
if (_port) _port = _port.replace(/:/g, '-');
|
||||
if (o["address"] && _port) {
|
||||
let _address = o["address"]
|
||||
if (o["full_address"])
|
||||
_address = o["full_address"]
|
||||
node_remarks += "<br>" + _address + ":" + o["port"]
|
||||
node_remarks += "<br>" + _address + ":" + _port
|
||||
}
|
||||
}
|
||||
innerHTML = innerHTML.split("{{remarks}}").join(node_remarks);
|
||||
|
||||
@@ -46,8 +46,8 @@ msgstr "لیست قوانین"
|
||||
msgid "Access control"
|
||||
msgstr "کنترل دسترسی"
|
||||
|
||||
msgid "Watch Logs"
|
||||
msgstr "مشاهده گزارشها"
|
||||
msgid "Runtime Logs"
|
||||
msgstr "گزارشهای زمان اجرا"
|
||||
|
||||
msgid "Node Config"
|
||||
msgstr "پیکربندی گره"
|
||||
@@ -437,6 +437,12 @@ msgstr "تعداد گرههای ترجیحی"
|
||||
msgid "The load balancer selects the optimal number of nodes, and traffic is randomly distributed among them."
|
||||
msgstr "توزیعکننده بار تعداد بهینهای از گرهها را انتخاب میکند و ترافیک به طور تصادفی بین آنها توزیع میشود."
|
||||
|
||||
msgid "Failure Tolerance (%)"
|
||||
msgstr "تحمل شکست (%)"
|
||||
|
||||
msgid "The maximum acceptable speed test failure rate. For example, 1 means allowing a 1% failure rate."
|
||||
msgstr "حداکثر نرخ شکست قابل قبول در تست سرعت. برای مثال، عدد ۱ به معنای مجاز بودن نرخ شکست ۱٪ است.
|
||||
|
||||
msgid "Shunt"
|
||||
msgstr "شنت (Shunt)"
|
||||
|
||||
@@ -1782,6 +1788,9 @@ msgstr "فقط گرههای نوع Xray یا Sing-box پشتیبانی می
|
||||
msgid "Chain Proxy"
|
||||
msgstr "پروکسی زنجیرهای"
|
||||
|
||||
msgid "Outbound Interface"
|
||||
msgstr "رابط خروجی"
|
||||
|
||||
msgid "Landing Node"
|
||||
msgstr "گره فرود (Landing Node)"
|
||||
|
||||
|
||||
@@ -46,8 +46,8 @@ msgstr "Список правил"
|
||||
msgid "Access control"
|
||||
msgstr "Контроль доступа"
|
||||
|
||||
msgid "Watch Logs"
|
||||
msgstr "Просмотр журнала"
|
||||
msgid "Runtime Logs"
|
||||
msgstr "Журналы выполнения"
|
||||
|
||||
msgid "Node Config"
|
||||
msgstr "Параметры узла"
|
||||
@@ -433,6 +433,12 @@ msgstr "Количество предпочтительных узлов"
|
||||
msgid "The load balancer selects the optimal number of nodes, and traffic is randomly distributed among them."
|
||||
msgstr "Балансировщик выбирает указанное количество наилучших узлов и распределяет трафик между ними случайным образом."
|
||||
|
||||
msgid "Failure Tolerance (%)"
|
||||
msgstr "Допуск на отказ (%)"
|
||||
|
||||
msgid "The maximum acceptable speed test failure rate. For example, 1 means allowing a 1% failure rate."
|
||||
msgstr "Максимально допустимый процент отказов при проверке скорости. Например, 1 означает допустимый процент отказов в 1%."
|
||||
|
||||
msgid "Shunt"
|
||||
msgstr "Shunt (разделение трафика)"
|
||||
|
||||
@@ -1783,6 +1789,9 @@ msgstr "Поддерживаются только узлы типа Xray или
|
||||
msgid "Chain Proxy"
|
||||
msgstr "Цепочка прокси"
|
||||
|
||||
msgid "Outbound Interface"
|
||||
msgstr "Исходящий интерфейс"
|
||||
|
||||
msgid "Landing Node"
|
||||
msgstr "Сервер выхода"
|
||||
|
||||
|
||||
@@ -46,8 +46,8 @@ msgstr "规则列表"
|
||||
msgid "Access control"
|
||||
msgstr "访问控制"
|
||||
|
||||
msgid "Watch Logs"
|
||||
msgstr "查看日志"
|
||||
msgid "Runtime Logs"
|
||||
msgstr "运行日志"
|
||||
|
||||
msgid "Node Config"
|
||||
msgstr "节点配置"
|
||||
@@ -433,6 +433,12 @@ msgstr "优选节点数量"
|
||||
msgid "The load balancer selects the optimal number of nodes, and traffic is randomly distributed among them."
|
||||
msgstr "负载均衡器选出最优节点的个数,流量将在这几个节点中随机分配。"
|
||||
|
||||
msgid "Failure Tolerance (%)"
|
||||
msgstr "测速失败率容忍度(%)"
|
||||
|
||||
msgid "The maximum acceptable speed test failure rate. For example, 1 means allowing a 1% failure rate."
|
||||
msgstr "最多可接受的测速失败率,例如 1 表示允许 1% 的测速失败率。"
|
||||
|
||||
msgid "Shunt"
|
||||
msgstr "分流"
|
||||
|
||||
@@ -1768,6 +1774,9 @@ msgstr "仅支持 Xray 或 Sing-box 类型节点。"
|
||||
msgid "Chain Proxy"
|
||||
msgstr "链式代理"
|
||||
|
||||
msgid "Outbound Interface"
|
||||
msgstr "出站接口"
|
||||
|
||||
msgid "Landing Node"
|
||||
msgstr "落地节点"
|
||||
|
||||
|
||||
@@ -46,8 +46,8 @@ msgstr "規則列表"
|
||||
msgid "Access control"
|
||||
msgstr "訪問控制"
|
||||
|
||||
msgid "Watch Logs"
|
||||
msgstr "查看日誌"
|
||||
msgid "Runtime Logs"
|
||||
msgstr "運行日誌"
|
||||
|
||||
msgid "Node Config"
|
||||
msgstr "節點配置"
|
||||
@@ -433,6 +433,12 @@ msgstr "優選節點數量"
|
||||
msgid "The load balancer selects the optimal number of nodes, and traffic is randomly distributed among them."
|
||||
msgstr "負載均衡器選出最優節點的個數,流量將在這几個節點中随機分配。"
|
||||
|
||||
msgid "Failure Tolerance (%)"
|
||||
msgstr "測速失敗率容忍度(%)"
|
||||
|
||||
msgid "The maximum acceptable speed test failure rate. For example, 1 means allowing a 1% failure rate."
|
||||
msgstr "最多可接受的測速失敗率,例如 1 表示允許 1% 的測速失敗率。"
|
||||
|
||||
msgid "Shunt"
|
||||
msgstr "分流"
|
||||
|
||||
@@ -1774,6 +1780,9 @@ msgstr "僅支援 Xray 或 Sing-box 類型節點。"
|
||||
msgid "Chain Proxy"
|
||||
msgstr "鏈式代理"
|
||||
|
||||
msgid "Outbound Interface"
|
||||
msgstr "出站接口"
|
||||
|
||||
msgid "Landing Node"
|
||||
msgstr "落地節點"
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
if [ "$ACTION" = "ifupdate" ]; then
|
||||
USE_TABLES=$(get_cache_var "USE_TABLES")
|
||||
[ -n "$USE_TABLES" ] && ${APP_PATH}/${USE_TABLES}.sh update_wan_sets >/dev/null 2>&1 &
|
||||
[ -n "$USE_TABLES" ] && { ${APP_PATH}/${USE_TABLES}.sh update_wan_sets >/dev/null 2>&1 & }
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ run_xray() {
|
||||
json_add_string "loglevel" "${loglevel}"
|
||||
|
||||
[ -n "$flag" ] && {
|
||||
pgrep -af "$TMP_BIN_PATH" | awk -v P1="${flag}" 'BEGIN{IGNORECASE=1}$0~P1{print $1}' | xargs kill -9 >/dev/null 2>&1
|
||||
busybox pgrep -af "$TMP_BIN_PATH" | awk -v P1="${flag}" 'BEGIN{IGNORECASE=1}$0~P1{print $1}' | xargs kill -9 >/dev/null 2>&1
|
||||
json_add_string "flag" "${flag}"
|
||||
}
|
||||
[ -n "$socks_address" ] && [ -n "$socks_port" ] && {
|
||||
@@ -112,12 +112,12 @@ run_xray() {
|
||||
local direct_ipset_conf=${GLOBAL_ACL_PATH}/dns_${flag}_direct.conf
|
||||
[ -n "$(echo ${flag} | grep '^acl')" ] && direct_ipset_conf=${TMP_ACL_PATH}/${sid}/dns_${flag}_direct.conf
|
||||
if [ "${nftflag}" = "1" ]; then
|
||||
local direct_nftset4="passwall2_${node}_white"
|
||||
local direct_nftset6="passwall2_${node}_white6"
|
||||
local direct_nftset4="psw2_${node}_white"
|
||||
local direct_nftset6="psw2_${node}_white6"
|
||||
local direct_nftset="4#inet#passwall2#${direct_nftset4},6#inet#passwall2#${direct_nftset6}"
|
||||
else
|
||||
local direct_ipset4="passwall2_${node}_white"
|
||||
local direct_ipset6="passwall2_${node}_white6"
|
||||
local direct_ipset4="psw2_${node}_white"
|
||||
local direct_ipset6="psw2_${node}_white6"
|
||||
local direct_ipset="${direct_ipset4},${direct_ipset6}"
|
||||
fi
|
||||
run_ipset_dns_server listen_port=${direct_dnsmasq_listen_port} server_dns=${AUTO_DNS} ipset="${direct_ipset}" nftset="${direct_nftset}" config_file=${direct_ipset_conf}
|
||||
@@ -225,7 +225,7 @@ run_singbox() {
|
||||
json_add_string "loglevel" "${loglevel}"
|
||||
|
||||
[ -n "$flag" ] && {
|
||||
pgrep -af "$TMP_BIN_PATH" | awk -v P1="${flag}" 'BEGIN{IGNORECASE=1}$0~P1{print $1}' | xargs kill -9 >/dev/null 2>&1
|
||||
busybox pgrep -af "$TMP_BIN_PATH" | awk -v P1="${flag}" 'BEGIN{IGNORECASE=1}$0~P1{print $1}' | xargs kill -9 >/dev/null 2>&1
|
||||
json_add_string "flag" "${flag}"
|
||||
}
|
||||
[ -n "$socks_address" ] && [ -n "$socks_port" ] && {
|
||||
@@ -251,12 +251,12 @@ run_singbox() {
|
||||
local direct_ipset_conf=${GLOBAL_ACL_PATH}/dns_${flag}_direct.conf
|
||||
[ -n "$(echo ${flag} | grep '^acl')" ] && direct_ipset_conf=${TMP_ACL_PATH}/${sid}/dns_${flag}_direct.conf
|
||||
if [ "${nftflag}" = "1" ]; then
|
||||
local direct_nftset4="passwall2_${node}_white"
|
||||
local direct_nftset6="passwall2_${node}_white6"
|
||||
local direct_nftset4="psw2_${node}_white"
|
||||
local direct_nftset6="psw2_${node}_white6"
|
||||
local direct_nftset="4#inet#passwall2#${direct_nftset4},6#inet#passwall2#${direct_nftset6}"
|
||||
else
|
||||
local direct_ipset4="passwall2_${node}_white"
|
||||
local direct_ipset6="passwall2_${node}_white6"
|
||||
local direct_ipset4="psw2_${node}_white"
|
||||
local direct_ipset6="psw2_${node}_white6"
|
||||
local direct_ipset="${direct_ipset4},${direct_ipset6}"
|
||||
fi
|
||||
run_ipset_dns_server listen_port=${direct_dnsmasq_listen_port} server_dns=${AUTO_DNS} ipset="${direct_ipset}" nftset="${direct_nftset}" config_file=${direct_ipset_conf}
|
||||
@@ -386,6 +386,10 @@ run_socks() {
|
||||
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
|
||||
unset error_msg
|
||||
fi
|
||||
|
||||
[ -n "${error_msg}" ] && {
|
||||
[ "$bind" != "127.0.0.1" ] && log 1 "$(i18n "Socks node: [%s]%s, start failed %s:%s %s" "${remarks}" "${tmp}" "${bind}" "${socks_port}" "${error_msg}")"
|
||||
return 1
|
||||
@@ -555,7 +559,7 @@ socks_node_switch() {
|
||||
[ -s "$pf" ] && kill -9 "$(head -n1 "$pf")" >/dev/null 2>&1
|
||||
done
|
||||
|
||||
pgrep -af "$TMP_BIN_PATH" | awk -v P1="${flag}" 'BEGIN{IGNORECASE=1}$0~P1 && !/acl\/|acl_/{print $1}' | xargs kill -9 >/dev/null 2>&1
|
||||
busybox pgrep -af "$TMP_BIN_PATH" | awk -v P1="${flag}" 'BEGIN{IGNORECASE=1}$0~P1 && !/acl\/|acl_/{print $1}' | xargs kill -9 >/dev/null 2>&1
|
||||
for prefix in "" "HTTP_" "HTTP2"; do
|
||||
rm -rf "$TMP_PATH/${prefix}SOCKS_${flag}"*
|
||||
done
|
||||
@@ -791,7 +795,7 @@ start_socks() {
|
||||
|
||||
# Auto switch logic
|
||||
local enable_autoswitch=$(config_n_get $id enable_autoswitch 0)
|
||||
[ "$enable_autoswitch" = "1" ] && $APP_PATH/socks_auto_switch.sh ${id} > /dev/null 2>&1 &
|
||||
[ "$enable_autoswitch" = "1" ] && { $APP_PATH/socks_auto_switch.sh ${id} > /dev/null 2>&1 & }
|
||||
done
|
||||
}
|
||||
}
|
||||
@@ -805,14 +809,14 @@ clean_crontab() {
|
||||
sed -i "/$(echo "lua ${APP_PATH}/rule_update.lua log" | sed 's#\/#\\\/#g')/d" /etc/crontabs/root >/dev/null 2>&1
|
||||
sed -i "/$(echo "lua ${APP_PATH}/subscribe.lua start" | sed 's#\/#\\\/#g')/d" /etc/crontabs/root >/dev/null 2>&1
|
||||
|
||||
pgrep -af "${CONFIG}/" | awk '/tasks\.sh/{print $1}' | xargs kill -9 >/dev/null 2>&1
|
||||
busybox pgrep -af "${CONFIG}/" | awk '/tasks\.sh/{print $1}' | xargs kill -9 >/dev/null 2>&1
|
||||
rm -rf /tmp/lock/${CONFIG}_tasks.lock
|
||||
}
|
||||
|
||||
start_crontab() {
|
||||
if [ "$ENABLED_DEFAULT_ACL" == 1 ] || [ "$ENABLED_ACLS" == 1 ]; then
|
||||
start_daemon=$(config_t_get global_delay start_daemon 0)
|
||||
[ "$start_daemon" = "1" ] && $APP_PATH/monitor.sh > /dev/null 2>&1 &
|
||||
[ "$start_daemon" = "1" ] && { $APP_PATH/monitor.sh > /dev/null 2>&1 & }
|
||||
fi
|
||||
|
||||
[ -f "/tmp/lock/${CONFIG}_cron.lock" ] && {
|
||||
@@ -982,11 +986,11 @@ run_ipset_chinadns_ng() {
|
||||
|
||||
[ -n "${ipset}" ] && {
|
||||
set_names=$ipset
|
||||
vps_set_names="passwall2_vps,passwall2_vps6"
|
||||
vps_set_names="psw2_vps,psw2_vps6"
|
||||
}
|
||||
[ -n "${nftset}" ] && {
|
||||
set_names=$(echo ${nftset} | awk -F, '{printf "%s,%s", substr($1,3), substr($2,3)}' | sed 's/#/@/g')
|
||||
vps_set_names="inet@passwall2@passwall2_vps,inet@passwall2@passwall2_vps6"
|
||||
vps_set_names="inet@passwall2@psw2_vps,inet@passwall2@psw2_vps6"
|
||||
}
|
||||
cat <<-EOF > $config_file
|
||||
bind-addr 127.0.0.1
|
||||
@@ -1162,7 +1166,7 @@ acl_app() {
|
||||
}
|
||||
|
||||
start() {
|
||||
pgrep -f /tmp/etc/passwall2/bin > /dev/null 2>&1 && {
|
||||
busybox pgrep -f /tmp/etc/passwall2/bin > /dev/null 2>&1 && {
|
||||
#log_i18n 0 "The program has started. Please stop it and then restart it!"
|
||||
stop
|
||||
}
|
||||
@@ -1241,8 +1245,8 @@ stop() {
|
||||
kill -9 "$pid" >/dev/null 2>&1
|
||||
fi
|
||||
done
|
||||
pgrep -f "sleep.*(6s|9s|58s)" | xargs kill -9 >/dev/null 2>&1
|
||||
pgrep -af "${CONFIG}/" | awk '! /app\.sh|subscribe\.lua|rule_update\.lua|tasks\.sh|server_app\.lua|ujail/{print $1}' | xargs kill -9 >/dev/null 2>&1
|
||||
busybox pgrep -f "sleep.*(6s|9s|58s)" | xargs kill -9 >/dev/null 2>&1
|
||||
busybox pgrep -af "${CONFIG}/" | awk '! /app\.sh|subscribe\.lua|rule_update\.lua|tasks\.sh|server_app\.lua|ujail/{print $1}' | xargs kill -9 >/dev/null 2>&1
|
||||
unset V2RAY_LOCATION_ASSET
|
||||
unset XRAY_LOCATION_ASSET
|
||||
unset SS_SYSTEM_DNS_RESOLVER_FORCE_BUILTIN
|
||||
|
||||
@@ -8,7 +8,8 @@ listen_port=$2
|
||||
server_address=$3
|
||||
server_port=$4
|
||||
|
||||
pgrep -af "${CONFIG}/" | grep -E 'app\.sh.*(start|stop)|nftables\.sh|iptables\.sh|subscribe\.lua' >/dev/null && {
|
||||
busybox pgrep -af "${CONFIG}/" | grep -E 'app\.sh.*(start|stop)|nftables\.sh|iptables\.sh|subscribe\.lua' >/dev/null && {
|
||||
# No detection during specific task execution
|
||||
exit 0
|
||||
}
|
||||
|
||||
|
||||
@@ -274,7 +274,7 @@ function add_rule(var)
|
||||
if address == "engage.cloudflareclient.com" then return end
|
||||
if datatypes.hostname(address) then
|
||||
set_domain_dns(address, fwd_dns)
|
||||
set_domain_ipset(address, setflag_4 .. "passwall2_vps," .. setflag_6 .. "passwall2_vps6")
|
||||
set_domain_ipset(address, setflag_4 .. "psw2_vps," .. setflag_6 .. "psw2_vps6")
|
||||
end
|
||||
end
|
||||
process_address(t.address)
|
||||
|
||||
@@ -3,17 +3,17 @@
|
||||
DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
MY_PATH=$DIR/iptables.sh
|
||||
UTILS_PATH=$DIR/utils.sh
|
||||
IPSET_LOCAL="passwall2_local"
|
||||
IPSET_PROXY_LAN="passwall2_proxy_lan"
|
||||
IPSET_LAN="passwall2_lan"
|
||||
IPSET_VPS="passwall2_vps"
|
||||
IPSET_WAN="passwall2_wan"
|
||||
IPSET_LOCAL="psw2_local"
|
||||
IPSET_PROXY_LAN="psw2_proxy_lan"
|
||||
IPSET_LAN="psw2_lan"
|
||||
IPSET_VPS="psw2_vps"
|
||||
IPSET_WAN="psw2_wan"
|
||||
|
||||
IPSET_LOCAL6="passwall2_local6"
|
||||
IPSET_PROXY_LAN6="passwall2_proxy_lan6"
|
||||
IPSET_LAN6="passwall2_lan6"
|
||||
IPSET_VPS6="passwall2_vps6"
|
||||
IPSET_WAN6="passwall2_wan6"
|
||||
IPSET_LOCAL6="psw2_local6"
|
||||
IPSET_PROXY_LAN6="psw2_proxy_lan6"
|
||||
IPSET_LAN6="psw2_lan6"
|
||||
IPSET_VPS6="psw2_vps6"
|
||||
IPSET_WAN6="psw2_wan6"
|
||||
|
||||
FWMARK="0x50535732"
|
||||
|
||||
@@ -194,8 +194,8 @@ gen_shunt_list() {
|
||||
for shunt_id in $shunt_ids; do
|
||||
local shunt_node=$(config_n_get ${node} "${shunt_id}")
|
||||
[ -n "$shunt_node" ] && {
|
||||
local ipset_v4="passwall2_${node}_${shunt_id}"
|
||||
local ipset_v6="passwall2_${node}_${shunt_id}6"
|
||||
local ipset_v4="psw2_${node}_${shunt_id}"
|
||||
local ipset_v6="psw2_${node}_${shunt_id}6"
|
||||
ipset -! create $ipset_v4 nethash maxelem 1048576
|
||||
ipset -! create $ipset_v6 nethash family inet6 maxelem 1048576
|
||||
local outbound="redirect"
|
||||
@@ -219,22 +219,14 @@ gen_shunt_list() {
|
||||
}
|
||||
local direct_ipset4=$(get_cache_var "node_${node}_direct_ipset4")
|
||||
[ -n "${direct_ipset4}" ] && {
|
||||
ipset -! create ${direct_ipset4} nethash maxelem 1048576 timeout 259200
|
||||
ipset -! create ${direct_ipset4} iphash maxelem 1048576 timeout 259200
|
||||
_SHUNT_LIST4="${_SHUNT_LIST4} ${direct_ipset4}:direct"
|
||||
}
|
||||
local direct_ipset6=$(get_cache_var "node_${node}_direct_ipset6")
|
||||
[ -n "${direct_ipset6}" ] && {
|
||||
ipset -! create ${direct_ipset6} nethash family inet6 maxelem 1048576 timeout 259200
|
||||
ipset -! create ${direct_ipset6} iphash family inet6 maxelem 1048576 timeout 259200
|
||||
_SHUNT_LIST6="${_SHUNT_LIST6} ${direct_ipset6}:direct"
|
||||
}
|
||||
[ "${preloading}" = "1" ] && [ -n "$default_node" ] && {
|
||||
local ipset_v4="passwall2_${node}_default"
|
||||
local ipset_v6="passwall2_${node}_default6"
|
||||
ipset -! create $ipset_v4 nethash maxelem 1048576
|
||||
ipset -! create $ipset_v6 nethash family inet6 maxelem 1048576
|
||||
_SHUNT_LIST4="${_SHUNT_LIST4} ${ipset_v4}:${default_outbound}"
|
||||
_SHUNT_LIST6="${_SHUNT_LIST6} ${ipset_v6}:${default_outbound}"
|
||||
}
|
||||
}
|
||||
[ -n "${_SHUNT_LIST4}" ] && eval ${shunt_list4_var_name}=\"${_SHUNT_LIST4}\"
|
||||
[ -n "${_SHUNT_LIST6}" ] && eval ${shunt_list6_var_name}=\"${_SHUNT_LIST6}\"
|
||||
@@ -618,6 +610,8 @@ filter_direct_node_list() {
|
||||
}
|
||||
|
||||
update_wan_sets() {
|
||||
[ -z "$(command -v get_wan_ips)" ] && . "$UTILS_PATH"
|
||||
|
||||
local WAN_IP=$(get_wan_ips ip4)
|
||||
[ -n "$WAN_IP" ] && {
|
||||
ipset -F "$IPSET_WAN"
|
||||
@@ -641,13 +635,13 @@ add_firewall_rule() {
|
||||
ipset -! create $IPSET_LOCAL nethash maxelem 1048576
|
||||
ipset -! create $IPSET_PROXY_LAN nethash maxelem 1048576
|
||||
ipset -! create $IPSET_LAN nethash maxelem 1048576
|
||||
ipset -! create $IPSET_VPS nethash maxelem 1048576
|
||||
ipset -! create $IPSET_VPS iphash maxelem 1048576
|
||||
ipset -! create $IPSET_WAN nethash maxelem 1048576
|
||||
|
||||
ipset -! create $IPSET_LOCAL6 nethash family inet6 maxelem 1048576
|
||||
ipset -! create $IPSET_PROXY_LAN6 nethash family inet6 maxelem 1048576
|
||||
ipset -! create $IPSET_LAN6 nethash family inet6 maxelem 1048576
|
||||
ipset -! create $IPSET_VPS6 nethash family inet6 maxelem 1048576
|
||||
ipset -! create $IPSET_VPS6 iphash family inet6 maxelem 1048576
|
||||
ipset -! create $IPSET_WAN6 nethash family inet6 maxelem 1048576
|
||||
|
||||
get_local_ips ip4 | sed "s/^/add $IPSET_LOCAL /" | ipset -! -R
|
||||
@@ -1025,7 +1019,7 @@ del_firewall_rule() {
|
||||
|
||||
flush_ipset() {
|
||||
log_i18n 0 "Clear %s." "IPSet"
|
||||
for _name in $(ipset list | grep "Name: " | grep "passwall2_" | awk '{print $2}'); do
|
||||
for _name in $(ipset list | grep "Name: " | grep "psw2_" | awk '{print $2}'); do
|
||||
destroy_ipset ${_name}
|
||||
done
|
||||
}
|
||||
@@ -1105,7 +1099,7 @@ start() {
|
||||
}
|
||||
|
||||
stop() {
|
||||
[ -z "$(command -v log_i18n)" ] && . /usr/share/passwall2/utils.sh
|
||||
[ -z "$(command -v log_i18n)" ] && . "$UTILS_PATH"
|
||||
del_firewall_rule
|
||||
destroy_ipset $IPSET_PROXY_LAN
|
||||
destroy_ipset $IPSET_PROXY_LAN6
|
||||
|
||||
@@ -18,7 +18,7 @@ while [ "$ENABLED" -eq 1 ]; do
|
||||
for filename in $(ls ${TMP_SCRIPT_FUNC_PATH} | grep -v "^_"); do
|
||||
cmd=$(cat ${TMP_SCRIPT_FUNC_PATH}/${filename})
|
||||
cmd_check=$(echo $cmd | awk -F '>' '{print $1}')
|
||||
icount=$(pgrep -f "$(echo $cmd_check)" | wc -l)
|
||||
icount=$(busybox pgrep -f "$(echo $cmd_check)" | wc -l)
|
||||
if [ $icount = 0 ]; then
|
||||
#echo "${cmd} crashed, restarting." >> /tmp/log/passwall2.log
|
||||
eval $(echo "nohup ${cmd} 2>&1 &") >/dev/null 2>&1 &
|
||||
|
||||
@@ -4,17 +4,17 @@ DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
MY_PATH=$DIR/nftables.sh
|
||||
UTILS_PATH=$DIR/utils.sh
|
||||
NFTABLE_NAME="inet passwall2"
|
||||
NFTSET_LOCAL="passwall2_local"
|
||||
NFTSET_PROXY_LAN="passwall2_proxy_lan"
|
||||
NFTSET_LAN="passwall2_lan"
|
||||
NFTSET_VPS="passwall2_vps"
|
||||
NFTSET_WAN="passwall2_wan"
|
||||
NFTSET_LOCAL="psw2_local"
|
||||
NFTSET_PROXY_LAN="psw2_proxy_lan"
|
||||
NFTSET_LAN="psw2_lan"
|
||||
NFTSET_VPS="psw2_vps"
|
||||
NFTSET_WAN="psw2_wan"
|
||||
|
||||
NFTSET_LOCAL6="passwall2_local6"
|
||||
NFTSET_PROXY_LAN6="passwall2_proxy_lan6"
|
||||
NFTSET_LAN6="passwall2_lan6"
|
||||
NFTSET_VPS6="passwall2_vps6"
|
||||
NFTSET_WAN6="passwall2_wan6"
|
||||
NFTSET_LOCAL6="psw2_local6"
|
||||
NFTSET_PROXY_LAN6="psw2_proxy_lan6"
|
||||
NFTSET_LAN6="psw2_lan6"
|
||||
NFTSET_VPS6="psw2_vps6"
|
||||
NFTSET_WAN6="psw2_wan6"
|
||||
|
||||
FWMARK="0x50535732"
|
||||
|
||||
@@ -231,8 +231,8 @@ gen_shunt_list() {
|
||||
for shunt_id in $shunt_ids; do
|
||||
local shunt_node=$(config_n_get ${node} "${shunt_id}")
|
||||
[ -n "$shunt_node" ] && {
|
||||
local nftset_v4="passwall2_${node}_${shunt_id}"
|
||||
local nftset_v6="passwall2_${node}_${shunt_id}6"
|
||||
local nftset_v4="psw2_${node}_${shunt_id}"
|
||||
local nftset_v6="psw2_${node}_${shunt_id}6"
|
||||
gen_nftset $nftset_v4 ipv4_addr 0 0
|
||||
gen_nftset $nftset_v6 ipv6_addr 0 0
|
||||
local outbound="redirect"
|
||||
@@ -263,14 +263,6 @@ gen_shunt_list() {
|
||||
gen_nftset $direct_nftset6 ipv6_addr 0 0
|
||||
_SHUNT_LIST6="${_SHUNT_LIST6} ${direct_nftset6}:direct"
|
||||
}
|
||||
[ "${preloading}" = "1" ] && [ -n "$default_node" ] && {
|
||||
local nftset_v4="passwall2_${node}_default"
|
||||
local nftset_v6="passwall2_${node}_default6"
|
||||
gen_nftset $nftset_v4 ipv4_addr 0 0
|
||||
gen_nftset $nftset_v6 ipv6_addr 0 0
|
||||
_SHUNT_LIST4="${_SHUNT_LIST4} ${nftset_v4}:${default_outbound}"
|
||||
_SHUNT_LIST6="${_SHUNT_LIST6} ${nftset_v6}:${default_outbound}"
|
||||
}
|
||||
}
|
||||
[ -n "${_SHUNT_LIST4}" ] && eval ${shunt_list4_var_name}=\"${_SHUNT_LIST4}\"
|
||||
[ -n "${_SHUNT_LIST6}" ] && eval ${shunt_list6_var_name}=\"${_SHUNT_LIST6}\"
|
||||
@@ -681,6 +673,8 @@ mwan3_start() {
|
||||
}
|
||||
|
||||
update_wan_sets() {
|
||||
[ -z "$(command -v get_wan_ips)" ] && . "$UTILS_PATH"
|
||||
|
||||
local WAN_IP=$(get_wan_ips ip4)
|
||||
[ -n "$WAN_IP" ] && {
|
||||
nft flush set $NFTABLE_NAME $NFTSET_WAN
|
||||
@@ -1073,7 +1067,7 @@ del_firewall_rule() {
|
||||
|
||||
flush_nftset() {
|
||||
log_i18n 0 "Clear %s." "NFTSet"
|
||||
for _name in $(nft -a list sets | grep -E "passwall2_" | awk -F 'set ' '{print $2}' | awk '{print $1}'); do
|
||||
for _name in $(nft -a list sets | grep -E "psw2_" | awk -F 'set ' '{print $2}' | awk '{print $1}'); do
|
||||
destroy_nftset ${_name}
|
||||
done
|
||||
}
|
||||
@@ -1116,7 +1110,7 @@ start() {
|
||||
}
|
||||
|
||||
stop() {
|
||||
[ -z "$(command -v log_i18n)" ] && . /usr/share/passwall2/utils.sh
|
||||
[ -z "$(command -v log_i18n)" ] && . "$UTILS_PATH"
|
||||
del_firewall_rule
|
||||
destroy_nftset $NFTSET_PROXY_LAN
|
||||
destroy_nftset $NFTSET_PROXY_LAN6
|
||||
|
||||
@@ -6,7 +6,7 @@ APP_FILE=${APP_PATH}/app.sh
|
||||
flag=0
|
||||
|
||||
check_process() {
|
||||
while pgrep -af "${CONFIG}/" | grep -E 'app\.sh.*(start|stop)|nftables\.sh|iptables\.sh|subscribe\.lua' >/dev/null; do
|
||||
while busybox pgrep -af "${CONFIG}/" | grep -E 'app\.sh.*(start|stop)|nftables\.sh|iptables\.sh|subscribe\.lua' >/dev/null; do
|
||||
sleep 6s
|
||||
done
|
||||
}
|
||||
@@ -63,7 +63,7 @@ test_node() {
|
||||
# Kill the SS plugin process
|
||||
local pid_file="/tmp/etc/${CONFIG}/test_node_${node_id}_plugin.pid"
|
||||
[ -s "$pid_file" ] && kill -9 "$(head -n 1 "$pid_file")" >/dev/null 2>&1
|
||||
pgrep -af "test_node_${node_id}" | awk '! /socks_auto_switch\.sh/{print $1}' | xargs kill -9 >/dev/null 2>&1
|
||||
busybox pgrep -af "test_node_${node_id}" | awk '! /socks_auto_switch\.sh/{print $1}' | xargs kill -9 >/dev/null 2>&1
|
||||
rm -rf /tmp/etc/${CONFIG}/test_node_${node_id}*.*
|
||||
if [ "${_proxy_status}" -eq 200 ]; then
|
||||
return 0
|
||||
|
||||
@@ -1688,22 +1688,19 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
||||
local insecure = params.allowinsecure or params.insecure
|
||||
result.tls_allowInsecure = (insecure == "1" or insecure == "0") and insecure or (sub_allowinsecure and "1" or "0")
|
||||
result.hysteria2_hop = params.mport
|
||||
if params["obfs-password"] or params["obfs_password"] then
|
||||
result.hysteria2_obfs_type = "salamander"
|
||||
result.hysteria2_obfs_password = params["obfs-password"] or params["obfs_password"]
|
||||
end
|
||||
|
||||
if (sub_hysteria2_type == "sing-box" and has_singbox) or (sub_hysteria2_type == "xray" and has_xray) then
|
||||
local is_singbox = sub_hysteria2_type == "sing-box" and has_singbox
|
||||
result.type = is_singbox and 'sing-box' or 'Xray'
|
||||
result.protocol = "hysteria2"
|
||||
if params["obfs-password"] or params["obfs_password"] then
|
||||
result.hysteria2_obfs_type = "salamander"
|
||||
result.hysteria2_obfs_password = params["obfs-password"] or params["obfs_password"]
|
||||
end
|
||||
result.use_finalmask = (params.fm and params.fm ~= "") and "1" or nil
|
||||
result.finalmask = (params.fm and params.fm ~= "") and api.base64Encode(params.fm) or nil
|
||||
elseif has_hysteria2 then
|
||||
result.type = "Hysteria2"
|
||||
if params["obfs-password"] or params["obfs_password"] then
|
||||
result.hysteria2_obfs = params["obfs-password"] or params["obfs_password"]
|
||||
end
|
||||
else
|
||||
log(2, i18n.translatef("Skipping the %s node is due to incompatibility with the %s core program or incorrect node usage type settings.", "Hysteria2", "Hysteria2"))
|
||||
return nil
|
||||
@@ -1761,7 +1758,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
||||
end
|
||||
result.tls_serverName = params.sni
|
||||
result.tls_disable_sni = params.disable_sni
|
||||
result.tuic_alpn = params.alpn or "default"
|
||||
result.tuic_alpn = params.alpn or "h3"
|
||||
result.tuic_congestion_control = params.congestion_control or "cubic"
|
||||
result.tuic_udp_relay_mode = params.udp_relay_mode or "native"
|
||||
local insecure = params.allowinsecure or params.insecure or params.allow_insecure
|
||||
@@ -2049,12 +2046,12 @@ local function select_node(nodes, config, parentConfig)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- First priority: Type + Notes + IP + Port
|
||||
-- First priority: Type + Notes + IP + Port + Group
|
||||
if not server then
|
||||
for index, node in pairs(nodes) do
|
||||
if config.currentNode.type and config.currentNode.remarks and config.currentNode.address and config.currentNode.port then
|
||||
if node.type and node.remarks and node.address and node.port then
|
||||
if node.type == config.currentNode.type and node.remarks == config.currentNode.remarks and (node.address .. ':' .. node.port == config.currentNode.address .. ':' .. config.currentNode.port) then
|
||||
if node.type == config.currentNode.type and node.remarks == config.currentNode.remarks and (node.address .. ':' .. node.port == config.currentNode.address .. ':' .. config.currentNode.port) and node.group == config.currentNode.group then
|
||||
if config.log == nil or config.log == true then
|
||||
log(log_level, i18n.translatef("Update [%s]", config.remarks) .. " " .. i18n.translatef("First Matching node:") .. " " .. node.remarks)
|
||||
end
|
||||
@@ -2065,12 +2062,12 @@ local function select_node(nodes, config, parentConfig)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Second priority: Type + IP + Port
|
||||
-- Second priority: Type + IP + Port + Group
|
||||
if not server then
|
||||
for index, node in pairs(nodes) do
|
||||
if config.currentNode.type and config.currentNode.address and config.currentNode.port then
|
||||
if node.type and node.address and node.port then
|
||||
if node.type == config.currentNode.type and (node.address .. ':' .. node.port == config.currentNode.address .. ':' .. config.currentNode.port) then
|
||||
if node.type == config.currentNode.type and (node.address .. ':' .. node.port == config.currentNode.address .. ':' .. config.currentNode.port) and node.group == config.currentNode.group then
|
||||
if config.log == nil or config.log == true then
|
||||
log(log_level, i18n.translatef("Update [%s]", config.remarks) .. " " .. i18n.translatef("Second Matching node:") .. " " .. node.remarks)
|
||||
end
|
||||
@@ -2081,12 +2078,12 @@ local function select_node(nodes, config, parentConfig)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Third priority: IP + Port
|
||||
-- Third priority: IP + Port + Group
|
||||
if not server then
|
||||
for index, node in pairs(nodes) do
|
||||
if config.currentNode.address and config.currentNode.port then
|
||||
if node.address and node.port then
|
||||
if node.address .. ':' .. node.port == config.currentNode.address .. ':' .. config.currentNode.port then
|
||||
if node.address .. ':' .. node.port == config.currentNode.address .. ':' .. config.currentNode.port and node.group == config.currentNode.group then
|
||||
if config.log == nil or config.log == true then
|
||||
log(log_level, i18n.translatef("Update [%s]", config.remarks) .. " " .. i18n.translatef("Third Matching node:") .. " " .. node.remarks)
|
||||
end
|
||||
@@ -2097,12 +2094,12 @@ local function select_node(nodes, config, parentConfig)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Fourth priority: IP
|
||||
-- Fourth priority: IP + Group
|
||||
if not server then
|
||||
for index, node in pairs(nodes) do
|
||||
if config.currentNode.address then
|
||||
if node.address then
|
||||
if node.address == config.currentNode.address then
|
||||
if node.address == config.currentNode.address and node.group == config.currentNode.group then
|
||||
if config.log == nil or config.log == true then
|
||||
log(log_level, i18n.translatef("Update [%s]", config.remarks) .. " " .. i18n.translatef("Fourth Matching node:") .. " " .. node.remarks)
|
||||
end
|
||||
@@ -2113,12 +2110,12 @@ local function select_node(nodes, config, parentConfig)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Fifth priority: remarks
|
||||
-- Fifth priority: remarks + Group
|
||||
if not server then
|
||||
for index, node in pairs(nodes) do
|
||||
if config.currentNode.remarks then
|
||||
if node.remarks then
|
||||
if node.remarks == config.currentNode.remarks then
|
||||
if node.remarks == config.currentNode.remarks and node.group == config.currentNode.group then
|
||||
if config.log == nil or config.log == true then
|
||||
log(log_level, i18n.translatef("Update [%s]", config.remarks) .. " " .. i18n.translatef("Fifth Matching node:") .. " " .. node.remarks)
|
||||
end
|
||||
|
||||
@@ -22,7 +22,7 @@ do
|
||||
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 &
|
||||
[ "$(expr "$CFG_UPDATE_INT" % "$stop_interval_mode")" -eq 0 ] && { /etc/init.d/$CONFIG stop > /dev/null 2>&1 & }
|
||||
}
|
||||
fi
|
||||
|
||||
@@ -31,7 +31,7 @@ do
|
||||
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 &
|
||||
[ "$(expr "$CFG_UPDATE_INT" % "$start_interval_mode")" -eq 0 ] && { /etc/init.d/$CONFIG start > /dev/null 2>&1 & }
|
||||
}
|
||||
fi
|
||||
|
||||
@@ -40,7 +40,7 @@ do
|
||||
restart_interval_mode=$(expr "$restart_interval_mode" \* 60)
|
||||
if [ -n "$restart_week_mode" ]; then
|
||||
[ "$restart_week_mode" = "8" ] && {
|
||||
[ "$(expr "$CFG_UPDATE_INT" % "$restart_interval_mode")" -eq 0 ] && /etc/init.d/$CONFIG restart > /dev/null 2>&1 &
|
||||
[ "$(expr "$CFG_UPDATE_INT" % "$restart_interval_mode")" -eq 0 ] && { /etc/init.d/$CONFIG restart > /dev/null 2>&1 & }
|
||||
}
|
||||
fi
|
||||
|
||||
@@ -50,7 +50,7 @@ do
|
||||
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 &
|
||||
[ "$(expr "$CFG_UPDATE_INT" % "$hourupdate")" -eq 0 ] && { lua $APP_PATH/rule_update.lua log all cron > /dev/null 2>&1 & }
|
||||
}
|
||||
fi
|
||||
|
||||
@@ -73,7 +73,7 @@ do
|
||||
hour_update=$(expr "$hour_update" \* 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 &
|
||||
[ "$(expr "$CFG_UPDATE_INT" % "$hour_update")" -eq 0 ] && { lua $APP_PATH/subscribe.lua start $cfgids cron > /dev/null 2>&1 & }
|
||||
}
|
||||
|
||||
done
|
||||
|
||||
@@ -50,10 +50,13 @@ url_test_node() {
|
||||
NO_REC_PROCESS=1 /usr/share/${CONFIG}/app.sh run_socks flag="url_test_${node_id}" node=${node_id} bind=127.0.0.1 socks_port=${_tmp_port} config_file=url_test_${node_id}.json
|
||||
sleep 2s
|
||||
local curlx="socks5h://127.0.0.1:${_tmp_port}"
|
||||
local url=$(config_t_get global_other url_test_url https://www.google.com/generate_204)
|
||||
result=$(curl --connect-timeout 3 -o /dev/null -I -skL -w "%{http_code}:%{time_starttransfer}" -x $curlx "${url}")
|
||||
pgrep -af "url_test_${node_id}" | awk '! /test\.sh/{print $1}' | xargs kill -9 >/dev/null 2>&1
|
||||
rm -rf /tmp/etc/${CONFIG}/*url_test_${node_id}*.json
|
||||
local probeUrl=$(config_t_get global_other url_test_url https://www.google.com/generate_204)
|
||||
result=$(curl --connect-timeout 3 --max-time 5 -o /dev/null -I -skL -w "%{http_code}:%{time_pretransfer}" -x ${curlx} "${probeUrl}")
|
||||
# End the SS plugin process
|
||||
local pid_file="/tmp/etc/${CONFIG}/url_test_${node_id}_plugin.pid"
|
||||
[ -s "$pid_file" ] && kill -9 "$(head -n 1 "$pid_file")" >/dev/null 2>&1
|
||||
busybox pgrep -af "url_test_${node_id}" | awk '! /test\.sh/{print $1}' | xargs kill -9 >/dev/null 2>&1
|
||||
rm -rf /tmp/etc/${CONFIG}/*url_test_${node_id}*.*
|
||||
}
|
||||
echo $result
|
||||
}
|
||||
|
||||
@@ -412,7 +412,7 @@ run_process_queue() {
|
||||
for filename in $(ls ${TMP_PROCESS_LIST_PATH}); do
|
||||
cmd=$(cat ${TMP_PROCESS_LIST_PATH}/${filename})
|
||||
cmd_check=$(echo $cmd | awk -F '>' '{print $1}')
|
||||
icount=$(pgrep -f "$(echo $cmd_check)" | wc -l)
|
||||
icount=$(busybox pgrep -f "$(echo $cmd_check)" | wc -l)
|
||||
if [ $icount = 0 ]; then
|
||||
eval $(echo "nohup ${cmd} 2>&1 &") >/dev/null 2>&1 &
|
||||
fi
|
||||
|
||||
@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-xray
|
||||
PKG_VERSION:=3.7.1
|
||||
PKG_RELEASE:=1
|
||||
PKG_RELEASE:=2
|
||||
|
||||
PKG_LICENSE:=MPLv2
|
||||
PKG_LICENSE_FILES:=LICENSE
|
||||
|
||||
@@ -261,7 +261,7 @@ function gen_config() {
|
||||
|
||||
const general = filter(values(config), k => k[".type"] == "general")[0] || {};
|
||||
const custom_configuration_hook = loadstring(general["custom_configuration_hook"] || "return i => i;")();
|
||||
return custom_configuration_hook({
|
||||
let result = {
|
||||
inbounds: inbounds(general, config, extra_inbound),
|
||||
outbounds: outbounds(general, config, manual_tproxy, bridge, extra_inbound, fakedns),
|
||||
dns: dns_conf(general, config, manual_tproxy, fakedns),
|
||||
@@ -274,15 +274,19 @@ function gen_config() {
|
||||
place: "holder"
|
||||
} : null,
|
||||
observatory: observatory(general, manual_tproxy),
|
||||
reverse: {
|
||||
bridges: bridges(bridge)
|
||||
},
|
||||
routing: {
|
||||
domainStrategy: general["routing_domain_strategy"] || "AsIs",
|
||||
rules: rules(general, bridge, manual_tproxy, extra_inbound, fakedns),
|
||||
balancers: balancers(general, extra_inbound, fakedns)
|
||||
}
|
||||
});
|
||||
};
|
||||
const bridges_deprecated = bridges(bridge);
|
||||
if (length(bridges_deprecated) > 0) {
|
||||
result["reverse"] = {
|
||||
bridges: bridges_deprecated
|
||||
};
|
||||
};
|
||||
return custom_configuration_hook(result);
|
||||
}
|
||||
|
||||
printf("%.4J", gen_config());
|
||||
@@ -1,17 +1,176 @@
|
||||
'use strict';'require baseclass';'require ui';return baseclass.extend({__init__:function(){ui.menu.load().then(L.bind(this.render,this));},render:function(tree){var node=tree,url='',children=ui.menu.getChildren(tree);for(var i=0;i<children.length;i++){var isActive=(L.env.requestpath.length?children[i].name==L.env.requestpath[0]:i==0);if(isActive)
|
||||
this.renderMainMenu(children[i],children[i].name);}
|
||||
if(L.env.dispatchpath.length>=3){for(var i=0;i<3&&node;i++){node=node.children[L.env.dispatchpath[i]];url=url+(url?'/':'')+L.env.dispatchpath[i];}
|
||||
if(node)
|
||||
this.renderTabMenu(node,url);}
|
||||
document.querySelector('a.showSide').addEventListener('click',ui.createHandlerFn(this,'handleSidebarToggle'));document.querySelector('.darkMask').addEventListener('click',ui.createHandlerFn(this,'handleSidebarToggle'));},handleMenuExpand:function(ev){var a=ev.target,slide=a.parentNode,slide_menu=a.nextElementSibling;var collapse=false;document.querySelectorAll('.main .main-left .nav > li >ul.active').forEach(function(ul){$(ul).stop(true).slideUp("fast",function(){ul.classList.remove('active');ul.previousElementSibling.classList.remove('active');});if(!collapse&&ul===slide_menu){collapse=true;}});if(!slide_menu)
|
||||
return;if(!collapse){$(slide).find(".slide-menu").slideDown("fast",function(){slide_menu.classList.add('active');a.classList.add('active');});a.blur();}
|
||||
ev.preventDefault();ev.stopPropagation();},renderMainMenu:function(tree,url,level){var l=(level||0)+1,ul=E('ul',{'class':level?'slide-menu':'nav'}),children=ui.menu.getChildren(tree);if(children.length==0||l>2)
|
||||
return E([]);for(var i=0;i<children.length;i++){var isActive=((L.env.dispatchpath[l]==children[i].name)&&(L.env.dispatchpath[l-1]==tree.name)),submenu=this.renderMainMenu(children[i],url+'/'+children[i].name,l),hasChildren=submenu.children.length,slideClass=hasChildren?'slide':null,menuClass=hasChildren?'menu':'food';if(isActive){ul.classList.add('active');slideClass+=" active";menuClass+=" active";}
|
||||
ul.appendChild(E('li',{'class':slideClass},[E('a',{'href':L.url(url,children[i].name),'click':(l==1)?ui.createHandlerFn(this,'handleMenuExpand'):null,'class':menuClass,'data-title':hasChildren?children[i].title.replace(" ","_"):children[i].title.replace(" ","_"),},[_(children[i].title)]),submenu]));}
|
||||
if(l==1){document.querySelector('#mainmenu').appendChild(ul);document.querySelector('#mainmenu').style.display='';}
|
||||
return ul;},renderTabMenu:function(tree,url,level){var container=document.querySelector('#tabmenu'),l=(level||0)+1,ul=E('ul',{'class':'tabs'}),children=ui.menu.getChildren(tree),activeNode=null;if(children.length==0)
|
||||
return E([]);for(var i=0;i<children.length;i++){var isActive=(L.env.dispatchpath[l+2]==children[i].name),activeClass=isActive?' active':'',className='tabmenu-item-%s %s'.format(children[i].name,activeClass);ul.appendChild(E('li',{'class':className},[E('a',{'href':L.url(url,children[i].name)},[_(children[i].title)])]));if(isActive)
|
||||
activeNode=children[i];}
|
||||
container.appendChild(ul);container.style.display='';if(activeNode)
|
||||
container.appendChild(this.renderTabMenu(activeNode,url+'/'+activeNode.name,l));return ul;},handleSidebarToggle:function(ev){var showside=document.querySelector('a.showSide'),sidebar=document.querySelector('#mainmenu'),darkmask=document.querySelector('.darkMask'),scrollbar=document.querySelector('.main-right');if(showside.classList.contains('active')){showside.classList.remove('active');sidebar.classList.remove('active');scrollbar.classList.remove('active');darkmask.classList.remove('active');}
|
||||
else{showside.classList.add('active');sidebar.classList.add('active');scrollbar.classList.add('active');darkmask.classList.add('active');}}});
|
||||
'use strict';
|
||||
'require baseclass';
|
||||
'require ui';
|
||||
|
||||
return baseclass.extend({
|
||||
__init__: function () {
|
||||
ui.menu.load().then(L.bind(this.render, this));
|
||||
},
|
||||
|
||||
render: function (tree) {
|
||||
var node = tree,
|
||||
url = '',
|
||||
children = ui.menu.getChildren(tree);
|
||||
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
var isActive =
|
||||
L.env.requestpath.length
|
||||
? children[i].name == L.env.requestpath[0]
|
||||
: i == 0;
|
||||
if (isActive) this.renderMainMenu(children[i], children[i].name);
|
||||
}
|
||||
|
||||
if (L.env.dispatchpath.length >= 3) {
|
||||
for (var i = 0; i < 3 && node; i++) {
|
||||
node = node.children[L.env.dispatchpath[i]];
|
||||
url = url + (url ? '/' : '') + L.env.dispatchpath[i];
|
||||
}
|
||||
if (node) this.renderTabMenu(node, url);
|
||||
}
|
||||
|
||||
document
|
||||
.querySelector('a.showSide')
|
||||
.addEventListener('click', ui.createHandlerFn(this, 'handleSidebarToggle'));
|
||||
document
|
||||
.querySelector('.darkMask')
|
||||
.addEventListener('click', ui.createHandlerFn(this, 'handleSidebarToggle'));
|
||||
},
|
||||
|
||||
handleMenuExpand: function (ev) {
|
||||
var a = ev.target,
|
||||
slide = a.parentNode,
|
||||
slide_menu = a.nextElementSibling;
|
||||
var collapse = false;
|
||||
|
||||
document
|
||||
.querySelectorAll('.main .main-left .nav > li >ul.active')
|
||||
.forEach(function (ul) {
|
||||
$(ul).stop(true).slideUp('fast', function () {
|
||||
ul.classList.remove('active');
|
||||
ul.previousElementSibling.classList.remove('active');
|
||||
});
|
||||
if (!collapse && ul === slide_menu) {
|
||||
collapse = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (!slide_menu) return;
|
||||
|
||||
if (!collapse) {
|
||||
$(slide)
|
||||
.find('.slide-menu')
|
||||
.slideDown('fast', function () {
|
||||
slide_menu.classList.add('active');
|
||||
a.classList.add('active');
|
||||
});
|
||||
a.blur();
|
||||
}
|
||||
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
},
|
||||
|
||||
renderMainMenu: function (tree, url, level) {
|
||||
var l = (level || 0) + 1,
|
||||
ul = E('ul', { class: level ? 'slide-menu' : 'nav' }),
|
||||
children = ui.menu.getChildren(tree);
|
||||
|
||||
if (children.length == 0 || l > 2) return E([]);
|
||||
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
var isActive =
|
||||
L.env.dispatchpath[l] == children[i].name &&
|
||||
L.env.dispatchpath[l - 1] == tree.name,
|
||||
submenu = this.renderMainMenu(children[i], url + '/' + children[i].name, l),
|
||||
hasChildren = submenu.children.length,
|
||||
slideClass = hasChildren ? 'slide' : null,
|
||||
menuClass = hasChildren ? 'menu' : 'food';
|
||||
|
||||
if (isActive) {
|
||||
ul.classList.add('active');
|
||||
slideClass += ' active';
|
||||
menuClass += ' active';
|
||||
}
|
||||
|
||||
ul.appendChild(
|
||||
E(
|
||||
'li',
|
||||
{ class: slideClass },
|
||||
[
|
||||
E(
|
||||
'a',
|
||||
{
|
||||
href: L.url(url, children[i].name),
|
||||
click: l == 1 ? ui.createHandlerFn(this, 'handleMenuExpand') : null,
|
||||
class: menuClass,
|
||||
'data-title': hasChildren
|
||||
? children[i].title.replace(' ', '_')
|
||||
: children[i].title.replace(' ', '_'),
|
||||
},
|
||||
[_(children[i].title)]
|
||||
),
|
||||
submenu,
|
||||
]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (l == 1) {
|
||||
document.querySelector('#mainmenu').appendChild(ul);
|
||||
document.querySelector('#mainmenu').style.display = '';
|
||||
}
|
||||
|
||||
return ul;
|
||||
},
|
||||
|
||||
renderTabMenu: function (tree, url, level) {
|
||||
var container = document.querySelector('#tabmenu'),
|
||||
l = (level || 0) + 1,
|
||||
ul = E('ul', { class: 'tabs' }),
|
||||
children = ui.menu.getChildren(tree),
|
||||
activeNode = null;
|
||||
|
||||
if (children.length == 0) return E([]);
|
||||
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
var isActive = L.env.dispatchpath[l + 2] == children[i].name,
|
||||
activeClass = isActive ? ' active' : '',
|
||||
className = 'tabmenu-item-%s %s'.format(children[i].name, activeClass);
|
||||
|
||||
ul.appendChild(
|
||||
E('li', { class: className }, [
|
||||
E('a', { href: L.url(url, children[i].name) }, [_(children[i].title)]),
|
||||
])
|
||||
);
|
||||
|
||||
if (isActive) activeNode = children[i];
|
||||
}
|
||||
|
||||
container.appendChild(ul);
|
||||
container.style.display = '';
|
||||
|
||||
if (activeNode)
|
||||
container.appendChild(this.renderTabMenu(activeNode, url + '/' + activeNode.name, l));
|
||||
|
||||
return ul;
|
||||
},
|
||||
|
||||
handleSidebarToggle: function (ev) {
|
||||
var showside = document.querySelector('a.showSide'),
|
||||
sidebar = document.querySelector('#mainmenu'),
|
||||
darkmask = document.querySelector('.darkMask'),
|
||||
scrollbar = document.querySelector('.main-right');
|
||||
|
||||
if (showside.classList.contains('active')) {
|
||||
showside.classList.remove('active');
|
||||
sidebar.classList.remove('active');
|
||||
scrollbar.classList.remove('active');
|
||||
darkmask.classList.remove('active');
|
||||
} else {
|
||||
showside.classList.add('active');
|
||||
sidebar.classList.add('active');
|
||||
scrollbar.classList.add('active');
|
||||
darkmask.classList.add('active');
|
||||
}
|
||||
},
|
||||
});
|
||||
File diff suppressed because it is too large.
Load diff
+3230
-1
File diff suppressed because it is too large.
Load diff
@@ -1,2 +1 @@
|
||||
|
||||
(function(undefined){}).call('object'===typeof window&&window||'object'===typeof self&&self||'object'===typeof global&&global||{});
|
||||
(function(undefined) {}).call('object' === typeof window && window || 'object' === typeof self && self || 'object' === typeof global && global || {});
|
||||
@@ -1,14 +1,14 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=mihomo-alpha
|
||||
PKG_VERSION:=2026.05.08
|
||||
PKG_RELEASE:=7
|
||||
PKG_VERSION:=2026.05.16
|
||||
PKG_RELEASE:=8
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/MetaCubeX/mihomo.git
|
||||
PKG_SOURCE_VERSION:=35d5d4e44d7a7b8352617b1fec7faf0ba26efc8a
|
||||
PKG_SOURCE_VERSION:=e9e23c4e98c34b158953f1414b317f25f3e3aa1e
|
||||
PKG_MIRROR_HASH:=skip
|
||||
|
||||
PKG_LICENSE:=GPL3.0+
|
||||
@@ -18,7 +18,7 @@ PKG_BUILD_DEPENDS:=golang/host
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
PKG_BUILD_FLAGS:=no-mips16
|
||||
|
||||
PKG_BUILD_VERSION:=alpha-35d5d4e4
|
||||
PKG_BUILD_VERSION:=alpha-e9e23c4e
|
||||
PKG_BUILD_TIME:=$(shell date -u -Iseconds)
|
||||
|
||||
GO_PKG:=github.com/metacubex/mihomo
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=mihomo-meta
|
||||
PKG_VERSION:=1.19.24
|
||||
PKG_RELEASE:=4
|
||||
PKG_VERSION:=1.19.25
|
||||
PKG_RELEASE:=5
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/MetaCubeX/mihomo.git
|
||||
PKG_SOURCE_VERSION:=v1.19.24
|
||||
PKG_SOURCE_VERSION:=v1.19.25
|
||||
PKG_MIRROR_HASH:=skip
|
||||
|
||||
PKG_LICENSE:=GPL3.0+
|
||||
@@ -18,7 +18,7 @@ PKG_BUILD_DEPENDS:=golang/host
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
PKG_BUILD_FLAGS:=no-mips16
|
||||
|
||||
PKG_BUILD_VERSION:=v1.19.24
|
||||
PKG_BUILD_VERSION:=v1.19.25
|
||||
PKG_BUILD_TIME:=$(shell date -u -Iseconds)
|
||||
|
||||
GO_PKG:=github.com/metacubex/mihomo
|
||||
|
||||
+2
-2
@@ -5,8 +5,8 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=mihomo
|
||||
PKG_VERSION:=1.19.24
|
||||
PKG_RELEASE:=8
|
||||
PKG_VERSION:=1.19.25
|
||||
PKG_RELEASE:=9
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://codeload.github.com/metacubex/mihomo/tar.gz/v$(PKG_VERSION)?
|
||||
|
||||
@@ -9,7 +9,7 @@ PKG_NAME:=natmapt
|
||||
PKG_UPSTREAM_VERSION:=20260214
|
||||
PKG_UPSTREAM_GITHASH:=
|
||||
PKG_VERSION:=$(PKG_UPSTREAM_VERSION)$(if $(PKG_UPSTREAM_GITHASH),~$(call version_abbrev,$(PKG_UPSTREAM_GITHASH)))
|
||||
PKG_RELEASE:=3
|
||||
PKG_RELEASE:=4
|
||||
SCRIPTS_VERSION:=0.2026.01.24
|
||||
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_UPSTREAM_NAME)-$(PKG_UPSTREAM_VERSION)
|
||||
@@ -23,7 +23,7 @@ PKG_SOURCE:=$(PKG_SOURCE_SUBDIR).tar.xz
|
||||
else
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/heiher/natmap.git
|
||||
PKG_SOURCE_VERSION:=079bce1d6c5798fa6f47d364b737762dae89aafc
|
||||
PKG_SOURCE_VERSION:=e0975d64fbd22a34e30d573e51c44fc017b3ff8c
|
||||
PKG_MIRROR_HASH:=skip
|
||||
|
||||
PKG_SOURCE:=$(PKG_SOURCE_SUBDIR)-$(PKG_SOURCE_VERSION).tar.gz
|
||||
|
||||
+2
-2
@@ -5,12 +5,12 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=rtl8189es
|
||||
PKG_RELEASE:=1
|
||||
PKG_RELEASE:=2
|
||||
|
||||
PKG_SOURCE_URL:=https://github.com/jwrdegoede/rtl8189ES_linux.git
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_DATE:=2025-09-27
|
||||
PKG_SOURCE_VERSION:=0a5d04114fac3c9f48a343cb905fbb6a3f9f5df5
|
||||
PKG_SOURCE_VERSION:=36d917d5069f25f4c36b8b4d8b17b5d02e9116e9
|
||||
PKG_MIRROR_HASH:=skip
|
||||
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=tuic-client
|
||||
PKG_VERSION:=1.8.1
|
||||
PKG_RELEASE:=4
|
||||
PKG_VERSION:=1.8.2
|
||||
PKG_RELEASE:=5
|
||||
|
||||
PKG_LICENSE_FILES:=LICENSE
|
||||
PKG_MAINTAINER:=Tianling Shen <cnsztl@immortalwrt.org>
|
||||
|
||||
Reference in new issue
Block a user