mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-29 07:35:13 +08:00
🎉 Sync 2026-07-14 20:29:41
This commit is contained in:
1 parent
9307433a4c
commit
09a1b41f45
15 files changed
+3478
-3132
No files matched your search
@@ -165,6 +165,7 @@ const inbound_type = [
|
||||
['tuic', _('TUIC') + ' - ' + _('UDP')],
|
||||
['hysteria2', _('Hysteria2') + ' - ' + _('UDP')],
|
||||
['hysteria2-realm', _('Hysteria2 Realm Server') + ' - ' + _('TCP/UDP')],
|
||||
['shadowquic', _('ShadowQUIC') + ' - ' + _('UDP')],
|
||||
['trusttunnel', _('TrustTunnel') + ' - ' + _('TCP/UDP')],
|
||||
['tunnel', _('Tunnel') + ' - ' + _('TCP/UDP')]
|
||||
];
|
||||
@@ -201,6 +202,7 @@ const outbound_type = [
|
||||
['tuic', _('TUIC') + ' - ' + _('UDP')],
|
||||
//['hysteria', _('Hysteria') + ' - ' + _('UDP')],
|
||||
['hysteria2', _('Hysteria2') + ' - ' + _('UDP')],
|
||||
['shadowquic', _('ShadowQUIC') + ' - ' + _('UDP')],
|
||||
['trusttunnel', _('TrustTunnel') + ' - ' + _('TCP/UDP')],
|
||||
['wireguard', _('WireGuard') + ' - ' + _('UDP')],
|
||||
['masque', _('Masque') + ' - ' + _('UDP')], // https://blog.cloudflare.com/post-quantum-warp/
|
||||
|
||||
@@ -117,6 +117,7 @@ function renderListeners(s, uciconfig, isClient) {
|
||||
let o;
|
||||
|
||||
s.tab('field_general', _('General fields'));
|
||||
s.tab('field_plugin', _('Plugin fields'));
|
||||
s.tab('field_vless_encryption', _('Vless Encryption fields'));
|
||||
s.tab('field_hysteria2_realm', _('Hysteria2 Realm fields'));
|
||||
s.tab('field_tls', _('TLS fields'));
|
||||
@@ -160,14 +161,14 @@ function renderListeners(s, uciconfig, isClient) {
|
||||
/* hm.validateAuth */
|
||||
o = s.taboption('field_general', form.Value, 'username', _('Username'));
|
||||
o.validate = hm.validateAuthUsername;
|
||||
o.depends({type: /^(http|socks|mixed|mieru|trojan|anytls|hysteria2|trusttunnel)$/});
|
||||
o.depends({type: /^(http|socks|mixed|mieru|trojan|anytls|hysteria2|shadowquic|trusttunnel)$/});
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_general', hm.GenValue, 'password', _('Password'));
|
||||
o.password = true;
|
||||
o.validate = hm.validateAuthPassword;
|
||||
o.rmempty = false;
|
||||
o.depends({type: /^(http|socks|mixed|mieru|trojan|anytls|hysteria2|trusttunnel)$/, username: /.+/});
|
||||
o.depends({type: /^(http|socks|mixed|mieru|trojan|anytls|hysteria2|shadowquic|trusttunnel)$/, username: /.+/});
|
||||
o.depends({type: /^(tuic)$/, uuid: /.+/});
|
||||
o.modalonly = true;
|
||||
|
||||
@@ -453,13 +454,6 @@ function renderListeners(s, uciconfig, isClient) {
|
||||
o.depends('type', 'tuic');
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_general', form.Value, 'tuic_max_idle_time', _('Idle timeout'),
|
||||
_('In seconds.'));
|
||||
o.default = '15000';
|
||||
o.validate = hm.validateTimeDuration;
|
||||
o.depends('type', 'tuic');
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_general', form.Value, 'tuic_authentication_timeout', _('Auth timeout'),
|
||||
_('In seconds.'));
|
||||
o.default = '1000';
|
||||
@@ -547,6 +541,19 @@ function renderListeners(s, uciconfig, isClient) {
|
||||
o.depends('type', 'hysteria2-realm');
|
||||
o.modalonly = true;
|
||||
|
||||
/* ShadowQUIC fields */
|
||||
o = s.taboption('field_general', form.DynamicList, 'shadowquic_quic_versions', _('QUIC versions'),
|
||||
_('Default version, Support %s.').format('v1/v2'));
|
||||
o.default = 'v1';
|
||||
o.rmempty = false;
|
||||
o.depends('type', 'shadowquic');
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_general', form.Flag, 'shadowquic_zero_rtt', _('QUIC based 0-RTT'));
|
||||
o.default = o.disabled;
|
||||
o.depends('type', 'shadowquic');
|
||||
o.modalonly = true;
|
||||
|
||||
/* TrustTunnel fields */
|
||||
|
||||
/* Tunnel fields */
|
||||
@@ -556,68 +563,6 @@ function renderListeners(s, uciconfig, isClient) {
|
||||
o.depends('type', 'tunnel');
|
||||
o.modalonly = true;
|
||||
|
||||
/* 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('restls', _('restls'));
|
||||
//o.value('kcp-tun', _('kcp-tun'));
|
||||
o.validate = function(section_id, value) {
|
||||
const type = this.section.getOption('type').formvalue(section_id);
|
||||
|
||||
if (value) {
|
||||
if (type === 'snell' && !['obfs', 'shadow-tls'].includes(value)) {
|
||||
return _('Expecting: only support %s.').format(_('obfs-simple') +
|
||||
' / ' + _('shadow-tls'));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
o.depends({type: /^(shadowsocks|snell)$/});
|
||||
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_host', _('Plugin: ') + _('Host that supports TLS 1.3'));
|
||||
o.datatype = 'hostname';
|
||||
o.placeholder = 'cloud.tencent.com';
|
||||
o.rmempty = false;
|
||||
o.depends({plugin: 'obfs', type: 'snell'});
|
||||
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';
|
||||
o.rmempty = false;
|
||||
o.depends({plugin: /^(shadow-tls|restls)$/});
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_general', hm.GenValue, 'plugin_opts_thetlspassword', _('Plugin: ') + _('Password'));
|
||||
o.password = true;
|
||||
o.rmempty = false;
|
||||
o.depends({plugin: /^(shadow-tls|restls)$/});
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_general', form.ListValue, 'plugin_opts_shadowtls_version', _('Plugin: ') + _('Version'));
|
||||
o.value('1', _('v1'));
|
||||
o.value('2', _('v2'));
|
||||
o.value('3', _('v3'));
|
||||
o.default = '3';
|
||||
o.depends({plugin: 'shadow-tls'});
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_general', form.Value, 'plugin_opts_restls_script', _('Plugin: ') + _('Restls script'));
|
||||
o.default = '300?100<1,400~100,350~100,600~100,300~200,300~100';
|
||||
o.rmempty = false;
|
||||
o.depends({plugin: 'restls'});
|
||||
o.modalonly = true;
|
||||
|
||||
/* Extra fields */
|
||||
if (isClient) {
|
||||
o = s.taboption('field_general', form.Value, 'routing_mark', _('Routing mark (Fwmark)'));
|
||||
@@ -658,7 +603,7 @@ function renderListeners(s, uciconfig, isClient) {
|
||||
hm.congestion_controller.forEach((res) => {
|
||||
o.value.apply(o, res);
|
||||
})
|
||||
o.depends({type: /^(tuic|trusttunnel)$/});
|
||||
o.depends({type: /^(tuic|shadowquic|trusttunnel)$/});
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_general', form.ListValue, 'bbr_profile', _('BBR profile'));
|
||||
@@ -666,8 +611,15 @@ function renderListeners(s, uciconfig, isClient) {
|
||||
hm.bbr_profiles.forEach((res) => {
|
||||
o.value.apply(o, res);
|
||||
})
|
||||
o.depends({congestion_controller: 'bbr'});
|
||||
o.depends({type: 'hysteria2'});
|
||||
o.depends('congestion_controller', 'bbr');
|
||||
o.depends('type', 'hysteria2');
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_general', form.Value, 'max_idle_time', _('Idle timeout'),
|
||||
_('In seconds.'));
|
||||
o.placeholder = '15000';
|
||||
o.validate = hm.validateTimeDuration;
|
||||
o.depends({type: /^(tuic|shadowquic)$/});
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_general', form.MultiValue, 'network', _('Network type'));
|
||||
@@ -682,6 +634,111 @@ function renderListeners(s, uciconfig, isClient) {
|
||||
o.depends({type: /^(socks|mixed|shadowsocks|snell)$/});
|
||||
o.modalonly = true;
|
||||
|
||||
/* Plugin fields */
|
||||
o = s.taboption('field_general', form.Flag, 'plugin', _('Plugin'));
|
||||
o.default = o.disabled;
|
||||
o.depends({type: /^(shadowsocks|snell)$/});
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_plugin', form.ListValue, 'plugin_type', _('Plugin type'));
|
||||
o.value('obfs', _('obfs-simple'));
|
||||
o.value('shadow-tls', _('ShadowTLS'));
|
||||
o.value('restls', _('Restls'));
|
||||
o.value('jls', _('JLS'));
|
||||
//o.value('kcp-tun', _('kcp-tun'));
|
||||
o.validate = function(section_id, value) {
|
||||
const type = this.section.getOption('type').formvalue(section_id);
|
||||
|
||||
if (value) {
|
||||
if (type === 'snell' && !['obfs', 'shadow-tls'].includes(value)) {
|
||||
return _('Expecting: only support %s.').format(_('obfs-simple') +
|
||||
' / ' + _('ShadowTLS'));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
o.depends('plugin', '1');
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_plugin', form.ListValue, 'plugin_opts_obfsmode', _('Obfs Mode'));
|
||||
o.value('http', _('HTTP'));
|
||||
o.value('tls', _('TLS'));
|
||||
o.depends('plugin_type', 'obfs');
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_plugin', form.Value, 'plugin_opts_host', _('Host that supports TLS 1.3'));
|
||||
o.datatype = 'hostname';
|
||||
o.placeholder = 'cloud.tencent.com';
|
||||
o.rmempty = false;
|
||||
o.depends({plugin_type: 'obfs', type: 'snell'});
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_plugin', form.Value, 'plugin_opts_handshake_dest', _('Handshake target that supports TLS 1.3'));
|
||||
o.datatype = 'hostport';
|
||||
o.placeholder = 'cloud.tencent.com:443';
|
||||
o.rmempty = false;
|
||||
o.depends({plugin_type: /^(shadow-tls|restls|jls)$/});
|
||||
o.depends({type: 'shadowquic'});
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_plugin', form.Value, 'plugin_opts_thetlsusername', _('Username'));
|
||||
o.validate = hm.validateAuthUsername;
|
||||
o.rmempty = false;
|
||||
o.depends({plugin_type: 'jls'});
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_plugin', hm.GenValue, 'plugin_opts_thetlspassword', _('Password'));
|
||||
o.password = true;
|
||||
o.rmempty = false;
|
||||
o.depends({plugin_type: /^(shadow-tls|restls|jls)$/});
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_plugin', form.ListValue, 'plugin_opts_shadowtls_version', _('Version'));
|
||||
o.value('1', _('v1'));
|
||||
o.value('2', _('v2'));
|
||||
o.value('3', _('v3'));
|
||||
o.default = '3';
|
||||
o.depends({plugin_type: 'shadow-tls'});
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_plugin', form.Value, 'plugin_opts_restls_script', _('Restls script'));
|
||||
o.default = '300?100<1,400~100,350~100,600~100,300~200,300~100';
|
||||
o.rmempty = false;
|
||||
o.depends({plugin_type: 'restls'});
|
||||
o.modalonly = true;
|
||||
|
||||
if (isClient) {
|
||||
o = s.taboption('field_plugin', form.ListValue, 'plugin_opts_dest_proxy', _('Handshake target proxy'),
|
||||
_('The proxy used to connect to the handshake target.'));
|
||||
o.default = hm.preset_outbound.direct[0][0];
|
||||
hm.preset_outbound.direct.forEach((res) => {
|
||||
o.value.apply(o, res);
|
||||
})
|
||||
o.load = function(section_id) {
|
||||
return hm.loadLabel.call(this, [
|
||||
...hm.preset_outbound.direct,
|
||||
...hm.loadLabelValues(this.config, 'proxy_group')
|
||||
], section_id);
|
||||
}
|
||||
o.depends({plugin_type: /^(restls|jls)$/});
|
||||
o.depends({type: 'shadowquic'});
|
||||
o.modalonly = true;
|
||||
}
|
||||
|
||||
o = s.taboption('field_plugin', form.Value, 'plugin_opts_rate_limit', _('Forwarding rate limit'),
|
||||
_('In bps. 0 means no speed limit.'));
|
||||
o.datatype = 'uinteger';
|
||||
o.depends({plugin_type: 'jls'});
|
||||
o.depends({type: 'shadowquic'});
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_plugin', form.Flag, 'plugin_opts_quic_version_probe', _('QUIC version probe'),
|
||||
_('Probe the QUIC version of the handshake target during the first connection.'));
|
||||
o.default = o.disabled;
|
||||
o.depends({type: 'shadowquic'});
|
||||
o.modalonly = true;
|
||||
|
||||
/* Vless Encryption fields */
|
||||
o = s.taboption('field_general', form.Flag, 'vless_decryption', _('decryption'));
|
||||
o.default = o.disabled;
|
||||
@@ -925,7 +982,7 @@ function renderListeners(s, uciconfig, isClient) {
|
||||
o.depends('hysteria2_realm', '1');
|
||||
o.modalonly = true;
|
||||
|
||||
// @ 下面支持填写针对server-url的TLS配置(sni, skip-cert-verify, fingerprint, certificate, private-key, alpn)
|
||||
// @ 下面支持填写针对server-url的TLS配置(sni, skip-cert-verify, name-cert-verify, fingerprint, certificate, private-key, alpn)
|
||||
|
||||
/* TLS fields */
|
||||
o = s.taboption('field_general', form.Flag, 'tls', _('TLS'));
|
||||
@@ -934,24 +991,65 @@ function renderListeners(s, uciconfig, isClient) {
|
||||
const type = this.section.getOption('type').formvalue(section_id);
|
||||
let tls = this.section.getUIElement(section_id, 'tls').node.querySelector('input');
|
||||
let allow_insecure = this.section.getUIElement(section_id, 'allow_insecure').node.querySelector('input');
|
||||
let tls_alpn = this.section.getUIElement(section_id, 'tls_alpn');
|
||||
let tls_reality = this.section.getUIElement(section_id, 'tls_reality').node.querySelector('input');
|
||||
|
||||
// Force enabled
|
||||
if (['trojan', 'anytls', 'tuic', 'hysteria2', 'trusttunnel'].includes(type)) {
|
||||
if (['trojan', 'anytls', 'tuic', 'hysteria2', 'shadowquic', 'trusttunnel'].includes(type)) {
|
||||
tls.checked = true;
|
||||
tls.disabled = true;
|
||||
} else {
|
||||
tls.removeAttribute('disabled');
|
||||
}
|
||||
|
||||
// Force disabled
|
||||
if (!['vless', 'trojan', 'anytls'].includes(type)) {
|
||||
allow_insecure.checked = false;
|
||||
} else if (allow_insecure.checked) {
|
||||
tls.checked = false;
|
||||
tls.disabled = true;
|
||||
}
|
||||
if (!['vmess', 'vless', 'trojan'].includes(type)) {
|
||||
tls_reality.checked = false;
|
||||
tls_reality.disabled = true;
|
||||
} else {
|
||||
tls_reality.removeAttribute('disabled');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
o.depends({type: /^(http|socks|mixed|vmess|vless|trojan|anytls|tuic|hysteria2|hysteria2-realm|shadowquic|trusttunnel)$/});
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_general', form.Flag, 'allow_insecure', _('Allow insecure connections'),
|
||||
_('Only applicable when %s are used as a frontend.').format('nginx/caddy'));
|
||||
o.default = o.disabled;
|
||||
o.depends({type: /^(vless|trojan|anytls)$/});
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_tls', form.Value, 'tls_sni', _('TLS SNI'),
|
||||
_('Hostname that the client attempts to connect to at the start of the TLS handshake process.'));
|
||||
o.depends('plugin_type', 'jls');
|
||||
o.depends({tls: '1', type: 'shadowquic'});
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_tls', form.DynamicList, 'tls_alpn', _('TLS ALPN'),
|
||||
_('List of supported application level protocols, in order of preference.'));
|
||||
o.validate = function(section_id, value) {
|
||||
const type = this.section.getOption('type').formvalue(section_id);
|
||||
//const plugin_type = this.section.getOption('plugin_type').formvalue(section_id);
|
||||
let tls_alpn = this.section.getUIElement(section_id, 'tls_alpn');
|
||||
|
||||
// Default alpn
|
||||
if (!`${tls_alpn.getValue()}`) {
|
||||
let def_alpn;
|
||||
|
||||
switch (type) {
|
||||
case 'shadowsocks':
|
||||
def_alpn = ['h2', 'http/1.1']; // when plugin_type in ['jls']
|
||||
break;
|
||||
case 'tuic':
|
||||
case 'hysteria2':
|
||||
case 'shadowquic':
|
||||
def_alpn = ['h3'];
|
||||
break;
|
||||
case 'hysteria2-realm':
|
||||
@@ -965,45 +1063,23 @@ function renderListeners(s, uciconfig, isClient) {
|
||||
}
|
||||
|
||||
// Force disabled
|
||||
if (!['vless', 'trojan', 'anytls'].includes(type)) {
|
||||
allow_insecure.checked = false;
|
||||
} else if (allow_insecure.checked) {
|
||||
tls.checked = false;
|
||||
tls.disabled = true;
|
||||
}
|
||||
if (['trusttunnel'].includes(type)) {
|
||||
tls_alpn.node.querySelector('input').disabled = true;
|
||||
tls_alpn.setValue('');
|
||||
} else {
|
||||
tls_alpn.node.querySelector('input').removeAttribute('disabled');
|
||||
}
|
||||
if (!['vmess', 'vless', 'trojan'].includes(type)) {
|
||||
tls_reality.checked = false;
|
||||
tls_reality.disabled = true;
|
||||
} else {
|
||||
tls_reality.removeAttribute('disabled');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
o.depends({type: /^(http|socks|mixed|vmess|vless|trojan|anytls|tuic|hysteria2|hysteria2-realm|trusttunnel)$/});
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_general', form.Flag, 'allow_insecure', _('Allow insecure connections'),
|
||||
_('Only applicable when %s are used as a frontend.').format('nginx/caddy'));
|
||||
o.default = o.disabled;
|
||||
o.depends({type: /^(vless|trojan|anytls)$/});
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_tls', form.DynamicList, 'tls_alpn', _('TLS ALPN'),
|
||||
_('List of supported application level protocols, in order of preference.'));
|
||||
o.depends('tls', '1');
|
||||
o.depends({type: 'shadowsocks', plugin_type: 'jls'});
|
||||
o.modalonly = true;
|
||||
|
||||
o = s.taboption('field_tls', form.Value, 'tls_cert_path', _('Certificate path'),
|
||||
_('The %s public key, in PEM format.').format(_('Server')));
|
||||
o.value('/etc/fchomo/certs/server_publickey.pem');
|
||||
o.depends({tls: '1', tls_reality: '0'});
|
||||
o.depends({tls: '1', tls_reality: '0', type: /^(http|socks|mixed|vmess|vless|trojan|anytls|tuic|hysteria2|hysteria2-realm|trusttunnel)$/});
|
||||
o.rmempty = false;
|
||||
o.modalonly = true;
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ const parseProviderYaml = hm.parseYaml.extend({
|
||||
if (!cfg.type)
|
||||
return null;
|
||||
|
||||
// key mapping // 2026/06/06
|
||||
// key mapping // 2026/07/12
|
||||
let config = hm.removeBlankAttrs({
|
||||
id: this.id,
|
||||
label: this.label,
|
||||
@@ -130,6 +130,8 @@ const parseProviderYaml = hm.parseYaml.extend({
|
||||
override_prefix: this.jq(cfg, "override.additional-prefix"),
|
||||
override_suffix: this.jq(cfg, "override.additional-suffix"),
|
||||
override_replace: (this.jq(cfg, "override.proxy-name") || []).map((obj) => JSON.stringify(obj)), // array.string: array.object
|
||||
// Programmable replacement
|
||||
override_expr: this.jq(cfg, "override.override-expr") || [], // array.string
|
||||
// Other configuration items
|
||||
override_tfo: this.bool2str(this.jq(cfg, "override.tfo")), // bool
|
||||
override_mptcp: this.bool2str(this.jq(cfg, "override.mptcp")), // bool
|
||||
@@ -137,6 +139,7 @@ const parseProviderYaml = hm.parseYaml.extend({
|
||||
override_uot: this.bool2str(this.jq(cfg, "override.udp-over-tcp")), // bool
|
||||
override_up: this.jq(cfg, "override.up"),
|
||||
override_down: this.jq(cfg, "override.down"),
|
||||
override_name_cert_verify: this.jq(cfg, "override.name-cert-verify"),
|
||||
override_skip_cert_verify: this.bool2str(this.jq(cfg, "override.skip-cert-verify")), // bool
|
||||
//override_dialer_proxy: this.jq(cfg, "override.dialer-proxy"),
|
||||
override_interface_name: this.jq(cfg, "override.interface-name"),
|
||||
@@ -231,6 +234,7 @@ return view.extend({
|
||||
ss.hm_lowcase_only = true;
|
||||
|
||||
ss.tab('field_general', _('General fields'));
|
||||
ss.tab('field_plugin', _('Plugin fields'));
|
||||
ss.tab('field_vless_encryption', _('Vless Encryption fields'));
|
||||
ss.tab('field_hysteria2_realm', _('Hysteria2 Realm fields'));
|
||||
ss.tab('field_tls', _('TLS fields'));
|
||||
@@ -300,13 +304,13 @@ return view.extend({
|
||||
/* hm.validateAuth */
|
||||
so = ss.taboption('field_general', form.Value, 'username', _('Username'));
|
||||
so.validate = hm.validateAuthUsername;
|
||||
so.depends({type: /^(http|socks5|mieru|trusttunnel|ssh)$/});
|
||||
so.depends({type: /^(http|socks5|mieru|shadowquic|trusttunnel|ssh)$/});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_general', form.Value, 'password', _('Password'));
|
||||
so.password = true;
|
||||
so.validate = hm.validateAuthPassword;
|
||||
so.depends({type: /^(http|socks5|mieru|trojan|anytls|tuic|hysteria2|trusttunnel|ssh)$/});
|
||||
so.depends({type: /^(http|socks5|mieru|trojan|anytls|tuic|hysteria2|shadowquic|trusttunnel|ssh)$/});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_general', hm.TextValue, 'headers', _('HTTP header'));
|
||||
@@ -663,12 +667,6 @@ return view.extend({
|
||||
so.depends('type', 'tuic');
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_general', form.Value, 'tuic_max_open_streams', _('Max open streams'));
|
||||
so.datatype = 'uinteger';
|
||||
so.placeholder = '100';
|
||||
so.depends('type', 'tuic');
|
||||
so.modalonly = true;
|
||||
|
||||
/* Hysteria / Hysteria2 fields */
|
||||
so = ss.taboption('field_general', form.DynamicList, 'hysteria_ports', _('Ports pool'));
|
||||
so.datatype = 'or(port, portrange)';
|
||||
@@ -729,6 +727,31 @@ return view.extend({
|
||||
so.depends('type', 'trusttunnel');
|
||||
so.modalonly = true;
|
||||
|
||||
/* ShadowQUIC fields */
|
||||
so = ss.taboption('field_general', form.DynamicList, 'shadowquic_quic_versions', _('QUIC versions'),
|
||||
_('Support %s, default %s.').format('v1/v2', 'v1'));
|
||||
so.default = 'v1';
|
||||
so.rmempty = false;
|
||||
so.depends('type', 'shadowquic');
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_general', form.Flag, 'shadowquic_udp_over_stream', _('UDP over stream'));
|
||||
so.default = so.disabled;
|
||||
so.depends('type', 'shadowquic');
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_general', form.Flag, 'shadowquic_zero_rtt', _('QUIC based 0-RTT'));
|
||||
so.default = so.disabled;
|
||||
so.depends('type', 'shadowquic');
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_general', form.Value, 'shadowquic_heartbeat', _('Heartbeat interval'),
|
||||
_('In millisecond.'));
|
||||
so.datatype = 'uinteger';
|
||||
so.placeholder = '10000';
|
||||
so.depends('type', 'shadowquic');
|
||||
so.modalonly = true;
|
||||
|
||||
/* WireGuard fields */
|
||||
so = ss.taboption('field_general', form.Value, 'wireguard_ip', _('Local address'),
|
||||
_('The %s address used by local machine in the Wireguard network.').format('IPv4'));
|
||||
@@ -888,76 +911,13 @@ return view.extend({
|
||||
so.depends({type: 'ssh', ssh_host_key_algorithms: /.+/});
|
||||
so.modalonly = true;
|
||||
|
||||
/* Plugin fields */
|
||||
so = ss.taboption('field_general', form.ListValue, 'plugin', _('Plugin'));
|
||||
so.value('', _('none'));
|
||||
so.value('obfs', _('obfs-simple'));
|
||||
//so.value('v2ray-plugin', _('v2ray-plugin'));
|
||||
//so.value('gost-plugin', _('gost-plugin'));
|
||||
so.value('shadow-tls', _('shadow-tls'));
|
||||
so.value('restls', _('restls'));
|
||||
//so.value('kcptun', _('kcptun'));
|
||||
so.validate = function(section_id, value) {
|
||||
const type = this.section.getOption('type').formvalue(section_id);
|
||||
|
||||
if (value) {
|
||||
if (type === 'snell' && !['obfs', 'shadow-tls'].includes(value)) {
|
||||
return _('Expecting: only support %s.').format(_('obfs-simple') +
|
||||
' / ' + _('shadow-tls'));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
so.depends({type: /^(ss|snell)$/});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_general', form.ListValue, 'plugin_opts_obfsmode', _('Plugin: ') + _('Obfs Mode'));
|
||||
so.value('http', _('HTTP'));
|
||||
so.value('tls', _('TLS'));
|
||||
so.depends('plugin', 'obfs');
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_general', form.Value, 'plugin_opts_host', _('Plugin: ') + _('Host that supports TLS 1.3'));
|
||||
so.datatype = 'hostname';
|
||||
so.placeholder = 'cloud.tencent.com';
|
||||
so.rmempty = false;
|
||||
so.depends({plugin: /^(obfs|v2ray-plugin|shadow-tls|restls)$/});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_general', form.Value, 'plugin_opts_thetlspassword', _('Plugin: ') + _('Password'));
|
||||
so.password = true;
|
||||
so.rmempty = false;
|
||||
so.depends({plugin: /^(shadow-tls|restls)$/});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_general', form.ListValue, 'plugin_opts_shadowtls_version', _('Plugin: ') + _('Version'));
|
||||
so.value('1', _('v1'));
|
||||
so.value('2', _('v2'));
|
||||
so.value('3', _('v3'));
|
||||
so.default = '2';
|
||||
so.depends({plugin: 'shadow-tls'});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_general', form.Value, 'plugin_opts_restls_versionhint', _('Plugin: ') + _('Version hint'));
|
||||
so.default = 'tls13';
|
||||
so.rmempty = false;
|
||||
so.depends({plugin: 'restls'});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_general', form.Value, 'plugin_opts_restls_script', _('Plugin: ') + _('Restls script'));
|
||||
so.default = '300?100<1,400~100,350~100,600~100,300~200,300~100';
|
||||
so.rmempty = false;
|
||||
so.depends({plugin: 'restls'});
|
||||
so.modalonly = true;
|
||||
|
||||
/* Extra fields */
|
||||
so = ss.taboption('field_general', form.ListValue, 'congestion_controller', _('Congestion controller'));
|
||||
so.default = hm.congestion_controller[0][0];
|
||||
hm.congestion_controller.forEach((res) => {
|
||||
so.value.apply(so, res);
|
||||
})
|
||||
so.depends({type: /^(tuic|trusttunnel)$/});
|
||||
so.depends({type: /^(tuic|shadowquic|trusttunnel)$/});
|
||||
so.depends({type: 'masque', masque_network: /^(|h3-l4proxy)$/});
|
||||
so.modalonly = true;
|
||||
|
||||
@@ -966,8 +926,14 @@ return view.extend({
|
||||
hm.bbr_profiles.forEach((res) => {
|
||||
so.value.apply(so, res);
|
||||
})
|
||||
so.depends({congestion_controller: 'bbr'});
|
||||
so.depends({type: 'hysteria2'});
|
||||
so.depends('congestion_controller', 'bbr');
|
||||
so.depends('type', 'hysteria2');
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_general', form.Value, 'max_open_streams', _('Max open streams'));
|
||||
so.datatype = 'uinteger';
|
||||
so.placeholder = '1024';
|
||||
so.depends({type: /^(tuic|shadowquic)$/});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_general', form.Value, 'handshake_timeout', _('Handshake timeout'),
|
||||
@@ -997,6 +963,80 @@ return view.extend({
|
||||
so.depends('uot', '1');
|
||||
so.modalonly = true;
|
||||
|
||||
/* Plugin fields */
|
||||
so = ss.taboption('field_general', form.Flag, 'plugin', _('Plugin'));
|
||||
so.default = so.disabled;
|
||||
so.depends({type: /^(ss|snell)$/});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_plugin', form.ListValue, 'plugin_type', _('Plugin type'));
|
||||
so.value('obfs', _('obfs-simple'));
|
||||
//so.value('v2ray-plugin', _('v2ray-plugin'));
|
||||
//so.value('gost-plugin', _('gost-plugin'));
|
||||
so.value('shadow-tls', _('ShadowTLS'));
|
||||
so.value('restls', _('Restls'));
|
||||
so.value('jls', _('JLS'));
|
||||
//so.value('kcptun', _('kcptun'));
|
||||
so.validate = function(section_id, value) {
|
||||
const type = this.section.getOption('type').formvalue(section_id);
|
||||
|
||||
if (value) {
|
||||
if (type === 'snell' && !['obfs', 'shadow-tls'].includes(value)) {
|
||||
return _('Expecting: only support %s.').format(_('obfs-simple') +
|
||||
' / ' + _('ShadowTLS'));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
so.depends('plugin', '1');
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_plugin', form.ListValue, 'plugin_opts_obfsmode', _('Obfs Mode'));
|
||||
so.value('http', _('HTTP'));
|
||||
so.value('tls', _('TLS'));
|
||||
so.depends('plugin_type', 'obfs');
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_plugin', form.Value, 'plugin_opts_host', _('Host that supports TLS 1.3'));
|
||||
so.datatype = 'hostname';
|
||||
so.placeholder = 'cloud.tencent.com';
|
||||
so.rmempty = false;
|
||||
so.depends({plugin_type: /^(obfs|v2ray-plugin|shadow-tls|restls|jls)$/});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_plugin', form.Value, 'plugin_opts_thetlsusername', _('Username'));
|
||||
so.validate = hm.validateAuthUsername;
|
||||
so.rmempty = false;
|
||||
so.depends({plugin_type: 'jls'});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_plugin', form.Value, 'plugin_opts_thetlspassword', _('Password'));
|
||||
so.password = true;
|
||||
so.rmempty = false;
|
||||
so.depends({plugin_type: /^(shadow-tls|restls|jls)$/});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_plugin', form.ListValue, 'plugin_opts_shadowtls_version', _('Version'));
|
||||
so.value('1', _('v1'));
|
||||
so.value('2', _('v2'));
|
||||
so.value('3', _('v3'));
|
||||
so.default = '2';
|
||||
so.depends({plugin_type: 'shadow-tls'});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_plugin', form.Value, 'plugin_opts_restls_versionhint', _('Version hint'));
|
||||
so.default = 'tls13';
|
||||
so.rmempty = false;
|
||||
so.depends({plugin_type: 'restls'});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_plugin', form.Value, 'plugin_opts_restls_script', _('Restls script'));
|
||||
so.default = '300?100<1,400~100,350~100,600~100,300~200,300~100';
|
||||
so.rmempty = false;
|
||||
so.depends({plugin_type: 'restls'});
|
||||
so.modalonly = true;
|
||||
|
||||
/* Vless Encryption fields */
|
||||
so = ss.taboption('field_general', form.Flag, 'vless_encryption', _('encryption'));
|
||||
so.default = so.disabled;
|
||||
@@ -1096,7 +1136,7 @@ return view.extend({
|
||||
so.depends('hysteria2_realm', '1');
|
||||
so.modalonly = true;
|
||||
|
||||
// @ 下面支持填写针对server-url的TLS配置(sni, skip-cert-verify, fingerprint, certificate, private-key, alpn)
|
||||
// @ 下面支持填写针对server-url的TLS配置(sni, skip-cert-verify, name-cert-verify, fingerprint, certificate, private-key, alpn)
|
||||
|
||||
/* TLS fields */
|
||||
so = ss.taboption('field_general', form.Flag, 'tls', _('TLS'));
|
||||
@@ -1106,7 +1146,7 @@ return view.extend({
|
||||
let tls = this.section.getUIElement(section_id, 'tls').node.querySelector('input');
|
||||
|
||||
// Force enabled
|
||||
if (['trojan', 'anytls', 'hysteria', 'hysteria2', 'tuic', 'trusttunnel', 'masque'].includes(type)) {
|
||||
if (['trojan', 'anytls', 'tuic', 'hysteria', 'hysteria2', 'shadowquic', 'trusttunnel', 'masque'].includes(type)) {
|
||||
tls.checked = true;
|
||||
tls.disabled = true;
|
||||
} else {
|
||||
@@ -1115,7 +1155,7 @@ return view.extend({
|
||||
|
||||
return true;
|
||||
}
|
||||
so.depends({type: /^(http|socks5|vmess|vless|trojan|anytls|tuic|hysteria|hysteria2|trusttunnel|masque)$/});
|
||||
so.depends({type: /^(http|socks5|vmess|vless|trojan|anytls|tuic|hysteria|hysteria2|shadowquic|trusttunnel|masque)$/});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_tls', form.Flag, 'tls_disable_sni', _('Disable SNI'),
|
||||
@@ -1125,8 +1165,8 @@ return view.extend({
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_tls', form.Value, 'tls_sni', _('TLS SNI'),
|
||||
_('Used to verify the hostname on the returned certificates.'));
|
||||
so.depends({tls: '1', type: /^(http|vmess|vless|trojan|anytls|hysteria|hysteria2|trusttunnel|masque)$/});
|
||||
_('Hostname that the client attempts to connect to at the start of the TLS handshake process.'));
|
||||
so.depends({tls: '1', type: /^(http|vmess|vless|trojan|anytls|hysteria|hysteria2|shadowquic|trusttunnel|masque)$/});
|
||||
so.depends({tls: '1', type: /^(tuic)$/, tls_disable_sni: '0'});
|
||||
so.modalonly = true;
|
||||
|
||||
@@ -1134,7 +1174,7 @@ return view.extend({
|
||||
_('List of supported application level protocols, in order of preference.'));
|
||||
so.validate = function(section_id, value) {
|
||||
const type = this.section.getOption('type').formvalue(section_id);
|
||||
//const plugin = this.section.getOption('plugin').formvalue(section_id);
|
||||
//const plugin_type = this.section.getOption('plugin_type').formvalue(section_id);
|
||||
let tls_alpn = this.section.getUIElement(section_id, 'tls_alpn');
|
||||
|
||||
// Default alpn
|
||||
@@ -1144,11 +1184,12 @@ return view.extend({
|
||||
switch (type) {
|
||||
case 'ss':
|
||||
case 'snell':
|
||||
def_alpn = ['h2', 'http/1.1']; // when plugin === 'shadow-tls'
|
||||
def_alpn = ['h2', 'http/1.1']; // when plugin_type in ['shadow-tls', 'jls']
|
||||
break;
|
||||
case 'tuic':
|
||||
case 'hysteria':
|
||||
case 'hysteria2':
|
||||
case 'shadowquic':
|
||||
def_alpn = ['h3'];
|
||||
break;
|
||||
case 'vmess':
|
||||
@@ -1171,8 +1212,9 @@ return view.extend({
|
||||
|
||||
return true;
|
||||
}
|
||||
so.depends({tls: '1', type: /^(vmess|vless|trojan|anytls|tuic|hysteria|hysteria2|trusttunnel)$/});
|
||||
so.depends({type: /^(ss|snell)$/, plugin: 'shadow-tls'});
|
||||
so.depends({tls: '1', type: /^(vmess|vless|trojan|anytls|tuic|hysteria|hysteria2|shadowquic|trusttunnel)$/});
|
||||
so.depends({type: /^(ss|snell)$/, plugin_type: 'shadow-tls'});
|
||||
so.depends({type: 'ss', plugin_type: 'jls'});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_tls', form.Value, 'tls_fingerprint', _('Cert fingerprint'),
|
||||
@@ -1188,6 +1230,12 @@ return view.extend({
|
||||
so.depends({tls: '1', type: /^(http|socks5|vmess|vless|trojan|hysteria|hysteria2)$/});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_tls', form.Value, 'tls_name_cert_verify', _('Override cert DNSName'),
|
||||
_('Used to verify the hostname on the returned certificates.'));
|
||||
so.datatype = 'hostname';
|
||||
so.depends({tls: '1', type: /^(http|socks5|vmess|vless|trojan|anytls|tuic|hysteria|hysteria2|trusttunnel)$/});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_tls', form.Flag, 'tls_skip_cert_verify', _('Skip cert verify'),
|
||||
_('Donot verifying server certificate.') +
|
||||
'<br/>' +
|
||||
@@ -1227,7 +1275,7 @@ return view.extend({
|
||||
so = ss.taboption('field_tls', form.Flag, 'tls_ech', _('Enable ECH'));
|
||||
so.default = so.disabled;
|
||||
so.depends({tls: '1', type: /^(vmess|vless|trojan|anytls|tuic|hysteria|hysteria2)$/});
|
||||
so.depends({type: 'ss', plugin: /^(v2ray-plugin|gost-plugin)$/});
|
||||
so.depends({type: 'ss', plugin_type: /^(v2ray-plugin|gost-plugin)$/});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_tls', form.Value, 'tls_ech_config', _('ECH config'),
|
||||
@@ -1248,7 +1296,8 @@ return view.extend({
|
||||
so.value.apply(so, res);
|
||||
})
|
||||
so.depends({tls: '1', type: /^(vmess|vless|trojan|anytls|trusttunnel)$/});
|
||||
so.depends({type: /^(ss|snell)$/, plugin: /^(shadow-tls|restls)$/});
|
||||
so.depends({type: /^(ss|snell)$/, plugin_type: /^(shadow-tls|restls)$/});
|
||||
so.depends({type: 'ss', plugin_type: 'jls'});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_tls', form.Flag, 'tls_reality', _('REALITY'));
|
||||
@@ -1638,6 +1687,7 @@ return view.extend({
|
||||
' udp-over-tcp: false\n' +
|
||||
' down: "50 Mbps"\n' +
|
||||
' up: "10 Mbps"\n' +
|
||||
' name-cert-verify: example.com\n' +
|
||||
' skip-cert-verify: true\n' +
|
||||
' dialer-proxy: proxy\n' +
|
||||
' interface-name: tailscale0\n' +
|
||||
@@ -1650,6 +1700,19 @@ return view.extend({
|
||||
' target: "TEST"\n' +
|
||||
' - pattern: "IPLC-(.*?)倍"\n' +
|
||||
' target: "iplc x $1"\n' +
|
||||
' override-expr:\n' +
|
||||
" - '.name = \"[provider1] \" + .name' # 普通赋值\n" +
|
||||
" - '.plugin-opts.mode = \"tls\"' # 自动创建缺失的 mapping\n" +
|
||||
" - '.alpn[] |= upcase' # 更新数组中的每一项\n" +
|
||||
" - 'del(.skip-cert-verify)' # 删除字段\n" +
|
||||
" - '.name = (.name | trim | upcase)' # 赋值右侧的管道需加括号\n" +
|
||||
" - '.name = \"[\\(.type)] \\(.name):\\(.port)\"' # 字符串插值\n" +
|
||||
" - '(select(.port == 443) | .tls) = true' # 条件不匹配时不修改\n" +
|
||||
" - '.tags |= (unique | sort)' # 去重后排序\n" +
|
||||
" - '.names = [.servers[] | select(.enabled) | .name]' # 收集多个结果\n" +
|
||||
" - '.servers |= map(select(.enabled))' # 筛选数组\n" +
|
||||
" - '.options |= with_entries(.key |= upcase)' # 转换 mapping\n" +
|
||||
" - '. | with_entries(.key |= upcase)' # 整体过滤结果仍须为 mapping\n" +
|
||||
' filter: "(?i)港|hk|hongkong|hong kong"\n' +
|
||||
' exclude-filter: "xxx"\n' +
|
||||
' exclude-type: "ss|http"\n' +
|
||||
@@ -1896,6 +1959,13 @@ return view.extend({
|
||||
so.depends({type: 'inline', '!reverse': true});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_override', form.DynamicList, 'override_expr', _('Programmable replacement'),
|
||||
_('For format see <a target="_blank" href="%s" rel="noreferrer noopener">%s</a>.')
|
||||
.format('https://wiki.metacubex.one/config/proxy-providers/#override_expr', _('override.override-expr')));
|
||||
so.placeholder = '.name = "[provider1] " + .name';
|
||||
so.depends({type: 'inline', '!reverse': true});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_override', form.DummyValue, '_config_items', null);
|
||||
so.load = function() {
|
||||
return '<a target="_blank" href="%s" rel="noreferrer noopener">%s</a>'
|
||||
@@ -1938,6 +2008,12 @@ return view.extend({
|
||||
so.depends({type: 'inline', '!reverse': true});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_override', form.Value, 'override_name_cert_verify', _('Override cert DNSName'),
|
||||
_('Used to verify the hostname on the returned certificates.'));
|
||||
so.datatype = 'hostname';
|
||||
so.depends({type: 'inline', '!reverse': true});
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.taboption('field_override', form.ListValue, 'override_skip_cert_verify', _('Skip cert verify'),
|
||||
_('Donot verifying server certificate.') +
|
||||
'<br/>' +
|
||||
|
||||
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
@@ -0,0 +1,41 @@
|
||||
#!/bin/sh
|
||||
# Migration script for fchomo inbound
|
||||
# Used to migrate LuCI application inbound option.
|
||||
|
||||
. /lib/functions.sh
|
||||
. /usr/share/libubox/jshn.sh
|
||||
|
||||
CONF=fchomo
|
||||
|
||||
config_load "$CONF"
|
||||
|
||||
# isDefined <section> <option>
|
||||
isDefined() {
|
||||
local opt=CONFIG_${1}_${2};
|
||||
|
||||
eval "[ -n \"\${$opt+x}\" ] && return 0 || return 1"
|
||||
}
|
||||
|
||||
migrate() {
|
||||
# tuic_max_idle_time -> max_idle_time
|
||||
if isDefined "$1" tuic_max_idle_time; then
|
||||
local tuic_max_idle_time
|
||||
config_get tuic_max_idle_time "$1" tuic_max_idle_time ""
|
||||
uci_remove "$CONF" "$1" tuic_max_idle_time
|
||||
uci_set "$CONF" "$1" max_idle_time "$tuic_max_idle_time"
|
||||
fi
|
||||
|
||||
# plugin -> plugin_type
|
||||
if isDefined "$1" plugin; then
|
||||
local plugin
|
||||
config_get plugin "$1" plugin ""
|
||||
uci_set "$CONF" "$1" plugin "1"
|
||||
uci_set "$CONF" "$1" plugin_type "$plugin"
|
||||
fi
|
||||
}
|
||||
|
||||
config_foreach migrate inbound
|
||||
|
||||
uci_commit "$CONF"
|
||||
|
||||
exit 0
|
||||
@@ -50,6 +50,22 @@ migrate() {
|
||||
uci_remove "$CONF" "$1" masque_congestion_controller
|
||||
uci_set "$CONF" "$1" congestion_controller "$masque_congestion_controller"
|
||||
fi
|
||||
|
||||
# tuic_max_open_streams -> max_open_streams
|
||||
if isDefined "$1" tuic_max_open_streams; then
|
||||
local tuic_max_open_streams
|
||||
config_get tuic_max_open_streams "$1" tuic_max_open_streams ""
|
||||
uci_remove "$CONF" "$1" tuic_max_open_streams
|
||||
uci_set "$CONF" "$1" max_open_streams "$tuic_max_open_streams"
|
||||
fi
|
||||
|
||||
# plugin -> plugin_type
|
||||
if isDefined "$1" plugin; then
|
||||
local plugin
|
||||
config_get plugin "$1" plugin ""
|
||||
uci_set "$CONF" "$1" plugin "1"
|
||||
uci_set "$CONF" "$1" plugin_type "$plugin"
|
||||
fi
|
||||
}
|
||||
|
||||
config_foreach migrate node
|
||||
|
||||
@@ -24,6 +24,22 @@ migrate() {
|
||||
uci_remove "$CONF" "$1" tuic_congestion_controller
|
||||
uci_set "$CONF" "$1" congestion_controller "$tuic_congestion_controller"
|
||||
fi
|
||||
|
||||
# tuic_max_idle_time -> max_idle_time
|
||||
if isDefined "$1" tuic_max_idle_time; then
|
||||
local tuic_max_idle_time
|
||||
config_get tuic_max_idle_time "$1" tuic_max_idle_time ""
|
||||
uci_remove "$CONF" "$1" tuic_max_idle_time
|
||||
uci_set "$CONF" "$1" max_idle_time "$tuic_max_idle_time"
|
||||
fi
|
||||
|
||||
# plugin -> plugin_type
|
||||
if isDefined "$1" plugin; then
|
||||
local plugin
|
||||
config_get plugin "$1" plugin ""
|
||||
uci_set "$CONF" "$1" plugin "1"
|
||||
uci_set "$CONF" "$1" plugin_type "$plugin"
|
||||
fi
|
||||
}
|
||||
|
||||
config_foreach migrate server
|
||||
|
||||
@@ -121,7 +121,7 @@ function parse_filter(cfg) {
|
||||
return cfg;
|
||||
}
|
||||
|
||||
function get_proxy(cfg, pass_undefined) {
|
||||
function get_proxy(cfg, no_verify) {
|
||||
if (isEmpty(cfg))
|
||||
return null;
|
||||
|
||||
@@ -130,7 +130,7 @@ function get_proxy(cfg, pass_undefined) {
|
||||
|
||||
const label = uci.get(uciconf, cfg, 'label');
|
||||
if (isEmpty(label)) {
|
||||
if (pass_undefined)
|
||||
if (no_verify)
|
||||
return cfg;
|
||||
else
|
||||
die(sprintf("%s's label is missing, please check your configuration.", cfg));
|
||||
@@ -343,7 +343,16 @@ uci.foreach(uciconf, uciinbd, (cfg) => {
|
||||
if (cfg.enabled === '0')
|
||||
return;
|
||||
|
||||
push(config.listeners, parseListener(cfg, true, get_proxy(cfg.proxy)));
|
||||
const listener = parseListener(cfg);
|
||||
listener.proxy = get_proxy(listener.proxy);
|
||||
if (listener["res-tls"])
|
||||
listener["res-tls"].proxy = get_proxy(listener["res-tls"].proxy);
|
||||
if (listener["jls-config"])
|
||||
listener["jls-config"].proxy = get_proxy(listener["jls-config"].proxy);
|
||||
if (listener["jls-upstream"])
|
||||
listener["jls-upstream"].proxy = get_proxy(listener["jls-upstream"].proxy);
|
||||
|
||||
push(config.listeners, listener);
|
||||
});
|
||||
/* Tun settings */
|
||||
if (match(proxy_mode, /tun/))
|
||||
@@ -490,7 +499,7 @@ uci.foreach(uciconf, ucinode, (cfg) => {
|
||||
"target-rematch-name": cfg.target_rematch_name,
|
||||
"target-sub-rule": cfg.target_sub_rule,
|
||||
|
||||
/* HTTP / SOCKS / Shadowsocks / VMess / VLESS / Trojan / TUIC / hysteria2 / WireGuard / Masque */
|
||||
/* HTTP / SOCKS / Shadowsocks / VMess / VLESS / Trojan / TUIC / hysteria2 / ShadowQUIC / WireGuard / Masque */
|
||||
username: cfg.username,
|
||||
uuid: cfg.vmess_uuid || cfg.uuid,
|
||||
cipher: cfg.vmess_chipher || cfg.shadowsocks_chipher,
|
||||
@@ -558,14 +567,11 @@ uci.foreach(uciconf, ucinode, (cfg) => {
|
||||
/* TUIC */
|
||||
ip: cfg.tuic_ip,
|
||||
"udp-relay-mode": cfg.tuic_udp_relay_mode,
|
||||
"udp-over-stream": strToBool(cfg.tuic_udp_over_stream),
|
||||
"udp-over-stream-version": cfg.tuic_udp_over_stream_version,
|
||||
"max-udp-relay-packet-size": strToInt(cfg.tuic_max_udp_relay_packet_size) || null,
|
||||
"fast-open": strToBool(cfg.tuic_fast_open),
|
||||
"reduce-rtt": strToBool(cfg.tuic_reduce_rtt),
|
||||
"heartbeat-interval": strToInt(cfg.tuic_heartbeat) || null,
|
||||
"request-timeout": strToInt(cfg.tuic_request_timeout) || null,
|
||||
"max-open-streams": strToInt(cfg.tuic_max_open_streams) || null,
|
||||
|
||||
/* Hysteria / Hysteria2 */
|
||||
ports: isEmpty(cfg.hysteria_ports) ? null : join(',', cfg.hysteria_ports),
|
||||
@@ -591,6 +597,15 @@ uci.foreach(uciconf, ucinode, (cfg) => {
|
||||
//"private-key"
|
||||
} : null,
|
||||
|
||||
/* ShadowQUIC */
|
||||
"quic-versions": cfg.shadowquic_quic_versions,
|
||||
"zero-rtt": strToBool(cfg.shadowquic_zero_rtt),
|
||||
// @# cwnd: 10 # default: 32,
|
||||
// @# max-datagram-frame-size: 1400,
|
||||
// @# recv-window-conn: 0,
|
||||
// @# recv-window: 0,
|
||||
// @# disable-mtu-discovery: false,
|
||||
|
||||
/* TrustTunnel */
|
||||
"health-check": cfg.type === 'trusttunnel' ? (cfg.trusttunnel_health_check === '0' ? false : true) : null,
|
||||
quic: strToBool(cfg.trusttunnel_quic),
|
||||
@@ -609,12 +624,25 @@ uci.foreach(uciconf, ucinode, (cfg) => {
|
||||
"host-key-algorithms": cfg.ssh_host_key_algorithms,
|
||||
"host-key": cfg.ssh_host_key,
|
||||
|
||||
/* Extra fields */
|
||||
"udp-over-stream": strToBool(cfg.shadowquic_udp_over_stream || cfg.tuic_udp_over_stream),
|
||||
"heartbeat-interval": strToInt(cfg.tuic_heartbeat) || null,
|
||||
"keep-alive-interval": strToInt(cfg.shadowquic_heartbeat) || null,
|
||||
"congestion-controller": cfg.congestion_controller,
|
||||
"bbr-profile": cfg.bbr_profile,
|
||||
"max-open-streams": strToInt(cfg.max_open_streams) || null,
|
||||
|
||||
"handshake-timeout": strToInt(cfg.handshake_timeout),
|
||||
udp: strToBool(cfg.udp),
|
||||
"udp-over-tcp": strToBool(cfg.uot),
|
||||
"udp-over-tcp-version": cfg.uot_version,
|
||||
|
||||
/* Plugin fields */
|
||||
...(cfg.plugin ? (
|
||||
...(cfg.plugin === '1' ? (
|
||||
cfg.type === 'snell' ? {
|
||||
// snell
|
||||
"obfs-opts": {
|
||||
mode: cfg.plugin in ['shadow-tls'] ? cfg.plugin : cfg.plugin_opts_obfsmode,
|
||||
mode: cfg.plugin_type === 'shadow-tls' ? cfg.plugin_type : cfg.plugin_opts_obfsmode,
|
||||
host: cfg.plugin_opts_host,
|
||||
password: cfg.plugin_opts_thetlspassword,
|
||||
version: strToInt(cfg.plugin_opts_shadowtls_version),
|
||||
@@ -622,10 +650,11 @@ uci.foreach(uciconf, ucinode, (cfg) => {
|
||||
}
|
||||
} : {
|
||||
// others
|
||||
plugin: cfg.plugin,
|
||||
plugin: cfg.plugin_type,
|
||||
"plugin-opts": {
|
||||
mode: cfg.plugin_opts_obfsmode,
|
||||
host: cfg.plugin_opts_host,
|
||||
username: cfg.plugin_opts_thetlsusername,
|
||||
password: cfg.plugin_opts_thetlspassword,
|
||||
version: strToInt(cfg.plugin_opts_shadowtls_version),
|
||||
alpn: cfg.tls_alpn, // Array
|
||||
@@ -635,21 +664,14 @@ uci.foreach(uciconf, ucinode, (cfg) => {
|
||||
}
|
||||
) : {}),
|
||||
|
||||
/* Extra fields */
|
||||
"congestion-controller": cfg.congestion_controller,
|
||||
"bbr-profile": cfg.bbr_profile,
|
||||
"handshake-timeout": strToInt(cfg.handshake_timeout),
|
||||
udp: strToBool(cfg.udp),
|
||||
"udp-over-tcp": strToBool(cfg.uot),
|
||||
"udp-over-tcp-version": cfg.uot_version,
|
||||
|
||||
/* SSH / WireGuard / Masque */
|
||||
/* TLS fields */
|
||||
tls: (cfg.type in ['trojan', 'anytls', 'hysteria', 'hysteria2', 'tuic', 'trusttunnel']) ? null : strToBool(cfg.tls),
|
||||
tls: (cfg.type in ['trojan', 'anytls', 'tuic', 'hysteria', 'hysteria2', 'shadowquic', 'trusttunnel']) ? null : strToBool(cfg.tls),
|
||||
"disable-sni": strToBool(cfg.tls_disable_sni),
|
||||
...arrToObj([[(cfg.type in ['vmess', 'vless']) ? 'servername' : 'sni', cfg.tls_sni]]),
|
||||
fingerprint: cfg.tls_fingerprint,
|
||||
alpn: cfg.plugin in ['shadow-tls'] ? null : cfg.tls_alpn, // Array
|
||||
alpn: cfg.plugin_type in ['shadow-tls', 'jls'] ? null : cfg.tls_alpn, // Array
|
||||
"name-cert-verify": cfg.tls_name_cert_verify,
|
||||
"skip-cert-verify": strToBool(cfg.tls_skip_cert_verify),
|
||||
certificate: cfg.tls_cert_path, // mTLS
|
||||
"private-key": cfg.masque_private_key || cfg.wireguard_private_key || cfg.ssh_priv_key || cfg.tls_key_path, // mTLS/SSH/WireGuard/Masque
|
||||
@@ -827,11 +849,13 @@ uci.foreach(uciconf, uciprov, (cfg) => {
|
||||
"udp-over-tcp": strToBool(cfg.override_uot),
|
||||
up: cfg.override_up ? cfg.override_up + ' Mbps' : null,
|
||||
down: cfg.override_down ? cfg.override_down + ' Mbps' : null,
|
||||
"name-cert-verify": cfg.override_name_cert_verify,
|
||||
"skip-cert-verify": cfg.override_skip_cert_verify ? strToBool(cfg.override_skip_cert_verify) || false : null,
|
||||
"dialer-proxy": dialerproxy[cfg['.name']]?.detour,
|
||||
"interface-name": cfg.override_interface_name,
|
||||
"routing-mark": strToInt(cfg.override_routing_mark) || null,
|
||||
"ip-version": cfg.override_ip_version
|
||||
"ip-version": cfg.override_ip_version,
|
||||
"override-expr": cfg.override_expr
|
||||
},
|
||||
/* General fields */
|
||||
filter: parse_filter(cfg.filter),
|
||||
|
||||
@@ -53,7 +53,7 @@ uci.foreach(uciconf, uciserver, (cfg) => {
|
||||
if (cfg.enabled === '0')
|
||||
return;
|
||||
|
||||
push(config.listeners, parseListener(cfg, false));
|
||||
push(config.listeners, parseListener(cfg));
|
||||
});
|
||||
/* Inbound END */
|
||||
|
||||
|
||||
@@ -211,23 +211,21 @@ export function parseVlessEncryption(payload, side) {
|
||||
(isEmpty(content.keypairs) ? '' : '.' + join('.', map(content.keypairs, e => e[side]))); // Required
|
||||
};
|
||||
|
||||
export function parseListener(cfg, isClient, label) {
|
||||
export function parseListener(cfg) {
|
||||
return {
|
||||
name: cfg['.name'],
|
||||
type: cfg.type,
|
||||
|
||||
listen: cfg.listen || '::',
|
||||
port: strToInt(cfg.port),
|
||||
...(isClient ? {
|
||||
"routing-mark": strToInt(cfg.routing_mark) || null,
|
||||
rule: cfg.rule,
|
||||
proxy: label,
|
||||
} : {}),
|
||||
"routing-mark": strToInt(cfg.routing_mark) || null,
|
||||
rule: cfg.rule,
|
||||
proxy: cfg.proxy, // raw data need post-processing
|
||||
|
||||
/* HTTP / SOCKS / VMess / VLESS / Trojan / AnyTLS / Tuic / Hysteria2 */
|
||||
users: (cfg.type in ['http', 'socks', 'mixed', 'vmess', 'vless', 'trojan', 'trusttunnel']) ? [
|
||||
/* HTTP / SOCKS / Mieru / VMess / VLESS / Trojan / AnyTLS / Tuic / Hysteria2 / ShadowQUIC / TrustTunnel */
|
||||
users: (cfg.type in ['http', 'socks', 'mixed', 'vmess', 'vless', 'trojan', 'shadowquic', 'trusttunnel']) ? [
|
||||
(cfg.username || cfg.vmess_uuid) ? {
|
||||
/* HTTP / SOCKS */
|
||||
/* HTTP / SOCKS / Trojan / ShadowQUIC / TrustTunnel */
|
||||
username: cfg.username,
|
||||
password: cfg.password,
|
||||
|
||||
@@ -291,7 +289,6 @@ export function parseListener(cfg, isClient, label) {
|
||||
"padding-scheme": cfg.anytls_padding_scheme,
|
||||
|
||||
/* Tuic */
|
||||
"max-idle-time": durationToSecond(cfg.tuic_max_idle_time),
|
||||
"authentication-timeout": durationToSecond(cfg.tuic_authentication_timeout),
|
||||
"max-udp-relay-packet-size": strToInt(cfg.tuic_max_udp_relay_packet_size),
|
||||
|
||||
@@ -326,14 +323,38 @@ export function parseListener(cfg, isClient, label) {
|
||||
"trusted-proxy-header": cfg.hysteria2_realmserver_trusted_proxy_header,
|
||||
"realm-name-pattern": cfg.hysteria2_realmserver_realm_name_pattern,
|
||||
|
||||
/* ShadowQUIC */
|
||||
"quic-versions": cfg.shadowquic_quic_versions,
|
||||
"zero-rtt": strToBool(cfg.shadowquic_zero_rtt),
|
||||
"jls-upstream": cfg.type === 'shadowquic' ? {
|
||||
addr: cfg.plugin_opts_handshake_dest,
|
||||
sni: cfg.tls_sni,
|
||||
proxy: cfg.plugin_opts_dest_proxy, // raw data need post-processing
|
||||
"rate-limit": strToInt(cfg.plugin_opts_rate_limit),
|
||||
"quic-version-probe": strToBool(cfg.plugin_opts_quic_version_probe)
|
||||
} : null,
|
||||
// @# cwnd: 10 # default: 32,
|
||||
// @# max-datagram-frame-size: 1400,
|
||||
// @# recv-window-conn: 0,
|
||||
// @# recv-window: 0,
|
||||
// @# disable-mtu-discovery: false,
|
||||
|
||||
/* TrustTunnel */
|
||||
|
||||
/* Tunnel */
|
||||
target: cfg.tunnel_target,
|
||||
|
||||
/* Extra fields */
|
||||
"congestion-controller": cfg.congestion_controller,
|
||||
"bbr-profile": cfg.bbr_profile,
|
||||
"max-idle-time": durationToSecond(cfg.max_idle_time),
|
||||
|
||||
network: cfg.network,
|
||||
udp: cfg.udp === '0' ? false : true,
|
||||
|
||||
/* Plugin fields */
|
||||
...(cfg.plugin ? (
|
||||
cfg.plugin === 'obfs' ? (
|
||||
...(cfg.plugin === '1' ? (
|
||||
cfg.plugin_type === 'obfs' ? (
|
||||
// obfs-simple
|
||||
cfg.type === 'snell' ? {
|
||||
// snell
|
||||
@@ -348,7 +369,7 @@ export function parseListener(cfg, isClient, label) {
|
||||
mode: cfg.plugin_opts_obfsmode
|
||||
}
|
||||
}
|
||||
) : cfg.plugin === 'shadow-tls' ? {
|
||||
) : cfg.plugin_type === 'shadow-tls' ? {
|
||||
// shadow-tls
|
||||
"shadow-tls": {
|
||||
enable: true,
|
||||
@@ -365,7 +386,7 @@ export function parseListener(cfg, isClient, label) {
|
||||
dest: cfg.plugin_opts_handshake_dest
|
||||
}
|
||||
}
|
||||
} : cfg.plugin === 'restls' ? {
|
||||
} : cfg.plugin_type === 'restls' ? {
|
||||
// restls
|
||||
"res-tls": {
|
||||
enable: true,
|
||||
@@ -373,17 +394,27 @@ export function parseListener(cfg, isClient, label) {
|
||||
password: cfg.plugin_opts_thetlspassword,
|
||||
"restls-script": cfg.plugin_opts_restls_script,
|
||||
//"min-record-len": 0,
|
||||
//proxy: ""
|
||||
proxy: cfg.plugin_opts_dest_proxy // raw data need post-processing
|
||||
}
|
||||
} : cfg.plugin_type === 'jls' ? {
|
||||
// jls
|
||||
"jls-config": {
|
||||
enable: true,
|
||||
users: [
|
||||
{
|
||||
username: cfg.plugin_opts_thetlsusername,
|
||||
password: cfg.plugin_opts_thetlspassword
|
||||
}
|
||||
],
|
||||
dest: cfg.plugin_opts_handshake_dest,
|
||||
sni: cfg.tls_sni,
|
||||
alpn: cfg.tls_alpn,
|
||||
proxy: cfg.plugin_opts_dest_proxy, // raw data need post-processing
|
||||
"rate-limit": strToInt(cfg.plugin_opts_rate_limit)
|
||||
}
|
||||
} : {}
|
||||
) : {}),
|
||||
|
||||
/* Extra fields */
|
||||
"congestion-controller": cfg.congestion_controller,
|
||||
"bbr-profile": cfg.bbr_profile,
|
||||
network: cfg.network,
|
||||
udp: cfg.udp === '0' ? false : true,
|
||||
|
||||
/* TLS fields */
|
||||
...(cfg.allow_insecure === '1' ? { "allow-insecure": true } : cfg.tls === '1' ? {
|
||||
alpn: cfg.tls_alpn,
|
||||
|
||||
@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-xray
|
||||
PKG_VERSION:=3.7.1
|
||||
PKG_RELEASE:=5
|
||||
PKG_RELEASE:=6
|
||||
|
||||
PKG_LICENSE:=MPLv2
|
||||
PKG_LICENSE_FILES:=LICENSE
|
||||
|
||||
@@ -481,6 +481,7 @@
|
||||
|
||||
chain xray_output {
|
||||
type route hook output priority mangle {{ firewall_priority }}; policy accept;
|
||||
ct direction reply {{ counter }} accept comment "Xray reply to inbound connection"
|
||||
{% if (length(uids_direct) > 0): %}
|
||||
meta skuid { {{ join(", ", uids_direct) }} } {{ counter }} accept
|
||||
{% endif %}
|
||||
|
||||
+2
-2
@@ -10,12 +10,12 @@ include $(INCLUDE_DIR)/kernel.mk
|
||||
|
||||
PKG_NAME:=natflow
|
||||
PKG_VERSION:=20260531
|
||||
PKG_RELEASE:=47
|
||||
PKG_RELEASE:=48
|
||||
|
||||
PKG_SOURCE:=$(PKG_VERSION).tar.xz
|
||||
PKG_SOURCE_URL:=https://github.com/ptpt52/natflow.git
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_VERSION:=d86173db3839524e6125bc729866aefe2e18976c
|
||||
PKG_SOURCE_VERSION:=a850d7324770f8893ac7373f5fbcde7d61e51857
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_MAINTAINER:=Chen Minqiang <ptpt52@gmail.com>
|
||||
PKG_LICENSE:=GPL-2.0
|
||||
|
||||
Reference in new issue
Block a user