mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-07-27 02:11:19 +08:00
🎉 Sync 2026-07-14 20:29:41
This commit is contained in:
parent
9307433a4c
commit
09a1b41f45
@ -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
41
luci-app-fchomo/root/etc/uci-defaults/99_luci-app-fchomo-migration_inbound
Executable file
41
luci-app-fchomo/root/etc/uci-defaults/99_luci-app-fchomo-migration_inbound
Executable file
@ -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 %}
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user