🎉 Sync 2026-08-04 00:17:08

This commit is contained in:
github-actions[bot] committed 2026-08-04 00:17:08 +08:00
1 parent 6e23f4416b
commit e03a23fe6b
18 files changed
+352 -171

No files matched your search

+3 -3
View File
@@ -5,10 +5,10 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=dae PKG_NAME:=dae
PKG_VERSION:=2026.08.02 PKG_VERSION:=2026.08.03
PKG_RELEASE:=29 PKG_RELEASE:=30
PKG_SOURCE:=dae-src-2026.08.02-82d4db4266d3.tar.gz PKG_SOURCE:=dae-src-2026.08.03-354bb6787b4e.tar.gz
PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/dae-src PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/dae-src
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_HASH:=skip PKG_HASH:=skip
+3 -3
View File
@@ -5,10 +5,10 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=daed PKG_NAME:=daed
PKG_VERSION:=2026.08.02 PKG_VERSION:=2026.08.03
PKG_RELEASE:=39 PKG_RELEASE:=40
PKG_SOURCE:=daed-src-2026.08.02-9233e4ccf701.tar.gz PKG_SOURCE:=daed-src-2026.08.03-5f7939adc12a.tar.gz
PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/daed-src PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/daed-src
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
PKG_HASH:=skip PKG_HASH:=skip
+1
View File
@@ -64,6 +64,7 @@ endef
define Package/luci-app-fchomo/prerm define Package/luci-app-fchomo/prerm
#!/bin/sh #!/bin/sh
/etc/init.d/fchomo stop 2>/dev/null
uci delete firewall.fchomo_pre uci delete firewall.fchomo_pre
uci delete firewall.fchomo_post uci delete firewall.fchomo_post
uci commit firewall uci commit firewall
@@ -204,8 +204,8 @@ const outbound_type = [
['hysteria2', _('Hysteria2') + ' - ' + _('UDP')], ['hysteria2', _('Hysteria2') + ' - ' + _('UDP')],
['shadowquic', _('ShadowQUIC') + ' - ' + _('UDP')], ['shadowquic', _('ShadowQUIC') + ' - ' + _('UDP')],
['trusttunnel', _('TrustTunnel') + ' - ' + _('TCP/UDP')], ['trusttunnel', _('TrustTunnel') + ' - ' + _('TCP/UDP')],
['wireguard', _('WireGuard') + ' - ' + _('UDP')], ['wireguard', _('WireGuard') + ' - ' + _('UDP')], // Endpoint
['masque', _('Masque') + ' - ' + _('UDP')], // https://blog.cloudflare.com/post-quantum-warp/ ['masque', _('Masque') + ' - ' + _('UDP')], // Endpoint // https://blog.cloudflare.com/post-quantum-warp/
['ssh', _('SSH') + ' - ' + _('TCP')] ['ssh', _('SSH') + ' - ' + _('TCP')]
]; ];
@@ -1806,7 +1806,7 @@ function validateCommonPort(section_id, value) {
for (let custom of arr) { for (let custom of arr) {
if (!routing_port_type.map(e => e[0]).includes(custom)) { if (!routing_port_type.map(e => e[0]).includes(custom)) {
let ports = []; let ports = [];
for (let i of custom.split(',')) { for (let i of custom.split(this.hm_separator ?? ',')) {
if (!stubValidator.apply('port', i) && !stubValidator.apply('portrange', i)) if (!stubValidator.apply('port', i) && !stubValidator.apply('portrange', i))
return _('Expecting: %s').format(_('valid port value')); return _('Expecting: %s').format(_('valid port value'));
if (ports.includes(i)) if (ports.includes(i))
@@ -151,11 +151,11 @@ function renderListeners(s, uciconfig, isClient) {
o.placeholder = '::'; o.placeholder = '::';
o.modalonly = true; o.modalonly = true;
o = s.taboption('field_general', form.Value, 'port', _('Listen port') + ' / ' + _('Ports pool')); o = s.taboption('field_general', form.Value, 'listen_port', _('Listen port') + ' / ' + _('Ports pool'));
o.datatype = 'or(port, portrange)'; //o.datatype = 'or(port, portrange)'; // ⬇️ migrated to validate
//o.placeholder = '1080,2079-2080,3080'; // @fw4 does not support port lists with commas o.placeholder = '1080,2079-2080,3080';
o.rmempty = false; o.rmempty = false;
//o.validate = hm.validateCommonPort; // @fw4 does not support port lists with commas o.validate = hm.validateCommonPort;
/* HTTP / SOCKS fields */ /* HTTP / SOCKS fields */
/* hm.validateAuth */ /* hm.validateAuth */
@@ -595,11 +595,23 @@ function renderPayload(s, total, uciconfig) {
initPayload(o, n, 'factor', uciconfig); initPayload(o, n, 'factor', uciconfig);
o = s.option(form.Value, prefix + 'port', _('Factor') + ` ${n+1}`); o = s.option(form.Value, prefix + 'port', _('Factor') + ` ${n+1}`);
o.datatype = 'or(port, portrange)'; //o.datatype = 'or(port, portrange)'; // ⬇️ migrated to validate
o.placeholder = '1080/2079-2080/3080';
if (n === 0) if (n === 0)
o.depends({type: /\bPORT\b/}); o.depends({type: /\bPORT\b/});
o.depends(Object.fromEntries([[prefix + 'type', /\bPORT\b/]])); o.depends(Object.fromEntries([[prefix + 'type', /\bPORT\b/]]));
initPayload(o, n, 'factor', uciconfig); initPayload(o, n, 'factor', uciconfig);
// if validate is already defined in initPayload
const port_old_validate = o.validate;
o.validate = function(section_id, value) {
const result = port_old_validate.apply(this, arguments);
if (result === true) {
this.hm_separator = '/';
return hm.validateCommonPort.apply(this, arguments);
}
return result;
}
o = s.option(form.ListValue, prefix + 'l4', _('Factor') + ` ${n+1}`); o = s.option(form.ListValue, prefix + 'l4', _('Factor') + ` ${n+1}`);
o.value('udp', _('UDP')); o.value('udp', _('UDP'));
@@ -1919,7 +1931,7 @@ return view.extend({
_('Lazy query.')); _('Lazy query.'));
so.default = so.disabled; so.default = so.disabled;
so.validate = function(section_id, value) { so.validate = function(section_id, value) {
let desc = this.getUIElement(section_id).node.nextSibling; const desc = this.getUIElement(section_id).node.nextSibling;
value = this.formvalue(section_id); value = this.formvalue(section_id);
if (value == 1) if (value == 1)
@@ -823,7 +823,7 @@ return view.extend({
_('As the TOP upstream of dnsmasq.')); _('As the TOP upstream of dnsmasq.'));
so.default = so.disabled; so.default = so.disabled;
so.validate = function(section_id, value) { so.validate = function(section_id, value) {
let desc = this.getUIElement(section_id).node.nextSibling; const desc = this.getUIElement(section_id).node.nextSibling;
value = this.formvalue(section_id); value = this.formvalue(section_id);
if (value == 1) if (value == 1)
@@ -238,6 +238,7 @@ return view.extend({
ss.tab('field_vless_encryption', _('Vless Encryption fields')); ss.tab('field_vless_encryption', _('Vless Encryption fields'));
ss.tab('field_hysteria2_realm', _('Hysteria2 Realm fields')); ss.tab('field_hysteria2_realm', _('Hysteria2 Realm fields'));
ss.tab('field_tls', _('TLS fields')); ss.tab('field_tls', _('TLS fields'));
ss.tab('field_vpn', _('VPN fields'));
ss.tab('field_transport', _('Transport fields')); ss.tab('field_transport', _('Transport fields'));
ss.tab('field_multiplex', _('Multiplex fields')); ss.tab('field_multiplex', _('Multiplex fields'));
ss.tab('field_dial', _('Dial fields')); ss.tab('field_dial', _('Dial fields'));
@@ -782,20 +783,6 @@ return view.extend({
so.modalonly = true; so.modalonly = true;
/* WireGuard fields */ /* 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'));
so.datatype = 'ip4addr(1)';
so.placeholder = '172.16.0.2';
so.rmempty = false;
so.depends('type', 'wireguard');
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'wireguard_ipv6', _('Local IPv6 address'),
_('The %s address used by local machine in the Wireguard network.').format('IPv6'));
so.datatype = 'ip6addr(1)';
so.depends('type', 'wireguard');
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'wireguard_private_key', _('Private key'), so = ss.taboption('field_general', form.Value, 'wireguard_private_key', _('Private key'),
_('WireGuard requires base64-encoded private keys.')); _('WireGuard requires base64-encoded private keys.'));
so.password = true; so.password = true;
@@ -804,7 +791,7 @@ return view.extend({
so.depends('type', 'wireguard'); so.depends('type', 'wireguard');
so.modalonly = true; so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'wireguard_peer_public_key', _('Peer pubkic key'), so = ss.taboption('field_general', form.Value, 'wireguard_peer_public_key', _('Peer public key'),
_('WireGuard peer public key.')); _('WireGuard peer public key.'));
so.validate = L.bind(hm.validateBase64Key, so, 44); so.validate = L.bind(hm.validateBase64Key, so, 44);
so.rmempty = false; so.rmempty = false;
@@ -836,23 +823,6 @@ return view.extend({
so.depends('type', 'wireguard'); so.depends('type', 'wireguard');
so.modalonly = true; so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'wireguard_mtu', _('MTU'));
so.datatype = 'range(0,9000)';
so.placeholder = '1408';
so.depends('type', 'wireguard');
so.modalonly = true;
so = ss.taboption('field_general', form.Flag, 'wireguard_remote_dns_resolve', _('Remote DNS resolve'),
_('Force DNS remote resolution.'));
so.default = so.disabled;
so.depends('type', 'wireguard');
so.modalonly = true;
so = ss.taboption('field_general', form.DynamicList, 'wireguard_dns', _('DNS server'));
so.datatype = 'or(host, hostport)';
so.depends('wireguard_remote_dns_resolve', '1');
so.modalonly = true;
/* Masque fields */ /* Masque fields */
so = ss.taboption('field_general', form.Value, 'masque_private_key', _('Private key'), so = ss.taboption('field_general', form.Value, 'masque_private_key', _('Private key'),
_('Base64 encoded ECDSA private key on the NIST P-256 curve.')); _('Base64 encoded ECDSA private key on the NIST P-256 curve.'));
@@ -862,33 +832,13 @@ return view.extend({
so.depends('type', 'masque'); so.depends('type', 'masque');
so.modalonly = true; so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'masque_endpoint_public_key', _('Endpoint pubkic key'), so = ss.taboption('field_general', form.Value, 'masque_endpoint_public_key', _('Endpoint public key'),
_('Base64 encoded ECDSA public key on the NIST P-256 curve.')); _('Base64 encoded ECDSA public key on the NIST P-256 curve.'));
so.validate = L.bind(hm.validateBase64Key, so, 124); so.validate = L.bind(hm.validateBase64Key, so, 124);
so.rmempty = false; so.rmempty = false;
so.depends('type', 'masque'); so.depends('type', 'masque');
so.modalonly = true; so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'masque_ip', _('Local address'),
_('The %s address used by local machine in the Cloudflare WARP network.').format('IPv4'));
so.datatype = 'ip4addr(1)';
so.placeholder = '172.16.0.2';
so.rmempty = false;
so.depends({type: 'masque', masque_network: /^(|h2)$/});
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'masque_ipv6', _('Local IPv6 address'),
_('The %s address used by local machine in the Cloudflare WARP network.').format('IPv6'));
so.datatype = 'ip6addr(1)';
so.depends({type: 'masque', masque_network: /^(|h2)$/});
so.modalonly = true;
so = ss.taboption('field_general', form.Value, 'masque_mtu', _('MTU'));
so.datatype = 'range(0,9000)';
so.placeholder = '1280';
so.depends({type: 'masque', masque_network: /^(|h2)$/});
so.modalonly = true;
so = ss.taboption('field_general', form.ListValue, 'masque_network', _('Network')); so = ss.taboption('field_general', form.ListValue, 'masque_network', _('Network'));
so.default = ''; so.default = '';
so.value('', _('h3')); so.value('', _('h3'));
@@ -909,17 +859,6 @@ return view.extend({
so.depends('type', 'masque'); so.depends('type', 'masque');
so.modalonly = true; so.modalonly = true;
so = ss.taboption('field_general', form.Flag, 'masque_remote_dns_resolve', _('Remote DNS resolve'),
_('Force DNS remote resolution.'));
so.default = so.disabled;
so.depends('type', 'masque');
so.modalonly = true;
so = ss.taboption('field_general', form.DynamicList, 'masque_dns', _('DNS server'));
so.datatype = 'or(host, hostport)';
so.depends('masque_remote_dns_resolve', '1');
so.modalonly = true;
/* SSH fields */ /* SSH fields */
so = ss.taboption('field_general', form.TextValue, 'ssh_priv_key', _('Priv-key')); so = ss.taboption('field_general', form.TextValue, 'ssh_priv_key', _('Priv-key'));
so.depends('type', 'ssh'); so.depends('type', 'ssh');
@@ -1375,6 +1314,92 @@ return view.extend({
// @VMess-TLSmirror fields // @VMess-TLSmirror fields
/* VPN fields */
so = ss.taboption('field_vpn', form.Value, 'endpoint_ip', _('Virtual address'),
_('The %s address used by local machine in the %s network.').format(_('IPv4'), _('VPN')));
so.datatype = 'or(ip4addr(1), cidr4)';
so.placeholder = '172.16.0.2';
so.validate = function(section_id, value) {
const type = this.section.getOption('type').formvalue(section_id);
const desc = this.getUIElement(section_id).node.nextSibling;
switch (type) {
case 'wireguard':
desc.innerHTML = _('The %s address used by local machine in the %s network.')
.format(_('IPv4'), _('Wireguard'));
break;
case 'masque':
desc.innerHTML = _('The %s address used by local machine in the %s network.')
.format(_('IPv4'), _('Cloudflare WARP'));
break;
}
return true;
}
so.rmempty = false;
so.depends('type', 'wireguard');
so.depends({type: 'masque', masque_network: /^(|h2)$/});
so.modalonly = true;
so = ss.taboption('field_vpn', form.Value, 'endpoint_ipv6', _('Virtual IPv6 address'),
_('The %s address used by local machine in the %s network.').format(_('IPv6'), _('VPN')));
so.datatype = 'or(ip6addr(1), cidr6)';
so.validate = function(section_id, value) {
const type = this.section.getOption('type').formvalue(section_id);
const desc = this.getUIElement(section_id).node.nextSibling;
switch (type) {
case 'wireguard':
desc.innerHTML = _('The %s address used by local machine in the %s network.')
.format(_('IPv6'), _('Wireguard'));
break;
case 'masque':
desc.innerHTML = _('The %s address used by local machine in the %s network.')
.format(_('IPv6'), _('Cloudflare WARP'));
break;
}
return true;
}
so.depends('type', 'wireguard');
so.depends({type: 'masque', masque_network: /^(|h2)$/});
so.modalonly = true;
so = ss.taboption('field_vpn', form.Value, 'endpoint_mtu', _('MTU'));
so.datatype = 'range(0,9000)';
so.placeholder = '1400';
so.validate = function(section_id, value) {
const type = this.section.getOption('type').formvalue(section_id);
const UIEl = this.getUIElement(section_id);
let def_mtu;
switch (type) {
case 'wireguard':
def_mtu = '1408';
break;
case 'masque':
def_mtu = '1280';
break;
}
UIEl.node.querySelector('input').placeholder = def_mtu;
return true;
}
so.depends('type', 'wireguard');
so.depends({type: 'masque', masque_network: /^(|h2)$/});
so.modalonly = true;
so = ss.taboption('field_vpn', form.Flag, 'endpoint_remote_dns_resolve', _('Remote DNS resolve'),
_('Force DNS remote resolution.'));
so.default = so.disabled;
so.depends({type: /^(wireguard|masque)$/});
so.modalonly = true;
so = ss.taboption('field_vpn', form.DynamicList, 'endpoint_dns', _('DNS server'));
so.datatype = 'or(host, hostport)';
so.depends('endpoint_remote_dns_resolve', '1');
so.modalonly = true;
/* Transport fields */ /* Transport fields */
so = ss.taboption('field_general', form.Flag, 'transport_enabled', _('Transport')); so = ss.taboption('field_general', form.Flag, 'transport_enabled', _('Transport'));
so.default = so.disabled; so.default = so.disabled;
+9 -5
View File
@@ -964,7 +964,7 @@ msgid "Encryption method"
msgstr "" msgstr ""
#: htdocs/luci-static/resources/view/fchomo/node.js:866 #: htdocs/luci-static/resources/view/fchomo/node.js:866
msgid "Endpoint pubkic key" msgid "Endpoint public key"
msgstr "" msgstr ""
#: htdocs/luci-static/resources/view/fchomo/global.js:540 #: htdocs/luci-static/resources/view/fchomo/global.js:540
@@ -1811,12 +1811,12 @@ msgstr ""
#: htdocs/luci-static/resources/view/fchomo/node.js:794 #: htdocs/luci-static/resources/view/fchomo/node.js:794
#: htdocs/luci-static/resources/view/fchomo/node.js:881 #: htdocs/luci-static/resources/view/fchomo/node.js:881
msgid "Local IPv6 address" msgid "Virtual IPv6 address"
msgstr "" msgstr ""
#: htdocs/luci-static/resources/view/fchomo/node.js:786 #: htdocs/luci-static/resources/view/fchomo/node.js:786
#: htdocs/luci-static/resources/view/fchomo/node.js:873 #: htdocs/luci-static/resources/view/fchomo/node.js:873
msgid "Local address" msgid "Virtual address"
msgstr "" msgstr ""
#: root/usr/share/luci/menu.d/luci-app-fchomo.json:70 #: root/usr/share/luci/menu.d/luci-app-fchomo.json:70
@@ -2333,7 +2333,7 @@ msgid "Payload"
msgstr "" msgstr ""
#: htdocs/luci-static/resources/view/fchomo/node.js:808 #: htdocs/luci-static/resources/view/fchomo/node.js:808
msgid "Peer pubkic key" msgid "Peer public key"
msgstr "" msgstr ""
#: htdocs/luci-static/resources/view/fchomo/global.js:541 #: htdocs/luci-static/resources/view/fchomo/global.js:541
@@ -3256,7 +3256,7 @@ msgstr ""
#: htdocs/luci-static/resources/view/fchomo/node.js:787 #: htdocs/luci-static/resources/view/fchomo/node.js:787
#: htdocs/luci-static/resources/view/fchomo/node.js:795 #: htdocs/luci-static/resources/view/fchomo/node.js:795
msgid "The %s address used by local machine in the Wireguard network." msgid "The %s address used by local machine in the %s network."
msgstr "" msgstr ""
#: htdocs/luci-static/resources/fchomo/listeners.js:1152 #: htdocs/luci-static/resources/fchomo/listeners.js:1152
@@ -3641,6 +3641,10 @@ msgstr ""
msgid "VMess" msgid "VMess"
msgstr "" msgstr ""
#: htdocs/luci-static/resources/view/fchomo/node.js:241
msgid "VPN fields"
msgstr ""
#: htdocs/luci-static/resources/view/fchomo/node.js:1835 #: htdocs/luci-static/resources/view/fchomo/node.js:1835
#: htdocs/luci-static/resources/view/fchomo/node.js:2206 #: htdocs/luci-static/resources/view/fchomo/node.js:2206
#: htdocs/luci-static/resources/view/fchomo/ruleset.js:328 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:328
+13 -9
View File
@@ -984,7 +984,7 @@ msgid "Encryption method"
msgstr "加密方法" msgstr "加密方法"
#: htdocs/luci-static/resources/view/fchomo/node.js:866 #: htdocs/luci-static/resources/view/fchomo/node.js:866
msgid "Endpoint pubkic key" msgid "Endpoint public key"
msgstr "端点公钥" msgstr "端点公钥"
#: htdocs/luci-static/resources/view/fchomo/global.js:540 #: htdocs/luci-static/resources/view/fchomo/global.js:540
@@ -1841,13 +1841,13 @@ msgstr "本地"
#: htdocs/luci-static/resources/view/fchomo/node.js:794 #: htdocs/luci-static/resources/view/fchomo/node.js:794
#: htdocs/luci-static/resources/view/fchomo/node.js:881 #: htdocs/luci-static/resources/view/fchomo/node.js:881
msgid "Local IPv6 address" msgid "Virtual IPv6 address"
msgstr "本地 IPv6 地址" msgstr "虚拟 IPv6 地址"
#: htdocs/luci-static/resources/view/fchomo/node.js:786 #: htdocs/luci-static/resources/view/fchomo/node.js:786
#: htdocs/luci-static/resources/view/fchomo/node.js:873 #: htdocs/luci-static/resources/view/fchomo/node.js:873
msgid "Local address" msgid "Virtual address"
msgstr "本地地址" msgstr "虚拟地址"
#: root/usr/share/luci/menu.d/luci-app-fchomo.json:70 #: root/usr/share/luci/menu.d/luci-app-fchomo.json:70
msgid "Log" msgid "Log"
@@ -2365,7 +2365,7 @@ msgid "Payload"
msgstr "Payload" msgstr "Payload"
#: htdocs/luci-static/resources/view/fchomo/node.js:808 #: htdocs/luci-static/resources/view/fchomo/node.js:808
msgid "Peer pubkic key" msgid "Peer public key"
msgstr "对端公钥" msgstr "对端公钥"
#: htdocs/luci-static/resources/view/fchomo/global.js:541 #: htdocs/luci-static/resources/view/fchomo/global.js:541
@@ -3266,7 +3266,7 @@ msgstr ""
#: htdocs/luci-static/resources/fchomo/listeners.js:123 #: htdocs/luci-static/resources/fchomo/listeners.js:123
#: htdocs/luci-static/resources/view/fchomo/node.js:240 #: htdocs/luci-static/resources/view/fchomo/node.js:240
msgid "TLS fields" msgid "TLS fields"
msgstr "TLS字段" msgstr "TLS 字段"
#: htdocs/luci-static/resources/fchomo.js:165 #: htdocs/luci-static/resources/fchomo.js:165
#: htdocs/luci-static/resources/fchomo.js:202 #: htdocs/luci-static/resources/fchomo.js:202
@@ -3293,8 +3293,8 @@ msgstr "Cloudflare WARP 网络中使用的本机 %s 地址。"
#: htdocs/luci-static/resources/view/fchomo/node.js:787 #: htdocs/luci-static/resources/view/fchomo/node.js:787
#: htdocs/luci-static/resources/view/fchomo/node.js:795 #: htdocs/luci-static/resources/view/fchomo/node.js:795
msgid "The %s address used by local machine in the Wireguard network." msgid "The %s address used by local machine in the %s network."
msgstr "WireGuard 网络中使用的本机 %s 地址。" msgstr "本机 %s 地址,用于在 %s 网络中使用。"
#: htdocs/luci-static/resources/fchomo/listeners.js:1152 #: htdocs/luci-static/resources/fchomo/listeners.js:1152
#: htdocs/luci-static/resources/view/fchomo/node.js:1302 #: htdocs/luci-static/resources/view/fchomo/node.js:1302
@@ -3682,6 +3682,10 @@ msgstr ""
msgid "VMess" msgid "VMess"
msgstr "" msgstr ""
#: htdocs/luci-static/resources/view/fchomo/node.js:241
msgid "VPN fields"
msgstr "VPN 字段"
#: htdocs/luci-static/resources/view/fchomo/node.js:1835 #: htdocs/luci-static/resources/view/fchomo/node.js:1835
#: htdocs/luci-static/resources/view/fchomo/node.js:2206 #: htdocs/luci-static/resources/view/fchomo/node.js:2206
#: htdocs/luci-static/resources/view/fchomo/ruleset.js:328 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:328
+13 -9
View File
@@ -984,7 +984,7 @@ msgid "Encryption method"
msgstr "加密方法" msgstr "加密方法"
#: htdocs/luci-static/resources/view/fchomo/node.js:866 #: htdocs/luci-static/resources/view/fchomo/node.js:866
msgid "Endpoint pubkic key" msgid "Endpoint public key"
msgstr "端點公鑰" msgstr "端點公鑰"
#: htdocs/luci-static/resources/view/fchomo/global.js:540 #: htdocs/luci-static/resources/view/fchomo/global.js:540
@@ -1841,13 +1841,13 @@ msgstr "本地"
#: htdocs/luci-static/resources/view/fchomo/node.js:794 #: htdocs/luci-static/resources/view/fchomo/node.js:794
#: htdocs/luci-static/resources/view/fchomo/node.js:881 #: htdocs/luci-static/resources/view/fchomo/node.js:881
msgid "Local IPv6 address" msgid "Virtual IPv6 address"
msgstr "本地 IPv6 位址" msgstr "虛擬 IPv6 位址"
#: htdocs/luci-static/resources/view/fchomo/node.js:786 #: htdocs/luci-static/resources/view/fchomo/node.js:786
#: htdocs/luci-static/resources/view/fchomo/node.js:873 #: htdocs/luci-static/resources/view/fchomo/node.js:873
msgid "Local address" msgid "Virtual address"
msgstr "本地位址" msgstr "虛擬位址"
#: root/usr/share/luci/menu.d/luci-app-fchomo.json:70 #: root/usr/share/luci/menu.d/luci-app-fchomo.json:70
msgid "Log" msgid "Log"
@@ -2365,7 +2365,7 @@ msgid "Payload"
msgstr "Payload" msgstr "Payload"
#: htdocs/luci-static/resources/view/fchomo/node.js:808 #: htdocs/luci-static/resources/view/fchomo/node.js:808
msgid "Peer pubkic key" msgid "Peer public key"
msgstr "對端公鑰" msgstr "對端公鑰"
#: htdocs/luci-static/resources/view/fchomo/global.js:541 #: htdocs/luci-static/resources/view/fchomo/global.js:541
@@ -3266,7 +3266,7 @@ msgstr ""
#: htdocs/luci-static/resources/fchomo/listeners.js:123 #: htdocs/luci-static/resources/fchomo/listeners.js:123
#: htdocs/luci-static/resources/view/fchomo/node.js:240 #: htdocs/luci-static/resources/view/fchomo/node.js:240
msgid "TLS fields" msgid "TLS fields"
msgstr "TLS欄位" msgstr "TLS 欄位"
#: htdocs/luci-static/resources/fchomo.js:165 #: htdocs/luci-static/resources/fchomo.js:165
#: htdocs/luci-static/resources/fchomo.js:202 #: htdocs/luci-static/resources/fchomo.js:202
@@ -3293,8 +3293,8 @@ msgstr "Cloudflare WARP 網路中使用的本機 %s 位址。"
#: htdocs/luci-static/resources/view/fchomo/node.js:787 #: htdocs/luci-static/resources/view/fchomo/node.js:787
#: htdocs/luci-static/resources/view/fchomo/node.js:795 #: htdocs/luci-static/resources/view/fchomo/node.js:795
msgid "The %s address used by local machine in the Wireguard network." msgid "The %s address used by local machine in the %s network."
msgstr "WireGuard 網路中使用的本機 %s 位址。" msgstr "本機 %s 位址,用於在 %s 網路中使用。"
#: htdocs/luci-static/resources/fchomo/listeners.js:1152 #: htdocs/luci-static/resources/fchomo/listeners.js:1152
#: htdocs/luci-static/resources/view/fchomo/node.js:1302 #: htdocs/luci-static/resources/view/fchomo/node.js:1302
@@ -3682,6 +3682,10 @@ msgstr ""
msgid "VMess" msgid "VMess"
msgstr "" msgstr ""
#: htdocs/luci-static/resources/view/fchomo/node.js:241
msgid "VPN fields"
msgstr "VPN 欄位"
#: htdocs/luci-static/resources/view/fchomo/node.js:1835 #: htdocs/luci-static/resources/view/fchomo/node.js:1835
#: htdocs/luci-static/resources/view/fchomo/node.js:2206 #: htdocs/luci-static/resources/view/fchomo/node.js:2206
#: htdocs/luci-static/resources/view/fchomo/ruleset.js:328 #: htdocs/luci-static/resources/view/fchomo/ruleset.js:328
+16 -14
View File
@@ -47,27 +47,29 @@ opmc() { # @less_25_12
# add_firewall # add_firewall
add_firewall() { add_firewall() {
local enabled auto_firewall listen port local enabled auto_firewall listen listen_port
config_get_bool enabled "$1" "enabled" "1" config_get_bool enabled "$1" "enabled" "1"
config_get_bool auto_firewall "$1" "auto_firewall" "1" config_get_bool auto_firewall "$1" "auto_firewall" "1"
config_get listen "$1" "listen" "::" config_get listen "$1" "listen" "::"
config_get port "$1" "port" config_get listen_port "$1" "listen_port"
[ "$enabled" = "0" ] && return 0 [ "$enabled" = "0" ] && return 0
[ "$auto_firewall" = "0" ] && return 0 [ "$auto_firewall" = "0" ] && return 0
json_add_object '' for port in ${listen_port//,/ }; do
json_add_string type rule json_add_object ''
json_add_string target ACCEPT json_add_string type rule
json_add_string name "$1" json_add_string target ACCEPT
#json_add_string family '' # '' = IPv4 and IPv6 json_add_string name "$1"
json_add_string proto 'tcp udp' #json_add_string family '' # '' = IPv4 and IPv6
json_add_string direction in json_add_string proto 'tcp udp'
json_add_string src "*" json_add_string direction in
#json_add_string dest '' # '' = input json_add_string src "*"
json_add_string dest_ip "$(echo "$listen" | grep -vE '^(0\.\d+\.\d+\.\d+|::)$')" #json_add_string dest '' # '' = input
json_add_string dest_port "$port" json_add_string dest_ip "$(echo "$listen" | grep -vE '^(0\.\d+\.\d+\.\d+|::)$')"
json_close_object json_add_string dest_port "$port"
json_close_object
done
} }
config_load "$CONF" config_load "$CONF"
@@ -56,6 +56,14 @@ migrate() {
uci_set "$CONF" "$1" plugin "1" uci_set "$CONF" "$1" plugin "1"
uci_set "$CONF" "$1" plugin_type "$plugin" uci_set "$CONF" "$1" plugin_type "$plugin"
fi fi
# port -> listen_port
if isDefined "$1" port; then
local port
config_get port "$1" port ""
uci_remove "$CONF" "$1" port
uci_set "$CONF" "$1" listen_port "$port"
fi
} }
config_foreach migrate inbound config_foreach migrate inbound
@@ -16,6 +16,11 @@ isDefined() {
eval "[ -n \"\${$opt+x}\" ] && return 0 || return 1" eval "[ -n \"\${$opt+x}\" ] && return 0 || return 1"
} }
# add_list <value> <config> <section> <option>
add_list() {
uci_add_list "$2" "$3" "$4" "$1"
}
migrate() { migrate() {
# mieru_port_range -> mieru_ports # mieru_port_range -> mieru_ports
if isDefined "$1" mieru_port_range; then if isDefined "$1" mieru_port_range; then
@@ -82,6 +87,82 @@ migrate() {
uci_set "$CONF" "$1" plugin "1" uci_set "$CONF" "$1" plugin "1"
uci_set "$CONF" "$1" plugin_type "$plugin" uci_set "$CONF" "$1" plugin_type "$plugin"
fi fi
# wireguard_ip -> endpoint_ip
if isDefined "$1" wireguard_ip; then
local wireguard_ip
config_get wireguard_ip "$1" wireguard_ip ""
uci_remove "$CONF" "$1" wireguard_ip
uci_set "$CONF" "$1" endpoint_ip "$wireguard_ip"
fi
# masque_ip -> endpoint_ip
if isDefined "$1" masque_ip; then
local masque_ip
config_get masque_ip "$1" masque_ip ""
uci_remove "$CONF" "$1" masque_ip
uci_set "$CONF" "$1" endpoint_ip "$masque_ip"
fi
# wireguard_ipv6 -> endpoint_ipv6
if isDefined "$1" wireguard_ipv6; then
local wireguard_ipv6
config_get wireguard_ipv6 "$1" wireguard_ipv6 ""
uci_remove "$CONF" "$1" wireguard_ipv6
uci_set "$CONF" "$1" endpoint_ipv6 "$wireguard_ipv6"
fi
# masque_ipv6 -> endpoint_ipv6
if isDefined "$1" masque_ipv6; then
local masque_ipv6
config_get masque_ipv6 "$1" masque_ipv6 ""
uci_remove "$CONF" "$1" masque_ipv6
uci_set "$CONF" "$1" endpoint_ipv6 "$masque_ipv6"
fi
# wireguard_mtu -> endpoint_mtu
if isDefined "$1" wireguard_mtu; then
local wireguard_mtu
config_get wireguard_mtu "$1" wireguard_mtu ""
uci_remove "$CONF" "$1" wireguard_mtu
uci_set "$CONF" "$1" endpoint_mtu "$wireguard_mtu"
fi
# masque_mtu -> endpoint_mtu
if isDefined "$1" masque_mtu; then
local masque_mtu
config_get masque_mtu "$1" masque_mtu ""
uci_remove "$CONF" "$1" masque_mtu
uci_set "$CONF" "$1" endpoint_mtu "$masque_mtu"
fi
# wireguard_remote_dns_resolve -> endpoint_remote_dns_resolve
if isDefined "$1" wireguard_remote_dns_resolve; then
local wireguard_remote_dns_resolve
config_get wireguard_remote_dns_resolve "$1" wireguard_remote_dns_resolve ""
uci_remove "$CONF" "$1" wireguard_remote_dns_resolve
uci_set "$CONF" "$1" endpoint_remote_dns_resolve "$wireguard_remote_dns_resolve"
fi
# masque_remote_dns_resolve -> endpoint_remote_dns_resolve
if isDefined "$1" masque_remote_dns_resolve; then
local masque_remote_dns_resolve
config_get masque_remote_dns_resolve "$1" masque_remote_dns_resolve ""
uci_remove "$CONF" "$1" masque_remote_dns_resolve
uci_set "$CONF" "$1" endpoint_remote_dns_resolve "$masque_remote_dns_resolve"
fi
# wireguard_dns -> endpoint_dns
if isDefined "$1" wireguard_dns; then
config_list_foreach "$1" wireguard_dns add_list "$CONF" "$1" endpoint_dns
uci_remove "$CONF" "$1" wireguard_dns
fi
# masque_dns -> endpoint_dns
if isDefined "$1" masque_dns; then
config_list_foreach "$1" masque_dns add_list "$CONF" "$1" endpoint_dns
uci_remove "$CONF" "$1" masque_dns
fi
} }
config_foreach migrate node config_foreach migrate node
@@ -64,6 +64,14 @@ migrate() {
uci_set "$CONF" "$1" plugin "1" uci_set "$CONF" "$1" plugin "1"
uci_set "$CONF" "$1" plugin_type "$plugin" uci_set "$CONF" "$1" plugin_type "$plugin"
fi fi
# port -> listen_port
if isDefined "$1" port; then
local port
config_get port "$1" port ""
uci_remove "$CONF" "$1" port
uci_set "$CONF" "$1" listen_port "$port"
fi
} }
config_foreach migrate server config_foreach migrate server
@@ -148,16 +148,21 @@ function get_nameserver(cfg, detour) {
let servers = []; let servers = [];
for (let k in cfg) { for (let k in cfg) {
if (k === 'system-dns') { switch (k) {
push(servers, 'system'); case 'system-dns':
} else if (k === 'default-dns') { push(servers, 'system');
map(wan_dns, (dns) => { break;
push(servers, dns + '#DIRECT'); case 'default-dns':
}); map(wan_dns, (dns) => {
} else push(servers, dns + '#DIRECT');
push(servers, replace(dnsservers[k]?.address || '', /#detour=([^&]+)/, (m, c1) => { });
return '#' + urlencode(get_proxy(detour || c1)); break;
})); default:
push(servers, replace(dnsservers[k]?.address || '', /#detour=([^&]+)/, (m, c1) => {
return '#' + urlencode(get_proxy(detour || c1));
}));
break;
}
} }
return servers; return servers;
@@ -209,12 +214,16 @@ uci.foreach(uciconf, ucichain, (cfg) => {
return; return;
let identifier = ''; let identifier = '';
if (cfg.type === 'provider') switch (cfg.type) {
identifier = cfg.chain_head_sub; case 'provider':
else if (cfg.type === 'node') identifier = cfg.chain_head_sub;
identifier = cfg.chain_head; break;
else case 'node':
return; identifier = cfg.chain_head;
break;
default:
return;
}
dialerproxy[identifier] = { dialerproxy[identifier] = {
detour: get_proxy(cfg.chain_tail_group) || get_proxy(cfg.chain_tail) detour: get_proxy(cfg.chain_tail_group) || get_proxy(cfg.chain_tail)
@@ -431,13 +440,17 @@ map([
return null; return null;
let key; let key;
if (cfg.type === 'domain') { switch (cfg.type) {
key = isEmpty(cfg.domain) ? null : join(',', cfg.domain); case 'domain':
} else if (cfg.type === 'geosite') { key = isEmpty(cfg.domain) ? null : join(',', cfg.domain);
key = isEmpty(cfg.geosite) ? null : 'geosite:' + join(',', cfg.geosite); break;
} else if (cfg.type === 'rule_set') { case 'geosite':
key = isEmpty(cfg.rule_set) ? null : 'rule-set:' + join(',', cfg.rule_set); key = isEmpty(cfg.geosite) ? null : 'geosite:' + join(',', cfg.geosite);
}; break;
case 'rule_set':
key = isEmpty(cfg.rule_set) ? null : 'rule-set:' + join(',', cfg.rule_set);
break;
}
if (!key) if (!key)
return null; return null;
@@ -501,17 +514,12 @@ uci.foreach(uciconf, ucinode, (cfg) => {
"target-rematch-name": cfg.target_rematch_name, "target-rematch-name": cfg.target_rematch_name,
"target-sub-rule": cfg.target_sub_rule, "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 */
username: cfg.username, username: cfg.username,
uuid: cfg.vmess_uuid || cfg.uuid, uuid: cfg.vmess_uuid || cfg.uuid,
cipher: cfg.vmess_chipher || cfg.shadowsocks_chipher, cipher: cfg.vmess_chipher || cfg.shadowsocks_chipher,
password: cfg.shadowsocks_password || cfg.password, password: cfg.shadowsocks_password || cfg.password,
headers: cfg.headers ? json(cfg.headers) : null, headers: cfg.headers ? json(cfg.headers) : null,
ip: cfg.masque_ip || cfg.wireguard_ip,
ipv6: cfg.masque_ipv6 || cfg.wireguard_ipv6,
mtu: strToInt(cfg.masque_mtu ?? cfg.wireguard_mtu) || null,
"remote-dns-resolve": strToBool(cfg.masque_remote_dns_resolve ?? cfg.wireguard_remote_dns_resolve),
dns: cfg.masque_dns || cfg.wireguard_dns,
/* Shadowsocks */ /* Shadowsocks */
@@ -709,6 +717,13 @@ uci.foreach(uciconf, ucinode, (cfg) => {
"support-x25519mlkem768": strToBool(cfg.tls_reality_support_x25519mlkem768) "support-x25519mlkem768": strToBool(cfg.tls_reality_support_x25519mlkem768)
} : null, } : null,
/* VPN fields */
ip: cfg.endpoint_ip,
ipv6: cfg.endpoint_ipv6,
mtu: strToInt(cfg.endpoint_mtu) || null,
"remote-dns-resolve": strToBool(cfg.endpoint_remote_dns_resolve),
dns: cfg.endpoint_dns, // Array
/* Transport fields */ /* Transport fields */
// https://github.com/muink/mihomo/blob/3e966e82c793ca99e3badc84bf3f2907b100edae/adapter/outbound/vmess.go#L74 // https://github.com/muink/mihomo/blob/3e966e82c793ca99e3badc84bf3f2907b100edae/adapter/outbound/vmess.go#L74
...(cfg.transport_enabled === '1' ? { ...(cfg.transport_enabled === '1' ? {
@@ -56,12 +56,16 @@ const methods = {
let result = {}; let result = {};
let cmd = `generate ${type}`; let cmd = `generate ${type}`;
if (type === 'age-x25519') { switch (type) {
cmd = 'age keygen'; case 'age-x25519':
} else if (type === 'age-mlkem768-x25519') { cmd = 'age keygen';
cmd = 'age keygen-pq'; break;
} else if (type === 'age-convert') { case 'age-mlkem768-x25519':
cmd = 'age convert'; cmd = 'age keygen-pq';
break;
case 'age-convert':
cmd = 'age convert';
break;
} }
const fd = popen(`/usr/bin/mihomo ${cmd} ${shellQuote(req.args.params ?? '')}`); const fd = popen(`/usr/bin/mihomo ${cmd} ${shellQuote(req.args.params ?? '')}`);
+32 -19
View File
@@ -116,14 +116,20 @@ export function bytesizeToByte(str) {
let bytes = 0; let bytes = 0;
let arr = match(str, /^(\d+)(k|m|g)?b?$/); let arr = match(str, /^(\d+)(k|m|g)?b?$/);
if (arr) { if (arr) {
if (arr[2] === 'k') { switch (arr[2]) {
bytes = strToInt(arr[1]) * 1024; case 'k':
} else if (arr[2] === 'm') { bytes = strToInt(arr[1]) * 1024;
bytes = strToInt(arr[1]) * 1048576; break;
} else if (arr[2] === 'g') { case 'm':
bytes = strToInt(arr[1]) * 1073741824; bytes = strToInt(arr[1]) * 1048576;
} else break;
bytes = strToInt(arr[1]); case 'g':
bytes = strToInt(arr[1]) * 1073741824;
break;
default:
bytes = strToInt(arr[1]);
break;
}
} }
return bytes; return bytes;
@@ -135,16 +141,23 @@ export function durationToSecond(str) {
let seconds = 0; let seconds = 0;
let arr = match(str, /^(\d+)(s|m|h|d)?$/); let arr = match(str, /^(\d+)(s|m|h|d)?$/);
if (arr) { if (arr) {
if (arr[2] === 's') { switch (arr[2]) {
seconds = strToInt(arr[1]); case 's':
} else if (arr[2] === 'm') { seconds = strToInt(arr[1]);
seconds = strToInt(arr[1]) * 60; break;
} else if (arr[2] === 'h') { case 'm':
seconds = strToInt(arr[1]) * 3600; seconds = strToInt(arr[1]) * 60;
} else if (arr[2] === 'd') { break;
seconds = strToInt(arr[1]) * 86400; case 'h':
} else seconds = strToInt(arr[1]) * 3600;
seconds = strToInt(arr[1]); break;
case 'd':
seconds = strToInt(arr[1]) * 86400;
break;
default:
seconds = strToInt(arr[1]);
break;
}
} }
return seconds; return seconds;
@@ -217,7 +230,7 @@ export function parseListener(cfg) {
type: cfg.type, type: cfg.type,
listen: cfg.listen || '::', listen: cfg.listen || '::',
port: strToInt(cfg.port), port: strToInt(cfg.listen_port),
"routing-mark": strToInt(cfg.routing_mark) || null, "routing-mark": strToInt(cfg.routing_mark) || null,
rule: cfg.rule, rule: cfg.rule,
proxy: cfg.proxy, // raw data need post-processing proxy: cfg.proxy, // raw data need post-processing