diff --git a/luci-app-mwan3-ledhelper-nft/Makefile b/luci-app-mwan3-ledhelper-nft/Makefile new file mode 100644 index 000000000..5007d2e26 --- /dev/null +++ b/luci-app-mwan3-ledhelper-nft/Makefile @@ -0,0 +1,11 @@ +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=MWAN3 Ledhelper simple webUI +LUCI_DEPENDS:=+luci-app-mwan3-nft +mwan3-ledhelper-nft +PKG_LICENSE:=GPLv3 +PKG_VERSION:=0.0.1 +PKG_RELEASE:=1 + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-mwan3-ledhelper-nft/htdocs/luci-static/resources/view/mwan3/network/led.js b/luci-app-mwan3-ledhelper-nft/htdocs/luci-static/resources/view/mwan3/network/led.js new file mode 100644 index 000000000..d3dcf6fbb --- /dev/null +++ b/luci-app-mwan3-ledhelper-nft/htdocs/luci-static/resources/view/mwan3/network/led.js @@ -0,0 +1,110 @@ +'use strict'; +'require form'; +'require fs'; +'require view'; +'require uci'; +'require rpc'; +'require ui'; +'require network'; +'require tools.widgets as widgets' + +var callLEDs = rpc.declare({ + object: 'luci', + method: 'getLEDs', + expect: { '': {} } +}); + +return view.extend({ + load: function() { + return Promise.all([ + callLEDs(), + L.resolveDefault(fs.list('/www' + L.resource('view/system/led-trigger')), []), + // load config mwan3 + fs.read('/etc/config/mwan3').catch(function(err) { return ''; }) + ]).then(function(data) { + var plugins = data[1]; + var mwan3Config = data[2]; + var tasks = []; + + // parce ifaces mwan3 config + var mwan3Interfaces = []; + if (mwan3Config) { + var lines = mwan3Config.split('\n'); + for (var i = 0; i < lines.length; i++) { + var line = lines[i].trim(); + var match = line.match(/^config interface '([^']+)'/); + if (match) { + mwan3Interfaces.push(match[1]); + } + } + } + + for (var i = 0; i < plugins.length; i++) { + var m = plugins[i].name.match(/^(.+)\.js$/); + + if (plugins[i].type != 'file' || m == null) + continue; + + tasks.push(L.require('view.system.led-trigger.' + m[1]).then(L.bind(function(name){ + return L.resolveDefault(L.require('view.system.led-trigger.' + name)).then(function(form) { + return { + name: name, + form: form, + }; + }); + }, this, m[1]))); + } + + return Promise.all(tasks).then(function(plugins) { + var value = {}; + value[0] = data[0]; + value[1] = plugins; + value[2] = mwan3Interfaces; // add mwan3 iface + return value; + }); + }); + }, + + render: function(data) { + var m, s, o, triggers = []; + var leds = data[0]; + var mwan3Interfaces = data[2]; // get ifaces from mwan3 config + + for (var k in leds) + for (var i = 0; i < leds[k].triggers.length; i++) + triggers[i] = leds[k].triggers[i]; + + m = new form.Map('mwan3_led', _('MWAN3 Ledhelper'), _('Flash led on link state.')); + s = m.section(form.GridSection, 'led', null); + s.anonymous = false; + s.addremove = true; + + // filter NetworkSelect + o = s.option(widgets.NetworkSelect, 'iface', _('Set interface')); + o.exclude = s.section; + o.nocreate = true; + o.optional = true; + // filter interfaces + o.filter = function(section_id, value) { + return mwan3Interfaces.indexOf(value) !== -1; + }; + + o = s.option(form.ListValue, 'led_on', _('Select LED online')); + Object.keys(leds).sort().forEach(function(name) { + o.value(name); + }); + o.value('', _('Exclude')); + o.default = ''; + o.rmempty = true; + + o = s.option(form.ListValue, 'led_off', _('Select LED offline')); + Object.keys(leds).sort().forEach(function(name) { + o.value(name); + }); + o.value('', _('Exclude')); + o.default = ''; + o.rmempty = true; + + return m.render(); + } +}); diff --git a/luci-app-mwan3-ledhelper-nft/po/ru/mwan3-ledhelper.po b/luci-app-mwan3-ledhelper-nft/po/ru/mwan3-ledhelper.po new file mode 100644 index 000000000..b65f816b8 --- /dev/null +++ b/luci-app-mwan3-ledhelper-nft/po/ru/mwan3-ledhelper.po @@ -0,0 +1,22 @@ +"Language: ru\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Last-Translator: Konstantine Shevlakov \n" + +msgid "Flash led on link state." +msgstr "Индикация светодиодов" + +msgid "Name" +msgstr "Имя" + +msgid "Set interface" +msgstr "Интерфейс" + +msgid "Exclude" +msgstr "Не использовать" + +msgid "Select LED online" +msgstr "LED \"в сети\"" + +msgid "Select LED offline" +msgstr "LED \"вне сети\"" diff --git a/luci-app-mwan3-ledhelper-nft/root/usr/share/luci/menu.d/luci-app-mwan3-ledhelper-nft.json b/luci-app-mwan3-ledhelper-nft/root/usr/share/luci/menu.d/luci-app-mwan3-ledhelper-nft.json new file mode 100644 index 000000000..22ea9a314 --- /dev/null +++ b/luci-app-mwan3-ledhelper-nft/root/usr/share/luci/menu.d/luci-app-mwan3-ledhelper-nft.json @@ -0,0 +1,10 @@ +{ + "admin/network/mwan3/led": { + "title": "LED", + "order": 55, + "action": { + "type": "view", + "path": "mwan3/network/led" + } + } +} diff --git a/luci-app-mwan3-ledhelper-nft/root/usr/share/rpcd/acl.d/luci-app-mwan3-ledhelper-nft.json b/luci-app-mwan3-ledhelper-nft/root/usr/share/rpcd/acl.d/luci-app-mwan3-ledhelper-nft.json new file mode 100644 index 000000000..55b25647e --- /dev/null +++ b/luci-app-mwan3-ledhelper-nft/root/usr/share/rpcd/acl.d/luci-app-mwan3-ledhelper-nft.json @@ -0,0 +1,25 @@ +{ + "luci-app-mwan3-ledhelper-nft": { + "description": "Grant access to MWAN3 LED configuration", + "read": { + "file": { + "/etc/init.d/mwan3": [ "exec" ], + "/etc/config/mwan3": [ "read" ] + }, + "cgi-io": [ "exec" ], + "ubus": { + "file": [ "exec" ], + "uci": [ "changes", "get" ] + }, + "uci": [ "mwan3_led" ] + }, + "write": { + "cgi-io": [ "exec" ], + "ubus": { + "file": [ "exec" ], + "uci": [ "add", "apply", "confirm", "delete", "order", "rename", "set" ] + }, + "uci": [ "mwan3_led" ] + } + } +} diff --git a/luci-app-mwan3-nft/Makefile b/luci-app-mwan3-nft/Makefile new file mode 100644 index 000000000..c2d69c1f4 --- /dev/null +++ b/luci-app-mwan3-nft/Makefile @@ -0,0 +1,16 @@ +# +# Copyright (C) 2017 Dan Luedtke +# +# This is free software, licensed under the GNU General Public License v2. + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=LuCI support for the MWAN3 MultiWAN Manager +LUCI_DEPENDS:=+luci-base +mwan3-nft +PKG_LICENSE:=GPL-2.0 + +PKG_MAINTAINER:=Florian Eckert + +include $(TOPDIR)/feeds/luci/luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/mwan3.css b/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/mwan3.css new file mode 100644 index 000000000..ebe7764c8 --- /dev/null +++ b/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/mwan3.css @@ -0,0 +1,8 @@ +#mwan3-service-status > .alert-message { + display: inline-block; + margin: 1rem; + padding: 1rem; + width: 15rem; + height: 6rem; + vertical-align: middle; +} diff --git a/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/network/globals.js b/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/network/globals.js new file mode 100644 index 000000000..bcf58138c --- /dev/null +++ b/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/network/globals.js @@ -0,0 +1,48 @@ +'use strict'; +'require form'; +'require view'; + +return view.extend({ + + render: function () { + let m, s, o; + + m = new form.Map('mwan3', _('MultiWAN Manager - Globals')); + + s = m.section(form.NamedSection, 'globals', 'globals'); + + o = s.option(form.Value, 'mmx_mask', _('Firewall mask'), + _('Enter value in hex, starting with 0x')); + o.datatype = 'hex(4)'; + o.default = '0x3F00'; + + o = s.option(form.Flag, 'logging', _('Logging'), + _('Enables global firewall logging')); + + o = s.option(form.ListValue, 'loglevel', _('Loglevel'), + _('Firewall loglevel')); + o.default = 'notice'; + o.value('emerg', _('Emergency')); + o.value('alert', _('Alert')); + o.value('crit', _('Critical')); + o.value('error', _('Error')); + o.value('warning', _('Warning')); + o.value('notice', _('Notice')); + o.value('info', _('Info')); + o.value('debug', _('Debug')); + o.depends('logging', '1'); + + o = s.option(form.DynamicList, 'rt_table_lookup', + _('Routing table lookup'), + _('Also scan this Routing table for connected networks')); + o.datatype = 'uinteger'; + o.value('220', _('Routing table %d').format('220')); + + o = s.option(form.Flag, 'show_overview', _('Show on overview'), + _('Show MultiWAN status section on the overview page')); + o.default = o.enabled; + o.rmempty = false; + + return m.render(); + } +}) diff --git a/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/network/interface.js b/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/network/interface.js new file mode 100644 index 000000000..2761a8674 --- /dev/null +++ b/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/network/interface.js @@ -0,0 +1,324 @@ +'use strict'; +'require form'; +'require fs'; +'require view'; +'require uci'; +'require ui'; + +return view.extend({ + load: function() { + return Promise.all([ + L.resolveDefault(fs.stat('/usr/bin/httping'), {}), + L.resolveDefault(fs.stat('/usr/bin/nping'), {}), + L.resolveDefault(fs.stat('/usr/bin/arping'), {}), + uci.load('network') + ]); + }, + + render: function (stats) { + let m, s, o; + + m = new form.Map('mwan3', _('MultiWAN Manager - Interfaces'), + _('Mwan3 requires that all interfaces have a unique metric configured in /etc/config/network.') + '
' + + _('Names must match the interface name found in /etc/config/network.') + '
' + + _('Names may contain characters A-Z, a-z, 0-9, _ and no spaces-') + '
' + + _('Interfaces may not share the same name as configured members, policies or rules.')); + + s = m.section(form.GridSection, 'interface'); + s.addremove = true; + s.anonymous = false; + s.nodescriptions = true; + + s.renderSectionAdd = function(extra_class) { + var usedNames = [ + ...uci.sections('mwan3', 'interface'), + ...uci.sections('mwan3', 'member'), + ...uci.sections('mwan3', 'policy'), + ...uci.sections('mwan3', 'rule') + ].map(function(sec) { return sec['.name']; }); + + var available = uci.sections('network', 'interface') + .map(function(sec) { return sec['.name']; }) + .filter(function(name) { + return name !== 'loopback' && + name.length <= 15 && + usedNames.indexOf(name) === -1; + }); + + var el = E('div', { 'class': 'cbi-section-create' + (extra_class ? ' ' + extra_class : '') }, [ + E('div', { 'class': 'cbi-section-create-name-container' }, [ + E('select', { + 'class': 'cbi-section-create-name', + 'style': 'min-width: 12em' + }, available.length + ? available.map(function(name) { + return E('option', { 'value': name }, name); + }) + : [E('option', { 'value': '', 'disabled': true, 'selected': true }, + _('No available interfaces'))] + ), + E('button', { + 'class': 'cbi-button cbi-button-add', + 'title': _('Add'), + 'disabled': available.length === 0 || null, + 'click': ui.createHandlerFn(this, function(ev) { + var select = ev.target.closest('.cbi-section-create') + .querySelector('select.cbi-section-create-name'); + var name = select ? select.value : ''; + if (!name) return; + return this.handleAdd(ev, name); + }) + }, _('Add')) + ]) + ]); + + return el; + }; + + o = s.option(form.Flag, 'enabled', _('Enabled')); + o.default = false; + + o = s.option(form.ListValue, 'initial_state', _('Initial state'), + _('Expect interface state on up event')); + o.default = 'online'; + o.value('online', _('Online')); + o.value('offline', _('Offline')); + o.modalonly = true; + + o = s.option(form.ListValue, 'family', _('Internet Protocol')); + o.default = 'ipv4'; + o.value('ipv4', _('IPv4')); + o.value('ipv6', _('IPv6')); + o.modalonly = true; + + o = s.option(form.DynamicList, 'track_ip', _('Tracking hostname or IP address'), + _('This hostname or IP address will be pinged to determine if the link is up or down. Leave blank to assume interface is always online')); + o.datatype = 'host'; + o.modalonly = true; + + o = s.option(form.ListValue, 'track_method', _('Tracking method')); + o.default = 'ping'; + o.value('ping'); + if (stats[0].type === 'file') { + o.value('httping'); + } + if (stats[1].type === 'file') { + o.value('nping-tcp'); + o.value('nping-udp'); + o.value('nping-icmp'); + o.value('nping-arp'); + } + if (stats[2].type === 'file') { + o.value('arping'); + } + + o = s.option(form.Flag, 'httping_ssl', _('Enable ssl tracking'), + _('Enables https tracking on ssl port 443')); + o.depends('track_method', 'httping'); + o.rmempty = false; + o.modalonly = true; + + o = s.option(form.Value, 'reliability', _('Tracking reliability'), + _('Acceptable values: 1-100. This many Tracking IP addresses must respond for the link to be deemed up')); + o.datatype = 'range(1, 100)'; + o.default = '1'; + + o = s.option(form.ListValue, 'count', _('Ping count')); + o.default = '1'; + o.value('1'); + o.value('2'); + o.value('3'); + o.value('4'); + o.value('5'); + o.modalonly = true; + + o = s.option(form.Value, 'size', _('Ping size')); + o.default = '56'; + o.depends('track_method', 'ping'); + o.value('8'); + o.value('24'); + o.value('56'); + o.value('120'); + o.value('248'); + o.value('504'); + o.value('1016'); + o.value('1472'); + o.value('2040'); + o.datatype = 'range(1, 65507)'; + o.modalonly = true; + + o =s.option(form.Value, 'max_ttl', _('Max TTL')); + o.default = '60'; + o.depends('track_method', 'ping'); + o.value('10'); + o.value('20'); + o.value('30'); + o.value('40'); + o.value('50'); + o.value('60'); + o.value('70'); + o.datatype = 'range(1, 255)'; + o.modalonly = true; + + o = s.option(form.Flag, 'check_quality', _('Check link quality')); + o.depends('track_method', 'ping'); + o.default = false; + o.modalonly = true; + + o = s.option(form.Value, 'failure_latency', _('Failure latency [ms]')); + o.depends('check_quality', '1'); + o.default = '1000'; + o.value('25'); + o.value('50'); + o.value('75'); + o.value('100'); + o.value('150'); + o.value('200'); + o.value('250'); + o.value('300'); + o.modalonly = true; + + o = s.option(form.Value, 'failure_loss', _('Failure packet loss [%]')); + o.depends('check_quality', '1'); + o.default = '40'; + o.value('2'); + o.value('5'); + o.value('10'); + o.value('20'); + o.value('25'); + o.modalonly = true; + + o = s.option(form.Value, 'recovery_latency', _('Recovery latency [ms]')); + o.depends('check_quality', '1'); + o.default = '500'; + o.value('25'); + o.value('50'); + o.value('75'); + o.value('100'); + o.value('150'); + o.value('200'); + o.value('250'); + o.value('300'); + o.modalonly = true; + + o = s.option(form.Value, 'recovery_loss', _('Recovery packet loss [%]')); + o.depends('check_quality', '1'); + o.default = '10'; + o.value('2'); + o.value('5'); + o.value('10'); + o.value('20'); + o.value('25'); + o.modalonly = true; + + o = s.option(form.ListValue, "timeout", _("Ping timeout")); + o.default = '4'; + o.value('1', _('%d second').format('1')); + for (var i = 2; i <= 10; i++) + o.value(String(i), _('%d seconds').format(i)); + o.modalonly = true; + + o = s.option(form.ListValue, 'interval', _('Ping interval')); + o.default = '10'; + o.value('1', _('%d second').format('1')); + o.value('3', _('%d seconds').format('3')); + o.value('5', _('%d seconds').format('5')); + o.value('10', _('%d seconds').format('10')); + o.value('20', _('%d seconds').format('20')); + o.value('30', _('%d seconds').format('30')); + o.value('60', _('%d minute').format('1')); + o.value('300', _('%d minutes').format('5')); + o.value('600', _('%d minutes').format('10')); + o.value('900', _('%d minutes').format('15')); + o.value('1800', _('%d minutes').format('30')); + o.value('3600', _('%d hour').format('1')); + + o = s.option(form.Value, 'failure_interval', _('Failure interval'), + _('Ping interval during failure detection')); + o.default = '5'; + o.value('1', _('%d second').format('1')); + o.value('3', _('%d seconds').format('3')); + o.value('5', _('%d seconds').format('5')); + o.value('10', _('%d seconds').format('10')); + o.value('20', _('%d seconds').format('20')); + o.value('30', _('%d seconds').format('30')); + o.value('60', _('%d minute').format('1')); + o.value('300', _('%d minutes').format('5')); + o.value('600', _('%d minutes').format('10')); + o.value('900', _('%d minutes').format('15')); + o.value('1800', _('%d minutes').format('30')); + o.value('3600', _('%d hour').format('1')); + o.modalonly = true; + + o = s.option(form.Flag, 'keep_failure_interval', _('Keep failure interval'), + _('Keep ping failure interval during failure state')); + o.default = false; + o.modalonly = true; + + o = s.option(form.Value, 'recovery_interval', _('Recovery interval'), + _('Ping interval during failure recovering')); + o.default = '5'; + o.value('1', _('%d second').format('1')); + o.value('3', _('%d seconds').format('3')); + o.value('5', _('%d seconds').format('5')); + o.value('10', _('%d seconds').format('10')); + o.value('20', _('%d seconds').format('20')); + o.value('30', _('%d seconds').format('30')); + o.value('60', _('%d minute').format('1')); + o.value('300', _('%d minutes').format('5')); + o.value('600', _('%d minutes').format('10')); + o.value('900', _('%d minutes').format('15')); + o.value('1800', _('%d minutes').format('30')); + o.value('3600', _('%d hour').format('1')); + o.modalonly = true; + + o = s.option(form.ListValue, 'down', _('Interface down'), + _('Interface will be deemed down after this many failed ping tests')); + o.default = '5'; + o.value('1'); + o.value('2'); + o.value('3'); + o.value('4'); + o.value('5'); + o.value('6'); + o.value('7'); + o.value('8'); + o.value('9'); + o.value('10'); + + o = s.option(form.ListValue, 'up', _('Interface up'), + _('Downed interface will be deemed up after this many successful ping tests')); + o.default = "5"; + o.value('1'); + o.value('2'); + o.value('3'); + o.value('4'); + o.value('5'); + o.value('6'); + o.value('7'); + o.value('8'); + o.value('9'); + o.value('10'); + + o = s.option(form.DynamicList, 'flush_conntrack', _('Flush conntrack table'), + _('Flush global firewall conntrack table on interface events')); + o.value('ifup', _('ifup (netifd)')); + o.value('ifdown', _('ifdown (netifd)')); + o.value('connected', _('connected (mwan3)')); + o.value('disconnected', _('disconnected (mwan3)')); + o.modalonly = true; + + o = s.option(form.DummyValue, 'metric', _('Metric'), + _('This displays the metric assigned to this interface in /etc/config/network')); + o.rawhtml = true; + o.cfgvalue = function(s) { + var metric = uci.get('network', s, 'metric') + if (metric) + return metric; + else + return _('No interface metric set!'); + } + + return m.render(); + } +}) diff --git a/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/network/member.js b/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/network/member.js new file mode 100644 index 000000000..8a4195243 --- /dev/null +++ b/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/network/member.js @@ -0,0 +1,67 @@ +'use strict'; +'require form'; +'require view'; +'require uci'; +'require ui'; + +return view.extend({ + load: function() { + return Promise.all([ + uci.load('mwan3') + ]); + }, + + render: function () { + let m, s, o; + + m = new form.Map('mwan3', _('MultiWAN Manager - Members'), + _('Members are profiles attaching a metric and weight to an MWAN interface.') + '
' + + _('Names may contain characters A-Z, a-z, 0-9, _ and no spaces.') + '
' + + _('Members may not share the same name as configured interfaces, policies or rules.')); + + s = m.section(form.GridSection, 'member'); + s.addremove = true; + s.anonymous = false; + s.nodescriptions = true; + + /* This name length error check can likely be removed when mwan3 migrates to nftables */ + s.renderSectionAdd = function(extra_class) { + var el = form.GridSection.prototype.renderSectionAdd.apply(this, arguments), + nameEl = el.querySelector('.cbi-section-create-name'); + ui.addValidator(nameEl, 'uciname', true, function(v) { + let sections = [ + ...uci.sections('mwan3', 'interface'), + ...uci.sections('mwan3', 'member'), + ...uci.sections('mwan3', 'policy'), + ...uci.sections('mwan3', 'rule') + ]; + + for (let j = 0; j < sections.length; j++) { + if (sections[j]['.name'] == v) { + return _('Members may not share the same name as configured interfaces, policies or rules.'); + } + } + if (v.length > 15) return _('Name length shall not exceed 15 characters'); + return true; + }, 'blur', 'keyup'); + return el; + }; + + o = s.option(form.ListValue, 'interface', _('Interface')); + var options = uci.sections('mwan3', 'interface') + for (var i = 0; i < options.length; i++) { + var value = options[i]['.name']; + o.value(value); + } + + o = s.option(form.Value, 'metric', _('Metric'), + _('Acceptable values: 1-256. Defaults to 1 if not set')); + o.datatype = 'range(1, 256)'; + + o = s.option(form.Value, 'weight', _('Weight'), + _('Acceptable values: 1-1000. Defaults to 1 if not set')); + o.datatype = 'range(1, 1000)'; + + return m.render(); + } +}) diff --git a/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/network/notify.js b/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/network/notify.js new file mode 100644 index 000000000..31dbdb2be --- /dev/null +++ b/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/network/notify.js @@ -0,0 +1,52 @@ +'use strict'; +'require view'; +'require fs'; +'require ui'; + +const isReadonlyView = !L.hasViewPermission() || null; + +return view.extend({ + load() { + return L.resolveDefault(fs.read('/etc/mwan3.user'), ''); + }, + + handleSave(ev) { + const value = (document.querySelector('textarea').value || '').trim().replace(/\r\n/g, '\n') + '\n'; + + return fs.write('/etc/mwan3.user', value).then(function(rc) { + document.querySelector('textarea').value = value; + ui.addNotification(null, E('p', _('Contents have been saved.')), 'info'); + }).catch(function(e) { + ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message))); + }); + }, + + render(mwan3user) { + return E([ + E('h2', _('MultiWAN Manager - Notify')), + E('p', { 'class': 'cbi-section-descr' }, + _('This section allows you to modify the content of "/etc/mwan3.user".') + '
' + + _('The file is also preserved during sysupgrade.') + '
' + + '
' + + _('Notes:') + '
' + + _('This file is interpreted as a shell script.') + '
' + + _('The first line of the script must be "#!/bin/sh" without quotes.') + '
' + + _('Lines beginning with # are comments and are not executed.') + '
' + + _('Put your custom mwan3 action here, they will be executed with each netifd hotplug interface event on interfaces for which mwan3 is enabled.') + '
' + + '
' + + _('There are three main environment variables that are passed to this script.') + '
' + + '
' + + _('%s: Name of the action that triggered this event').format('$ACTION') + '
' + + _('* %s: Is called by netifd and mwan3track').format('ifup') + '
' + + _('* %s: Is called by netifd and mwan3track').format('ifdown') + '
' + + _('* %s: Is only called by mwan3track if tracking was successful').format('connected') + '
' + + _('* %s: Is only called by mwan3track if tracking has failed').format('disonnected') + '
' + + _('%s: Name of the interface which went up or down (e.g. "wan" or "wwan")').format('$INTERFACE') + '
' + + _('%s: Name of Physical device which interface went up or down (e.g. "eth0" or "wwan0")').format('$DEVICE') + '
'), + E('p', {}, E('textarea', { 'style': 'width:100%', 'rows': 10, 'disabled': isReadonlyView }, [ mwan3user != null ? mwan3user : '' ])) + ]); + }, + + handleSaveApply: null, + handleReset: null +}); diff --git a/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/network/policy.js b/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/network/policy.js new file mode 100644 index 000000000..73ab7b746 --- /dev/null +++ b/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/network/policy.js @@ -0,0 +1,70 @@ +'use strict'; +'require form'; +'require view'; +'require uci'; +'require ui'; + +return view.extend({ + load: function() { + return Promise.all([ + uci.load('mwan3') + ]); + }, + + render: function () { + let m, s, o; + + m = new form.Map('mwan3', _('MultiWAN Manager - Policies'), + _('Policies are profiles grouping one or more members controlling how Mwan3 distributes traffic.') + '
' + + _('Member interfaces with lower metrics are used first.') + '
' + + _('Member interfaces with the same metric will be load-balanced.') + '
' + + _('Load-balanced member interfaces distribute more traffic out those with higher weights.') + '
' + + _('Names may contain characters A-Z, a-z, 0-9, _ and no spaces.') + '
' + + _('Names must be 15 characters or less.') + '
' + + _('Policies may not share the same name as configured interfaces, members or rules')); + + s = m.section(form.GridSection, 'policy'); + s.addremove = true; + s.anonymous = false; + s.nodescriptions = true; + + /* This name length error check can likely be removed when mwan3 migrates to nftables */ + s.renderSectionAdd = function(extra_class) { + var el = form.GridSection.prototype.renderSectionAdd.apply(this, arguments), + nameEl = el.querySelector('.cbi-section-create-name'); + ui.addValidator(nameEl, 'uciname', true, function(v) { + let sections = [ + ...uci.sections('mwan3', 'interface'), + ...uci.sections('mwan3', 'member'), + ...uci.sections('mwan3', 'policy'), + ...uci.sections('mwan3', 'rule') + ]; + + for (let j = 0; j < sections.length; j++) { + if (sections[j]['.name'] == v) { + return _('Policies may not share the same name as configured interfaces, members or rules'); + } + } + if (v.length > 15) return _('Name length shall not exceed 15 characters'); + return true; + }, 'blur', 'keyup'); + return el; + }; + + o = s.option(form.DynamicList, 'use_member', _('Member used')); + var options = uci.sections('mwan3', 'member') + for (var i = 0; i < options.length; i++) { + var value = options[i]['.name']; + o.value(value); + } + + o = s.option(form.ListValue, 'last_resort', _('Last resort'), + _('When all policy members are offline use this behavior for matched traffic')); + o.default = 'unreachable'; + o.value('unreachable', _('unreachable (reject)')); + o.value('blackhole', _('blackhole (drop)')); + o.value('default', _('default (use main routing table)')); + + return m.render(); + } +}) diff --git a/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/network/rule.js b/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/network/rule.js new file mode 100644 index 000000000..134231d54 --- /dev/null +++ b/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/network/rule.js @@ -0,0 +1,132 @@ +'use strict'; +'require form'; +'require fs'; +'require view'; +'require uci'; +'require ui'; + +return view.extend({ + load: function() { + return Promise.all([ + fs.exec_direct('/usr/libexec/luci-mwan3', ['ipset', 'dump']), + uci.load('mwan3') + ]); + }, + + render: function (data) { + let m, s, o; + + m = new form.Map('mwan3', _('MultiWAN Manager - Rules'), + _('Rules specify which traffic will use a particular MWAN policy.') + '
' + + _('Rules are based on IP address, port or protocol.') + '
' + + _('Rules are matched from top to bottom.') + '
' + + _('Rules below a matching rule are ignored.') + '
' + + _('Traffic not matching any rule is routed using the main routing table.') + '
' + + _('Traffic destined for known (other than default) networks is handled by the main routing table.') + '
' + + _('Traffic matching a rule, but all WAN interfaces for that policy are down will be blackholed.') + '
' + + _('Names may contain characters A-Z, a-z, 0-9, _ and no spaces.') + '
' + + _('Rules may not share the same name as configured interfaces, members or policies.')); + + s = m.section(form.GridSection, 'rule'); + s.addremove = true; + s.anonymous = false; + s.nodescriptions = true; + s.sortable = true; + + /* This name length error check can likely be removed when mwan3 migrates to nftables */ + s.renderSectionAdd = function(extra_class) { + const el = form.GridSection.prototype.renderSectionAdd.apply(this, arguments); + const nameEl = el.querySelector('.cbi-section-create-name'); + ui.addValidator(nameEl, 'uciname', true, function(v) { + let sections = [ + ...uci.sections('mwan3', 'interface'), + ...uci.sections('mwan3', 'member'), + ...uci.sections('mwan3', 'policy'), + ...uci.sections('mwan3', 'rule') + ]; + + for (let j = 0; j < sections.length; j++) { + if (sections[j]['.name'] == v) { + return _('Rules may not share the same name as configured interfaces, members or policies.'); + } + } + if (v.length > 15) return _('Name length shall not exceed 15 characters'); + return true; + }, 'blur', 'keyup'); + return el; + }; + + o = s.option(form.ListValue, 'family', _('Internet Protocol')); + o.default = ''; + o.value('', _('IPv4 and IPv6')); + o.value('ipv4', _('IPv4 only')); + o.value('ipv6', _('IPv6 only')); + o.modalonly = true; + + o = s.option(form.Value, 'proto', _('Protocol'), + _('View the content of /etc/protocols for protocol description')); + o.default = 'all'; + o.rmempty = false; + o.value('all'); + o.value('tcp'); + o.value('udp'); + o.value('icmp'); + o.value('esp'); + + o = s.option(form.Value, 'src_ip', _('Source address'), + _('Supports CIDR notation (eg "192.168.100.0/24") without quotes')); + o.datatype = 'ipaddr'; + + o = s.option(form.Value, 'src_port', _('Source port'), + _('May be entered as a single or multiple port(s) (eg "22" or "80,443") or as a portrange (eg "1024:2048") without quotes')); + o.depends('proto', 'tcp'); + o.depends('proto', 'udp'); + + o = s.option(form.Value, 'dest_ip', _('Destination address'), + _('Supports CIDR notation (eg "192.168.100.0/24") without quotes')); + o.datatype = 'ipaddr'; + + o = s.option(form.Value, 'dest_port', _('Destination port'), + _('May be entered as a single or multiple port(s) (eg "22" or "80,443") or as a portrange (eg "1024:2048") without quotes')); + o.depends('proto', 'tcp'); + o.depends('proto', 'udp'); + + o = s.option(form.ListValue, 'sticky', _('Sticky'), + _('Traffic from the same source IP address that previously matched this rule within the sticky timeout period will use the same WAN interface')); + o.default = '0'; + o.value('1', _('Yes')); + o.value('0', _('No')); + o.modalonly = true; + + o = s.option(form.Value, 'timeout', _('Sticky timeout'), + _('Seconds. Acceptable values: 1-1000000. Defaults to 600 if not set')); + o.datatype = 'range(1, 1000000)'; + o.modalonly = true; + o.depends('sticky', '1'); + + o = s.option(form.Value, 'ipset', _('IPset'), + _('Name of IPset rule. Requires IPset rule in /etc/dnsmasq.conf (eg "ipset=/youtube.com/youtube")')); + o.value('', _('-- Please choose --')); + let ipsets = data[0].split(/\n/); + for (let ips of ipsets) { + if (ips.length > 0) + o.value(ips); + } + o.modalonly = true; + + o = s.option(form.Flag, 'logging', _('Logging'), + _('Enables firewall rule logging (global mwan3 logging must also be enabled)')); + o.modalonly = true; + + o = s.option(form.ListValue, 'use_policy', _('Policy assigned')); + let options = uci.sections('mwan3', 'policy') + for (let opt of options) { + o.value(opt['.name']); + } + o.value('unreachable', _('unreachable (reject)')); + o.value('blackhole', _('blackhole (drop)')); + o.value('default', _('default (use main routing table)')); + + return m.render(); + } +}) diff --git a/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/status/detail.js b/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/status/detail.js new file mode 100644 index 000000000..552b1321f --- /dev/null +++ b/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/status/detail.js @@ -0,0 +1,22 @@ +'use strict'; +'require fs'; +'require view'; + +return view.extend({ + load: function() { + return L.resolveDefault(fs.exec_direct('/usr/sbin/mwan3', [ 'status' ]),''); + }, + + render: function (report) { + return E('div', { 'class': 'cbi-map', 'id': 'map' }, [ + E('h2', _('MultiWAN Manager - Status')), + E('div', { 'class': 'cbi-section' }, [ + E('pre', [ report ]) + ]), + ]) + }, + + handleSaveApply: null, + handleSave: null, + handleReset: null +}) diff --git a/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/status/diagnostics.js b/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/status/diagnostics.js new file mode 100644 index 000000000..71bee68f8 --- /dev/null +++ b/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/status/diagnostics.js @@ -0,0 +1,116 @@ +'use strict'; +'require fs'; +'require uci'; +'require dom'; +'require ui'; +'require view'; + +return view.extend({ + handleCommand: function(exec, args) { + var buttons = document.querySelectorAll('.cbi-button'); + + for (var i = 0; i < buttons.length; i++) + buttons[i].setAttribute('disabled', 'true'); + + return fs.exec(exec, args).then(function(res) { + var out = document.querySelector('.command-output'); + out.style.display = ''; + + dom.content(out, [ res.stdout || '', res.stderr || '' ]); + }).catch(function(err) { + ui.addNotification(null, E('p', [ err ])) + }).finally(function() { + for (var i = 0; i < buttons.length; i++) + buttons[i].removeAttribute('disabled'); + }); + }, + + handleAction: function(ev) { + var iface = document.getElementById('iface'); + var task = document.getElementById('task'); + + switch (task.value) { + case 'gateway': + return this.handleCommand('/usr/libexec/luci-mwan3', + [ 'diag', 'gateway', iface.value ]); + case 'tracking': + return this.handleCommand('/usr/libexec/luci-mwan3', + [ 'diag', 'tracking', iface.value ]); + case 'rules': + return this.handleCommand('/usr/libexec/luci-mwan3', + [ 'diag', 'rules', iface.value ]); + case 'routes': + return this.handleCommand('/usr/libexec/luci-mwan3', + [ 'diag', 'routes', iface.value ]); + case 'ifup': + return this.handleCommand('/usr/sbin/mwan3', + [ 'ifup', iface.value]); + case 'ifdown': + return this.handleCommand('/usr/sbin/mwan3', + [ 'ifdown', iface.value]); + } + }, + + load: function() { + return Promise.all([ + uci.load('mwan3') + ]); + }, + + render: function () { + + var taskSel = [ + E('option', { 'value': 'gateway' }, [ _('Ping default gateway') ]), + E('option', { 'value': 'tracking' }, [ _('Ping tracking IP') ]), + E('option', { 'value': 'rules' }, [ _('Check IP rules') ]), + E('option', { 'value': 'routes' }, [ _('Check routing table') ]), + E('option', { 'value': 'ifup' }, [ _('Hotplug ifup') ]), + E('option', { 'value': 'ifdown' }, [ _('Hotplug ifdown') ]) + ]; + + var ifaceSel = [E('option', { value: '' }, [_('-- Interface Selection --')])]; + + var options = uci.sections('mwan3', 'interface') + for (var i = 0; i < options.length; i++) { + ifaceSel.push(E('option', { 'value': options[i]['.name'] }, options[i]['.name'])); + } + + return E('div', { 'class': 'cbi-map', 'id': 'map' }, [ + E('h2', {}, [ _('MultiWAN Manager - Diagnostics') ]), + E('div', { 'class': 'cbi-section' }, [ + E('div', { 'class': 'cbi-section-node' }, [ + E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title' }, [ _('Interface') ]), + E('div', { 'class': 'cbi-value-field' }, [ + E('select', {'class': 'cbi-input-select', 'id': 'iface'}, + ifaceSel + ) + ]) + ]), + E('div', { 'class': 'cbi-value' }, [ + E('label', { 'class': 'cbi-value-title' }, [ _('Task') ]), + E('div', { 'class': 'cbi-value-field' }, [ + E('select', { 'class': 'cbi-input-select', 'id': 'task' }, + taskSel + ) + ]) + ]) + ]) + ]), + '\xa0', + E('pre', { 'class': 'command-output', 'style': 'display:none' }), + '\xa0', + E('div', { 'class': 'right' }, [ + E('button', { + 'class': 'cbi-button cbi-button-apply', + 'id': 'execute', + 'click': ui.createHandlerFn(this, 'handleAction') + }, [ _('Execute') ]), + ]), + ]); + }, + + handleSaveApply: null, + handleSave: null, + handleReset: null +}) diff --git a/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/status/overview.js b/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/status/overview.js new file mode 100644 index 000000000..d63fb6540 --- /dev/null +++ b/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/status/overview.js @@ -0,0 +1,109 @@ +'use strict'; +'require poll'; +'require view'; +'require rpc'; + +const callMwan3Status = rpc.declare({ + object: 'mwan3', + method: 'status', + params: ['section'], + expect: { }, +}); + +function getStatusBackgroundClass(status) { + switch (status) { + case 'online': + return 'label success'; + case 'offline': + return 'label warning'; + case 'disabled': + return 'label'; + case 'notracking': + return 'label'; + default: + return 'label'; + } +} + +function renderMwan3Status(status) { + if (!status.interfaces) + return '%h'.format(_('No MWAN interfaces found')); + + var tableHtml = ''; + tableHtml += ''; + tableHtml += ''; + tableHtml += ''; + tableHtml += ''; + tableHtml += ''; + + for (var iface in status.interfaces) { + var state = ''; + var time = ''; + var statusType = status.interfaces[iface].status; + + switch (statusType) { + case 'online': + state = _('Online'); + time = '%t'.format(status.interfaces[iface].online); + break; + case 'offline': + state = _('Offline'); + time = '%t'.format(status.interfaces[iface].offline); + break; + case 'notracking': + state = _('No Tracking'); + if ((status.interfaces[iface].uptime) > 0) { + time = '%t'.format(status.interfaces[iface].uptime); + } else { + time = ''; + } + break; + default: + state = _('Disabled'); + time = ''; + break; + } + + var statusClass = getStatusBackgroundClass(statusType); + + tableHtml += ''; + tableHtml += ''; + tableHtml += ''; + tableHtml += ''; + tableHtml += ''; + } + + tableHtml += '
' + _('Interface') + '' + _('Status') + '' + _('Uptime') + '
' + iface + '' + state + '' + (time || '') + '
'; + + return tableHtml; +} + +return view.extend({ + load: function() { + return Promise.all([ + callMwan3Status("interfaces"), + ]); + }, + + render: function (data) { + poll.add(function() { + return callMwan3Status("interfaces").then(function(result) { + var view = document.getElementById('mwan3-service-status'); + view.innerHTML = renderMwan3Status(result); + }); + }); + + return E('div', { class: 'cbi-map' }, [ + E('h2', [ _('MultiWAN Manager - Overview') ]), + E('div', { class: 'cbi-section' }, [ + E('div', { 'id': 'mwan3-service-status' }, [ + E('em', { 'class': 'spinning' }, [ _('Collecting data ...') ]) + ]) + ]) + ]); + }, + + handleSaveApply: null, + handleSave: null, + handleReset: null +}); diff --git a/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/status/troubleshooting.js b/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/status/troubleshooting.js new file mode 100644 index 000000000..644612517 --- /dev/null +++ b/luci-app-mwan3-nft/htdocs/luci-static/resources/view/mwan3/status/troubleshooting.js @@ -0,0 +1,22 @@ +'use strict'; +'require fs'; +'require view'; + +return view.extend({ + load: function() { + return L.resolveDefault(fs.exec_direct('/usr/sbin/mwan3', [ 'internal', 'ipv4' ]),''); + }, + + render: function (report) { + return E('div', { 'class': 'cbi-map', 'id': 'map' }, [ + E('h2', _('MultiWAN Manager - Troubleshooting')), + E('div', { 'class': 'cbi-section' }, [ + E('pre', [ report ]) + ]), + ]) + }, + + handleSaveApply: null, + handleSave: null, + handleReset: null +}) diff --git a/luci-app-mwan3-nft/htdocs/luci-static/resources/view/status/include/90_mwan3.js b/luci-app-mwan3-nft/htdocs/luci-static/resources/view/status/include/90_mwan3.js new file mode 100644 index 000000000..20cef8463 --- /dev/null +++ b/luci-app-mwan3-nft/htdocs/luci-static/resources/view/status/include/90_mwan3.js @@ -0,0 +1,117 @@ +'use strict'; +'require baseclass'; +'require rpc'; +'require uci'; + +const callMwan3Status = rpc.declare({ + object: 'mwan3', + method: 'status', + params: ['section'], + expect: { }, +}); + +function getStatusBackgroundClass(status) { + switch (status) { + case 'online': + return 'label success'; + case 'offline': + return 'label warning'; + case 'disabled': + return 'label'; + case 'notracking': + return 'label'; + default: + return 'label'; + } +} + +return baseclass.extend({ + title: _('MultiWAN Manager'), + + load: function() { + return uci.load('mwan3').then(function() { + var globals = uci.sections('mwan3', 'globals'); + if (!globals || !globals[0] || globals[0].show_overview !== '1') + return null; + return Promise.all([ + callMwan3Status("interfaces"), + ]); + }); + }, + + render: function (result) { + if (!result) + return null; + + if (!result[0]?.interfaces || Object.keys(result[0].interfaces).length === 0) + return null; + + // Основной контейнер + var container = E('div', { 'class': 'cbi-section' }); + + // Таблица с системными классами LuCI + var table = E('table', { 'class': 'table cbi-section-table' }); + + // Заголовок + var thead = E('tr', { 'class': 'tr cbi-section-table-titles' }); + thead.appendChild(E('th', { 'class': 'th left' }, [ _('Interface') ])); + thead.appendChild(E('th', { 'class': 'th left' }, [ _('Status') ])); + thead.appendChild(E('th', { 'class': 'th left' }, [ _('Uptime') ])); + table.appendChild(thead); + + // Тело таблицы + var tbody = E('tbody'); + + for (var iface in result[0].interfaces) { + var state = ''; + var time = ''; + var statusType = result[0].interfaces[iface].status; + + switch (statusType) { + case 'online': + state = _('Online'); + time = '%t'.format(result[0].interfaces[iface].online); + break; + case 'offline': + state = _('Offline'); + time = '%t'.format(result[0].interfaces[iface].offline); + break; + case 'notracking': + state = _('No Tracking'); + if ((result[0].interfaces[iface].uptime) > 0) { + time = '%t'.format(result[0].interfaces[iface].uptime); + } else { + time = ''; + } + break; + default: + state = _('Disabled'); + time = ''; + break; + } + + var tr = E('tr', { 'class': 'tr cbi-section-table-row' }); + + // Ячейка интерфейса + tr.appendChild(E('td', { 'class': 'td left' }, [ + E('strong', {}, [ iface ]) + ])); + + // Ячейка статуса с цветным фоном через системные классы label + var statusClass = getStatusBackgroundClass(statusType); + tr.appendChild(E('td', { 'class': 'td left' }, [ + E('span', { 'class': statusClass }, [ state ]) + ])); + + // Ячейка времени + tr.appendChild(E('td', { 'class': 'td left' }, [ time || '' ])); + + tbody.appendChild(tr); + } + + table.appendChild(tbody); + container.appendChild(table); + + return container; + } +}); diff --git a/luci-app-mwan3-nft/po/ru/mwan3.po b/luci-app-mwan3-nft/po/ru/mwan3.po new file mode 100644 index 000000000..8beacc4ef --- /dev/null +++ b/luci-app-mwan3-nft/po/ru/mwan3.po @@ -0,0 +1,886 @@ +msgid "" +msgstr "" +"Project-Id-Version: LuCI: mwan3\n" +"POT-Creation-Date: 2017-09-14 16:00+0300\n" +"PO-Revision-Date: 2026-05-02 12:03+0000\n" +"Last-Translator: SnIPeRSnIPeR " +"\n" +"Language-Team: Russian \n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"X-Generator: Weblate 5.17.1\n" +"Project-Info: Это технический перевод, не дословный. Главное-удобный русский " +"интерфейс, все проверялось в графическом режиме, совместим с другими apps\n" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:211 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:227 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:249 +msgid "%d hour" +msgstr "%d час" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:206 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:222 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:244 +msgid "%d minute" +msgstr "%d минута" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:207 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:208 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:209 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:210 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:223 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:224 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:225 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:226 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:245 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:246 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:247 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:248 +msgid "%d minutes" +msgstr "%d минут" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:193 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:200 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:216 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:238 +msgid "%d second" +msgstr "%d секунда" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:195 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:201 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:202 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:203 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:204 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:205 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:217 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:218 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:219 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:220 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:221 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:239 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:240 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:241 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:242 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:243 +msgid "%d seconds" +msgstr "%d секунд" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/notify.js:45 +msgid "" +"%s: Name of Physical device which interface went up or down (e.g. \"eth0\" " +"or \"wwan0\")" +msgstr "" +"%s: Название физического устройства, интерфейс которого поднялся или упал " +"(прим. \"eth0\" или \"wwan0\")" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/notify.js:39 +msgid "%s: Name of the action that triggered this event" +msgstr "%s: Название действия вызвавшего это событие" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/notify.js:44 +msgid "" +"%s: Name of the interface which went up or down (e.g. \"wan\" or \"wwan\")" +msgstr "" +"%s: Название интерфейса который поднялся или упал (прим. \"wan\" или " +"\"wwan\")" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/notify.js:40 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/notify.js:41 +msgid "* %s: Is called by netifd and mwan3track" +msgstr "* %s: Вызывается netifd и mwan3track" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/notify.js:43 +msgid "* %s: Is only called by mwan3track if tracking has failed" +msgstr "" +"* %s: Вызывается mwan3track только в том случае, если отслеживание не удалось" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/notify.js:42 +msgid "* %s: Is only called by mwan3track if tracking was successful" +msgstr "* %s: Вызывается mwan3track только в случае успешного отслеживания" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/diagnostics.js:71 +msgid "-- Interface Selection --" +msgstr "-- Выбор интерфейса --" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:109 +msgid "-- Please choose --" +msgstr "-- Выберите --" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:99 +msgid "" +"Acceptable values: 1-100. This many Tracking IP addresses must respond for " +"the link to be deemed up" +msgstr "" +"Допустимые значения: 1–100. Количество IP-адресов, которое должно ответить " +"чтобы соединение было признано активным" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/member.js:62 +msgid "Acceptable values: 1-1000. Defaults to 1 if not set" +msgstr "Допустимые значения: 1–1000. По умолчанию 1, если значение не задано" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/member.js:58 +msgid "Acceptable values: 1-256. Defaults to 1 if not set" +msgstr "Допустимые значения: 1–256 По умолчанию 1, если значение не задано" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/globals.js:26 +msgid "Alert" +msgstr "Тревога" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/globals.js:37 +msgid "Also scan this Routing table for connected networks" +msgstr "" +"Также сканировать эту таблицу маршрутизации на предмет подключённых сетей" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/diagnostics.js:65 +msgid "Check IP rules" +msgstr "Проверить правила IP" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:140 +msgid "Check link quality" +msgstr "Проверка качества подключения" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/diagnostics.js:66 +msgid "Check routing table" +msgstr "Проверить таблицу маршрутизации" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/overview.js:96 +msgid "Collecting data ..." +msgstr "Сбор данных ..." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/notify.js:18 +msgid "Contents have been saved." +msgstr "Содержимое сохранено." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/globals.js:27 +msgid "Critical" +msgstr "Критический" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/globals.js:32 +msgid "Debug" +msgstr "Отладка" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:85 +msgid "Destination address" +msgstr "Адрес назначения" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:89 +msgid "Destination port" +msgstr "Порт назначения" + +#: applications/luci-app-mwan3/root/usr/share/luci/menu.d/luci-app-mwan3.json:31 +msgid "Diagnostics" +msgstr "Диагностика" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/overview.js:57 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/status/include/90_mwan3.js:66 +msgid "Disabled" +msgstr "Отключено" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:267 +msgid "" +"Downed interface will be deemed up after this many successful ping tests" +msgstr "" +"Отключённый интерфейс будет считаться активным после указанного количество " +"успешных ping проверок" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/overview.js:41 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/status/include/90_mwan3.js:49 +msgid "Downtime" +msgstr "Время простоя" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/globals.js:25 +msgid "Emergency" +msgstr "Аварийный" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:92 +msgid "Enable ssl tracking" +msgstr "Включить отслеживание SSL" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:55 +msgid "Enabled" +msgstr "Включено" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:118 +msgid "" +"Enables firewall rule logging (global mwan3 logging must also be enabled)" +msgstr "" +"Включает журналирование правил брандмауэра (также должно быть включено " +"глобальное журналирование mwan3)" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/globals.js:20 +msgid "Enables global firewall logging" +msgstr "Включает глобальное журналирование правил брандмауэера" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:93 +msgid "Enables https tracking on ssl port 443" +msgstr "Включает отслеживание HTTPS на SSL порту 443" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/globals.js:15 +msgid "Enter value in hex, starting with 0x" +msgstr "Введите значение в шестнадцатеричной форме, начиная с 0x" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/globals.js:28 +msgid "Error" +msgstr "Ошибка" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/diagnostics.js:108 +msgid "Execute" +msgstr "Выполнить" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:59 +msgid "Expect interface state on up event" +msgstr "Ожидать состояние интерфейса при событии подключения интерейса" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:213 +msgid "Failure interval" +msgstr "Интервал отказа" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:145 +msgid "Failure latency [ms]" +msgstr "Задержка при отказе [мс]" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:158 +msgid "Failure packet loss [%]" +msgstr "Потери пакетов при отказе [%]" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/globals.js:23 +msgid "Firewall loglevel" +msgstr "Уровень журналирования брандмауэра" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/globals.js:14 +msgid "Firewall mask" +msgstr "Маска межсетевого экрана" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:280 +msgid "Flush conntrack table" +msgstr "Сбрасывать conntrack таблицу" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:281 +msgid "Flush global firewall conntrack table on interface events" +msgstr "" +"Сбрасывать глобальную таблицу conntrack межсетевого экрана при событиях " +"интерфейса" + +#: applications/luci-app-mwan3/root/usr/share/luci/menu.d/luci-app-mwan3.json:59 +msgid "Globals" +msgstr "Глобальные" + +#: applications/luci-app-mwan3/root/usr/share/rpcd/acl.d/luci-app-mwan3.json:51 +msgid "Grant access for luci-app-mwan3 configuration" +msgstr "Предоставить доступ для настройки luci-app-mwan3" + +#: applications/luci-app-mwan3/root/usr/share/rpcd/acl.d/luci-app-mwan3.json:3 +msgid "Grant access for luci-app-mwan3 status information" +msgstr "Предоставить доступ к информации о состоянии luci-app-mwan3" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/diagnostics.js:68 +msgid "Hotplug ifdown" +msgstr "Hotplug ifdown" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/diagnostics.js:67 +msgid "Hotplug ifup" +msgstr "Hotplug ifup" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:107 +msgid "IPset" +msgstr "IPset" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:67 +msgid "IPv4" +msgstr "IPv4" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:61 +msgid "IPv4 and IPv6" +msgstr "IPv4 и IPv6" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:62 +msgid "IPv4 only" +msgstr "Только IPv4" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:68 +msgid "IPv6" +msgstr "IPv6" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:63 +msgid "IPv6 only" +msgstr "Только IPv6" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/globals.js:31 +msgid "Info" +msgstr "Информация" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:58 +msgid "Initial state" +msgstr "Исходное состояние" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/member.js:50 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/diagnostics.js:83 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/overview.js:65 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/status/include/90_mwan3.js:77 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/status/include/90_mwan3.js:101 +#: applications/luci-app-mwan3/root/usr/share/luci/menu.d/luci-app-mwan3.json:67 +msgid "Interface" +msgstr "Интерфейс" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:252 +msgid "Interface down" +msgstr "Отключение интерфейса" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:266 +msgid "Interface up" +msgstr "Включение интерфейса" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:253 +msgid "Interface will be deemed down after this many failed ping tests" +msgstr "" +"Интерфейс будет считаться неработающим после заданного количество неудачных " +"пинг-запросов" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:25 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:46 +msgid "" +"Interfaces may not share the same name as configured members, policies or " +"rules." +msgstr "" +"Интерфейсы не могут иметь то же имя, что и настроенные элементы, политики " +"или правила." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:65 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:59 +msgid "Internet Protocol" +msgstr "Протокол Интернета (IP)" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:230 +msgid "Keep failure interval" +msgstr "Сохранять интервал отказа" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:231 +msgid "Keep ping failure interval during failure state" +msgstr "Сохранять интервал отказа пинг-запроса во время состояния отказа" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/policy.js:61 +msgid "Last resort" +msgstr "Крайнее средство" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/notify.js:34 +msgid "Lines beginning with # are comments and are not executed." +msgstr "Строки, начинающиеся с #, являются комментариями и не выполняются." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/policy.js:21 +msgid "" +"Load-balanced member interfaces distribute more traffic out those with " +"higher weights." +msgstr "" +"Интерфейсы с балансировкой нагрузки распределяют больше трафика между " +"интерфейсами с большим весом." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/globals.js:19 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:117 +msgid "Logging" +msgstr "Журналирование" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/globals.js:22 +msgid "Loglevel" +msgstr "Уровень журналирования" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:127 +msgid "Max TTL" +msgstr "Максимальное TTL" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:81 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:90 +msgid "" +"May be entered as a single or multiple port(s) (eg \"22\" or \"80,443\") or " +"as a portrange (eg \"1024:2048\") without quotes" +msgstr "" +"Может быть введено как один или несколько портов (например, «22» или " +"«80,443») или как диапазон портов (например, «1024:2048») без кавычек" + +#: applications/luci-app-mwan3/root/usr/share/luci/menu.d/luci-app-mwan3.json:75 +msgid "Member" +msgstr "Узел" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/policy.js:19 +msgid "Member interfaces with lower metrics are used first." +msgstr "Интерфейсы с более низкими метриками используются в первую очередь." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/policy.js:20 +msgid "Member interfaces with the same metric will be load-balanced." +msgstr "Интерфейсы с одинаковой метрикой будут сбалансированы по нагрузке." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/policy.js:54 +msgid "Member used" +msgstr "Используемый узел" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/member.js:18 +msgid "" +"Members are profiles attaching a metric and weight to an MWAN interface." +msgstr "Элементы - это профили, прикрепляющие метрику и вес к интерфейсу MWAN." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/member.js:20 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/member.js:41 +msgid "" +"Members may not share the same name as configured interfaces, policies or " +"rules." +msgstr "" +"Элементы не могут иметь одинаковые имена с настроенными интерфейсами, " +"политиками или правилами." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:288 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/member.js:57 +msgid "Metric" +msgstr "Метрика" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/status/include/90_mwan3.js:19 +#: applications/luci-app-mwan3/root/usr/share/luci/menu.d/luci-app-mwan3.json:3 +#: applications/luci-app-mwan3/root/usr/share/luci/menu.d/luci-app-mwan3.json:47 +msgid "MultiWAN Manager" +msgstr "Менеджер MultiWAN" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/diagnostics.js:79 +msgid "MultiWAN Manager - Diagnostics" +msgstr "Менеджер MultiWAN - Диагностика" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/globals.js:10 +msgid "MultiWAN Manager - Globals" +msgstr "Менеджер MultiWAN - Глобальные" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:21 +msgid "MultiWAN Manager - Interfaces" +msgstr "Менеджер MultiWAN - Интерфейсы" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/member.js:17 +msgid "MultiWAN Manager - Members" +msgstr "Менеджер MultiWAN - Элементы" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/notify.js:26 +msgid "MultiWAN Manager - Notify" +msgstr "Менеджер MultiWAN - Уведомления" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/overview.js:93 +msgid "MultiWAN Manager - Overview" +msgstr "Менеджер MultiWAN - Обзор" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/policy.js:17 +msgid "MultiWAN Manager - Policies" +msgstr "Менеджер MultiWAN - Политики" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:19 +msgid "MultiWAN Manager - Rules" +msgstr "Менеджер MultiWAN - Правила" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/detail.js:12 +msgid "MultiWAN Manager - Status" +msgstr "Менеджер MultiWAN - Статус" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/troubleshooting.js:12 +msgid "MultiWAN Manager - Troubleshooting" +msgstr "Менеджер MultiWAN - Устранение неполадок" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:22 +msgid "" +"Mwan3 requires that all interfaces have a unique metric configured in /etc/" +"config/network." +msgstr "" +"Mwan3 требует, чтобы все интерфейсы имели уникальную метрику, настроенную в /" +"etc/config/network." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:49 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/member.js:44 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/policy.js:48 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:53 +msgid "Name length shall not exceed 15 characters" +msgstr "Длина имени не должна превышать 15 символов" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:108 +msgid "" +"Name of IPset rule. Requires IPset rule in /etc/dnsmasq.conf (eg \"ipset=/" +"youtube.com/youtube\")" +msgstr "" +"Имя IPset правила. Требуется правило IPset в /etc/dnsmasq.conf (например " +"«ipset=/youtube.com/youtube»)" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:24 +msgid "Names may contain characters A-Z, a-z, 0-9, _ and no spaces-" +msgstr "Имена могут содержать символы A-Z, a-z, 0-9, _ и без пробелов и -" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/member.js:19 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/policy.js:22 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:27 +msgid "Names may contain characters A-Z, a-z, 0-9, _ and no spaces." +msgstr "Имена могут содержать символы A-Z, a-z, 0-9, _ и без пробелов." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/policy.js:23 +msgid "Names must be 15 characters or less." +msgstr "Имена должны состоять из 15 символов или менее." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:23 +msgid "Names must match the interface name found in /etc/config/network." +msgstr "Имена должны совпадать с именем интерфейса из /etc/config/network." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:98 +msgid "No" +msgstr "Нет" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/overview.js:21 +msgid "No MWAN interfaces found" +msgstr "Интерфейсы MWAN не найдены" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/overview.js:44 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/status/include/90_mwan3.js:52 +msgid "No Tracking" +msgstr "Нет отслеживания" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:296 +msgid "No interface metric set!" +msgstr "Не задана метрика интерфейса!" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/notify.js:31 +msgid "Notes:" +msgstr "Примечания:" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/globals.js:30 +msgid "Notice" +msgstr "Уведомление" + +#: applications/luci-app-mwan3/root/usr/share/luci/menu.d/luci-app-mwan3.json:99 +msgid "Notify" +msgstr "Уведомить" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:62 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/overview.js:38 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/status/include/90_mwan3.js:46 +msgid "Offline" +msgstr "Отключён" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:61 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/overview.js:31 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/status/include/90_mwan3.js:40 +msgid "Online" +msgstr "Онлайн" + +#: applications/luci-app-mwan3/root/usr/share/luci/menu.d/luci-app-mwan3.json:15 +msgid "Overview" +msgstr "Обзор" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:103 +msgid "Ping count" +msgstr "Количество пинг-запросов" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/diagnostics.js:63 +msgid "Ping default gateway" +msgstr "Пинг-запрос шлюза по умолчанию" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:198 +msgid "Ping interval" +msgstr "Интервал пинг-запроса" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:214 +msgid "Ping interval during failure detection" +msgstr "Интервал пинг-запросов во время обнаруженного отказа" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:236 +msgid "Ping interval during failure recovering" +msgstr "Интервал пинг-запросов при восстановлении отказа" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:112 +msgid "Ping size" +msgstr "Размер пакета пинг-запроса" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:191 +msgid "Ping timeout" +msgstr "Время ожидания ответа пинг-запроса" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/diagnostics.js:64 +msgid "Ping tracking IP" +msgstr "Пинг-запрос отслеживаемого IP" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/policy.js:18 +msgid "" +"Policies are profiles grouping one or more members controlling how Mwan3 " +"distributes traffic." +msgstr "" +"Политики - это профили, объединяющие один или несколько элементов, " +"управляющих распределением трафика в Mwan3." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/policy.js:24 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/policy.js:45 +msgid "" +"Policies may not share the same name as configured interfaces, members or " +"rules" +msgstr "" +"Политики не могут иметь одинаковые имена с настроенными интерфейсами, " +"элементами или правилами" + +#: applications/luci-app-mwan3/root/usr/share/luci/menu.d/luci-app-mwan3.json:83 +msgid "Policy" +msgstr "Политика" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:121 +msgid "Policy assigned" +msgstr "Назначенная политика" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:66 +msgid "Protocol" +msgstr "Протокол" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/notify.js:35 +msgid "" +"Put your custom mwan3 action here, they will be executed with each netifd " +"hotplug interface event on interfaces for which mwan3 is enabled." +msgstr "" +"Поместите сюда ваши пользовательские действия mwan3, они будут выполняться " +"при каждом событии интерфейса netifd hotplug на интерфейсах, для которых " +"включён mwan3." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:235 +msgid "Recovery interval" +msgstr "Интервал восстановления" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:168 +msgid "Recovery latency [ms]" +msgstr "Задержка восстановления [мс]" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:181 +msgid "Recovery packet loss [%]" +msgstr "Потери пакетов для восстановления [%]" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/globals.js:39 +msgid "Routing table %d" +msgstr "Таблица маршрутизации %d" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/globals.js:36 +msgid "Routing table lookup" +msgstr "Поиск таблицы маршрутизации" + +#: applications/luci-app-mwan3/root/usr/share/luci/menu.d/luci-app-mwan3.json:91 +msgid "Rule" +msgstr "Правило" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:21 +msgid "Rules are based on IP address, port or protocol." +msgstr "Правила основаны на IP-адресе, порте или протоколе." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:22 +msgid "Rules are matched from top to bottom." +msgstr "Правила сопоставляются сверху вниз." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:23 +msgid "Rules below a matching rule are ignored." +msgstr "Правила, находящиеся ниже соответствующего правила, игнорируются." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:28 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:50 +msgid "" +"Rules may not share the same name as configured interfaces, members or " +"policies." +msgstr "" +"Правила не могут иметь одинаковые имена с настроенными интерфейсами, " +"элементами или политиками." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:20 +msgid "Rules specify which traffic will use a particular MWAN policy." +msgstr "" +"Правила определяют, какой трафик будет использовать определённую политику " +"MWAN." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:102 +msgid "Seconds. Acceptable values: 1-1000000. Defaults to 600 if not set" +msgstr "" +"Секунды. Допустимые значения: 1–1000000. По умолчанию 600, если значение не " +"установлено" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:76 +msgid "Source address" +msgstr "Адрес источника" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:80 +msgid "Source port" +msgstr "Порт источника" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/overview.js:66 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/status/include/90_mwan3.js:83 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/status/include/90_mwan3.js:107 +#: applications/luci-app-mwan3/root/usr/share/luci/menu.d/luci-app-mwan3.json:23 +msgid "Status" +msgstr "Статус" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:94 +msgid "Sticky" +msgstr "Режим Sticky" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:101 +msgid "Sticky timeout" +msgstr "Время ожидания режима Sticky" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:77 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:86 +msgid "Supports CIDR notation (eg \"192.168.100.0/24\") without quotes" +msgstr "Поддерживает CIDR нотацию (например «192.168.100.0/24») без кавычек" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/diagnostics.js:91 +msgid "Task" +msgstr "Задача" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/notify.js:29 +msgid "The file is also preserved during sysupgrade." +msgstr "Этот файл также сохраняется при обновлении системы." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/notify.js:33 +msgid "" +"The first line of the script must be "#!/bin/sh" without quotes." +msgstr "Первая строка скрипта должна быть "#!/bin/sh" без кавычек." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/notify.js:37 +msgid "" +"There are three main environment variables that are passed to this script." +msgstr "В этот сценарий передаются три основные переменные среды окружения." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:289 +msgid "" +"This displays the metric assigned to this interface in /etc/config/network" +msgstr "" +"Здесь отображается метрика, назначенная этому интерфейсу в файле /etc/config/" +"network" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/notify.js:32 +msgid "This file is interpreted as a shell script." +msgstr "Этот файл интерпретируется как shell-скрипт." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:72 +msgid "" +"This hostname or IP address will be pinged to determine if the link is up or " +"down. Leave blank to assume interface is always online" +msgstr "" +"Имя хоста или IP-адрес для пинг-запроса, чтобы определить активно соединение " +"или нет. Оставьте пустым, чтобы указать, что интерфейс всегда в сети" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/notify.js:28 +msgid "This section allows you to modify the content of \"/etc/mwan3.user\"." +msgstr "Этот раздел позволяет изменять содержимое файла \"/etc/mwan3.user\"." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:71 +msgid "Tracking hostname or IP address" +msgstr "Отслеживамое имя хоста или IP-адрес" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:76 +msgid "Tracking method" +msgstr "Метод отслеживания" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:98 +msgid "Tracking reliability" +msgstr "Надёжность отслеживания" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:25 +msgid "" +"Traffic destined for known (other than default) networks is handled by the " +"main routing table." +msgstr "" +"Трафик, предназначенный для известных (кроме стандартных) сетей, " +"обрабатывается основной таблицей маршрутизации." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:95 +msgid "" +"Traffic from the same source IP address that previously matched this rule " +"within the sticky timeout period will use the same WAN interface" +msgstr "" +"Трафик с того же IP-адреса источника, который ранее соответствовал этому " +"правилу в период времени ожидания режима Sticky, будет использовать тот же " +"интерфейс WAN" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:26 +msgid "" +"Traffic matching a rule, but all WAN interfaces for that policy are down " +"will be blackholed." +msgstr "" +"Трафик, соответствующий правилу, но все интерфейсы WAN для этой политики не " +"работают, будет заблокирован." + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:24 +msgid "Traffic not matching any rule is routed using the main routing table." +msgstr "" +"Трафик, не соответствующий какому-либо правилу, направляется по основной " +"таблице маршрутизации." + +#: applications/luci-app-mwan3/root/usr/share/luci/menu.d/luci-app-mwan3.json:39 +msgid "Troubleshooting" +msgstr "Устранение неполадок" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/notify.js:20 +msgid "Unable to save contents: %s" +msgstr "Не удалось сохранить содержимое: %s" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/overview.js:34 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/status/overview.js:48 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/status/include/90_mwan3.js:43 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/status/include/90_mwan3.js:56 +msgid "Uptime" +msgstr "Время работы" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:67 +msgid "View the content of /etc/protocols for protocol description" +msgstr "Просмотр содержимого файла /etc/protocols для описания протокола" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/globals.js:29 +msgid "Warning" +msgstr "Предупреждение" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/member.js:61 +msgid "Weight" +msgstr "Вес" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/policy.js:62 +msgid "" +"When all policy members are offline use this behavior for matched traffic" +msgstr "" +"Когда все члены политики находятся в автономном режиме, используйте это " +"поведение для сопоставляемого трафика" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:97 +msgid "Yes" +msgstr "Да" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/policy.js:65 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:127 +msgid "blackhole (drop)" +msgstr "blackhole (отбросить)" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:284 +msgid "connected (mwan3)" +msgstr "подключено (connected, mwan3)" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/policy.js:66 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:128 +msgid "default (use main routing table)" +msgstr "default (использовать основную таблицу маршрутизации)" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:285 +msgid "disconnected (mwan3)" +msgstr "отключено (disconnected, mwan3)" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:283 +msgid "ifdown (netifd)" +msgstr "отключено (ifdown, netifd)" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/interface.js:282 +msgid "ifup (netifd)" +msgstr "подключено (ifup, netifd)" + +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/policy.js:64 +#: applications/luci-app-mwan3/htdocs/luci-static/resources/view/mwan3/network/rule.js:126 +msgid "unreachable (reject)" +msgstr "unreachable (отклонить)" + +msgid "Show on overview" +msgstr "Показать на главной" + +msgid "Show MultiWAN status section on the overview page" +msgstr "Показывать секцию состояния MultiWan на главной странице" + +msgid "No available interfaces" +msgstr "Нет доступных интерфейсов" diff --git a/luci-app-mwan3-nft/root/etc/uci-defaults/60_luci-mwan3 b/luci-app-mwan3-nft/root/etc/uci-defaults/60_luci-mwan3 new file mode 100755 index 000000000..414146b5e --- /dev/null +++ b/luci-app-mwan3-nft/root/etc/uci-defaults/60_luci-mwan3 @@ -0,0 +1,10 @@ +#!/bin/sh + +uci -q get mwan3.globals >/dev/null || { + uci -q add mwan3 globals >/dev/null + uci -q rename mwan3.@globals[-1]="globals" >/dev/null + uci -q set mwan3.globals.local_source="none" >/dev/null + uci commit mwan3 +} + +exit 0 diff --git a/luci-app-mwan3-nft/root/usr/libexec/luci-mwan3 b/luci-app-mwan3-nft/root/usr/libexec/luci-mwan3 new file mode 100755 index 000000000..5a38634fe --- /dev/null +++ b/luci-app-mwan3-nft/root/usr/libexec/luci-mwan3 @@ -0,0 +1,199 @@ +#!/bin/sh +# +# Copyright (C) 2021 TDT AG +# +# This is free software, licensed under the GNU General Public License v2. +# See https://www.gnu.org/licenses/gpl-2.0.txt for more information. +# + +. /lib/functions.sh +. /lib/functions/network.sh +. /usr/share/libubox/jshn.sh + +IIF=1000 +FWMARK=2000 +ID=0 + +usage() { + local status="$1" + local msg="$2" + if [ -n "$msg" ]; then + echo "$msg" + echo "" + fi + echo "Usage: $(basename "$0") " + echo "command:" + echo " diag: diagnostic commands" + echo " nftset: nft set commands" + echo "" + echo "diag " + echo "command:" + echo " gateway : ping interface gateway" + echo " tracking : ping interface tracking targets" + echo " rules : check interface routing rules" + echo " routes : check interface routing tables" + echo "" + echo "nftset " + echo "command:" + echo " dump: show all configured nft set names" + + exit "$status" +} + +diag_gateway() { + local iface="$1" + + local gw + + network_get_gateway gw "${iface}" + [ -z "$gw" ] && network_get_gateway gw "${iface}_4" + + [ -z "$gw" ] && { + echo "No gateway for interface ${iface} found." + exit 2 + } + + mwan3 use "$iface" "ping" "-c" "5" "-W" "1" "$gw" +} + +diag_tracking() { + local iface="$1" + + checkips() { + local ip="$1" + local iface="$2" + + mwan3 use "$iface" "ping" "-c" "5" "-W" "1" "$ip" + } + + config_load mwan3 + config_list_foreach "$iface" "track_ip" checkips "$iface" +} + +iface_number() { + local cfg="$1" + local iface="$2" + + let number++ + + [ "$cfg" = "$iface" ] && { + ID="$number" + } +} + +diag_rules() { + local iface="$1" + + local number=0 + local iif=0 + local fwmark=0 + + local iif_rule iif_result + local fwmark_rule fwmark_result + + config_load mwan3 + config_foreach iface_number 'interface' "$iface" + + [ "$ID" = "0" ] && { + echo "Unable to get mwan3 interface number for \"$iface\"." + exit 2 + } + + let "iif=$IIF+$ID" + let "fwmark=$FWMARK+$ID" + + iif_rule="$(ip rule | grep ${iif})" + iif_result="$?" + + fwmark_rule="$(ip rule | grep ${fwmark})" + fwmark_result="$?" + + if [ "$fwmark_result" = 0 ] && [ "$iif_result" = 0 ]; then + echo "All required IP rules for interface \"$iface\" found" + echo "$fwmark_rule" + echo "$iif_rule" + elif [ "$fwmark_result" = 1 ] && [ "$iif_result" = 0 ]; then + echo "Only iif IP rule for interface \"$iface\" found" + echo "$iif_rule" + elif [ "$fwmark_result" = 0 ] && [ "$iif_result" = 1 ]; then + echo "Only fwmark IP rule for interface \"$iface\" found" + echo "$fwmark_rule" + else + echo "Missing fwmark and iif IP rule for interface \"$iface\"" + fi +} + +diag_routes() { + local iface="$1" + + local table table_result + + config_load mwan3 + config_foreach iface_number 'interface' "$iface" + + [ "$ID" = "0" ] && { + echo "Unable to get mwan3 interface number for \"$iface\"." + exit 2 + } + + table="$(ip route list table $ID)" + table_result="$?" + + if [ "$table_result" = 0 ]; then + echo "Routing table \"$ID\" for interface \"$iface\" found" + echo "$table" + else + echo "Routing table \"$ID\" for interface \"$iface\" not found" + fi +} + +diag_cmd() { + case "$1" in + gateway) + diag_gateway "$2" + ;; + tracking) + diag_tracking "$2" + ;; + rules) + diag_rules "$2" + ;; + routes) + diag_routes "$2" + ;; + *) + usage "1" "Command not supported" + ;; + esac +} + +nftset_dump() { + nft -a list table inet mwan3 2>/dev/null | awk '/^\tset / && !/^\tset mwan3_/ {print $2}' | sort -u +} + +nftset_cmd() { + case "$1" in + dump) + nftset_dump + ;; + *) + usage "1" "Command not supported" + ;; + esac +} + +main () { + case "$1" in + diag) + diag_cmd "$2" "$3" + ;; + nftset) + nftset_cmd "$2" + ;; + *) + usage "1" "Command not supported" + ;; + esac +} + +main "$@" diff --git a/luci-app-mwan3-nft/root/usr/share/luci/menu.d/luci-app-mwan3.json b/luci-app-mwan3-nft/root/usr/share/luci/menu.d/luci-app-mwan3.json new file mode 100644 index 000000000..ee142df41 --- /dev/null +++ b/luci-app-mwan3-nft/root/usr/share/luci/menu.d/luci-app-mwan3.json @@ -0,0 +1,106 @@ +{ + "admin/status/mwan3": { + "title": "MultiWAN Manager", + "order": "600", + "action": { + "type": "firstchild" + }, + "depends": { + "acl": [ + "luci-app-mwan3-status" + ] + } + }, + "admin/status/mwan3/overview": { + "title": "Overview", + "order": 10, + "action": { + "type": "view", + "path": "mwan3/status/overview" + } + }, + "admin/status/mwan3/detail": { + "title": "Status", + "order": 20, + "action": { + "type": "view", + "path": "mwan3/status/detail" + } + }, + "admin/status/mwan3/diagnostics": { + "title": "Diagnostics", + "order": 30, + "action": { + "type": "view", + "path": "mwan3/status/diagnostics" + } + }, + "admin/status/mwan3/troubleshooting": { + "title": "Troubleshooting", + "order": 40, + "action": { + "type": "view", + "path": "mwan3/status/troubleshooting" + } + }, + "admin/network/mwan3": { + "title": "MultiWAN Manager", + "order": "600", + "action": { + "type": "firstchild" + }, + "depends": { + "acl": [ + "luci-app-mwan3" + ] + } + }, + "admin/network/mwan3/globals": { + "title": "Globals", + "order": 10, + "action": { + "type": "view", + "path": "mwan3/network/globals" + } + }, + "admin/network/mwan3/interface": { + "title": "Interface", + "order": 20, + "action": { + "type": "view", + "path": "mwan3/network/interface" + } + }, + "admin/network/mwan3/member": { + "title": "Member", + "order": 30, + "action": { + "type": "view", + "path": "mwan3/network/member" + } + }, + "admin/network/mwan3/policy": { + "title": "Policy", + "order": 40, + "action": { + "type": "view", + "path": "mwan3/network/policy" + } + }, + "admin/network/mwan3/rule": { + "title": "Rule", + "order": 50, + "action": { + "type": "view", + "path": "mwan3/network/rule" + } + }, + "admin/network/mwan3/notify": { + "title": "Notify", + "order": 60, + "action": { + "type": "view", + "path": "mwan3/network/notify" + } + } +} diff --git a/luci-app-mwan3-nft/root/usr/share/rpcd/acl.d/luci-app-mwan3.json b/luci-app-mwan3-nft/root/usr/share/rpcd/acl.d/luci-app-mwan3.json new file mode 100644 index 000000000..a50ff1979 --- /dev/null +++ b/luci-app-mwan3-nft/root/usr/share/rpcd/acl.d/luci-app-mwan3.json @@ -0,0 +1,94 @@ +{ + "luci-app-mwan3-status": { + "description": "Grant access for luci-app-mwan3 status information", + "read": { + "cgi-io": [ + "exec" + ], + "file": { + "/usr/sbin/mwan3 status": [ + "exec" + ] + }, + "ubus": { + "mwan3": [ + "status" + ] + } + }, + "write": { + "file": { + "/usr/libexec/luci-mwan3 diag gateway *": [ + "exec" + ], + "/usr/libexec/luci-mwan3 diag tracking *": [ + "exec" + ], + "/usr/libexec/luci-mwan3 diag rules *": [ + "exec" + ], + "/usr/libexec/luci-mwan3 diag routes *": [ + "exec" + ], + "/usr/sbin/mwan3 internal ipv4": [ + "exec" + ], + "/usr/sbin/mwan3 ifup *": [ + "exec" + ], + "/usr/sbin/mwan3 ifdown *": [ + "exec" + ] + }, + "ubus": { + "file": [ + "exec" + ] + } + } + }, + "luci-app-mwan3": { + "description": "Grant access for luci-app-mwan3 configuration", + "read": { + "cgi-io": [ + "exec" + ], + "file": { + "/etc/mwan3.user": [ + "read" + ], + "/usr/bin/httping": [ + "list" + ], + "/usr/bin/nping": [ + "list" + ], + "/usr/bin/arping": [ + "list" + ], + "/usr/libexec/luci-mwan3 ipset dump": [ + "exec" + ] + }, + "ubus": { + "mwan3": [ + "status" + ] + }, + "uci": [ + "mwan3", + "network" + ] + }, + "write": { + "file": { + "/etc/mwan3.user": [ + "write" + ] + }, + "uci": [ + "mwan3" + ] + } + } +} diff --git a/mwan3-ledhelper/Makefile b/mwan3-ledhelper/Makefile index 354f10218..531ff3b69 100644 --- a/mwan3-ledhelper/Makefile +++ b/mwan3-ledhelper/Makefile @@ -1,8 +1,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=mwan3-ledhelper -PKG_VERSION:=0.0.1 -PKG_RELEASE:=1 +PKG_VERSION:=0.0.2 +PKG_RELEASE:=2 PKG_MAINTAINER:=Konstantine Shevlakov include $(INCLUDE_DIR)/package.mk @@ -13,6 +13,12 @@ define Package/$(PKG_NAME) DEPENDS:=+mwan3 endef +define Package/$(PKG_NAME)-nft + PKGARCH:=all + TITLE:=MWAN3 Led Helper (nft variant) + DEPENDS:=+mwan3-nft +endef + define Package/$(PKG_NAME)/description Hotplug script to indicate led for mwan3 link states endef @@ -31,5 +37,10 @@ define Package/$(PKG_NAME)/install $(CP) ./root/* $(1)/ endef +define Package/$(PKG_NAME)-nft/install + $(CP) ./root/* $(1)/ +endef + $(eval $(call BuildPackage,$(PKG_NAME))) +$(eval $(call BuildPackage,$(PKG_NAME)-nft)) diff --git a/natflow/Makefile b/natflow/Makefile index 79d58f7e9..49cab7983 100644 --- a/natflow/Makefile +++ b/natflow/Makefile @@ -10,12 +10,12 @@ include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=natflow PKG_VERSION:=20260531 -PKG_RELEASE:=30 +PKG_RELEASE:=31 PKG_SOURCE:=$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=https://github.com/ptpt52/natflow.git PKG_SOURCE_PROTO:=git -PKG_SOURCE_VERSION:=e75d2a375835d1d158604864199669343bdcdac6 +PKG_SOURCE_VERSION:=834324456603e21efc73521fa6b87dc0cbac7e30 PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) PKG_MAINTAINER:=Chen Minqiang PKG_LICENSE:=GPL-2.0 diff --git a/quectel_MHI/Makefile b/quectel_MHI/Makefile old mode 100755 new mode 100644 index bc27daba2..de6385501 --- a/quectel_MHI/Makefile +++ b/quectel_MHI/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=pcie_mhi PKG_VERSION:=1.3.8 -PKG_RELEASE:=28 +PKG_RELEASE:=29 include $(INCLUDE_DIR)/kernel.mk include $(INCLUDE_DIR)/package.mk