mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-03 17:23:56 +08:00
🛸 Sync 2026-10-20 02:16:58
This commit is contained in:
1 parent
64729a26c6
commit
590565b35a
25 files changed
+887
-408
No files matched your search
+1
-1
@@ -9,7 +9,7 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=glorytun
|
||||
PKG_RELEASE:=6
|
||||
PKG_RELEASE:=7
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_VERSION:=95fa5ead2154adb546bcdb454c56c876e9f60bb5
|
||||
PKG_SOURCE:=glorytun-$(PKG_VERSION).tar.gz
|
||||
|
||||
+2
-1
@@ -56,7 +56,8 @@ start_instance() {
|
||||
}
|
||||
|
||||
[ "${enable}" = "1" ] || return 1
|
||||
[ "${proto}" = "tcp" ] || return 1
|
||||
# unset means tcp: instances added from LuCI before it wrote proto have none
|
||||
[ "${proto:-tcp}" = "tcp" ] || return 1
|
||||
[ -n "${key}" ] || {
|
||||
_err "Key empty"
|
||||
return 1
|
||||
|
||||
@@ -1 +1 @@
|
||||
both
|
||||
snapshot
|
||||
@@ -1 +1 @@
|
||||
26.291.65693~03c6023
|
||||
26.291.67080~0a601b6
|
||||
@@ -8,6 +8,10 @@
|
||||
'require ui';
|
||||
'require validation';
|
||||
|
||||
document.querySelector('head').appendChild(E('script', {
|
||||
src: L.resource('fchomo/md5.js')
|
||||
}));
|
||||
|
||||
function funcSed(originFunc, matrix = [], closure = []) {
|
||||
if (isEmpty(matrix))
|
||||
return originFunc;
|
||||
@@ -1039,79 +1043,8 @@ const UIDropdown = ui.Dropdown.extend({ // @pr8758_merged
|
||||
});
|
||||
|
||||
/* Method */
|
||||
/* thanks to homeproxy */
|
||||
function calcStringMD5(e) {
|
||||
/* Thanks to https://stackoverflow.com/a/41602636 */
|
||||
let h = (a, b) => {
|
||||
let c, d, e, f, g;
|
||||
c = a & 2147483648;
|
||||
d = b & 2147483648;
|
||||
e = a & 1073741824;
|
||||
f = b & 1073741824;
|
||||
g = (a & 1073741823) + (b & 1073741823);
|
||||
return e & f ? g ^ 2147483648 ^ c ^ d : e | f ? g & 1073741824 ? g ^ 3221225472 ^ c ^ d : g ^ 1073741824 ^ c ^ d : g ^ c ^ d;
|
||||
}, k = (a, b, c, d, e, f, g) => h((a = h(a, h(h(b & c | ~b & d, e), g))) << f | a >>> 32 - f, b),
|
||||
l = (a, b, c, d, e, f, g) => h((a = h(a, h(h(b & d | c & ~d, e), g))) << f | a >>> 32 - f, b),
|
||||
m = (a, b, c, d, e, f, g) => h((a = h(a, h(h(b ^ c ^ d, e), g))) << f | a >>> 32 - f, b),
|
||||
n = (a, b, c, d, e, f, g) => h((a = h(a, h(h(c ^ (b | ~d), e), g))) << f | a >>> 32 - f, b),
|
||||
p = a => { let b = '', d = ''; for (let c = 0; c <= 3; c++) d = a >>> 8 * c & 255, d = '0' + d.toString(16), b += d.substr(d.length - 2, 2); return b; };
|
||||
|
||||
let f = [], q, r, s, t, a, b, c, d;
|
||||
e = (() => {
|
||||
e = e.replace(/\r\n/g, '\n');
|
||||
let b = '';
|
||||
for (let d = 0; d < e.length; d++) {
|
||||
let c = e.charCodeAt(d);
|
||||
b += c < 128 ? String.fromCharCode(c) : c < 2048 ? String.fromCharCode(c >> 6 | 192) + String.fromCharCode(c & 63 | 128) :
|
||||
String.fromCharCode(c >> 12 | 224) + String.fromCharCode(c >> 6 & 63 | 128) + String.fromCharCode(c & 63 | 128);
|
||||
}
|
||||
return b;
|
||||
})();
|
||||
f = (() => {
|
||||
let c = e.length, a = c + 8, d = 16 * ((a - a % 64) / 64 + 1), b = Array(d - 1), f = 0, g = 0;
|
||||
for (; g < c;) a = (g - g % 4) / 4, f = g % 4 * 8, b[a] |= e.charCodeAt(g) << f, g++;
|
||||
a = (g - g % 4) / 4, b[a] |= 128 << g % 4 * 8, b[d - 2] = c << 3, b[d - 1] = c >>> 29;
|
||||
return b;
|
||||
})();
|
||||
|
||||
a = 1732584193, b = 4023233417, c = 2562383102, d = 271733878;
|
||||
for (e = 0; e < f.length; e += 16) {
|
||||
q = a, r = b, s = c, t = d;
|
||||
a = k(a, b, c, d, f[e + 0], 7, 3614090360), d = k(d, a, b, c, f[e + 1], 12, 3905402710),
|
||||
c = k(c, d, a, b, f[e + 2], 17, 606105819), b = k(b, c, d, a, f[e + 3], 22, 3250441966),
|
||||
a = k(a, b, c, d, f[e + 4], 7, 4118548399), d = k(d, a, b, c, f[e + 5], 12, 1200080426),
|
||||
c = k(c, d, a, b, f[e + 6], 17, 2821735955), b = k(b, c, d, a, f[e + 7], 22, 4249261313),
|
||||
a = k(a, b, c, d, f[e + 8], 7, 1770035416), d = k(d, a, b, c, f[e + 9], 12, 2336552879),
|
||||
c = k(c, d, a, b, f[e + 10], 17, 4294925233), b = k(b, c, d, a, f[e + 11], 22, 2304563134),
|
||||
a = k(a, b, c, d, f[e + 12], 7, 1804603682), d = k(d, a, b, c, f[e + 13], 12, 4254626195),
|
||||
c = k(c, d, a, b, f[e + 14], 17, 2792965006), b = k(b, c, d, a, f[e + 15], 22, 1236535329),
|
||||
a = l(a, b, c, d, f[e + 1], 5, 4129170786), d = l(d, a, b, c, f[e + 6], 9, 3225465664),
|
||||
c = l(c, d, a, b, f[e + 11], 14, 643717713), b = l(b, c, d, a, f[e + 0], 20, 3921069994),
|
||||
a = l(a, b, c, d, f[e + 5], 5, 3593408605), d = l(d, a, b, c, f[e + 10], 9, 38016083),
|
||||
c = l(c, d, a, b, f[e + 15], 14, 3634488961), b = l(b, c, d, a, f[e + 4], 20, 3889429448),
|
||||
a = l(a, b, c, d, f[e + 9], 5, 568446438), d = l(d, a, b, c, f[e + 14], 9, 3275163606),
|
||||
c = l(c, d, a, b, f[e + 3], 14, 4107603335), b = l(b, c, d, a, f[e + 8], 20, 1163531501),
|
||||
a = l(a, b, c, d, f[e + 13], 5, 2850285829), d = l(d, a, b, c, f[e + 2], 9, 4243563512),
|
||||
c = l(c, d, a, b, f[e + 7], 14, 1735328473), b = l(b, c, d, a, f[e + 12], 20, 2368359562),
|
||||
a = m(a, b, c, d, f[e + 5], 4, 4294588738), d = m(d, a, b, c, f[e + 8], 11, 2272392833),
|
||||
c = m(c, d, a, b, f[e + 11], 16, 1839030562), b = m(b, c, d, a, f[e + 14], 23, 4259657740),
|
||||
a = m(a, b, c, d, f[e + 1], 4, 2763975236), d = m(d, a, b, c, f[e + 4], 11, 1272893353),
|
||||
c = m(c, d, a, b, f[e + 7], 16, 4139469664), b = m(b, c, d, a, f[e + 10], 23, 3200236656),
|
||||
a = m(a, b, c, d, f[e + 13], 4, 681279174), d = m(d, a, b, c, f[e + 0], 11, 3936430074),
|
||||
c = m(c, d, a, b, f[e + 3], 16, 3572445317), b = m(b, c, d, a, f[e + 6], 23, 76029189),
|
||||
a = m(a, b, c, d, f[e + 9], 4, 3654602809), d = m(d, a, b, c, f[e + 12], 11, 3873151461),
|
||||
c = m(c, d, a, b, f[e + 15], 16, 530742520), b = m(b, c, d, a, f[e + 2], 23, 3299628645),
|
||||
a = n(a, b, c, d, f[e + 0], 6, 4096336452), d = n(d, a, b, c, f[e + 7], 10, 1126891415),
|
||||
c = n(c, d, a, b, f[e + 14], 15, 2878612391), b = n(b, c, d, a, f[e + 5], 21, 4237533241),
|
||||
a = n(a, b, c, d, f[e + 12], 6, 1700485571), d = n(d, a, b, c, f[e + 3], 10, 2399980690),
|
||||
c = n(c, d, a, b, f[e + 10], 15, 4293915773), b = n(b, c, d, a, f[e + 1], 21, 2240044497),
|
||||
a = n(a, b, c, d, f[e + 8], 6, 1873313359), d = n(d, a, b, c, f[e + 15], 10, 4264355552),
|
||||
c = n(c, d, a, b, f[e + 6], 15, 2734768916), b = n(b, c, d, a, f[e + 13], 21, 1309151649),
|
||||
a = n(a, b, c, d, f[e + 4], 6, 4149444226), d = n(d, a, b, c, f[e + 11], 10, 3174756917),
|
||||
c = n(c, d, a, b, f[e + 2], 15, 718787259), b = n(b, c, d, a, f[e + 9], 21, 3951481745),
|
||||
a = h(a, q), b = h(b, r), c = h(c, s), d = h(d, t);
|
||||
}
|
||||
return (p(a) + p(b) + p(c) + p(d)).toLowerCase();
|
||||
return md5(e);
|
||||
}
|
||||
|
||||
/* Thanks to luci-app-ssr-plus */
|
||||
@@ -1170,7 +1103,7 @@ function encodeBase64(input) {
|
||||
* Unzip Gzip data
|
||||
* @param {string|Array|ArrayBuffer|Uint8Array} input - Input data (Base64 string or binary object)
|
||||
* @param {boolean} asText - Return a string? (true: text, false: arrayBuffer)
|
||||
* @returns {Promise<string|Uint8Array>}
|
||||
* @returns {Promise} string|Uint8Array
|
||||
*/
|
||||
async function decompressGzip(input, asText = false) {
|
||||
if (isEmpty(input))
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../js-md5/build/md5-lite.min.js
|
||||
@@ -629,6 +629,10 @@ msgstr ""
|
||||
msgid "Common ports (bypass P2P traffic)"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1576
|
||||
msgid "Complete"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1040
|
||||
msgid "Configuration Document"
|
||||
msgstr ""
|
||||
@@ -890,11 +894,11 @@ msgstr ""
|
||||
msgid "Download bandwidth in Mbps."
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1507
|
||||
#: htdocs/luci-static/resources/fchomo.js:1433
|
||||
msgid "Download failed: %s"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1503
|
||||
#: htdocs/luci-static/resources/fchomo.js:1429
|
||||
msgid "Download successful."
|
||||
msgstr ""
|
||||
|
||||
@@ -1132,6 +1136,28 @@ msgstr ""
|
||||
#: htdocs/luci-static/resources/fchomo.js:525
|
||||
#: htdocs/luci-static/resources/fchomo.js:528
|
||||
#: htdocs/luci-static/resources/fchomo.js:531
|
||||
#: htdocs/luci-static/resources/fchomo.js:1593
|
||||
#: htdocs/luci-static/resources/fchomo.js:1601
|
||||
#: htdocs/luci-static/resources/fchomo.js:1609
|
||||
#: htdocs/luci-static/resources/fchomo.js:1632
|
||||
#: htdocs/luci-static/resources/fchomo.js:1635
|
||||
#: htdocs/luci-static/resources/fchomo.js:1642
|
||||
#: htdocs/luci-static/resources/fchomo.js:1658
|
||||
#: htdocs/luci-static/resources/fchomo.js:1667
|
||||
#: htdocs/luci-static/resources/fchomo.js:1679
|
||||
#: htdocs/luci-static/resources/fchomo.js:1682
|
||||
#: htdocs/luci-static/resources/fchomo.js:1692
|
||||
#: htdocs/luci-static/resources/fchomo.js:1704
|
||||
#: htdocs/luci-static/resources/fchomo.js:1707
|
||||
#: htdocs/luci-static/resources/fchomo.js:1720
|
||||
#: htdocs/luci-static/resources/fchomo.js:1729
|
||||
#: htdocs/luci-static/resources/fchomo.js:1739
|
||||
#: htdocs/luci-static/resources/fchomo.js:1774
|
||||
#: htdocs/luci-static/resources/fchomo.js:1776
|
||||
#: htdocs/luci-static/resources/fchomo.js:1789
|
||||
#: htdocs/luci-static/resources/fchomo.js:1795
|
||||
#: htdocs/luci-static/resources/fchomo.js:1802
|
||||
#: htdocs/luci-static/resources/fchomo.js:1811
|
||||
#: htdocs/luci-static/resources/fchomo/listeners.js:284
|
||||
#: htdocs/luci-static/resources/fchomo/listeners.js:339
|
||||
#: htdocs/luci-static/resources/fchomo/listeners.js:854
|
||||
@@ -1201,6 +1227,22 @@ msgstr ""
|
||||
msgid "Factor"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1534
|
||||
msgid "Failed to execute \"/etc/init.d/fchomo %s %s\" reason: %s"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1487
|
||||
msgid "Failed to generate %s, error: %s."
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1911
|
||||
msgid "Failed to upload %s, error: %s."
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1930
|
||||
msgid "Failed to upload, error: %s."
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:280
|
||||
#: htdocs/luci-static/resources/fchomo/listeners.js:378
|
||||
msgid "Fallback"
|
||||
@@ -1559,7 +1601,7 @@ msgstr ""
|
||||
msgid "Host/SNI override"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1062
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1063
|
||||
msgid "Hostname"
|
||||
msgstr ""
|
||||
|
||||
@@ -1653,6 +1695,10 @@ msgstr ""
|
||||
msgid "Idle timeout"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1635
|
||||
msgid "If All ports is selected, uncheck others"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/client.js:71
|
||||
msgid "If Block is selected, uncheck others"
|
||||
msgstr ""
|
||||
@@ -1866,6 +1912,13 @@ msgstr ""
|
||||
msgid "L2"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:241
|
||||
#: htdocs/luci-static/resources/fchomo.js:242
|
||||
#: htdocs/luci-static/resources/fchomo.js:243
|
||||
#: htdocs/luci-static/resources/fchomo.js:244
|
||||
msgid "L3"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo/listeners.js:129
|
||||
#: htdocs/luci-static/resources/view/fchomo/client.js:1055
|
||||
#: htdocs/luci-static/resources/view/fchomo/client.js:1347
|
||||
@@ -2253,16 +2306,6 @@ msgstr ""
|
||||
msgid "Network"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1046
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1057
|
||||
msgid "Room name"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1051
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1057
|
||||
msgid "Room secret"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo/listeners.js:662
|
||||
msgid "Network type"
|
||||
msgstr ""
|
||||
@@ -2336,7 +2379,7 @@ msgstr ""
|
||||
msgid "Not Installed"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1463
|
||||
#: htdocs/luci-static/resources/fchomo.js:1389
|
||||
msgid "Not Running"
|
||||
msgstr ""
|
||||
|
||||
@@ -2399,7 +2442,7 @@ msgstr ""
|
||||
msgid "Only applies to the %s."
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1056
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1057
|
||||
msgid ""
|
||||
"Only nodes using the same %s and %s as this network are permitted to perform "
|
||||
"a handshake or relay traffic through this node."
|
||||
@@ -2413,7 +2456,7 @@ msgstr ""
|
||||
msgid "Only the address %s is valid."
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1457
|
||||
#: htdocs/luci-static/resources/fchomo.js:1383
|
||||
msgid "Open Dashboard"
|
||||
msgstr ""
|
||||
|
||||
@@ -2612,6 +2655,10 @@ msgstr ""
|
||||
msgid "Port"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1644
|
||||
msgid "Port %s alrealy exists!"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:711
|
||||
msgid "Port hop interval"
|
||||
msgstr ""
|
||||
@@ -2681,7 +2728,7 @@ msgstr ""
|
||||
msgid "Private key"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1055
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1056
|
||||
msgid "Private room"
|
||||
msgstr ""
|
||||
|
||||
@@ -2906,7 +2953,7 @@ msgstr ""
|
||||
msgid "Refresh every %s seconds."
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1450
|
||||
#: htdocs/luci-static/resources/fchomo.js:1376
|
||||
#: htdocs/luci-static/resources/view/fchomo/client.js:966
|
||||
#: htdocs/luci-static/resources/view/fchomo/global.js:193
|
||||
#: htdocs/luci-static/resources/view/fchomo/server.js:45
|
||||
@@ -2942,6 +2989,11 @@ msgstr ""
|
||||
msgid "Remote trace target"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1565
|
||||
msgid "Remove"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1570
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:244
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:246
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:2341
|
||||
@@ -3035,6 +3087,16 @@ msgstr ""
|
||||
msgid "Reusing a single tunnel to carry multiple target connections within it."
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1046
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1058
|
||||
msgid "Room name"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1051
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1058
|
||||
msgid "Room secret"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/global.js:846
|
||||
msgid "Routing Control"
|
||||
msgstr ""
|
||||
@@ -3111,7 +3173,7 @@ msgstr ""
|
||||
msgid "Ruleset-URI-Scheme"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1463
|
||||
#: htdocs/luci-static/resources/fchomo.js:1389
|
||||
msgid "Running"
|
||||
msgstr ""
|
||||
|
||||
@@ -3383,6 +3445,10 @@ msgstr ""
|
||||
msgid "Successfully updated."
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1927
|
||||
msgid "Successfully uploaded."
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:192
|
||||
#: htdocs/luci-static/resources/fchomo.js:229
|
||||
msgid "Sudoku"
|
||||
@@ -3778,7 +3844,7 @@ msgstr ""
|
||||
msgid "UUID"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1510
|
||||
#: htdocs/luci-static/resources/fchomo.js:1436
|
||||
msgid "Unable to download unsupported type: %s"
|
||||
msgstr ""
|
||||
|
||||
@@ -4121,6 +4187,10 @@ msgstr ""
|
||||
msgid "YouTube"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1909
|
||||
msgid "Your %s was successfully uploaded. Size: %sB."
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:240
|
||||
msgid "ZeroTier"
|
||||
msgstr ""
|
||||
@@ -4321,6 +4391,13 @@ msgstr ""
|
||||
msgid "no-resolve"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1632
|
||||
#: htdocs/luci-static/resources/fchomo.js:1739
|
||||
#: htdocs/luci-static/resources/fchomo.js:1774
|
||||
#: htdocs/luci-static/resources/fchomo.js:1802
|
||||
msgid "non-empty value"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:416
|
||||
#: htdocs/luci-static/resources/fchomo.js:430
|
||||
#: htdocs/luci-static/resources/fchomo.js:442
|
||||
@@ -4470,6 +4547,10 @@ msgstr ""
|
||||
msgid "unique identifier"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1811
|
||||
msgid "unique value"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:2583
|
||||
msgid "up"
|
||||
msgstr ""
|
||||
@@ -4508,10 +4589,45 @@ msgstr ""
|
||||
msgid "v5"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1679
|
||||
#: htdocs/luci-static/resources/fchomo.js:1682
|
||||
msgid "valid JSON format"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1542
|
||||
msgid "valid SHA256 string with %d characters"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1704
|
||||
#: htdocs/luci-static/resources/fchomo.js:1707
|
||||
msgid "valid URL"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1729
|
||||
msgid "valid base64 key with %d characters"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1789
|
||||
#: htdocs/luci-static/resources/fchomo.js:1795
|
||||
msgid "valid format: 2x, 2p, 4v"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1720
|
||||
msgid "valid hex string with %d characters"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1776
|
||||
msgid "valid key length with %d characters"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1642
|
||||
msgid "valid port value"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1692
|
||||
msgid "valid uuid"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:488
|
||||
msgid "vless-mlkem768"
|
||||
msgstr ""
|
||||
@@ -4544,6 +4660,10 @@ msgstr ""
|
||||
msgid "zero"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1512
|
||||
#: htdocs/luci-static/resources/fchomo.js:1459
|
||||
msgid "🔗"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1438
|
||||
msgid "🡇"
|
||||
msgstr ""
|
||||
@@ -643,6 +643,10 @@ msgstr "收集数据中..."
|
||||
msgid "Common ports (bypass P2P traffic)"
|
||||
msgstr "常用端口(绕过 P2P 流量)"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1576
|
||||
msgid "Complete"
|
||||
msgstr "完成"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1040
|
||||
msgid "Configuration Document"
|
||||
msgstr "配置文档"
|
||||
@@ -906,11 +910,11 @@ msgstr "下载带宽"
|
||||
msgid "Download bandwidth in Mbps."
|
||||
msgstr "下载带宽(单位:Mbps)。"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1507
|
||||
#: htdocs/luci-static/resources/fchomo.js:1433
|
||||
msgid "Download failed: %s"
|
||||
msgstr "下载失败: %s"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1503
|
||||
#: htdocs/luci-static/resources/fchomo.js:1429
|
||||
msgid "Download successful."
|
||||
msgstr "下载成功。"
|
||||
|
||||
@@ -1154,6 +1158,28 @@ msgstr "预期状态"
|
||||
#: htdocs/luci-static/resources/fchomo.js:525
|
||||
#: htdocs/luci-static/resources/fchomo.js:528
|
||||
#: htdocs/luci-static/resources/fchomo.js:531
|
||||
#: htdocs/luci-static/resources/fchomo.js:1593
|
||||
#: htdocs/luci-static/resources/fchomo.js:1601
|
||||
#: htdocs/luci-static/resources/fchomo.js:1609
|
||||
#: htdocs/luci-static/resources/fchomo.js:1632
|
||||
#: htdocs/luci-static/resources/fchomo.js:1635
|
||||
#: htdocs/luci-static/resources/fchomo.js:1642
|
||||
#: htdocs/luci-static/resources/fchomo.js:1658
|
||||
#: htdocs/luci-static/resources/fchomo.js:1667
|
||||
#: htdocs/luci-static/resources/fchomo.js:1679
|
||||
#: htdocs/luci-static/resources/fchomo.js:1682
|
||||
#: htdocs/luci-static/resources/fchomo.js:1692
|
||||
#: htdocs/luci-static/resources/fchomo.js:1704
|
||||
#: htdocs/luci-static/resources/fchomo.js:1707
|
||||
#: htdocs/luci-static/resources/fchomo.js:1720
|
||||
#: htdocs/luci-static/resources/fchomo.js:1729
|
||||
#: htdocs/luci-static/resources/fchomo.js:1739
|
||||
#: htdocs/luci-static/resources/fchomo.js:1774
|
||||
#: htdocs/luci-static/resources/fchomo.js:1776
|
||||
#: htdocs/luci-static/resources/fchomo.js:1789
|
||||
#: htdocs/luci-static/resources/fchomo.js:1795
|
||||
#: htdocs/luci-static/resources/fchomo.js:1802
|
||||
#: htdocs/luci-static/resources/fchomo.js:1811
|
||||
#: htdocs/luci-static/resources/fchomo/listeners.js:284
|
||||
#: htdocs/luci-static/resources/fchomo/listeners.js:339
|
||||
#: htdocs/luci-static/resources/fchomo/listeners.js:854
|
||||
@@ -1223,6 +1249,22 @@ msgstr "实验性"
|
||||
msgid "Factor"
|
||||
msgstr "条件"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1534
|
||||
msgid "Failed to execute \"/etc/init.d/fchomo %s %s\" reason: %s"
|
||||
msgstr "无法执行 \"/etc/init.d/fchomo %s %s\" 原因: %s"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1487
|
||||
msgid "Failed to generate %s, error: %s."
|
||||
msgstr "生成 %s 失败,错误:%s。"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1911
|
||||
msgid "Failed to upload %s, error: %s."
|
||||
msgstr "上传 %s 失败,错误:%s。"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1930
|
||||
msgid "Failed to upload, error: %s."
|
||||
msgstr "上传失败,错误:%s。"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:280
|
||||
#: htdocs/luci-static/resources/fchomo/listeners.js:378
|
||||
msgid "Fallback"
|
||||
@@ -1585,7 +1627,7 @@ msgstr "主机密钥算法"
|
||||
msgid "Host/SNI override"
|
||||
msgstr "主机/SNI 覆盖"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1062
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1063
|
||||
msgid "Hostname"
|
||||
msgstr "主机名"
|
||||
|
||||
@@ -1679,6 +1721,10 @@ msgstr "闲置会话超时"
|
||||
msgid "Idle timeout"
|
||||
msgstr "闲置超时"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1635
|
||||
msgid "If All ports is selected, uncheck others"
|
||||
msgstr "如果选择了“所有端口”,则取消选中“其他”"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/client.js:71
|
||||
msgid "If Block is selected, uncheck others"
|
||||
msgstr "如果选择了“阻止”,则取消选中“其他”"
|
||||
@@ -1894,6 +1940,13 @@ msgstr "密钥对"
|
||||
msgid "L2"
|
||||
msgstr "L2"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:241
|
||||
#: htdocs/luci-static/resources/fchomo.js:242
|
||||
#: htdocs/luci-static/resources/fchomo.js:243
|
||||
#: htdocs/luci-static/resources/fchomo.js:244
|
||||
msgid "L3"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo/listeners.js:129
|
||||
#: htdocs/luci-static/resources/view/fchomo/client.js:1055
|
||||
#: htdocs/luci-static/resources/view/fchomo/client.js:1347
|
||||
@@ -2285,16 +2338,6 @@ msgstr "原生外观"
|
||||
msgid "Network"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1046
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1057
|
||||
msgid "Room name"
|
||||
msgstr "房间名称"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1051
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1057
|
||||
msgid "Room secret"
|
||||
msgstr "房间密码"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo/listeners.js:662
|
||||
msgid "Network type"
|
||||
msgstr "网络类型"
|
||||
@@ -2368,7 +2411,7 @@ msgstr "正常"
|
||||
msgid "Not Installed"
|
||||
msgstr "未安装"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1463
|
||||
#: htdocs/luci-static/resources/fchomo.js:1389
|
||||
msgid "Not Running"
|
||||
msgstr "未在运行"
|
||||
|
||||
@@ -2431,7 +2474,7 @@ msgstr "仅当 %s 用作前端时适用。"
|
||||
msgid "Only applies to the %s."
|
||||
msgstr "只对%s生效。"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1056
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1057
|
||||
msgid ""
|
||||
"Only nodes using the same %s and %s as this network are permitted to perform "
|
||||
"a handshake or relay traffic through this node."
|
||||
@@ -2445,7 +2488,7 @@ msgstr "只处理来自指定接口的流量。留空表示全部。"
|
||||
msgid "Only the address %s is valid."
|
||||
msgstr "只有地址 %s 是有效的。"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1457
|
||||
#: htdocs/luci-static/resources/fchomo.js:1383
|
||||
msgid "Open Dashboard"
|
||||
msgstr "打开面板"
|
||||
|
||||
@@ -2647,6 +2690,10 @@ msgstr "插件类型"
|
||||
msgid "Port"
|
||||
msgstr "端口"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1644
|
||||
msgid "Port %s alrealy exists!"
|
||||
msgstr "端口 %s 已存在!"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:711
|
||||
msgid "Port hop interval"
|
||||
msgstr "端口跳跃间隔"
|
||||
@@ -2716,7 +2763,7 @@ msgstr "密钥密码"
|
||||
msgid "Private key"
|
||||
msgstr "私钥"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1055
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1056
|
||||
msgid "Private room"
|
||||
msgstr "私密房间"
|
||||
|
||||
@@ -2941,7 +2988,7 @@ msgstr "降低后台流量和网络配置刷新频率。"
|
||||
msgid "Refresh every %s seconds."
|
||||
msgstr "每 %s 秒刷新。"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1450
|
||||
#: htdocs/luci-static/resources/fchomo.js:1376
|
||||
#: htdocs/luci-static/resources/view/fchomo/client.js:966
|
||||
#: htdocs/luci-static/resources/view/fchomo/global.js:193
|
||||
#: htdocs/luci-static/resources/view/fchomo/server.js:45
|
||||
@@ -2977,6 +3024,11 @@ msgstr "远程跟踪级别"
|
||||
msgid "Remote trace target"
|
||||
msgstr "远程跟踪目标"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1565
|
||||
msgid "Remove"
|
||||
msgstr "移除"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1570
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:244
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:246
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:2341
|
||||
@@ -3070,6 +3122,16 @@ msgstr "重用 HTTP 连接以减少每次建立连接的 RTT。"
|
||||
msgid "Reusing a single tunnel to carry multiple target connections within it."
|
||||
msgstr "复用单条隧道使其内部承载多条目标连线。"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1046
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1058
|
||||
msgid "Room name"
|
||||
msgstr "房间名称"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1051
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1058
|
||||
msgid "Room secret"
|
||||
msgstr "房间密码"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/global.js:846
|
||||
msgid "Routing Control"
|
||||
msgstr "路由控制"
|
||||
@@ -3146,7 +3208,7 @@ msgstr "规则集"
|
||||
msgid "Ruleset-URI-Scheme"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1463
|
||||
#: htdocs/luci-static/resources/fchomo.js:1389
|
||||
msgid "Running"
|
||||
msgstr "正在运行"
|
||||
|
||||
@@ -3418,6 +3480,10 @@ msgstr "已成功导入 %s 个%s (共 %s 个)。"
|
||||
msgid "Successfully updated."
|
||||
msgstr "更新成功。"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1927
|
||||
msgid "Successfully uploaded."
|
||||
msgstr "已成功上传。"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:192
|
||||
#: htdocs/luci-static/resources/fchomo.js:229
|
||||
msgid "Sudoku"
|
||||
@@ -3819,7 +3885,7 @@ msgstr "自动选择"
|
||||
msgid "UUID"
|
||||
msgstr "UUID"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1510
|
||||
#: htdocs/luci-static/resources/fchomo.js:1436
|
||||
msgid "Unable to download unsupported type: %s"
|
||||
msgstr "无法下载不支持的类型: %s"
|
||||
|
||||
@@ -4162,6 +4228,10 @@ msgstr "您可以将 %s 添加到 %s 中,以解析虚拟网络内的 A/PTR 记
|
||||
msgid "YouTube"
|
||||
msgstr "油管"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1909
|
||||
msgid "Your %s was successfully uploaded. Size: %sB."
|
||||
msgstr "您的 %s 已成功上传。大小:%sB。"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:240
|
||||
msgid "ZeroTier"
|
||||
msgstr ""
|
||||
@@ -4362,6 +4432,13 @@ msgstr "new_reno"
|
||||
msgid "no-resolve"
|
||||
msgstr "no-resolve"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1632
|
||||
#: htdocs/luci-static/resources/fchomo.js:1739
|
||||
#: htdocs/luci-static/resources/fchomo.js:1774
|
||||
#: htdocs/luci-static/resources/fchomo.js:1802
|
||||
msgid "non-empty value"
|
||||
msgstr "非空值"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:416
|
||||
#: htdocs/luci-static/resources/fchomo.js:430
|
||||
#: htdocs/luci-static/resources/fchomo.js:442
|
||||
@@ -4511,6 +4588,10 @@ msgstr "独立 UCI 标识"
|
||||
msgid "unique identifier"
|
||||
msgstr "独立标识"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1811
|
||||
msgid "unique value"
|
||||
msgstr "独立值"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:2583
|
||||
msgid "up"
|
||||
msgstr "Hysteria 上传速率"
|
||||
@@ -4549,10 +4630,45 @@ msgstr ""
|
||||
msgid "v5"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1679
|
||||
#: htdocs/luci-static/resources/fchomo.js:1682
|
||||
msgid "valid JSON format"
|
||||
msgstr "有效的 JSON 格式"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1542
|
||||
msgid "valid SHA256 string with %d characters"
|
||||
msgstr "包含 %d 个字符的有效 SHA256 字符串"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1704
|
||||
#: htdocs/luci-static/resources/fchomo.js:1707
|
||||
msgid "valid URL"
|
||||
msgstr "有效网址"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1729
|
||||
msgid "valid base64 key with %d characters"
|
||||
msgstr "包含 %d 个字符的有效 base64 密钥"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1789
|
||||
#: htdocs/luci-static/resources/fchomo.js:1795
|
||||
msgid "valid format: 2x, 2p, 4v"
|
||||
msgstr "有效格式: 2x, 2p, 4v"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1720
|
||||
msgid "valid hex string with %d characters"
|
||||
msgstr "包含 %d 个字符的有效 Hex 字符串"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1776
|
||||
msgid "valid key length with %d characters"
|
||||
msgstr "包含 %d 个字符的有效密钥"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1642
|
||||
msgid "valid port value"
|
||||
msgstr "有效端口值"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1692
|
||||
msgid "valid uuid"
|
||||
msgstr "有效 uuid"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:488
|
||||
msgid "vless-mlkem768"
|
||||
msgstr ""
|
||||
@@ -4585,6 +4701,10 @@ msgstr ""
|
||||
msgid "zero"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1512
|
||||
#: htdocs/luci-static/resources/fchomo.js:1459
|
||||
msgid "🔗"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1438
|
||||
msgid "🡇"
|
||||
msgstr ""
|
||||
@@ -643,6 +643,10 @@ msgstr "收集資料中..."
|
||||
msgid "Common ports (bypass P2P traffic)"
|
||||
msgstr "常用連接埠(繞過 P2P 流量)"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1576
|
||||
msgid "Complete"
|
||||
msgstr "完成"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1040
|
||||
msgid "Configuration Document"
|
||||
msgstr "配置文檔"
|
||||
@@ -906,11 +910,11 @@ msgstr "下載頻寬"
|
||||
msgid "Download bandwidth in Mbps."
|
||||
msgstr "下載頻寬(單位:Mbps)。"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1507
|
||||
#: htdocs/luci-static/resources/fchomo.js:1433
|
||||
msgid "Download failed: %s"
|
||||
msgstr "下載失敗: %s"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1503
|
||||
#: htdocs/luci-static/resources/fchomo.js:1429
|
||||
msgid "Download successful."
|
||||
msgstr "下載成功。"
|
||||
|
||||
@@ -1154,6 +1158,28 @@ msgstr "預期狀態"
|
||||
#: htdocs/luci-static/resources/fchomo.js:525
|
||||
#: htdocs/luci-static/resources/fchomo.js:528
|
||||
#: htdocs/luci-static/resources/fchomo.js:531
|
||||
#: htdocs/luci-static/resources/fchomo.js:1593
|
||||
#: htdocs/luci-static/resources/fchomo.js:1601
|
||||
#: htdocs/luci-static/resources/fchomo.js:1609
|
||||
#: htdocs/luci-static/resources/fchomo.js:1632
|
||||
#: htdocs/luci-static/resources/fchomo.js:1635
|
||||
#: htdocs/luci-static/resources/fchomo.js:1642
|
||||
#: htdocs/luci-static/resources/fchomo.js:1658
|
||||
#: htdocs/luci-static/resources/fchomo.js:1667
|
||||
#: htdocs/luci-static/resources/fchomo.js:1679
|
||||
#: htdocs/luci-static/resources/fchomo.js:1682
|
||||
#: htdocs/luci-static/resources/fchomo.js:1692
|
||||
#: htdocs/luci-static/resources/fchomo.js:1704
|
||||
#: htdocs/luci-static/resources/fchomo.js:1707
|
||||
#: htdocs/luci-static/resources/fchomo.js:1720
|
||||
#: htdocs/luci-static/resources/fchomo.js:1729
|
||||
#: htdocs/luci-static/resources/fchomo.js:1739
|
||||
#: htdocs/luci-static/resources/fchomo.js:1774
|
||||
#: htdocs/luci-static/resources/fchomo.js:1776
|
||||
#: htdocs/luci-static/resources/fchomo.js:1789
|
||||
#: htdocs/luci-static/resources/fchomo.js:1795
|
||||
#: htdocs/luci-static/resources/fchomo.js:1802
|
||||
#: htdocs/luci-static/resources/fchomo.js:1811
|
||||
#: htdocs/luci-static/resources/fchomo/listeners.js:284
|
||||
#: htdocs/luci-static/resources/fchomo/listeners.js:339
|
||||
#: htdocs/luci-static/resources/fchomo/listeners.js:854
|
||||
@@ -1223,6 +1249,22 @@ msgstr "實驗性"
|
||||
msgid "Factor"
|
||||
msgstr "條件"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1534
|
||||
msgid "Failed to execute \"/etc/init.d/fchomo %s %s\" reason: %s"
|
||||
msgstr "無法執行 \"/etc/init.d/fchomo %s %s\" 原因: %s"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1487
|
||||
msgid "Failed to generate %s, error: %s."
|
||||
msgstr "生成 %s 失敗,錯誤:%s。"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1911
|
||||
msgid "Failed to upload %s, error: %s."
|
||||
msgstr "上傳 %s 失敗,錯誤:%s。"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1930
|
||||
msgid "Failed to upload, error: %s."
|
||||
msgstr "上傳失敗,錯誤:%s。"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:280
|
||||
#: htdocs/luci-static/resources/fchomo/listeners.js:378
|
||||
msgid "Fallback"
|
||||
@@ -1585,7 +1627,7 @@ msgstr "主機金鑰演算法"
|
||||
msgid "Host/SNI override"
|
||||
msgstr "主機/SNI 覆蓋"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1062
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1063
|
||||
msgid "Hostname"
|
||||
msgstr "主機名稱"
|
||||
|
||||
@@ -1679,6 +1721,10 @@ msgstr "閒置會話逾時"
|
||||
msgid "Idle timeout"
|
||||
msgstr "閒置逾時"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1635
|
||||
msgid "If All ports is selected, uncheck others"
|
||||
msgstr "如果選擇了“所有連接埠”,則取消選取“其他”"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/client.js:71
|
||||
msgid "If Block is selected, uncheck others"
|
||||
msgstr "如果選擇了“封鎖”,則取消選取“其他”"
|
||||
@@ -1894,6 +1940,13 @@ msgstr "密鑰對"
|
||||
msgid "L2"
|
||||
msgstr "L2"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:241
|
||||
#: htdocs/luci-static/resources/fchomo.js:242
|
||||
#: htdocs/luci-static/resources/fchomo.js:243
|
||||
#: htdocs/luci-static/resources/fchomo.js:244
|
||||
msgid "L3"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo/listeners.js:129
|
||||
#: htdocs/luci-static/resources/view/fchomo/client.js:1055
|
||||
#: htdocs/luci-static/resources/view/fchomo/client.js:1347
|
||||
@@ -2285,16 +2338,6 @@ msgstr "原生外觀"
|
||||
msgid "Network"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1046
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1057
|
||||
msgid "Room name"
|
||||
msgstr "房間名稱"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1051
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1057
|
||||
msgid "Room secret"
|
||||
msgstr "房間密碼"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo/listeners.js:662
|
||||
msgid "Network type"
|
||||
msgstr "網路類型"
|
||||
@@ -2368,7 +2411,7 @@ msgstr "正常"
|
||||
msgid "Not Installed"
|
||||
msgstr "未安裝"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1463
|
||||
#: htdocs/luci-static/resources/fchomo.js:1389
|
||||
msgid "Not Running"
|
||||
msgstr "未在運作"
|
||||
|
||||
@@ -2431,7 +2474,7 @@ msgstr "僅當 %s 用作前端時適用。"
|
||||
msgid "Only applies to the %s."
|
||||
msgstr "只對%s生效。"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1056
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1057
|
||||
msgid ""
|
||||
"Only nodes using the same %s and %s as this network are permitted to perform "
|
||||
"a handshake or relay traffic through this node."
|
||||
@@ -2445,7 +2488,7 @@ msgstr "只處理來自指定介面的流量。留空表示全部。"
|
||||
msgid "Only the address %s is valid."
|
||||
msgstr "只有位址 %s 是有效的。"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1457
|
||||
#: htdocs/luci-static/resources/fchomo.js:1383
|
||||
msgid "Open Dashboard"
|
||||
msgstr "打開面板"
|
||||
|
||||
@@ -2647,6 +2690,10 @@ msgstr "外掛類型"
|
||||
msgid "Port"
|
||||
msgstr "連接埠"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1644
|
||||
msgid "Port %s alrealy exists!"
|
||||
msgstr "連接埠 %s 已存在!"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:711
|
||||
msgid "Port hop interval"
|
||||
msgstr "連接埠跳躍間隔"
|
||||
@@ -2716,7 +2763,7 @@ msgstr "金鑰密碼"
|
||||
msgid "Private key"
|
||||
msgstr "私鑰"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1055
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1056
|
||||
msgid "Private room"
|
||||
msgstr "私密房間"
|
||||
|
||||
@@ -2941,7 +2988,7 @@ msgstr "降低後台流量和網路配置刷新頻率。"
|
||||
msgid "Refresh every %s seconds."
|
||||
msgstr "每 %s 秒刷新。"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1450
|
||||
#: htdocs/luci-static/resources/fchomo.js:1376
|
||||
#: htdocs/luci-static/resources/view/fchomo/client.js:966
|
||||
#: htdocs/luci-static/resources/view/fchomo/global.js:193
|
||||
#: htdocs/luci-static/resources/view/fchomo/server.js:45
|
||||
@@ -2977,6 +3024,11 @@ msgstr "遠端追蹤等級"
|
||||
msgid "Remote trace target"
|
||||
msgstr "遠端追蹤目標"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1565
|
||||
msgid "Remove"
|
||||
msgstr "移除"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1570
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:244
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:246
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:2341
|
||||
@@ -3070,6 +3122,16 @@ msgstr "重用 HTTP 連接以減少每次建立連接的 RTT。"
|
||||
msgid "Reusing a single tunnel to carry multiple target connections within it."
|
||||
msgstr "複用單條隧道使其內部承載多條目標連線。"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1046
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1058
|
||||
msgid "Room name"
|
||||
msgstr "房間名稱"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1051
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1058
|
||||
msgid "Room secret"
|
||||
msgstr "房間密碼"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/global.js:846
|
||||
msgid "Routing Control"
|
||||
msgstr "路由控制"
|
||||
@@ -3146,7 +3208,7 @@ msgstr "規則集"
|
||||
msgid "Ruleset-URI-Scheme"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1463
|
||||
#: htdocs/luci-static/resources/fchomo.js:1389
|
||||
msgid "Running"
|
||||
msgstr "正在運作"
|
||||
|
||||
@@ -3418,6 +3480,10 @@ msgstr "已成功匯入 %s 個%s (共 %s 個)。"
|
||||
msgid "Successfully updated."
|
||||
msgstr "更新成功。"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1927
|
||||
msgid "Successfully uploaded."
|
||||
msgstr "已成功上傳。"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:192
|
||||
#: htdocs/luci-static/resources/fchomo.js:229
|
||||
msgid "Sudoku"
|
||||
@@ -3819,7 +3885,7 @@ msgstr "自動選擇"
|
||||
msgid "UUID"
|
||||
msgstr "UUID"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1510
|
||||
#: htdocs/luci-static/resources/fchomo.js:1436
|
||||
msgid "Unable to download unsupported type: %s"
|
||||
msgstr "無法下載不支援的類型: %s"
|
||||
|
||||
@@ -4162,6 +4228,10 @@ msgstr "您可以將 %s 新增到 %s 中,以解析虛擬網路內的 A/PTR 記
|
||||
msgid "YouTube"
|
||||
msgstr "YouTube"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1909
|
||||
msgid "Your %s was successfully uploaded. Size: %sB."
|
||||
msgstr "您的 %s 已成功上傳。大小:%sB。"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:240
|
||||
msgid "ZeroTier"
|
||||
msgstr ""
|
||||
@@ -4362,6 +4432,13 @@ msgstr "new_reno"
|
||||
msgid "no-resolve"
|
||||
msgstr "no-resolve"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1632
|
||||
#: htdocs/luci-static/resources/fchomo.js:1739
|
||||
#: htdocs/luci-static/resources/fchomo.js:1774
|
||||
#: htdocs/luci-static/resources/fchomo.js:1802
|
||||
msgid "non-empty value"
|
||||
msgstr "非空值"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:416
|
||||
#: htdocs/luci-static/resources/fchomo.js:430
|
||||
#: htdocs/luci-static/resources/fchomo.js:442
|
||||
@@ -4511,6 +4588,10 @@ msgstr "獨立 UCI 識別"
|
||||
msgid "unique identifier"
|
||||
msgstr "獨立標識"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1811
|
||||
msgid "unique value"
|
||||
msgstr "獨立值"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:2583
|
||||
msgid "up"
|
||||
msgstr "Hysteria 上傳速率"
|
||||
@@ -4549,10 +4630,45 @@ msgstr ""
|
||||
msgid "v5"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1679
|
||||
#: htdocs/luci-static/resources/fchomo.js:1682
|
||||
msgid "valid JSON format"
|
||||
msgstr "有效的 JSON 格式"
|
||||
|
||||
#: htdocs/luci-static/resources/view/fchomo/node.js:1542
|
||||
msgid "valid SHA256 string with %d characters"
|
||||
msgstr "包含 %d 個字元的有效 SHA256 字串"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1704
|
||||
#: htdocs/luci-static/resources/fchomo.js:1707
|
||||
msgid "valid URL"
|
||||
msgstr "有效網址"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1729
|
||||
msgid "valid base64 key with %d characters"
|
||||
msgstr "包含 %d 個字元的有效 base64 金鑰"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1789
|
||||
#: htdocs/luci-static/resources/fchomo.js:1795
|
||||
msgid "valid format: 2x, 2p, 4v"
|
||||
msgstr "有效格式: 2x, 2p, 4v"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1720
|
||||
msgid "valid hex string with %d characters"
|
||||
msgstr "包含 %d 个字符的有效 Hex 字串"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1776
|
||||
msgid "valid key length with %d characters"
|
||||
msgstr "包含 %d 個字元的有效金鑰"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1642
|
||||
msgid "valid port value"
|
||||
msgstr "有效連接埠值"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1692
|
||||
msgid "valid uuid"
|
||||
msgstr "有效 uuid"
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:488
|
||||
msgid "vless-mlkem768"
|
||||
msgstr ""
|
||||
@@ -4585,6 +4701,10 @@ msgstr ""
|
||||
msgid "zero"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1512
|
||||
#: htdocs/luci-static/resources/fchomo.js:1459
|
||||
msgid "🔗"
|
||||
msgstr ""
|
||||
|
||||
#: htdocs/luci-static/resources/fchomo.js:1438
|
||||
msgid "🡇"
|
||||
msgstr ""
|
||||
@@ -79,6 +79,13 @@ return L.view.extend({
|
||||
o.rmempty = false;
|
||||
o.modalonly = true;
|
||||
|
||||
// /etc/init.d/glorytun starts no instance without proto=tcp: an
|
||||
// instance added here was never started
|
||||
o = s.taboption('general', form.HiddenValue, 'proto');
|
||||
o.default = 'tcp';
|
||||
o.rmempty = false;
|
||||
o.modalonly = true;
|
||||
|
||||
return m.render();
|
||||
}
|
||||
});
|
||||
@@ -5,8 +5,9 @@
|
||||
%>
|
||||
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
var stxhr = new XHR();
|
||||
|
||||
// One XHR per request: the luci.js XHR shim drops the callback of a
|
||||
// request posted from another request's callback on the same object,
|
||||
// so the download result was never shown
|
||||
function update_speed(field, proto, mode,omit,parallel,transmit,bitrate)
|
||||
{
|
||||
update_upload(field,proto,mode,omit,parallel,transmit,bitrate);
|
||||
@@ -26,7 +27,7 @@
|
||||
'<%:Waiting for command to complete...%>'
|
||||
;
|
||||
|
||||
stxhr.post('<%=url('admin/services/iperf')%>/run_test' + '/' + addr + '/' + proto + '/' + mode + '/upload' + '/' + omit + '/' + parallel + '/' + transmit + '/' + bitrate, { token: '<%=token%>' },
|
||||
new XHR().post('<%=url('admin/services/iperf')%>/run_test' + '/' + addr + '/' + proto + '/' + mode + '/upload' + '/' + omit + '/' + parallel + '/' + transmit + '/' + bitrate, { token: '<%=token%>' },
|
||||
function(x)
|
||||
{
|
||||
if (x.responseText)
|
||||
@@ -66,7 +67,7 @@
|
||||
'<%:Waiting for command to complete...%>'
|
||||
;
|
||||
|
||||
stxhr.post('<%=url('admin/services/iperf')%>/run_test' + '/' + addr + '/' + proto + '/' + mode + '/download' + '/' + omit + '/' + parallel + '/' + transmit + '/' + bitrate, { token: '<%=token%>' },
|
||||
new XHR().post('<%=url('admin/services/iperf')%>/run_test' + '/' + addr + '/' + proto + '/' + mode + '/download' + '/' + omit + '/' + parallel + '/' + transmit + '/' + bitrate, { token: '<%=token%>' },
|
||||
function(x)
|
||||
{
|
||||
if (x.responseText)
|
||||
|
||||
@@ -393,8 +393,11 @@ return L.view.extend({
|
||||
|
||||
o = s.option(form.Value, "multipath_weight", _("Weight"), _("Only used by *weight schedulers/path managers. Ignored if no weight scheduler is selected.") + '<br />' + _("A weight >100 make it more attractive, a weight <100 make it less attractive. Max 256"));
|
||||
o.datatype = "uinteger";
|
||||
o.rmempty = false;
|
||||
o.default = 100;
|
||||
// 100 shown as a placeholder, not a default: with a default every Save
|
||||
// of this page wrote multipath_weight='100' on each interface that had
|
||||
// none. Unset means 100 for every reader (omr-weight-sync, mqvpn).
|
||||
o.placeholder = "100";
|
||||
o.rmempty = true;
|
||||
|
||||
return m.render();
|
||||
}
|
||||
|
||||
@@ -12,12 +12,10 @@ var callMptcpCheckTrace = rpc.declare({
|
||||
|
||||
return view.extend({
|
||||
load: function() {
|
||||
return Promise.all([
|
||||
uci.load('network'),
|
||||
// only for the old copy of the mode below: the ACL doesn't
|
||||
// give this config (VPS passwords and tokens) to non-root users
|
||||
L.resolveDefault(uci.load('openmptcprouter'), null)
|
||||
]);
|
||||
// network only: the old openmptcprouter.<iface>.multipath copy is
|
||||
// left out, the ACL does not grant that config (VPS password and
|
||||
// token)
|
||||
return uci.load('network');
|
||||
},
|
||||
|
||||
render: function() {
|
||||
@@ -25,8 +23,7 @@ return view.extend({
|
||||
uci.sections('network', 'interface', function(s) {
|
||||
var name = s['.name'];
|
||||
if (name === 'loopback') return;
|
||||
var multipath = s.multipath ||
|
||||
uci.get('openmptcprouter', name, 'multipath') || 'off';
|
||||
var multipath = s.multipath || 'off';
|
||||
if (multipath !== 'off')
|
||||
ifaces.push(name);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'use strict';
|
||||
'require form';
|
||||
'require uci';
|
||||
'require rpc';
|
||||
|
||||
/*
|
||||
* Copyright (C) 2026 Ycarus (Yannick Chabanois) <contact@openmptcprouter.com> for OpenMPTCProuter
|
||||
@@ -34,6 +35,13 @@ var DSCP_CLASSES = [
|
||||
['ef', _('EF (46) - Voice')]
|
||||
];
|
||||
|
||||
// mqvpn's state through rpcd: the ACL does not grant the mqvpn config (PSK)
|
||||
var callMqvpnState = rpc.declare({
|
||||
object: 'luci.mptcp',
|
||||
method: 'mqvpn_state',
|
||||
expect: { '': {} }
|
||||
});
|
||||
|
||||
// Same WAN filter as this app's own mptcp.js "Interfaces Settings"
|
||||
// section: excludes the pseudo-interfaces that are never a real WAN.
|
||||
function isEligibleIface(name) {
|
||||
@@ -76,21 +84,22 @@ return L.view.extend({
|
||||
load: function() {
|
||||
return Promise.all([
|
||||
uci.load('network'),
|
||||
// mqvpn may not be installed at all -- resolve to null instead
|
||||
// of rejecting the whole page's load() in that case.
|
||||
L.resolveDefault(uci.load('mqvpn'), null)
|
||||
// mqvpn may not be installed at all -- resolve to "disabled"
|
||||
// instead of rejecting the whole page's load() in that case.
|
||||
L.resolveDefault(callMqvpnState(), {})
|
||||
]);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
render: function(data) {
|
||||
var m, s, o;
|
||||
var mqvpn = (data && data[1]) || {};
|
||||
|
||||
var mptcpScheduler = normalizeSchedulerValue(uci.get('network', 'globals', 'mptcp_scheduler'));
|
||||
var mptcpHasDscpScheduler = (mptcpScheduler === 'bpf_dscp');
|
||||
var mptcpHasWeightScheduler = (mptcpScheduler === 'bpf_weight' || mptcpScheduler === 'bpf_weight_rr' || mptcpScheduler === 'bpf_burstweight');
|
||||
|
||||
var mqvpnEnabled = (uci.get('mqvpn', 'settings', 'enable') === '1');
|
||||
var mqvpnScheduler = uci.get('mqvpn', 'multipath', 'scheduler');
|
||||
var mqvpnEnabled = (mqvpn.enabled === true);
|
||||
var mqvpnScheduler = mqvpn.scheduler;
|
||||
// mqvpn has no scheduler value dedicated to DSCP the way MPTCP has
|
||||
// bpf_dscp -- 007-mqvpn-dscp pushes the DSCP mask unconditionally
|
||||
// whenever mqvpn is enabled, regardless of which scheduler is
|
||||
@@ -170,8 +179,10 @@ return L.view.extend({
|
||||
o = s.option(form.Value, 'multipath_weight', _('Weight'),
|
||||
_('A weight >100 makes a WAN more attractive, a weight <100 makes it less attractive. Max 256.'));
|
||||
o.datatype = 'uinteger';
|
||||
o.rmempty = false;
|
||||
o.default = 100;
|
||||
// a placeholder, not a default: a default made every Save write
|
||||
// multipath_weight='100' on each WAN that had none (unset is 100)
|
||||
o.placeholder = '100';
|
||||
o.rmempty = true;
|
||||
}
|
||||
|
||||
return m.render();
|
||||
|
||||
@@ -58,6 +58,26 @@ end
|
||||
|
||||
local IP_BIN = "/sbin/ip"
|
||||
|
||||
-- The VPS to trace to: the master server of the openmptcprouter config,
|
||||
-- else the server of the proxy in use. shadowsocks-libev's sss0 alone was
|
||||
-- read before, a stale or placeholder address with shadowsocks-rust or any
|
||||
-- other proxy.
|
||||
local function trace_server()
|
||||
local server
|
||||
uci:foreach("openmptcprouter", "server", function(s)
|
||||
if server or s.disabled == "1" or s.master ~= "1" then return end
|
||||
local ip = s.ip
|
||||
if type(ip) == "table" then ip = ip[1] end
|
||||
if ip and ip ~= "" then server = ip end
|
||||
end)
|
||||
if server then return server end
|
||||
local proxy = uci:get("openmptcprouter", "settings", "proxy") or ""
|
||||
if proxy:match("^shadowsocks%-rust") then
|
||||
return uci:get("shadowsocks-rust", "sss0", "server") or ""
|
||||
end
|
||||
return uci:get("shadowsocks-libev", "sss0", "server") or ""
|
||||
end
|
||||
|
||||
local function trim(s)
|
||||
return (tostring(s or ""):gsub("^%s+", ""):gsub("%s+$", ""))
|
||||
end
|
||||
@@ -159,7 +179,7 @@ function parse_counters(raw)
|
||||
end
|
||||
|
||||
-- Where to read the MPTcpExt* counters from for Diagnostics. Deliberately
|
||||
-- NOT "multipath -m" here: that wraps "nstat -z", and nstat (without -a)
|
||||
-- NOT "multipath -m" here: that wrapped "nstat -z", and nstat (without -a)
|
||||
-- reports the delta since the *previous* nstat invocation by anyone on the
|
||||
-- box (it keeps a shared per-uid history file) -- confirmed live: two
|
||||
-- consecutive calls a couple seconds apart came back ~0, while "nstat -a -z"
|
||||
@@ -896,6 +916,18 @@ local methods = {
|
||||
end
|
||||
},
|
||||
|
||||
-- Whether mqvpn is enabled and which scheduler it runs, for the DSCP /
|
||||
-- Weight Routing page: these two values only, the page's ACL does not
|
||||
-- grant the mqvpn config itself (it holds the PSK).
|
||||
mqvpn_state = {
|
||||
call = function()
|
||||
return {
|
||||
enabled = uci:get("mqvpn", "settings", "enable") == "1",
|
||||
scheduler = uci:get("mqvpn", "multipath", "scheduler") or ""
|
||||
}
|
||||
end
|
||||
},
|
||||
|
||||
-- Runs "multipath -f" and returns its output.
|
||||
mptcp_fullmesh = {
|
||||
call = function()
|
||||
@@ -923,7 +955,7 @@ local methods = {
|
||||
call = function(args)
|
||||
local iface = args.iface or ""
|
||||
local interface = get_device(iface)
|
||||
local server = uci:get("shadowsocks-libev", "sss0", "server") or ""
|
||||
local server = trace_server()
|
||||
-- Placeholders the shadowsocks config ships until a VPS is set
|
||||
-- (127.0.0.1 now, 192.168.1.3 in older releases): tracing to them
|
||||
-- would report a path that has nothing to do with the proxy.
|
||||
|
||||
@@ -86,5 +86,16 @@
|
||||
"depends": {
|
||||
"acl": [ "luci-app-mptcp" ]
|
||||
}
|
||||
},
|
||||
"admin/network/mptcp/mptcp_check": {
|
||||
"title": "MPTCP Support Check",
|
||||
"order": 70,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "mptcp/mptcp_check"
|
||||
},
|
||||
"depends": {
|
||||
"acl": [ "luci-app-mptcp" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@
|
||||
"mptcp_check_trace",
|
||||
"get_settings",
|
||||
"get_interface_settings",
|
||||
"mqvpn_state",
|
||||
"diagnose"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-passwall
|
||||
PKG_VERSION:=26.10.16
|
||||
PKG_RELEASE:=339
|
||||
PKG_RELEASE:=340
|
||||
PKG_PO_VERSION:=$(PKG_VERSION)
|
||||
|
||||
PKG_CONFIG_DEPENDS:= \
|
||||
|
||||
@@ -3,12 +3,86 @@
|
||||
-- Copyright(c): lwb1978 2025–2027
|
||||
|
||||
local api = require("luci.passwall.api")
|
||||
local urlencode = api.UrlEncode
|
||||
local base64 = api.base64Encode
|
||||
local json = api.jsonc
|
||||
|
||||
local domain_redir = {}
|
||||
|
||||
local function urlencode(value)
|
||||
return api.UrlEncode(value == nil and "" or tostring(value))
|
||||
end
|
||||
|
||||
local function add_param(params, key, value)
|
||||
if value ~= nil and value ~= "" then
|
||||
if type(value) == "boolean" then value = value and "1" or "0" end
|
||||
params[#params + 1] = key .. "=" .. urlencode(value)
|
||||
end
|
||||
end
|
||||
|
||||
local function build_ech(node)
|
||||
local opts = node["ech-opts"]
|
||||
if type(opts) ~= "table" or opts.enable ~= true then return nil end
|
||||
if opts.config and opts.config ~= "" then return opts.config end
|
||||
local name = opts["query-server-name"]
|
||||
if not name or name == "" then name = node.servername or node.sni or node.server end
|
||||
if name == "" then name = node.server end
|
||||
return name .. "+https://223.5.5.5/dns-query"
|
||||
end
|
||||
|
||||
local function bandwidth_mbps(value)
|
||||
if value == nil then return nil end
|
||||
local number = tonumber(value)
|
||||
if number then return number end
|
||||
local amount, prefix, unit = tostring(value):match("^%s*(%d+)%s*([KMGT]?)([Bb])ps%s*$")
|
||||
local scales = { [""] = 1, K = 1000, M = 1000000, G = 1000000000, T = 1000000000000 }
|
||||
if not amount then return nil end
|
||||
return tonumber(amount) * scales[prefix] * (unit == "B" and 8 or 1) / 1000000
|
||||
end
|
||||
|
||||
local function inherit(base, overrides)
|
||||
local result = {}
|
||||
for key, value in pairs(base or {}) do result[key] = value end
|
||||
for key, value in pairs(overrides or {}) do result[key] = value end
|
||||
return result
|
||||
end
|
||||
|
||||
local function build_xhttp_extra(opts)
|
||||
local extra = {}
|
||||
local fields = {
|
||||
headers = "headers", ["x-padding-bytes"] = "xPaddingBytes",
|
||||
["no-grpc-header"] = "noGRPCHeader", ["x-padding-obfs-mode"] = "xPaddingObfsMode",
|
||||
["x-padding-key"] = "xPaddingKey", ["x-padding-header"] = "xPaddingHeader",
|
||||
["x-padding-placement"] = "xPaddingPlacement", ["x-padding-method"] = "xPaddingMethod",
|
||||
["uplink-http-method"] = "uplinkHTTPMethod", ["session-placement"] = "sessionIDPlacement",
|
||||
["session-key"] = "sessionIDKey", ["session-table"] = "sessionIDTable",
|
||||
["session-length"] = "sessionIDLength", ["seq-placement"] = "seqPlacement", ["seq-key"] = "seqKey",
|
||||
["uplink-data-placement"] = "uplinkDataPlacement", ["uplink-data-key"] = "uplinkDataKey",
|
||||
["uplink-chunk-size"] = "uplinkChunkSize", ["sc-max-each-post-bytes"] = "scMaxEachPostBytes",
|
||||
["sc-min-posts-interval-ms"] = "scMinPostsIntervalMs"
|
||||
}
|
||||
for source, target in pairs(fields) do extra[target] = opts[source] end
|
||||
-- jsonc treats empty tables as arrays and repeated table references as null.
|
||||
if type(extra.headers) == "table" then
|
||||
extra.headers = next(extra.headers) and inherit(extra.headers) or nil
|
||||
end
|
||||
local reuse = opts["reuse-settings"]
|
||||
if reuse then
|
||||
local xmux = {}
|
||||
local ranges = {
|
||||
["max-concurrency"] = "maxConcurrency", ["max-connections"] = "maxConnections",
|
||||
["c-max-reuse-times"] = "cMaxReuseTimes", ["h-max-request-times"] = "hMaxRequestTimes",
|
||||
["h-max-reusable-secs"] = "hMaxReusableSecs"
|
||||
}
|
||||
for source, target in pairs(ranges) do
|
||||
local value = reuse[source]
|
||||
if value ~= nil then xmux[target] = tonumber(value) or value end
|
||||
end
|
||||
xmux.hKeepAlivePeriod = tonumber(reuse["h-keep-alive-period"])
|
||||
if next(xmux) then extra.xmux = xmux end
|
||||
end
|
||||
return extra
|
||||
end
|
||||
|
||||
local function host_format(host)
|
||||
if not host then return "" end
|
||||
local str = host:match("%[(.-)%]") or host
|
||||
@@ -62,18 +136,12 @@ local function build_common(node)
|
||||
o.tls.sni = node.servername or node.sni
|
||||
o.tls.fp = node["client-fingerprint"]
|
||||
o.tls.pcs = node.fingerprint
|
||||
o.tls.vcn = node["name-cert-verify"]
|
||||
o.tls.insecure = node["skip-cert-verify"] == true
|
||||
|
||||
o.tls.alpn = build_alpn(node.alpn)
|
||||
|
||||
local ech_opts = node["ech-opts"]
|
||||
if ech_opts and ech_opts.enable == true then
|
||||
if ech_opts["query-server-name"] then
|
||||
o.tls.ech = ech_opts["query-server-name"] .. "+https://223.5.5.5/dns-query"
|
||||
elseif ech_opts.config then
|
||||
o.tls.ech = ech_opts.config
|
||||
end
|
||||
end
|
||||
o.tls.ech = build_ech(node)
|
||||
|
||||
-- ===== transport =====
|
||||
o.transport = {}
|
||||
@@ -89,16 +157,15 @@ local function build_common(node)
|
||||
local opts = node["ws-opts"]
|
||||
if opts then
|
||||
local path = opts.path or "/"
|
||||
local ed = opts["max-early-data"]
|
||||
local eh = opts["early-data-header-name"]
|
||||
if ed then
|
||||
path = path .. "?ed=" .. ed
|
||||
if opts["v2ray-http-upgrade"] ~= true and opts["max-early-data"] then
|
||||
path = path .. (path:find("?", 1, true) and "&ed=" or "?ed=") .. opts["max-early-data"]
|
||||
end
|
||||
if eh then
|
||||
path = path .. (path:find("?", 1, true) and "&eh=" or "?eh=") .. eh
|
||||
if opts["v2ray-http-upgrade"] ~= true and opts["early-data-header-name"] then
|
||||
path = path .. (path:find("?", 1, true) and "&eh=" or "?eh=") .. opts["early-data-header-name"]
|
||||
end
|
||||
o.transport.path = path
|
||||
o.transport.host = opts.headers and opts.headers.Host
|
||||
if opts["v2ray-http-upgrade"] == true then o.transport.type = "httpupgrade" end
|
||||
end
|
||||
|
||||
elseif net == "grpc" then
|
||||
@@ -108,12 +175,17 @@ local function build_common(node)
|
||||
end
|
||||
|
||||
elseif net == "http" then
|
||||
-- Use TCP + HTTP camouflage so each core selects its matching transport.
|
||||
o.transport.type = "tcp"
|
||||
o.transport.headerType = "http"
|
||||
o.transport.host = node.server
|
||||
o.transport.path = "/"
|
||||
local opts = node["http-opts"]
|
||||
if opts then
|
||||
-- Clash http-opts carries the camouflage Host under headers.Host
|
||||
-- (a list), like ws-opts; opts.host is not standard for http.
|
||||
o.transport.host = get_first(opts.host) or (opts.headers and get_first(opts.headers.Host))
|
||||
o.transport.path = get_first(opts.path)
|
||||
o.transport.host = get_first(opts.host) or (opts.headers and get_first(opts.headers.Host)) or o.transport.host
|
||||
o.transport.path = get_first(opts.path) or o.transport.path
|
||||
end
|
||||
|
||||
elseif net == "h2" then
|
||||
@@ -130,85 +202,45 @@ local function build_common(node)
|
||||
o.transport.path = opts.path
|
||||
o.transport.mode = opts.mode
|
||||
|
||||
local extra = {}
|
||||
|
||||
-- headers
|
||||
if opts.headers then
|
||||
extra.headers = opts.headers
|
||||
end
|
||||
|
||||
if opts["x-padding-bytes"] then
|
||||
extra.xPaddingBytes = opts["x-padding-bytes"]
|
||||
end
|
||||
|
||||
if opts["no-grpc-header"] ~= nil then
|
||||
extra.noGRPCHeader = opts["no-grpc-header"]
|
||||
end
|
||||
|
||||
if opts["sc-max-each-post-bytes"] then
|
||||
extra.scMaxEachPostBytes = opts["sc-max-each-post-bytes"]
|
||||
end
|
||||
|
||||
if opts["sc-min-posts-interval-ms"] then
|
||||
extra.scMinPostsIntervalMs = opts["sc-min-posts-interval-ms"]
|
||||
end
|
||||
|
||||
-- xmux
|
||||
if opts["reuse-settings"] then
|
||||
local r = opts["reuse-settings"]
|
||||
local xmux = {}
|
||||
|
||||
if r["max-concurrency"] then xmux.maxConcurrency = r["max-concurrency"] end
|
||||
if r["max-connections"] then xmux.maxConnections = tonumber(r["max-connections"]) end
|
||||
if r["c-max-reuse-times"] then xmux.cMaxReuseTimes = tonumber(r["c-max-reuse-times"]) end
|
||||
if r["h-max-request-times"] then xmux.hMaxRequestTimes = r["h-max-request-times"] end
|
||||
if r["h-max-reusable-secs"] then xmux.hMaxReusableSecs = r["h-max-reusable-secs"] end
|
||||
if r["h-keep-alive-period"] then xmux.hKeepAlivePeriod = tonumber(r["h-keep-alive-period"]) end
|
||||
|
||||
if next(xmux) then extra.xmux = xmux end
|
||||
end
|
||||
local extra = build_xhttp_extra(opts)
|
||||
|
||||
-- download-settings
|
||||
if opts["download-settings"] then
|
||||
local d = opts["download-settings"]
|
||||
local ds = {}
|
||||
|
||||
if d.server then ds.address = domain_redir[d.server] or d.server end
|
||||
if d.port then ds.port = d.port end
|
||||
|
||||
ds.network = "xhttp"
|
||||
|
||||
-- TLS
|
||||
if d.tls then
|
||||
ds.security = "tls"
|
||||
ds.tlsSettings = {}
|
||||
|
||||
if d.servername then
|
||||
ds.tlsSettings.serverName = d.servername
|
||||
end
|
||||
if d["skip-cert-verify"] == true then
|
||||
ds.tlsSettings.allowInsecure = true
|
||||
end
|
||||
if d["client-fingerprint"] then
|
||||
ds.tlsSettings.fingerprint = d["client-fingerprint"]
|
||||
end
|
||||
if d.fingerprint then
|
||||
ds.tlsSettings.pinnedPeerCertSha256 = d.fingerprint
|
||||
end
|
||||
if d.alpn then
|
||||
ds.tlsSettings.alpn = d.alpn
|
||||
local effective = inherit(node, d)
|
||||
local ds = {
|
||||
address = domain_redir[effective.server] or effective.server,
|
||||
port = effective.port,
|
||||
network = "xhttp",
|
||||
security = effective.tls and "tls" or "none"
|
||||
}
|
||||
local sni = effective.servername or effective.sni or effective.server
|
||||
local alpn = build_alpn(effective.alpn)
|
||||
if effective.tls or effective["reality-opts"] then
|
||||
ds.tlsSettings = {
|
||||
serverName = sni,
|
||||
allowInsecure = effective["skip-cert-verify"] == true,
|
||||
fingerprint = effective["client-fingerprint"],
|
||||
pinnedPeerCertSha256 = effective.fingerprint and api.sha256_sb_xray(effective.fingerprint) or nil,
|
||||
verifyPeerCertByName = effective["name-cert-verify"],
|
||||
alpn = alpn and api.split(alpn, ",") or nil,
|
||||
echConfigList = build_ech(effective)
|
||||
}
|
||||
local reality = effective["reality-opts"]
|
||||
if reality then
|
||||
ds.security = "reality"
|
||||
ds.realitySettings = {
|
||||
serverName = sni, fingerprint = effective["client-fingerprint"] or "chrome",
|
||||
publicKey = reality["public-key"], shortId = reality["short-id"] or ""
|
||||
}
|
||||
ds.tlsSettings = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- xhttpSettings
|
||||
local xs = {}
|
||||
|
||||
if d.path then xs.path = d.path end
|
||||
if d.host then xs.host = d.host end
|
||||
|
||||
if next(xs) then
|
||||
ds.xhttpSettings = xs
|
||||
end
|
||||
local xs = build_xhttp_extra(inherit(opts, d))
|
||||
xs.path = d.path or opts.path or "/"
|
||||
xs.host = d.host or opts.host or sni
|
||||
xs.mode = opts.mode or "auto"
|
||||
ds.xhttpSettings = xs
|
||||
|
||||
extra.downloadSettings = ds
|
||||
end
|
||||
@@ -229,27 +261,29 @@ local function encode_vless(node)
|
||||
local link = "vless://" .. node.uuid .. "@" .. o.server .. ":" .. o.port
|
||||
local p = {}
|
||||
|
||||
if type(node.flow) == "string" and node.flow:sub(1, 5) == "xtls-" then table.insert(p, "flow=" .. urlencode(node.flow)) end
|
||||
if node.encryption then table.insert(p, "encryption=" .. urlencode(node.encryption)) end
|
||||
if type(node.flow) == "string" and node.flow:sub(1, 5) == "xtls-" then add_param(p, "flow", node.flow) end
|
||||
add_param(p, "encryption", node.encryption)
|
||||
|
||||
-- TLS
|
||||
if o.tls.security then table.insert(p, "security=" .. o.tls.security) end
|
||||
if o.tls.pbk then table.insert(p, "pbk=" .. urlencode(o.tls.pbk)) end
|
||||
if o.tls.sid then table.insert(p, "sid=" .. urlencode(o.tls.sid)) end
|
||||
if o.tls.sni then table.insert(p, "sni=" .. urlencode(o.tls.sni)) end
|
||||
if o.tls.fp then table.insert(p, "fp=" .. urlencode(o.tls.fp)) end
|
||||
if o.tls.alpn then table.insert(p, "alpn=" .. urlencode(o.tls.alpn)) end
|
||||
if o.tls.ech then table.insert(p, "ech=" .. urlencode(o.tls.ech)) end
|
||||
if o.tls.pcs then table.insert(p, "pcs=" .. urlencode(o.tls.pcs)) end
|
||||
table.insert(p, "allowInsecure=" .. (o.tls.insecure and "1" or "0"))
|
||||
add_param(p, "security", o.tls.security)
|
||||
add_param(p, "pbk", o.tls.pbk)
|
||||
add_param(p, "sid", o.tls.sid)
|
||||
add_param(p, "sni", o.tls.sni)
|
||||
add_param(p, "fp", o.tls.fp)
|
||||
add_param(p, "alpn", o.tls.alpn)
|
||||
add_param(p, "ech", o.tls.ech)
|
||||
add_param(p, "pcs", o.tls.pcs)
|
||||
add_param(p, "vcn", o.tls.vcn)
|
||||
add_param(p, "allowInsecure", o.tls.insecure)
|
||||
|
||||
-- transport
|
||||
table.insert(p, "type=" .. o.transport.type)
|
||||
if o.transport.host then table.insert(p, "host=" .. urlencode(o.transport.host)) end
|
||||
if o.transport.path then table.insert(p, "path=" .. urlencode(o.transport.path)) end
|
||||
if o.transport.serviceName then table.insert(p, "serviceName=" .. urlencode(o.transport.serviceName)) end
|
||||
if o.transport.mode then table.insert(p, "mode=" .. urlencode(o.transport.mode)) end
|
||||
if o.transport.extra then table.insert(p, "extra=" .. urlencode(o.transport.extra)) end
|
||||
add_param(p, "type", o.transport.type)
|
||||
add_param(p, "headerType", o.transport.headerType)
|
||||
add_param(p, "host", o.transport.host)
|
||||
add_param(p, "path", o.transport.path)
|
||||
add_param(p, "serviceName", o.transport.serviceName)
|
||||
add_param(p, "mode", o.transport.mode)
|
||||
add_param(p, "extra", o.transport.extra)
|
||||
|
||||
if #p > 0 then
|
||||
link = link .. "?" .. table.concat(p, "&")
|
||||
@@ -262,23 +296,24 @@ end
|
||||
local function encode_trojan(node)
|
||||
local o = build_common(node)
|
||||
|
||||
local link = "trojan://" .. node.password .. "@" .. o.server .. ":" .. o.port
|
||||
local link = "trojan://" .. urlencode(node.password) .. "@" .. o.server .. ":" .. o.port
|
||||
local p = {}
|
||||
|
||||
if o.tls.security then table.insert(p, "security=" .. o.tls.security) end
|
||||
if o.tls.pbk then table.insert(p, "pbk=" .. urlencode(o.tls.pbk)) end
|
||||
if o.tls.sid then table.insert(p, "sid=" .. urlencode(o.tls.sid)) end
|
||||
if o.tls.sni then table.insert(p, "sni=" .. urlencode(o.tls.sni)) end
|
||||
if o.tls.fp then table.insert(p, "fp=" .. urlencode(o.tls.fp)) end
|
||||
if o.tls.alpn then table.insert(p, "alpn=" .. urlencode(o.tls.alpn)) end
|
||||
if o.tls.ech then table.insert(p, "ech=" .. urlencode(o.tls.ech)) end
|
||||
if o.tls.pcs then table.insert(p, "pcs=" .. urlencode(o.tls.pcs)) end
|
||||
table.insert(p, "allowInsecure=" .. (o.tls.insecure and "1" or "0"))
|
||||
|
||||
table.insert(p, "type=" .. o.transport.type)
|
||||
if o.transport.host then table.insert(p, "host=" .. urlencode(o.transport.host)) end
|
||||
if o.transport.path then table.insert(p, "path=" .. urlencode(o.transport.path)) end
|
||||
if o.transport.serviceName then table.insert(p, "serviceName=" .. urlencode(o.transport.serviceName)) end
|
||||
add_param(p, "security", o.tls.security)
|
||||
add_param(p, "pbk", o.tls.pbk)
|
||||
add_param(p, "sid", o.tls.sid)
|
||||
add_param(p, "sni", o.tls.sni)
|
||||
add_param(p, "fp", o.tls.fp)
|
||||
add_param(p, "alpn", o.tls.alpn)
|
||||
add_param(p, "ech", o.tls.ech)
|
||||
add_param(p, "pcs", o.tls.pcs)
|
||||
add_param(p, "vcn", o.tls.vcn)
|
||||
add_param(p, "allowInsecure", o.tls.insecure)
|
||||
add_param(p, "type", o.transport.type)
|
||||
add_param(p, "headerType", o.transport.headerType)
|
||||
add_param(p, "host", o.transport.host)
|
||||
add_param(p, "path", o.transport.path)
|
||||
add_param(p, "serviceName", o.transport.serviceName)
|
||||
|
||||
if #p > 0 then
|
||||
link = link .. "?" .. table.concat(p, "&")
|
||||
@@ -301,21 +336,22 @@ local function encode_vmess(node)
|
||||
net = o.transport.type,
|
||||
security = node.cipher,
|
||||
scy = node.cipher,
|
||||
type = "none",
|
||||
type = o.transport.headerType or "none",
|
||||
host = o.transport.host or "",
|
||||
path = o.transport.path or "",
|
||||
path = urlencode(o.transport.path or ""),
|
||||
tls = o.tls.security == "tls" and "tls" or "",
|
||||
sni = o.tls.sni,
|
||||
alpn = o.tls.alpn,
|
||||
fp = o.tls.fp,
|
||||
ech = o.tls.ech,
|
||||
pcs = o.tls.pcs,
|
||||
vcn = o.tls.vcn,
|
||||
insecure = o.tls.insecure and "1" or "0",
|
||||
tfo = node.tfo and "1" or "0"
|
||||
}
|
||||
|
||||
if o.transport.type == "grpc" then
|
||||
obj.path = o.transport.serviceName or ""
|
||||
obj.path = urlencode(o.transport.serviceName or "")
|
||||
end
|
||||
|
||||
return 0, "vmess://" .. base64(json.stringify(obj))
|
||||
@@ -337,14 +373,14 @@ local function encode_ss(node)
|
||||
|
||||
local p = {}
|
||||
|
||||
if node.udp then table.insert(p, "udp=1") end
|
||||
if node["udp-over-tcp"] then table.insert(p, "uot=1") end
|
||||
if node.udp then add_param(p, "udp", true) end
|
||||
if node["udp-over-tcp"] then add_param(p, "uot", true) end
|
||||
|
||||
if node.plugin then
|
||||
local plugin = (node.plugin == "obfs") and "obfs-local" or node.plugin
|
||||
if plugin == "shadow-tls" then
|
||||
local shadow_tls = base64(json.stringify(node["plugin-opts"] or {}))
|
||||
table.insert(p, "shadow-tls=" .. urlencode(shadow_tls))
|
||||
add_param(p, "shadow-tls", shadow_tls)
|
||||
elseif plugin == "obfs-local" or plugin == "v2ray-plugin" then
|
||||
local opts = {}
|
||||
for k, v in pairs(node["plugin-opts"] or {}) do
|
||||
@@ -369,7 +405,7 @@ local function encode_ss(node)
|
||||
end
|
||||
end
|
||||
if #opts > 0 then plugin = plugin .. ";" .. table.concat(opts, ";") end
|
||||
table.insert(p, "plugin=" .. urlencode(plugin))
|
||||
add_param(p, "plugin", plugin)
|
||||
else
|
||||
return 1, "订阅转换 → 丢弃 SS 节点:" .. (node.name or "") .. ",因 Core 不支持 " .. plugin .. " 插件"
|
||||
end
|
||||
@@ -383,22 +419,24 @@ local function encode_ss(node)
|
||||
end
|
||||
|
||||
-- Hysteria
|
||||
local function encode_hysteria2(node)
|
||||
local function encode_hysteria(node)
|
||||
if node.protocol and node.protocol ~= "udp" then
|
||||
return 1, "订阅转换 → 丢弃 Hysteria 节点:" .. node.name .. ",当前 Core 不支持 " .. node.protocol .. " 传输"
|
||||
end
|
||||
local link = "hysteria://" .. host_format(node.server) .. ":" .. (node.port or "")
|
||||
local p = {}
|
||||
|
||||
if node["auth-str"] then table.insert(p, "auth=" .. node["auth-str"]) end
|
||||
if node["ports"] then table.insert(p, "mport=" .. node["ports"]) end
|
||||
if node.obfs then table.insert(p, "obfsParam=" .. node.obfs) end
|
||||
if node.sni then table.insert(p, "sni=" .. node.sni) end
|
||||
if node.up then table.insert(p, "upmbps=" .. node.up) end
|
||||
if node.down then table.insert(p, "downmbps=" .. node.down) end
|
||||
if node["skip-cert-verify"] then table.insert(p, "insecure=1") end
|
||||
if node["fingerprint"] then table.insert(p, "pinSHA256=" .. urlencode(node["fingerprint"])) end
|
||||
add_param(p, "auth", node["auth-str"])
|
||||
add_param(p, "mport", node.ports)
|
||||
add_param(p, "obfsParam", node.obfs)
|
||||
add_param(p, "sni", node.sni)
|
||||
add_param(p, "upmbps", bandwidth_mbps(node.up))
|
||||
add_param(p, "downmbps", bandwidth_mbps(node.down))
|
||||
add_param(p, "insecure", node["skip-cert-verify"] == true)
|
||||
add_param(p, "vcn", node["name-cert-verify"])
|
||||
add_param(p, "pinSHA256", node.fingerprint)
|
||||
|
||||
if node.alpn then
|
||||
table.insert(p, "alpn=" .. urlencode(build_alpn(node.alpn)))
|
||||
end
|
||||
add_param(p, "alpn", build_alpn(node.alpn))
|
||||
|
||||
if #p > 0 then
|
||||
link = link .. "?" .. table.concat(p, "&")
|
||||
@@ -409,20 +447,24 @@ end
|
||||
|
||||
-- Hysteria2
|
||||
local function encode_hysteria2(node)
|
||||
local link = "hysteria2://" .. (node.password or "") .. "@" .. host_format(node.server) .. ":" .. (node.port or "")
|
||||
-- Hopping subscriptions may omit port; keep a valid fallback for all cores.
|
||||
local port = node.port or tostring(node.ports or ""):match("^%s*(%d+)")
|
||||
local link = "hysteria2://" .. urlencode(node.password or "") .. "@" .. host_format(node.server) .. ":" .. port
|
||||
local p = {}
|
||||
|
||||
if node["ports"] then table.insert(p, "mport=" .. urlencode(node["ports"])) end
|
||||
if node.obfs then table.insert(p, "obfs=" .. node.obfs) end
|
||||
if node["obfs-password"] then table.insert(p, "obfs-password=" .. node["obfs-password"]) end
|
||||
if node["obfs-min-packet-size"] then table.insert(p, "minPacketSize=" .. node["obfs-min-packet-size"]) end
|
||||
if node["obfs-max-packet-size"] then table.insert(p, "maxPacketSize=" .. node["obfs-max-packet-size"]) end
|
||||
if node.up then table.insert(p, "upmbps=" .. node.up) end
|
||||
if node.down then table.insert(p, "downmbps=" .. node.down) end
|
||||
|
||||
if node.sni then table.insert(p, "sni=" .. urlencode(node.sni)) end
|
||||
if node["skip-cert-verify"] then table.insert(p, "insecure=1") end
|
||||
if node["fingerprint"] then table.insert(p, "pinSHA256=" .. urlencode(node["fingerprint"])) end
|
||||
add_param(p, "mport", node.ports)
|
||||
add_param(p, "hopInterval", node["hop-interval"])
|
||||
add_param(p, "obfs", node.obfs)
|
||||
add_param(p, "obfs-password", node["obfs-password"])
|
||||
add_param(p, "minPacketSize", node["obfs-min-packet-size"])
|
||||
add_param(p, "maxPacketSize", node["obfs-max-packet-size"])
|
||||
add_param(p, "upmbps", bandwidth_mbps(node.up))
|
||||
add_param(p, "downmbps", bandwidth_mbps(node.down))
|
||||
add_param(p, "ech", build_ech(node))
|
||||
add_param(p, "vcn", node["name-cert-verify"])
|
||||
add_param(p, "sni", node.sni)
|
||||
add_param(p, "insecure", node["skip-cert-verify"] == true)
|
||||
add_param(p, "pinSHA256", node.fingerprint)
|
||||
|
||||
if #p > 0 then
|
||||
link = link .. "?" .. table.concat(p, "&")
|
||||
@@ -433,22 +475,23 @@ end
|
||||
|
||||
-- TUIC
|
||||
local function encode_tuic(node)
|
||||
local link = "tuic://" .. node.uuid .. ":" .. node.password .. "@" .. host_format(node.server) .. ":" .. node.port
|
||||
if node.token then
|
||||
return 1, "订阅转换 → 丢弃 TUIC 节点:" .. node.name .. ",当前 Core 不支持 TUIC v4"
|
||||
end
|
||||
if not node.uuid or node.password == nil then
|
||||
return 1, "订阅转换 → 丢弃 TUIC 节点:" .. node.name .. ",认证信息不完整。"
|
||||
end
|
||||
local link = "tuic://" .. urlencode(node.uuid) .. ":" .. urlencode(node.password) .. "@" .. host_format(node.server) .. ":" .. node.port
|
||||
local p = {}
|
||||
|
||||
if node["congestion-controller"] then
|
||||
table.insert(p, "congestion_control=" .. node["congestion-controller"])
|
||||
end
|
||||
|
||||
if node.alpn then
|
||||
table.insert(p, "alpn=" .. urlencode(build_alpn(node.alpn)))
|
||||
end
|
||||
|
||||
if node.sni then table.insert(p, "sni=" .. urlencode(node.sni)) end
|
||||
if node["disable-sni"] then table.insert(p, "disable_sni=1") end
|
||||
if node["skip-cert-verify"] then table.insert(p, "allowInsecure=1") end
|
||||
if node["udp-relay-mode"] then table.insert(p, "udp_relay_mode=" .. node["udp-relay-mode"]) end
|
||||
if node["fingerprint"] then table.insert(p, "pcs=" .. urlencode(node["fingerprint"])) end
|
||||
add_param(p, "congestion_control", node["congestion-controller"])
|
||||
add_param(p, "alpn", build_alpn(node.alpn))
|
||||
add_param(p, "sni", node.sni)
|
||||
if node["disable-sni"] then add_param(p, "disable_sni", true) end
|
||||
add_param(p, "allowInsecure", node["skip-cert-verify"] == true)
|
||||
add_param(p, "udp_relay_mode", node["udp-relay-mode"])
|
||||
add_param(p, "pcs", node.fingerprint)
|
||||
add_param(p, "vcn", node["name-cert-verify"])
|
||||
|
||||
if #p > 0 then
|
||||
link = link .. "?" .. table.concat(p, "&")
|
||||
@@ -474,18 +517,18 @@ local function encode_anytls(node)
|
||||
|
||||
local o = build_common(node)
|
||||
|
||||
local link = "anytls://" .. (node.password or "") .. "@" .. host_format(node.server) .. ":" .. node.port
|
||||
local link = "anytls://" .. urlencode(node.password or "") .. "@" .. host_format(node.server) .. ":" .. node.port
|
||||
local p = {}
|
||||
|
||||
if o.tls.security then table.insert(p, "security=" .. o.tls.security) end
|
||||
if o.tls.pbk then table.insert(p, "pbk=" .. urlencode(o.tls.pbk)) end
|
||||
if o.tls.sid then table.insert(p, "sid=" .. urlencode(o.tls.sid)) end
|
||||
if o.tls.sni then table.insert(p, "sni=" .. urlencode(o.tls.sni)) end
|
||||
if o.tls.alpn then table.insert(p, "alpn=" .. urlencode(o.tls.alpn)) end
|
||||
if o.tls.fp then table.insert(p, "fp=" .. urlencode(o.tls.fp)) end
|
||||
if o.tls.ech then table.insert(p, "ech=" .. urlencode(o.tls.ech)) end
|
||||
if o.tls.pcs then table.insert(p, "pcs=" .. urlencode(o.tls.pcs)) end
|
||||
table.insert(p, "insecure=" .. (o.tls.insecure and "1" or "0"))
|
||||
add_param(p, "security", o.tls.security)
|
||||
add_param(p, "pbk", o.tls.pbk)
|
||||
add_param(p, "sid", o.tls.sid)
|
||||
add_param(p, "sni", o.tls.sni)
|
||||
add_param(p, "alpn", o.tls.alpn)
|
||||
add_param(p, "fp", o.tls.fp)
|
||||
add_param(p, "ech", o.tls.ech)
|
||||
add_param(p, "pcs", o.tls.pcs)
|
||||
add_param(p, "insecure", o.tls.insecure)
|
||||
|
||||
if #p > 0 then
|
||||
link = link .. "?" .. table.concat(p, "&")
|
||||
@@ -514,8 +557,8 @@ end
|
||||
-- snell
|
||||
local function encode_snell(node)
|
||||
local err_msg
|
||||
local obfs = node["obfs-opts"]
|
||||
if obfs and obfs.mode ~= "http" and obfs.mode ~= "none" then
|
||||
local obfs = node["obfs-opts"] or {}
|
||||
if obfs.mode and obfs.mode ~= "http" and obfs.mode ~= "none" then
|
||||
err_msg = obfs.mode
|
||||
end
|
||||
if err_msg then
|
||||
@@ -532,13 +575,13 @@ local function encode_snell(node)
|
||||
local link = "snell://" .. host_format(node.server) .. ":" .. node.port
|
||||
local p = {}
|
||||
|
||||
if node.psk then table.insert(p, "psk=" .. urlencode(node.psk)) end
|
||||
table.insert(p, "version=" .. version)
|
||||
add_param(p, "psk", node.psk)
|
||||
add_param(p, "version", version)
|
||||
if obfs.mode == "http" then
|
||||
table.insert(p, "obfs=http")
|
||||
if obfs.host then table.insert(p, "obfs-host=" .. urlencode(obfs.host)) end
|
||||
add_param(p, "obfs", "http")
|
||||
add_param(p, "obfs-host", obfs.host)
|
||||
end
|
||||
table.insert(p, "reuse=" .. (node.reuse and "1" or "0"))
|
||||
add_param(p, "reuse", node.reuse and "1" or "0")
|
||||
|
||||
if #p > 0 then
|
||||
link = link .. "?" .. table.concat(p, "&")
|
||||
@@ -548,9 +591,22 @@ local function encode_snell(node)
|
||||
end
|
||||
|
||||
local function encode_node(node)
|
||||
if (not node.type) or (not node.name) then return nil end
|
||||
if type(node) ~= "table" or not node.type or not node.name then
|
||||
return 1, "订阅转换 → 跳过格式不完整的节点。"
|
||||
end
|
||||
if not node.server or node.server == "" or not (node.port or (node.type == "hysteria2" and node.ports)) then
|
||||
return 1, "订阅转换 → 丢弃节点:" .. tostring(node.name) .. ",节点信息不完整。"
|
||||
end
|
||||
node = inherit(node)
|
||||
|
||||
local t = node.type
|
||||
if t == "hysteria" or t == "hysteria2" then
|
||||
local up, down = bandwidth_mbps(node.up), bandwidth_mbps(node.down)
|
||||
if (node.up ~= nil and up == nil) or (node.down ~= nil and down == nil) then
|
||||
return 1, "订阅转换 → 丢弃节点:" .. tostring(node.name) .. ",带宽格式不正确。"
|
||||
end
|
||||
node.up, node.down = up, down
|
||||
end
|
||||
|
||||
node.server = domain_redir[node.server] or node.server
|
||||
|
||||
@@ -570,17 +626,22 @@ end
|
||||
|
||||
function parseClashNode(raw, remark)
|
||||
if not raw then return "" end
|
||||
domain_redir = {}
|
||||
local ok, lyaml = pcall(require, "lyaml")
|
||||
if not ok then return raw end
|
||||
|
||||
local data = lyaml.load(raw)
|
||||
local parsed, data = pcall(lyaml.load, raw)
|
||||
if not parsed then
|
||||
api.log('订阅转换 → YAML 解析失败:' .. tostring(remark or ""))
|
||||
return ""
|
||||
end
|
||||
if not data or type(data) ~= "table" then return raw end
|
||||
if not data.proxies then return "" end
|
||||
if type(data.proxies) ~= "table" then return "" end
|
||||
|
||||
api.log('检测到 Clash 订阅,正在进行转换 ...')
|
||||
|
||||
-- Some airports use hosts domain redirect to disguise the real node domain name.
|
||||
for k, v in pairs(data.hosts or {}) do
|
||||
for k, v in pairs(type(data.hosts) == "table" and data.hosts or {}) do
|
||||
if type(k) == "string" and type(v) == "string" then
|
||||
if api.datatypes.hostname(k) and api.datatypes.hostname(v) then
|
||||
domain_redir[k] = v
|
||||
@@ -590,8 +651,11 @@ function parseClashNode(raw, remark)
|
||||
|
||||
local links = {}
|
||||
for _, node in ipairs(data.proxies) do
|
||||
local err, link = encode_node(node)
|
||||
if err == 1 and link then
|
||||
local converted, err, link = pcall(encode_node, node)
|
||||
if not converted then
|
||||
local name = type(node) == "table" and node.name or ""
|
||||
api.log('订阅转换 → 丢弃节点:' .. tostring(name or "") .. ',转换失败,已跳过。')
|
||||
elseif err == 1 and link then
|
||||
api.log(link)
|
||||
elseif link then
|
||||
table.insert(links, link)
|
||||
|
||||
@@ -144,6 +144,14 @@ local log = function(...)
|
||||
end
|
||||
end
|
||||
|
||||
local function flush_log_buffer()
|
||||
local buffered = log_buffer
|
||||
log_buffer = nil
|
||||
for _, msg in ipairs(buffered or {}) do
|
||||
log(msg)
|
||||
end
|
||||
end
|
||||
|
||||
local nodes_table = {}
|
||||
for k, e in ipairs(api.get_valid_nodes()) do
|
||||
if e.node_type == "normal" then
|
||||
@@ -889,6 +897,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
||||
result.method = method
|
||||
result.ss_method = method
|
||||
result.password = password
|
||||
result.uot = params.uot
|
||||
result.tcp_fast_open = params.tfo
|
||||
result.use_finalmask = (params.fm and params.fm ~= "") and "1" or nil
|
||||
result.finalmask = (params.fm and params.fm ~= "") and api.base64Encode(params.fm) or nil
|
||||
@@ -1043,7 +1052,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
||||
end
|
||||
local insecure = params.allowinsecure or params.allowInsecure or params.insecure
|
||||
result.tls_allowInsecure = (insecure == "1" or insecure == "0") and insecure or (sub_allowinsecure and "1" or "0")
|
||||
result.uot = params.udp
|
||||
result.uot = params.uot or params.udp
|
||||
else
|
||||
result.error_msg = "请更换 Xray 或 Sing-Box 来支持 SS 更多的传输方式。"
|
||||
end
|
||||
@@ -1424,7 +1433,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
||||
for _, v in pairs(split(query[2], '&')) do
|
||||
local s = v:find("=", 1, true)
|
||||
if s and s > 1 then
|
||||
params[v:sub(1, s - 1)] = v:sub(s + 1)
|
||||
params[v:sub(1, s - 1)] = UrlDecode(v:sub(s + 1))
|
||||
end
|
||||
end
|
||||
-- [2001:4860:4860::8888]:443
|
||||
@@ -1451,6 +1460,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
||||
result.hysteria_up_mbps = params.upmbps or sub_hy_up_mbps
|
||||
result.hysteria_down_mbps = params.downmbps or sub_hy_down_mbps
|
||||
result.hysteria_hop = params.mport
|
||||
result.tls_CertByName = params.vcn
|
||||
|
||||
elseif szType == 'hysteria2' or szType == 'hy2' then
|
||||
local alias = ""
|
||||
@@ -1494,6 +1504,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
||||
result.hysteria2_up_mbps = params.upmbps or (sub_cfg and sub_hy_up_mbps or nil)
|
||||
result.hysteria2_down_mbps = params.downmbps or (sub_cfg and sub_hy_down_mbps or nil)
|
||||
result.hysteria2_hop = params.mport
|
||||
result.hysteria2_hop_interval = params.hopinterval or params["hop-interval"]
|
||||
if params.ech and params.ech ~= "" then
|
||||
result.ech = "1"
|
||||
result.ech_config = params.ech
|
||||
@@ -1573,6 +1584,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
||||
end
|
||||
result.tls_serverName = params.sni
|
||||
result.tls_disable_sni = params.disable_sni
|
||||
result.tls_CertByName = params.vcn
|
||||
result.tls_pinSHA256 = params.pcs or params.pinsha256
|
||||
result.tuic_alpn = params.alpn or "h3"
|
||||
result.tuic_congestion_control = params.congestion_control or "cubic"
|
||||
@@ -1998,10 +2010,29 @@ local function select_node(nodes, config, parentConfig)
|
||||
end
|
||||
end
|
||||
|
||||
-- 账户信息只在实际变化时写回,由调用方统一提交。
|
||||
local function update_subscribe_info()
|
||||
local changed = {}
|
||||
for cfgid, info in pairs(subscribe_info) do
|
||||
for key, value in pairs(info) do
|
||||
value = value and value ~= "" and value or nil
|
||||
if uci_get(cfgid, key) ~= value then
|
||||
if value then
|
||||
uci_set(cfgid, key, value)
|
||||
else
|
||||
uci_del(cfgid, key)
|
||||
end
|
||||
changed[cfgid] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
return changed
|
||||
end
|
||||
|
||||
local function update_node(manual)
|
||||
if next(nodeResult) == nil then
|
||||
log("没有可用的节点信息更新。")
|
||||
return
|
||||
return false
|
||||
end
|
||||
|
||||
local group = {}
|
||||
@@ -2091,17 +2122,6 @@ local function update_node(manual)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- 更新机场信息
|
||||
for cfgid, info in pairs(subscribe_info) do
|
||||
for key, value in pairs(info) do
|
||||
if value ~= "" then
|
||||
uci_set(cfgid, key, value)
|
||||
else
|
||||
uci_del(cfgid, key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if next(CONFIG) then
|
||||
local nodes = {}
|
||||
uci_foreach("nodes", function(node)
|
||||
@@ -2123,9 +2143,7 @@ local function update_node(manual)
|
||||
end
|
||||
end
|
||||
|
||||
uci_save(true)
|
||||
|
||||
if manual ~= 1 then restart_required = true end
|
||||
return true
|
||||
end
|
||||
|
||||
local function parse_link(raw, add_mode, group, sub_cfg)
|
||||
@@ -2289,26 +2307,17 @@ local execute = function()
|
||||
if not manual_sub and new_md5 ~= "" and old_md5 == new_md5 then
|
||||
log_buffer = nil -- 无物理变动,直接丢弃暂存的丢弃与计数明细
|
||||
log('订阅:【' .. remark .. '】没有变化,无需更新。')
|
||||
if subscribe_info[cfgid] then
|
||||
log('订阅:【' .. remark .. '】已同步刷新账户用量与到期时间信息。')
|
||||
end
|
||||
else
|
||||
-- 节点发生变动时,回放前置解析期间的节点统计与丢弃日志
|
||||
if log_buffer then
|
||||
local bufs = log_buffer
|
||||
log_buffer = nil
|
||||
for _, msg in ipairs(bufs) do
|
||||
log(msg)
|
||||
end
|
||||
end
|
||||
-- 仅在成功解析出有效节点时才写入配置并记录新 MD5,防止解析失败时误存空数据或伪造无变更状态
|
||||
flush_log_buffer()
|
||||
-- 暂存有效节点及其 MD5,完成节点更新后再一起写入配置。
|
||||
if #parsed_nodes > 0 then
|
||||
nodeResult[#nodeResult + 1] = {
|
||||
remark = remark,
|
||||
list = parsed_nodes,
|
||||
sub_cfg = value
|
||||
sub_cfg = value,
|
||||
md5 = new_md5
|
||||
}
|
||||
uci_set(cfgid, "md5", new_md5)
|
||||
end
|
||||
end
|
||||
else
|
||||
@@ -2319,30 +2328,33 @@ local execute = function()
|
||||
end
|
||||
end
|
||||
end
|
||||
-- 无论节点物理配置是否变动,始终将最新提取到的账户用量与到期时间静默写回 UCI,确保 Web 面板实时刷新
|
||||
for c_id, info in pairs(subscribe_info) do
|
||||
for key, val in pairs(info) do
|
||||
if val and val ~= "" then
|
||||
uci_set(c_id, key, val)
|
||||
else
|
||||
uci_del(c_id, key)
|
||||
end
|
||||
end
|
||||
end
|
||||
uci_save(true)
|
||||
|
||||
if #fail_list > 0 then
|
||||
for index, value in ipairs(fail_list) do
|
||||
log(string.format('【%s】订阅失败,可能是订阅地址无效,或是网络问题,请诊断![%s]', (value.remark or ""), tostring(value.http_code or 0)))
|
||||
end
|
||||
end
|
||||
update_node(0)
|
||||
local nodes_changed = update_node(0)
|
||||
local info_changed = update_subscribe_info()
|
||||
-- 节点、引用关系和 MD5 必须在同一次提交中保存。
|
||||
for _, result in ipairs(nodeResult) do
|
||||
uci_set(result.sub_cfg[".name"], "md5", result.md5)
|
||||
end
|
||||
if nodes_changed or next(info_changed) then
|
||||
uci_save(true)
|
||||
restart_required = nodes_changed
|
||||
for _, value in ipairs(subscribe_list) do
|
||||
if info_changed[value[".name"]] then
|
||||
log(string.format('刷新订阅【%s】账户用量与到期时间信息。', (value.remark or "")))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if arg[1] == "start" then
|
||||
log('开始订阅...')
|
||||
xpcall(execute, function(e)
|
||||
flush_log_buffer()
|
||||
log(e)
|
||||
if type(debug) == "table" and type(debug.traceback) == "function" then
|
||||
log(debug.traceback())
|
||||
@@ -2355,7 +2367,7 @@ elseif arg[1] == "add" then
|
||||
local raw = f:read('*all')
|
||||
f:close()
|
||||
parse_link(raw, "1", arg[2])
|
||||
update_node(1)
|
||||
if update_node(1) then uci_save(true) end
|
||||
api.remove("/tmp/links.conf")
|
||||
elseif arg[1] == "truncate" then
|
||||
truncate_nodes(arg[2])
|
||||
|
||||
@@ -68,6 +68,19 @@ return view.extend({
|
||||
" and prioritisation on one " +
|
||||
"network interface.");
|
||||
|
||||
// For these options sqm-scripts and sqm-autorate read unset as the
|
||||
// default: a stored value equal to it was deleted on save (rmempty),
|
||||
// an unset one written (rmempty off). Keep either as it is.
|
||||
var keepAsStored = function(o) {
|
||||
var write = o.write;
|
||||
o.rmempty = false;
|
||||
o.write = function(section_id, value) {
|
||||
if (value == this.default && uci.get('sqm', section_id, this.option) == null)
|
||||
return;
|
||||
return write.apply(this, arguments);
|
||||
};
|
||||
};
|
||||
|
||||
s = m.section(form.TypedSection, 'queue', _('Queues'));
|
||||
s.tab("tab_basic", _("Basic Settings"));
|
||||
s.tab("tab_qdisc", _("Queue Discipline"));
|
||||
@@ -88,7 +101,7 @@ return view.extend({
|
||||
}, this);
|
||||
|
||||
o = s.taboption("tab_basic", form.Flag, "autorate", _("Enable SQM autorate"));
|
||||
o.rmempty = false;
|
||||
keepAsStored(o);
|
||||
|
||||
o = s.taboption("tab_basic", widgets.DeviceSelect, "interface", _("Interface name"));
|
||||
o.rmempty = false;
|
||||
@@ -132,6 +145,7 @@ return view.extend({
|
||||
o.value("8", "debug");
|
||||
o.value("10", "trace");
|
||||
o.default = "5";
|
||||
keepAsStored(o);
|
||||
|
||||
o = s.taboption("tab_qdisc", form.ListValue, "qdisc", _("Queuing disciplines useable on this system. After installing a new qdisc, you need to restart the router to see updates!"),_("Must be set to cake if autorate is used."));
|
||||
for (var i=0; i < qdiscs.length; i++) {
|
||||
@@ -156,6 +170,7 @@ return view.extend({
|
||||
|
||||
o = s.taboption("tab_qdisc", form.Flag, "qdisc_advanced", _("Show and Use Advanced Configuration. Advanced options will only be used as long as this box is checked."));
|
||||
o.default = false;
|
||||
keepAsStored(o);
|
||||
|
||||
o = s.taboption("tab_qdisc", form.Flag, "use_mq", _("Enable multi-queue config"), _("Enable multi-queue qdisc on supported hardware. If .qos script does not support mq this option is ignored."));
|
||||
o.default = false;
|
||||
@@ -217,6 +232,7 @@ return view.extend({
|
||||
o.value("ethernet", "Ethernet with overhead: select for e.g. VDSL2.");
|
||||
o.value("atm", "ATM: select for e.g. ADSL1, ADSL2, ADSL2+.");
|
||||
o.default = "none";
|
||||
keepAsStored(o);
|
||||
|
||||
o = s.taboption("tab_linklayer", form.Value, "overhead", _("Per Packet Overhead (byte):"));
|
||||
o.datatype = "and(integer,min(-1500))";
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=mptcp
|
||||
PKG_VERSION:=6.1
|
||||
PKG_RELEASE:=26
|
||||
PKG_RELEASE:=27
|
||||
|
||||
PKG_MAINTAINER:=Ycarus (Yannick Chabanois) <ycarus@zugaina.org>
|
||||
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
@@ -247,7 +247,10 @@ case $1 in
|
||||
if [ -f /proc/net/mptcp_net/snmp ]; then
|
||||
cat /proc/net/mptcp_net/snmp
|
||||
else
|
||||
nstat -z | grep -i mptcp
|
||||
# Absolute counters (-a), without touching nstat's history (-s):
|
||||
# plain "nstat -z" printed the delta since anyone's previous nstat
|
||||
# call and reset it, so two viewers zeroed each other's numbers.
|
||||
nstat -a -s -z | grep -i mptcp
|
||||
fi
|
||||
exit 0 ;;
|
||||
"-v")
|
||||
|
||||
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=sqm-autorate
|
||||
PKG_VERSION:=0.1
|
||||
PKG_RELEASE:=7
|
||||
PKG_RELEASE:=8
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
# defaults launcher.sh uses, and for the same reason).
|
||||
CONFIG_DIR="${SQM_AUTORATE_DIR:-/usr/share/sqm-autorate}"
|
||||
RUN_DIR="${SQM_AUTORATE_RUN_DIR:-/var/run/sqm-autorate}"
|
||||
SQM_RUN="${SQM_RUN_SH:-/usr/lib/sqm/run.sh}"
|
||||
AUTORATE_INIT="${SQM_AUTORATE_INIT:-/etc/init.d/sqm-autorate}"
|
||||
|
||||
# UCI options readable via get_config / settable via set_config -- mirrors
|
||||
# what luci-app-sqm-autorate's sqm.js form exposes, plus the autorate-only
|
||||
@@ -112,6 +114,23 @@ _metrics_json() {
|
||||
"$(_json_str "$base_ul")" "$(_json_str "$min_ul")" "$(_json_str "$max_ul")" "$(_iface_metrics_json "$ul_if")"
|
||||
}
|
||||
|
||||
# Re-apply sqm-scripts on the section's device. "uci commit" from a shell
|
||||
# fires no procd reload trigger, and run.sh start returns early while the
|
||||
# device's state file exists, so without a stop+start the qdisc kept its
|
||||
# old setup: CAKE stayed on after enabled=0, or never came up after
|
||||
# enabled=1. The previous device is stopped too when the section moved.
|
||||
_apply_sqm() {
|
||||
local old_if="$1" new_if="$2"
|
||||
|
||||
[ -x "$SQM_RUN" ] || return 1
|
||||
if [ -n "$old_if" ] && [ "$old_if" != "$new_if" ]; then
|
||||
"$SQM_RUN" stop "$old_if" >/dev/null 2>&1
|
||||
fi
|
||||
[ -n "$new_if" ] || return 0
|
||||
"$SQM_RUN" stop "$new_if" >/dev/null 2>&1
|
||||
"$SQM_RUN" start "$new_if" >/dev/null 2>&1
|
||||
return 0
|
||||
}
|
||||
|
||||
# Ask launcher.sh to kill+respawn only this section's cake-autorate.sh
|
||||
# instance, leaving every other WAN's warm state untouched (see
|
||||
@@ -152,8 +171,9 @@ case "$1" in
|
||||
# get_config/get_metrics: omit "section" to get every sqm queue section.
|
||||
# set_config: pass any subset of the known sqm option names alongside
|
||||
# "section" (e.g. download, max_download, delay_thr_ms, ...); only
|
||||
# recognised options are applied. restart=true bounces the whole
|
||||
# sqm-autorate service afterwards (regenerates and relaunches every
|
||||
# recognised options are applied. restart=true re-applies the
|
||||
# section's SQM qdisc on its device, then bounces the whole
|
||||
# sqm-autorate service (regenerates and relaunches every
|
||||
# instance). For a config change scoped to one WAN, prefer applying
|
||||
# it with restart:false and then calling restart_instance for just
|
||||
# that section instead -- it leaves every other WAN's cake-autorate
|
||||
@@ -198,6 +218,7 @@ case "$1" in
|
||||
exit 1
|
||||
fi
|
||||
|
||||
old_if=$(uci -q get "sqm.${section}.interface" 2>/dev/null)
|
||||
applied=""
|
||||
for opt in $VALID_OPTIONS; do
|
||||
val=$(echo "$input" | jsonfilter -q -e "@.${opt}" 2>/dev/null)
|
||||
@@ -226,12 +247,17 @@ case "$1" in
|
||||
|
||||
uci -q commit sqm
|
||||
|
||||
sqm_applied=false
|
||||
if [ "$restart" = "true" ]; then
|
||||
/etc/init.d/sqm-autorate restart >/dev/null 2>&1 &
|
||||
# Synchronous, so the qdisc matches the config when
|
||||
# the call returns; the autorate instances restart
|
||||
# after it, on the new qdisc.
|
||||
_apply_sqm "$old_if" "$(uci -q get "sqm.${section}.interface" 2>/dev/null)" && sqm_applied=true
|
||||
"$AUTORATE_INIT" restart >/dev/null 2>&1 &
|
||||
fi
|
||||
|
||||
printf '{"result":"ok","section":"%s","applied":[%s],"restarted":%s}' \
|
||||
"$(_json_str "$section")" "$applied" "$([ "$restart" = "true" ] && echo true || echo false)"
|
||||
printf '{"result":"ok","section":"%s","applied":[%s],"restarted":%s,"sqm_applied":%s}' \
|
||||
"$(_json_str "$section")" "$applied" "$([ "$restart" = "true" ] && echo true || echo false)" "$sqm_applied"
|
||||
;;
|
||||
|
||||
get_metrics)
|
||||
|
||||
Reference in new issue
Block a user