diff options
author | Vladislav Grigoryev <vg.aetera@gmail.com> | 2021-08-10 01:55:19 +0300 |
---|---|---|
committer | Vladislav Grigoryev <vg.aetera@gmail.com> | 2021-09-01 10:51:16 +0300 |
commit | b4f4799f9e745aae8b70df7ad27315eb997cf570 (patch) | |
tree | fe507980fc1880de40f7f0e684409739007a6162 /modules/luci-mod-network/htdocs/luci-static/resources | |
parent | 3ac88f88edd549db5fd6d9ef6765ceb90fdeb1a7 (diff) |
luci-mod-network: network/routing support for pbr
Provide comprehensive routing configuration:
* Rename the "Network > Routes" page to "Network > Routing".
* Unify sorting for the "Status" and "Network" menus.
* Add the tabs "IPv4 Rules" and "IPv6 Rules" to the "Routing" page.
* Provide configuration for IPv4 and IPv6 routing rules.
* Consolidate routing configuration and terminology for IPv4 and IPv6.
Policy-based routing is an increasingly popular problem.
Netifd natively supports policy-based routing:
* Interface-specific options "ip4table" and "ip6table".
* Routing rules using the "rule" and "rule6" sections.
LuCI is missing configuration for routing rules.
Signed-off-by: Vladislav Grigoryev <vg.aetera@gmail.com>
Diffstat (limited to 'modules/luci-mod-network/htdocs/luci-static/resources')
-rw-r--r-- | modules/luci-mod-network/htdocs/luci-static/resources/view/network/routes.js | 201 |
1 files changed, 149 insertions, 52 deletions
diff --git a/modules/luci-mod-network/htdocs/luci-static/resources/view/network/routes.js b/modules/luci-mod-network/htdocs/luci-static/resources/view/network/routes.js index 164619940c..f19a5b41cf 100644 --- a/modules/luci-mod-network/htdocs/luci-static/resources/view/network/routes.js +++ b/modules/luci-mod-network/htdocs/luci-static/resources/view/network/routes.js @@ -1,22 +1,35 @@ 'use strict'; 'require view'; +'require fs'; +'require uci'; 'require form'; 'require network'; 'require tools.widgets as widgets'; return view.extend({ load: function() { - return network.getDevices(); + return Promise.all([ + network.getDevices(), + fs.lines('/etc/iproute2/rt_tables') + ]); }, - render: function(netdevs) { - var m, s, o; + render: function(data) { + var netDevs = data[0], + m, s, o; - m = new form.Map('network', _('Routes'), _('Routes specify over which interface and gateway a certain host or network can be reached.')); + var rtTables = data[1].map(function(l) { + var m = l.trim().match(/^(\d+)\s+(\S+)$/); + return m ? [ +m[1], m[2] ] : null; + }).filter(function(e) { + return e && e[0] > 0; + }); + + m = new form.Map('network', _('Routing'), _('Routing defines over which interface and gateway a certain host or network can be reached.')); m.tabbed = true; - for (var i = 4; i <= 6; i += 2) { - s = m.section(form.GridSection, (i == 4) ? 'route' : 'route6', (i == 4) ? _('Static IPv4 Routes') : _('Static IPv6 Routes')); + for (var family = 4; family <= 6; family += 2) { + s = m.section(form.GridSection, (family == 6) ? 'route6' : 'route', (family == 6) ? _('Static IPv6 Routes') : _('Static IPv4 Routes')); s.anonymous = true; s.addremove = true; s.sortable = true; @@ -29,78 +42,162 @@ return view.extend({ o.rmempty = false; o.nocreate = true; - o = s.taboption('general', form.Flag, 'disabled', _('Disable'), _('Disable this route')); - o.rmempty = true; - o.default = o.disabled; + o = s.taboption('general', form.ListValue, 'type', _('Route type')); + o.modalonly = true; + o.value('', 'unicast'); + o.value('local'); + o.value('broadcast'); + o.value('multicast'); + o.value('unreachable'); + o.value('prohibit'); + o.value('blackhole'); + o.value('anycast'); - o = s.taboption('general', form.Value, 'target', _('Target'), (i == 4) ? _('Host-<abbr title="Internet Protocol Address">IP</abbr> or Network') : _('<abbr title="Internet Protocol Version 6">IPv6</abbr>-Address or Network (CIDR)')); - o.datatype = (i == 4) ? 'ip4addr' : 'ip6addr'; + o = s.taboption('general', form.Value, 'target', _('Target')); o.rmempty = false; - - if (i == 4) { - o = s.taboption('general', form.Value, 'netmask', _('<abbr title="Internet Protocol Version 4">IPv4</abbr>-Netmask'), _('if target is a network')); - o.placeholder = '255.255.255.255'; - o.datatype = 'ip4addr'; - o.rmempty = true; + o.datatype = (family == 6) ? 'cidr6' : 'cidr4'; + o.placeholder = (family == 6) ? '::/0' : '0.0.0.0/0'; + o.cfgvalue = function(section_id) { + var t = uci.get('network', section_id, 'target'), + m = uci.get('network', section_id, 'netmask'), + s = (family == 6) ? 128 : 32, + p = m ? network.maskToPrefix(m, (family == 6) ? true : false) : s; + if (t) { + return t.split('/')[1] ? t : t + '/' + p; + } + } + o.write = function(section_id, formvalue) { + uci.set('network', section_id, 'target', formvalue); + uci.unset('network', section_id, 'netmask'); } - o = s.taboption('general', form.Value, 'gateway', (i == 4) ? _('<abbr title="Internet Protocol Version 4">IPv4</abbr>-Gateway') : _('<abbr title="Internet Protocol Version 6">IPv6</abbr>-Gateway')); - o.datatype = (i == 4) ? 'ip4addr' : 'ip6addr'; - o.rmempty = true; + o = s.taboption('general', form.Value, 'gateway', _('Gateway')); + o.datatype = (family == 6) ? 'ip6addr("nomask")' : 'ip4addr("nomask")'; + o.placeholder = (family == 6) ? 'fe80::1' : '192.168.0.1'; o = s.taboption('advanced', form.Value, 'metric', _('Metric')); + o.datatype = 'uinteger'; o.placeholder = 0; - o.datatype = (i == 4) ? 'range(0,255)' : 'range(0,65535)'; - o.rmempty = true; o.textvalue = function(section_id) { return this.cfgvalue(section_id) || 0; }; o = s.taboption('advanced', form.Value, 'mtu', _('MTU')); + o.modalonly = true; + o.datatype = 'and(uinteger,range(64,9000))'; o.placeholder = 1500; - o.datatype = 'range(64,9000)'; - o.rmempty = true; + + o = s.taboption('advanced', form.Value, 'table', _('Table')); + o.datatype = 'or(uinteger, string)'; + for (var i = 0; i < rtTables.length; i++) + o.value(rtTables[i][1], '%s (%d)'.format(rtTables[i][1], rtTables[i][0])); + o.textvalue = function(section_id) { + return this.cfgvalue(section_id) || 'main'; + }; + + o = s.taboption('advanced', form.Value, 'source', _('Source')); + o.modalonly = true; + o.datatype = (family == 6) ? 'ip6addr("nomask")' : 'ip4addr("nomask")'; + o.placeholder = E('em', _('auto')); + for (var i = 0; i < netDevs.length; i++) { + var addrs = (family == 6) ? netDevs[i].getIP6Addrs() : netDevs[i].getIPAddrs(); + for (var j = 0; j < addrs.length; j++) + o.value(addrs[j].split('/')[0]); + } + + o = s.taboption('advanced', form.Flag, 'onlink', _('On-link')); o.modalonly = true; + o.default = o.disabled; + + o = s.taboption('advanced', form.Flag, 'disabled', _('Disable')); + o.modalonly = false; + o.editable = true; + o.default = o.disabled; + } + + for (var family = 4; family <= 6; family += 2) { + s = m.section(form.GridSection, (family == 6) ? 'rule6' : 'rule', (family == 6) ? _('IPv6 Rules') : _('IPv4 Rules')); + s.anonymous = true; + s.addremove = true; + s.sortable = true; + s.nodescriptions = true; + + s.tab('general', _('General Settings')); + s.tab('advanced', _('Advanced Settings')); + + o = s.taboption('general', form.Value, 'priority', _('Priority')); + o.datatype = 'uinteger'; + o.placeholder = 30000; + o.textvalue = function(section_id) { + return this.cfgvalue(section_id) || E('em', _('auto')); + }; - o = s.taboption('advanced', form.ListValue, 'type', _('Route type')); + o = s.taboption('general', form.ListValue, 'action', _('Rule type')); + o.modalonly = true; o.value('', 'unicast'); - o.value('local'); - o.value('broadcast'); - o.value('multicast'); o.value('unreachable'); o.value('prohibit'); o.value('blackhole'); - o.value('anycast'); - o.default = ''; - o.rmempty = true; + o.value('throw'); + + o = s.taboption('general', widgets.NetworkSelect, 'in', _('Incoming interface')); + o.loopback = true; + o.nocreate = true; + + o = s.taboption('general', form.Value, 'src', _('Source')); + o.datatype = (family == 6) ? 'cidr6' : 'cidr4'; + o.placeholder = (family == 6) ? '::/0' : '0.0.0.0/0'; + o.textvalue = function(section_id) { + return E('em', _('any')); + }; + + o = s.taboption('general', widgets.NetworkSelect, 'out', _('Outgoing interface')); + o.loopback = true; + o.nocreate = true; + + o = s.taboption('general', form.Value, 'dest', _('Destination')); + o.datatype = (family == 6) ? 'cidr6' : 'cidr4'; + o.placeholder = (family == 6) ? '::/0' : '0.0.0.0/0'; + o.textvalue = function(section_id) { + return E('em', _('any')); + }; + + o = s.taboption('general', form.Value, 'lookup', _('Table')); + o.datatype = 'or(uinteger, string)'; + for (var i = 0; i < rtTables.length; i++) + o.value(rtTables[i][1], '%s (%d)'.format(rtTables[i][1], rtTables[i][0])); + o.textvalue = function(section_id) { + return this.cfgvalue(section_id) || 'main'; + }; + + o = s.taboption('advanced', form.Value, 'goto', _('Jump to rule')); o.modalonly = true; + o.datatype = 'uinteger'; + o.placeholder = 80000; - o = s.taboption('advanced', form.Value, 'table', _('Route table')); - o.value('local', 'local (255)'); - o.value('main', 'main (254)'); - o.value('default', 'default (253)'); - o.rmempty = true; + o = s.taboption('advanced', form.Value, 'mark', _('Firewall mark')); o.modalonly = true; - o.cfgvalue = function(section_id) { - var cfgvalue = this.map.data.get('network', section_id, 'table'); - return cfgvalue || 'main'; - }; + o.datatype = 'string'; + o.placeholder = '0x1/0xf'; - o = s.taboption('advanced', form.Value, 'source', _('Source Address')); - o.placeholder = E('em', _('automatic')); - for (var j = 0; j < netdevs.length; j++) { - var addrs = (i == 4) ? netdevs[j].getIPAddrs() : netdevs[j].getIP6Addrs(); - for (var k = 0; k < addrs.length; k++) - o.value(addrs[k].split('/')[0]); - } - o.datatype = (i == 4) ? 'ip4addr' : 'ip6addr'; - o.default = ''; - o.rmempty = true; + o = s.taboption('advanced', form.Value, 'tos', _('Type of service')); + o.modalonly = true; + o.datatype = 'uinteger'; + o.placeholder = 10; + + o = s.taboption('advanced', form.Value, 'suppress_prefixlength', _('Prefix suppressor')); + o.modalonly = true; + o.datatype = (family == 6) ? 'ip6prefix' : 'ip4prefix'; + o.placeholder = (family == 6) ? 64 : 24; + + o = s.taboption('advanced', form.Flag, 'invert', _('Invert match')); o.modalonly = true; + o.default = o.disabled; - o = s.taboption('advanced', form.Flag, 'onlink', _('On-Link route')); + o = s.taboption('advanced', form.Flag, 'disabled', _('Disable')); + o.modalonly = false; + o.editable = true; o.default = o.disabled; - o.rmempty = true; } return m.render(); |