From 9c16090780b7430ffe88c770732604f6eb6cfda6 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Thu, 13 Jun 2019 15:23:26 +0200 Subject: [PATCH] luci-app-firewall: switch to client side CBI views Signed-off-by: Jo-Philipp Wich --- .../luci-static/resources/tools/firewall.js | 319 ++++++++++++++ .../resources/view/firewall/forwards.js | 290 +++++++++++++ .../resources/view/firewall/rules.js | 401 ++++++++++++++++++ .../resources/view/firewall/zones.js | 249 +++++++++++ .../luasrc/controller/firewall.lua | 9 +- .../model/cbi/firewall/forward-details.lua | 162 ------- .../luasrc/model/cbi/firewall/forwards.lua | 133 ------ .../model/cbi/firewall/rule-details.lua | 365 ---------------- .../luasrc/model/cbi/firewall/rules.lua | 273 ------------ .../model/cbi/firewall/zone-details.lua | 229 ---------- .../luasrc/model/cbi/firewall/zones.lua | 104 ----- 11 files changed, 1262 insertions(+), 1272 deletions(-) create mode 100644 applications/luci-app-firewall/htdocs/luci-static/resources/tools/firewall.js create mode 100644 applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/forwards.js create mode 100644 applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/rules.js create mode 100644 applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js delete mode 100644 applications/luci-app-firewall/luasrc/model/cbi/firewall/forward-details.lua delete mode 100644 applications/luci-app-firewall/luasrc/model/cbi/firewall/forwards.lua delete mode 100644 applications/luci-app-firewall/luasrc/model/cbi/firewall/rule-details.lua delete mode 100644 applications/luci-app-firewall/luasrc/model/cbi/firewall/rules.lua delete mode 100644 applications/luci-app-firewall/luasrc/model/cbi/firewall/zone-details.lua delete mode 100644 applications/luci-app-firewall/luasrc/model/cbi/firewall/zones.lua diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/tools/firewall.js b/applications/luci-app-firewall/htdocs/luci-static/resources/tools/firewall.js new file mode 100644 index 000000000..909540eaf --- /dev/null +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/tools/firewall.js @@ -0,0 +1,319 @@ +'use strict'; +'require ui'; +'require uci'; +'require form'; +'require network'; +'require firewall'; +'require tools.prng as random'; + +var protocols = [ + 'ip', 0, 'IP', + 'hopopt', 0, 'HOPOPT', + 'icmp', 1, 'ICMP', + 'igmp', 2, 'IGMP', + 'ggp', 3 , 'GGP', + 'ipencap', 4, 'IP-ENCAP', + 'st', 5, 'ST', + 'tcp', 6, 'TCP', + 'egp', 8, 'EGP', + 'igp', 9, 'IGP', + 'pup', 12, 'PUP', + 'udp', 17, 'UDP', + 'hmp', 20, 'HMP', + 'xns-idp', 22, 'XNS-IDP', + 'rdp', 27, 'RDP', + 'iso-tp4', 29, 'ISO-TP4', + 'dccp', 33, 'DCCP', + 'xtp', 36, 'XTP', + 'ddp', 37, 'DDP', + 'idpr-cmtp', 38, 'IDPR-CMTP', + 'ipv6', 41, 'IPv6', + 'ipv6-route', 43, 'IPv6-Route', + 'ipv6-frag', 44, 'IPv6-Frag', + 'idrp', 45, 'IDRP', + 'rsvp', 46, 'RSVP', + 'gre', 47, 'GRE', + 'esp', 50, 'IPSEC-ESP', + 'ah', 51, 'IPSEC-AH', + 'skip', 57, 'SKIP', + 'ipv6-icmp', 58, 'IPv6-ICMP', + 'ipv6-nonxt', 59, 'IPv6-NoNxt', + 'ipv6-opts', 60, 'IPv6-Opts', + 'rspf', 73, 'RSPF', 'CPHB', + 'vmtp', 81, 'VMTP', + 'eigrp', 88, 'EIGRP', + 'ospf', 89, 'OSPFIGP', + 'ax.25', 93, 'AX.25', + 'ipip', 94, 'IPIP', + 'etherip', 97, 'ETHERIP', + 'encap', 98, 'ENCAP', + 'pim', 103, 'PIM', + 'ipcomp', 108, 'IPCOMP', + 'vrrp', 112, 'VRRP', + 'l2tp', 115, 'L2TP', + 'isis', 124, 'ISIS', + 'sctp', 132, 'SCTP', + 'fc', 133, 'FC', + 'mobility-header', 135, 'Mobility-Header', + 'udplite', 136, 'UDPLite', + 'mpls-in-ip', 137, 'MPLS-in-IP', + 'manet', 138, 'MANET', + 'hip', 139, 'HIP', + 'shim6', 140, 'Shim6', + 'wesp', 141, 'WESP', + 'rohc', 142, 'ROHC', +]; + +function toArray(x) { + if (x == null) + return []; + else if (Array.isArray(x)) + return x.map(String); + else if (typeof(x) == 'object') + return [ x ]; + + var s = String(x).trim(); + + if (s == '') + return []; + + return s.split(/\s+/); +} + +function lookupProto(x) { + if (x == null || x == '') + return null; + + var s = String(x).toLowerCase(); + + for (var i = 0; i < protocols.length; i += 3) + if (s == protocols[i] || s == protocols[i+1]) + return [ protocols[i+1], protocols[i+2] ]; + + return [ -1, x ]; +} + + +return L.Class.extend({ + fmt_neg: function(x) { + var rv = E([]), + v = (typeof(x) == 'string') ? x.replace(/^ *! */, '') : ''; + + L.dom.append(rv, (v != '' && v != x) ? [ _('not') + ' ', v ] : [ '', x ]); + return rv; + }, + + fmt_mac: function(x) { + var rv = E([]), l = toArray(x); + + if (l.length == 0) + return null; + + L.dom.append(rv, [ _('MAC') + ' ' ]); + + for (var i = 0; i < l.length; i++) { + var n = this.fmt_neg(l[i]); + L.dom.append(rv, (i > 0) ? [ ', ', n ] : n); + } + + if (rv.childNodes.length > 2) + rv.firstChild.data = _('MACs') + ' '; + + return rv; + }, + + fmt_port: function(x, d) { + var rv = E([]), l = toArray(x); + + if (l.length == 0) { + if (d) { + L.dom.append(rv, E('var', {}, d)); + return rv; + } + + return null; + } + + L.dom.append(rv, [ _('port') + ' ' ]); + + for (var i = 0; i < l.length; i++) { + var n = this.fmt_neg(l[i]), + m = n.lastChild.data.match(/^(\d+)\D+(\d+)$/); + + if (i > 0) + L.dom.append(rv, [ ', ' ]); + + if (m) { + rv.firstChild.data = _('ports') + ' '; + L.dom.append(rv, E('var', [ n.firstChild, m[1], '-', m[2] ])); + } + else { + L.dom.append(rv, E('var', {}, n)); + } + } + + if (rv.childNodes.length > 2) + rv.firstChild.data = _('ports') + ' '; + + return rv; + }, + + fmt_ip: function(x, d) { + var rv = E([]), l = toArray(x); + + if (l.length == 0) { + if (d) { + L.dom.append(rv, E('var', {}, d)); + return rv; + } + + return null; + } + + L.dom.append(rv, [ _('IP') + ' ' ]); + + for (var i = 0; i < l.length; i++) { + var n = this.fmt_neg(l[i]), + m = n.lastChild.data.match(/^(\S+)\/(\d+\.\S+)$/); + + if (i > 0) + L.dom.append(rv, [ ', ' ]); + + if (m) + rv.firstChild.data = _('IP range') + ' '; + else if (n.lastChild.data.match(/^[a-zA-Z0-9_]+$/)) + rv.firstChild.data = _('Network') + ' '; + + L.dom.append(rv, E('var', {}, n)); + } + + if (rv.childNodes.length > 2) + rv.firstChild.data = _('IPs') + ' '; + + return rv; + }, + + fmt_zone: function(x, d) { + if (x == '*') + return E('var', _('any zone')); + else if (x != null && x != '') + return E('var', {}, [ x ]); + else if (d != null && d != '') + return E('var', {}, d); + else + return null; + }, + + fmt_icmp_type: function(x) { + var rv = E([]), l = toArray(x); + + if (l.length == 0) + return null; + + L.dom.append(rv, [ _('type') + ' ' ]); + + for (var i = 0; i < l.length; i++) { + var n = this.fmt_neg(l[i]); + + if (i > 0) + L.dom.append(rv, [ ', ' ]); + + L.dom.append(rv, E('var', {}, n)); + } + + if (rv.childNodes.length > 2) + rv.firstChild.data = _('types') + ' '; + + return rv; + }, + + fmt_proto: function(x, icmp_types) { + var rv = E([]), l = toArray(x); + + if (l.length == 0) + return null; + + var t = this.fmt_icmp_type(icmp_types); + + for (var i = 0; i < l.length; i++) { + var n = this.fmt_neg(l[i]), + p = lookupProto(n.lastChild.data); + + if (n.lastChild.data == 'all') + continue; + + if (i > 0) + L.dom.append(rv, [ ', ' ]); + + if (t && (p[0] == 1 || p[0] == 58)) + L.dom.append(rv, [ _('%s%s with %s').format(n.firstChild.data, p[1], ''), t ]); + else + L.dom.append(rv, [ n.firstChild.data, p[1] ]); + } + + return rv; + }, + + fmt_limit: function(limit, burst) { + if (limit == null || limit == '') + return null; + + var m = String(limit).match(/^(\d+)\/(\w+)$/), + u = m[2] || 'second', + l = +(m[1] || limit), + b = +burst; + + if (!isNaN(l)) { + if (u.match(/^s/)) + u = _('second'); + else if (u.match(/^m/)) + u = _('minute'); + else if (u.match(/^h/)) + u = _('hour'); + else if (u.match(/^d/)) + u = _('day'); + + if (!isNaN(b) && b > 0) + return E('' + + _('%d pkts. per %s, burst %d pkts.').format(l, u, b) + + ''); + else + return E('' + + _('%d pkts. per %s').format(l, u) + + ''); + } + }, + + fmt_target: function(x, src, dest) { + if (src == null || src == '') { + if (x == 'ACCEPT') + return _('Accept output'); + else if (x == 'REJECT') + return _('Refuse output'); + else if (x == 'NOTRACK') + return _('Do not track output'); + else /* if (x == 'DROP') */ + return _('Discard output'); + } + else if (dest != null && dest != '') { + if (x == 'ACCEPT') + return _('Accept forward'); + else if (x == 'REJECT') + return _('Refuse forward'); + else if (x == 'NOTRACK') + return _('Do not track forward'); + else /* if (x == 'DROP') */ + return _('Discard forward'); + } + else { + if (x == 'ACCEPT') + return _('Accept input'); + else if (x == 'REJECT' ) + return _('Refuse input'); + else if (x == 'NOTRACK') + return _('Do not track input'); + else /* if (x == 'DROP') */ + return _('Discard input'); + } + } +}); diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/forwards.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/forwards.js new file mode 100644 index 000000000..743d115e8 --- /dev/null +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/forwards.js @@ -0,0 +1,290 @@ +'use strict'; +'require ui'; +'require rpc'; +'require uci'; +'require form'; +'require tools.firewall as fwtool'; +'require tools.widgets as widgets'; + +function skeys(obj, key, mode) { + if (obj == null || typeof(obj) != 'object') + return []; + + return Object.keys(obj).map(function(e) { + var v = (key != null) ? obj[e][key] : e; + + switch (mode) { + case 'addr': + v = (v != null) ? v.replace(/(?:^|[.:])([0-9a-fA-F]{1,4})/g, + function(m0, m1) { return ('000' + m1.toLowerCase()).substr(-4) }) : null; + break; + + case 'num': + v = (v != null) ? +v : null; + break; + } + + return [ e, v ]; + }).filter(function(e) { + return (e[1] != null); + }).sort(function(a, b) { + return (a[1] > b[1]); + }).map(function(e) { + return e[0]; + }); +} + +function fmt(fmt /*, ...*/) { + var repl = [], wrap = false; + + for (var i = 1; i < arguments.length; i++) { + if (L.dom.elem(arguments[i])) { + switch (arguments[i].nodeType) { + case 1: + repl.push(arguments[i].outerHTML); + wrap = true; + break; + + case 3: + repl.push(arguments[i].data); + break; + + case 11: + var span = E('span'); + span.appendChild(arguments[i]); + repl.push(span.innerHTML); + wrap = true; + break; + + default: + repl.push(''); + } + } + else { + repl.push(arguments[i]); + } + } + + var rv = fmt.format.apply(fmt, repl); + return wrap ? E('span', rv) : rv; +} + +function forward_proto_txt(s) { + return fmt('%s-%s', _('IPv4'), + fwtool.fmt_proto(uci.get('firewall', s, 'proto'), + uci.get('firewall', s, 'icmp_type')) || 'TCP+UDP'); +} + +function forward_src_txt(s) { + var z = fwtool.fmt_zone(uci.get('firewall', s, 'src'), _('any zone')), + a = fwtool.fmt_ip(uci.get('firewall', s, 'src_ip'), _('any host')), + p = fwtool.fmt_port(uci.get('firewall', s, 'src_port')), + m = fwtool.fmt_mac(uci.get('firewall', s, 'src_mac')); + + if (p && m) + return fmt(_('From %s in %s with source %s and %s'), a, z, p, m); + else if (p || m) + return fmt(_('From %s in %s with source %s'), a, z, p || m); + else + return fmt(_('From %s in %s'), a, z); +} + +function forward_via_txt(s) { + var a = fwtool.fmt_ip(uci.get('firewall', s, 'src_dip'), _('any router IP')), + p = fwtool.fmt_port(uci.get('firewall', s, 'src_dport')); + + if (p) + return fmt(_('Via %s at %s'), a, p); + else + return fmt(_('Via %s'), a); +} + +return L.view.extend({ + callHostHints: rpc.declare({ + object: 'luci', + method: 'host_hints' + }), + + load: function() { + return Promise.all([ + this.callHostHints() + ]); + }, + + render: function(data) { + var hosts = data[0], + m, s, o; + + m = new form.Map('firewall', _('Firewall - Port Forwards'), + _('Port forwarding allows remote computers on the Internet to connect to a specific computer or service within the private LAN.')); + + s = m.section(form.GridSection, 'redirect', _('Port Forwards')); + s.addremove = true; + s.anonymous = true; + s.sortable = true; + + s.tab('general', _('General Settings')); + s.tab('advanced', _('Advanced Settings')); + + s.filter = function(section_id) { + return (uci.get('firewall', section_id, 'target') != 'SNAT'); + }; + + s.sectiontitle = function(section_id) { + return uci.get('firewall', section_id, 'name') || _('Unnamed forward'); + }; + + o = s.taboption('general', form.Value, 'name', _('Name')); + o.placeholder = _('Unnamed forward'); + o.modalonly = true; + + o = s.option(form.DummyValue, '_match', _('Match')); + o.modalonly = false; + o.textvalue = function(s) { + return E('small', [ + forward_proto_txt(s), E('br'), + forward_src_txt(s), E('br'), + forward_via_txt(s) + ]); + }; + + o = s.option(form.ListValue, '_dest', _('Forward to')); + o.modalonly = false; + o.textvalue = function(s) { + var z = fwtool.fmt_zone(uci.get('firewall', s, 'dest'), _('any zone')), + a = fwtool.fmt_ip(uci.get('firewall', s, 'dest_ip'), _('any host')), + p = fwtool.fmt_port(uci.get('firewall', s, 'dest_port')) || + fwtool.fmt_port(uci.get('firewall', s, 'src_dport')); + + if (p) + return fmt(_('%s, %s in %s'), a, p, z); + else + return fmt(_('%s in %s'), a, z); + }; + + o = s.option(form.Flag, 'enabled', _('Enable')); + o.modalonly = false; + o.default = o.enabled; + o.editable = true; + + o = s.taboption('general', form.Value, 'proto', _('Protocol')); + o.modalonly = true; + o.default = 'tcp udp'; + o.value('tcp udp', 'TCP+UDP'); + o.value('tcp', 'TCP'); + o.value('udp', 'UDP'); + o.value('icmp', 'ICMP'); + + o.cfgvalue = function(/* ... */) { + var v = this.super('cfgvalue', arguments); + return (v == 'tcpudp') ? 'tcp udp' : v; + }; + + o = s.taboption('general', widgets.ZoneSelect, 'src', _('Source zone')); + o.modalonly = true; + o.rmempty = false; + o.nocreate = true; + o.default = 'wan'; + + o = s.taboption('advanced', form.Value, 'src_mac', _('Source MAC address'), + _('Only match incoming traffic from these MACs.')); + o.modalonly = true; + o.rmempty = true; + o.datatype = 'neg(macaddr)'; + o.placeholder = E('em', _('any')); + skeys(hosts).forEach(function(mac) { + o.value(mac, '%s (%s)'.format( + mac, + hosts[mac].name || hosts[mac].ipv4 || hosts[mac].ipv6 || '?' + )); + }); + + o = s.taboption('advanced', form.Value, 'src_ip', _('Source IP address'), + _('Only match incoming traffic from this IP or range.')); + o.modalonly = true; + o.rmempty = true; + o.datatype = 'neg(ipmask4)'; + o.placeholder = E('em', _('any')); + skeys(hosts, 'ipv4', 'addr').forEach(function(mac) { + o.value(hosts[mac].ipv4, '%s (%s)'.format( + hosts[mac].ipv4, + hosts[mac].name || mac + )); + }); + + o = s.taboption('advanced', form.Value, 'src_port', _('Source port'), + _('Only match incoming traffic originating from the given source port or port range on the client host')); + o.modalonly = true; + o.rmempty = true; + o.datatype = 'neg(portrange)'; + o.placeholder = _('any'); + o.depends('proto', 'tcp'); + o.depends('proto', 'udp'); + o.depends('proto', 'tcp udp'); + o.depends('proto', 'tcpudp'); + + o = s.taboption('advanced', form.Value, 'src_dip', _('External IP address'), + _('Only match incoming traffic directed at the given IP address.')); + o.modalonly = true; + o.rmempty = true; + o.datatype = 'neg(ipmask4)'; + o.placeholder = E('em', _('any')); + skeys(hosts, 'ipv4', 'addr').forEach(function(mac) { + o.value(hosts[mac].ipv4, '%s (%s)'.format( + hosts[mac].ipv4, + hosts[mac].name || mac + )); + }); + + o = s.taboption('general', form.Value, 'src_dport', _('External port'), + _('Match incoming traffic directed at the given destination port or port range on this host')); + o.modalonly = true; + o.rmempty = false; + o.datatype = 'neg(portrange)'; + o.depends('proto', 'tcp'); + o.depends('proto', 'udp'); + o.depends('proto', 'tcp udp'); + o.depends('proto', 'tcpudp'); + + o = s.taboption('general', widgets.ZoneSelect, 'dest', _('Internal zone')); + o.modalonly = true; + o.rmempty = true; + o.nocreate = true; + o.default = 'lan'; + + o = s.taboption('general', form.Value, 'dest_ip', _('Internal IP address'), + _('Redirect matched incoming traffic to the specified internal host')); + o.modalonly = true; + o.rmempty = true; + o.datatype = 'ipmask4'; + skeys(hosts, 'ipv4', 'addr').forEach(function(mac) { + o.value(hosts[mac].ipv4, '%s (%s)'.format( + hosts[mac].ipv4, + hosts[mac].name || mac + )); + }); + + o = s.taboption('general', form.Value, 'dest_port', _('Internal port'), + _('Redirect matched incoming traffic to the given port on the internal host')); + o.modalonly = true; + o.rmempty = true; + o.placeholder = _('any'); + o.datatype = 'portrange'; + o.depends('proto', 'tcp'); + o.depends('proto', 'udp'); + o.depends('proto', 'tcp udp'); + o.depends('proto', 'tcpudp'); + + o = s.taboption('advanced', form.Flag, 'reflection', _('Enable NAT Loopback')); + o.modalonly = true; + o.rmempty = true; + o.default = o.enabled; + + o = s.taboption('advanced', form.Value, 'extra', _('Extra arguments'), + _('Passes additional arguments to iptables. Use with care!')); + o.modalonly = true; + o.rmempty = true; + + return m.render(); + } +}); diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/rules.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/rules.js new file mode 100644 index 000000000..9fa1aa252 --- /dev/null +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/rules.js @@ -0,0 +1,401 @@ +'use strict'; +'require ui'; +'require rpc'; +'require uci'; +'require form'; +'require tools.firewall as fwtool'; +'require tools.widgets as widgets'; + +function skeys(obj, key, mode) { + if (obj == null || typeof(obj) != 'object') + return []; + + return Object.keys(obj).map(function(e) { + var v = (key != null) ? obj[e][key] : e; + + switch (mode) { + case 'addr': + v = (v != null) ? v.replace(/(?:^|[.:])([0-9a-fA-F]{1,4})/g, + function(m0, m1) { return ('000' + m1.toLowerCase()).substr(-4) }) : null; + break; + + case 'num': + v = (v != null) ? +v : null; + break; + } + + return [ e, v ]; + }).filter(function(e) { + return (e[1] != null); + }).sort(function(a, b) { + return (a[1] > b[1]); + }).map(function(e) { + return e[0]; + }); +} + +function fmt(fmt /*, ...*/) { + var repl = [], wrap = false; + + for (var i = 1; i < arguments.length; i++) { + if (L.dom.elem(arguments[i])) { + switch (arguments[i].nodeType) { + case 1: + repl.push(arguments[i].outerHTML); + wrap = true; + break; + + case 3: + repl.push(arguments[i].data); + break; + + case 11: + var span = E('span'); + span.appendChild(arguments[i]); + repl.push(span.innerHTML); + wrap = true; + break; + + default: + repl.push(''); + } + } + else { + repl.push(arguments[i]); + } + } + + var rv = fmt.format.apply(fmt, repl); + return wrap ? E('span', rv) : rv; +} + +function forward_proto_txt(s) { + return fmt('%s-%s', _('IPv4'), + fwtool.fmt_proto(uci.get('firewall', s, 'proto'), + uci.get('firewall', s, 'icmp_type')) || 'TCP+UDP'); +} + +function rule_src_txt(s) { + var z = fwtool.fmt_zone(uci.get('firewall', s, 'src')), + p = fwtool.fmt_port(uci.get('firewall', s, 'src_port')), + m = fwtool.fmt_mac(uci.get('firewall', s, 'src_mac')); + + // Forward/Input + if (z) { + var a = fwtool.fmt_ip(uci.get('firewall', s, 'src_ip'), _('any host')); + if (p && m) + return fmt(_('From %s in %s with source %s and %s'), a, z, p, m); + else if (p || m) + return fmt(_('From %s in %s with source %s'), a, z, p || m); + else + return fmt(_('From %s in %s'), a, z); + } + + // Output + else { + var a = fwtool.fmt_ip(uci.get('firewall', s, 'src_ip'), _('any router IP')); + if (p && m) + return fmt(_('From %s on this device with source %s and %s'), a, p, m); + else if (p || m) + return fmt(_('From %s on this device with source %s'), a, p || m); + else + return fmt(_('From %s on this device'), a); + } +} + +function rule_dest_txt(s) { + var z = fwtool.fmt_zone(uci.get('firewall', s, 'dest')), + p = fwtool.fmt_port(uci.get('firewall', s, 'dest_port')); + + // Forward + if (z) { + var a = fwtool.fmt_ip(uci.get('firewall', s, 'dest_ip'), _('any host')); + if (p) + return fmt(_('To %s, %s in %s'), a, p, z); + else + return fmt(_('To %s in %s'), a, z); + } + + // Input + else { + var a = fwtool.fmt_ip(uci.get('firewall', s, 'dest_ip'), _('any router IP')); + if (p) + return fmt(_('To %s at %s on this device'), a, p); + else + return fmt(_('To %s on this device'), a); + } +} + +function rule_target_txt(s) { + var t = fwtool.fmt_target(uci.get('firewall', s, 'target'), uci.get('firewall', s, 'src'), uci.get('firewall', s, 'dest')), + l = fwtool.fmt_limit(uci.get('firewall', s, 'limit'), uci.get('firewall', s, 'limit_burst')); + + if (l) + return fmt(_('%s and limit to %s'), t, l); + else + return fmt('%s', t); +} + +return L.view.extend({ + callHostHints: rpc.declare({ + object: 'luci', + method: 'host_hints' + }), + + load: function() { + return this.callHostHints().catch(function(e) { + console.debug('load fail', e); + }); + }, + + render: function(hosts) { + var m, s, o; + + m = new form.Map('firewall', _('Firewall - Traffic Rules'), + _('Traffic rules define policies for packets traveling between different zones, for example to reject traffic between certain hosts or to open WAN ports on the router.')); + + s = m.section(form.GridSection, 'rule', _('Traffic Rules')); + s.addremove = true; + s.anonymous = true; + s.sortable = true; + + s.tab('general', _('General Settings')); + s.tab('advanced', _('Advanced Settings')); + s.tab('timed', _('Time Restrictions')); + + s.filter = function(section_id) { + return (uci.get('firewall', section_id, 'target') != 'SNAT'); + }; + + s.sectiontitle = function(section_id) { + return uci.get('firewall', section_id, 'name') || _('Unnamed rule'); + }; + + o = s.taboption('general', form.Value, 'name', _('Name')); + o.placeholder = _('Unnamed rule'); + o.modalonly = true; + + o = s.option(form.DummyValue, '_match', _('Match')); + o.modalonly = false; + o.textvalue = function(s) { + return E('small', [ + forward_proto_txt(s), E('br'), + rule_src_txt(s), E('br'), + rule_dest_txt(s) + ]); + }; + + o = s.option(form.ListValue, '_target', _('Action')); + o.modalonly = false; + o.textvalue = function(s) { + return rule_target_txt(s); + }; + + o = s.option(form.Flag, 'enabled', _('Enable')); + o.modalonly = false; + o.default = o.enabled; + o.editable = true; + + //ft.opt_enabled(s, Button); + //ft.opt_name(s, Value, _('Name')); + + + o = s.taboption('advanced', form.ListValue, 'family', _('Restrict to address family')); + o.modalonly = true; + o.rmempty = true; + o.value('', _('IPv4 and IPv6')); + o.value('ipv4', _('IPv4 only')); + o.value('ipv6', _('IPv6 only')); + + o = s.taboption('general', form.Value, 'proto', _('Protocol')); + o.modalonly = true; + o.default = 'tcp udp'; + o.value('all', _('Any')); + o.value('tcp udp', 'TCP+UDP'); + o.value('tcp', 'TCP'); + o.value('udp', 'UDP'); + o.value('icmp', 'ICMP'); + o.cfgvalue = function(/* ... */) { + var v = this.super('cfgvalue', arguments); + return (v == 'tcpudp') ? 'tcp udp' : v; + }; + + o = s.taboption('advanced', form.MultiValue, 'icmp_type', _('Match ICMP type')); + o.modalonly = true; + o.multiple = true; + o.custom = true; + o.cast = 'table'; + o.placeholder = _('any'); + o.value('', 'any'); + o.value('echo-reply'); + o.value('destination-unreachable'); + o.value('network-unreachable'); + o.value('host-unreachable'); + o.value('protocol-unreachable'); + o.value('port-unreachable'); + o.value('fragmentation-needed'); + o.value('source-route-failed'); + o.value('network-unknown'); + o.value('host-unknown'); + o.value('network-prohibited'); + o.value('host-prohibited'); + o.value('TOS-network-unreachable'); + o.value('TOS-host-unreachable'); + o.value('communication-prohibited'); + o.value('host-precedence-violation'); + o.value('precedence-cutoff'); + o.value('source-quench'); + o.value('redirect'); + o.value('network-redirect'); + o.value('host-redirect'); + o.value('TOS-network-redirect'); + o.value('TOS-host-redirect'); + o.value('echo-request'); + o.value('router-advertisement'); + o.value('router-solicitation'); + o.value('time-exceeded'); + o.value('ttl-zero-during-transit'); + o.value('ttl-zero-during-reassembly'); + o.value('parameter-problem'); + o.value('ip-header-bad'); + o.value('required-option-missing'); + o.value('timestamp-request'); + o.value('timestamp-reply'); + o.value('address-mask-request'); + o.value('address-mask-reply'); + o.depends('proto', 'icmp'); + + o = s.taboption('general', widgets.ZoneSelect, 'src', _('Source zone')); + o.modalonly = true; + o.nocreate = true; + o.allowany = true; + o.allowlocal = 'src'; + o.default = 'wan'; + + o = s.taboption('advanced', form.Value, 'src_mac', _('Source MAC address')); + o.modalonly = true; + o.datatype = 'list(macaddr)'; + o.placeholder = _('any'); + skeys(hosts).forEach(function(mac) { + o.value(mac, '%s (%s)'.format( + mac, + hosts[mac].name || hosts[mac].ipv4 || hosts[mac].ipv6 || '?' + )); + }); + + o = s.taboption('general', form.Value, 'src_ip', _('Source address')); + o.modalonly = true; + o.datatype = 'list(neg(ipmask))'; + o.placeholder = _('any'); + skeys(hosts, 'ipv4', 'addr').forEach(function(mac) { + o.value(hosts[mac].ipv4, '%s (%s)'.format( + hosts[mac].ipv4, + hosts[mac].name || mac + )); + }); + + o = s.taboption('general', form.Value, 'src_port', _('Source port')); + o.modalonly = true; + o.datatype = 'list(neg(portrange))'; + o.placeholder = _('any'); + o.depends('proto', 'tcp'); + o.depends('proto', 'udp'); + o.depends('proto', 'tcp udp'); + o.depends('proto', 'tcpudp'); + + o = s.taboption('general', widgets.ZoneSelect, 'dest_local', _('Output zone')); + o.modalonly = true; + o.nocreate = true; + o.allowany = true; + o.alias = 'dest'; + o.default = 'wan'; + o.depends('src', ''); + + o = s.taboption('general', widgets.ZoneSelect, 'dest_remote', _('Destination zone')); + o.modalonly = true; + o.nocreate = true; + o.allowany = true; + o.allowlocal = true; + o.alias = 'dest'; + o.default = 'lan'; + o.depends({'src': '', '!reverse': true}); + + o = s.taboption('general', form.Value, 'dest_ip', _('Destination address')); + o.modalonly = true; + o.datatype = 'list(neg(ipmask))'; + o.placeholder = _('any'); + skeys(hosts, 'ipv4', 'addr').forEach(function(mac) { + o.value(hosts[mac].ipv4, '%s (%s)'.format( + hosts[mac].ipv4, + hosts[mac].name || mac + )); + }); + + o = s.taboption('general', form.Value, 'dest_port', _('Destination port')); + o.modalonly = true; + o.datatype = 'list(neg(portrange))'; + o.placeholder = _('any'); + o.depends('proto', 'tcp'); + o.depends('proto', 'udp'); + o.depends('proto', 'tcp udp'); + o.depends('proto', 'tcpudp'); + + o = s.taboption('general', form.ListValue, 'target', _('Action')); + o.modalonly = true; + o.default = 'ACCEPT'; + o.value('DROP', _('drop')); + o.value('ACCEPT', _('accept')); + o.value('REJECT', _('reject')); + o.value('NOTRACK', _("don't track")); + + o = s.taboption('advanced', form.Value, 'extra', _('Extra arguments'), + _('Passes additional arguments to iptables. Use with care!')); + o.modalonly = true; + + o = s.taboption('timed', form.MultiValue, 'weekdays', _('Week Days')); + o.modalonly = true; + o.multiple = true; + o.display = 5; + o.placeholder = _('Any day'); + o.value('Sun', _('Sunday')); + o.value('Mon', _('Monday')); + o.value('Tue', _('Tuesday')); + o.value('Wed', _('Wednesday')); + o.value('Thu', _('Thursday')); + o.value('Fri', _('Friday')); + o.value('Sat', _('Saturday')); + + o = s.taboption('timed', form.MultiValue, 'monthdays', _('Month Days')); + o.modalonly = true; + o.multiple = true; + o.display_size = 15; + o.placeholder = _('Any day'); + for (var i = 1; i <= 31; i++) + o.value(i); + + o = s.taboption('timed', form.Value, 'start_time', _('Start Time (hh.mm.ss)')); + o.modalonly = true; + o.datatype = 'timehhmmss'; + + o = s.taboption('timed', form.Value, 'stop_time', _('Stop Time (hh.mm.ss)')); + o.modalonly = true; + o.datatype = 'timehhmmss'; + + o = s.taboption('timed', form.Value, 'start_date', _('Start Date (yyyy-mm-dd)')); + o.modalonly = true; + o.datatype = 'dateyyyymmdd'; + + o = s.taboption('timed', form.Value, 'stop_date', _('Stop Date (yyyy-mm-dd)')); + o.modalonly = true; + o.datatype = 'dateyyyymmdd'; + + o = s.taboption('timed', form.Flag, 'utc_time', _('Time in UTC')); + o.modalonly = true; + o.default = o.disabled; + + return m.render().catch(function(e) { + console.debug('render fail') + }); + + } +}); diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js new file mode 100644 index 000000000..3f1061a10 --- /dev/null +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/zones.js @@ -0,0 +1,249 @@ +'use strict'; +'require rpc'; +'require uci'; +'require form'; +'require network'; +'require firewall'; +'require tools.widgets as widgets'; + +return L.view.extend({ + callOffloadSupport: rpc.declare({ + object: 'luci', + method: 'offload_support', + expect: { offload_support: false } + }), + + load: function() { + return this.callOffloadSupport(); + }, + + render: function(hasOffloading) { + var m, s, o, inp, out; + + m = new form.Map('firewall', _('Firewall - Zone Settings'), + _('The firewall creates zones over your network interfaces to control network traffic flow.')); + + s = m.section(form.TypedSection, 'defaults', _('General Settings')); + s.anonymous = true; + s.addremove = false; + + o = s.option(form.Flag, 'syn_flood', _('Enable SYN-flood protection')); + o = s.option(form.Flag, 'drop_invalid', _('Drop invalid packets')); + + var p = [ + s.option(form.ListValue, 'input', _('Input')), + s.option(form.ListValue, 'output', _('Output')), + s.option(form.ListValue, 'forward', _('Forward')) + ]; + + for (var i = 0; i < p.length; i++) { + p[i].value('REJECT', _('reject')); + p[i].value('DROP', _('drop')); + p[i].value('ACCEPT', _('accept')); + } + + /* Netfilter flow offload support */ + + if (hasOffloading) { + s = m.section(form.TypedSection, 'defaults', _('Routing/NAT Offloading'), + _('Experimental feature. Not fully compatible with QoS/SQM.')); + + s.anonymous = true; + s.addremove = false; + + o = s.option(form.Flag, 'flow_offloading', + _('Software flow offloading'), + _('Software based offloading for routing/NAT')); + o.optional = true; + + o = s.option(form.Flag, 'flow_offloading_hw', + _('Hardware flow offloading'), + _('Requires hardware NAT support. Implemented at least for mt7621')); + o.optional = true; + o.depends('flow_offloading', '1'); + } + + + s = m.section(form.GridSection, 'zone', _('Zones')); + s.addremove = true; + s.anonymous = true; + s.sortable = true; + + s.tab('general', _('General Settings')); + s.tab('advanced', _('Advanced Settings')); + + o = s.taboption('general', form.DummyValue, '_generalinfo'); + o.rawhtml = true; + o.modalonly = true; + o.cfgvalue = function(section_id) { + var name = uci.get('firewall', section_id, 'name'); + + return _('This section defines common properties of %q. The input and output options set the default policies for traffic entering and leaving this zone while the forward option describes the policy for forwarded traffic between different networks within the zone. Covered networks specifies which available networks are members of this zone.') + .replace(/%s/g, name).replace(/%q/g, '"' + name + '"'); + }; + + o = s.taboption('general', form.Value, 'name', _('Name')); + o.placeholder = _('Unnamed zone'); + o.modalonly = true; + o.datatype = 'and(uciname,maxlength(11))'; + o.write = function(section_id, formvalue) { + var cfgvalue = this.cfgvalue(section_id); + + if (cfgvalue != formvalue) + return firewall.renameZone(cfgvalue, formvalue); + }; + + o = s.option(widgets.ZoneForwards, '_info', _('Zone ⇒ Forwardings')); + o.editable = true; + o.modalonly = false; + o.cfgvalue = function(section_id) { + return uci.get('firewall', section_id, 'name'); + }; + + var p = [ + s.taboption('general', form.ListValue, 'input', _('Input')), + s.taboption('general', form.ListValue, 'output', _('Output')), + s.taboption('general', form.ListValue, 'forward', _('Forward')) + ]; + + for (var i = 0; i < p.length; i++) { + p[i].value('REJECT', _('reject')); + p[i].value('DROP', _('drop')); + p[i].value('ACCEPT', _('accept')); + p[i].editable = true; + } + + o = s.taboption('general', form.Flag, 'masq', _('Masquerading')); + o.editable = true; + + o = s.taboption('general', form.Flag, 'mtu_fix', _('MSS clamping')); + o.modalonly = true; + + o = s.taboption('general', widgets.NetworkSelect, 'network', _('Covered networks')); + o.modalonly = true; + o.multiple = true; + o.write = function(section_id, formvalue) { + var name = uci.get('firewall', section_id, 'name'), + cfgvalue = this.cfgvalue(section_id); + + if (typeof(cfgvalue) == 'string' && Array.isArray(formvalue) && (cfgvalue == formvalue.join(' '))) + return; + + var tasks = [ firewall.getZone(name) ]; + + if (Array.isArray(formvalue)) + for (var i = 0; i < formvalue.length; i++) { + var netname = formvalue[i]; + tasks.push(network.getNetwork(netname).then(function(net) { + return net || network.addNetwork(netname, { 'proto': 'none' }); + })); + } + + return Promise.all(tasks).then(function(zone_networks) { + if (zone_networks[0]) + for (var i = 1; i < zone_networks.length; i++) + zone_networks[0].addNetwork(zone_networks[i].getName()); + }); + }; + + o = s.taboption('advanced', form.DummyValue, '_advancedinfo'); + o.rawhtml = true; + o.modalonly = true; + o.cfgvalue = function(section_id) { + var name = uci.get('firewall', section_id, 'name'); + + return _('The options below control the forwarding policies between this zone (%s) and other zones. Destination zones cover forwarded traffic originating from %q. Source zones match forwarded traffic from other zones targeted at %q. The forwarding rule is unidirectional, e.g. a forward from lan to wan does not imply a permission to forward from wan to lan as well.') + .format(name); + }; + + o = s.taboption('advanced', form.ListValue, 'family', _('Restrict to address family')); + o.value('', _('IPv4 and IPv6')); + o.value('ipv4', _('IPv4 only')); + o.value('ipv6', _('IPv6 only')); + o.modalonly = true; + + o = s.taboption('advanced', form.DynamicList, 'masq_src', _('Restrict Masquerading to given source subnets')); + o.depends('family', ''); + o.depends('family', 'ipv4'); + o.datatype = 'list(neg(or(uciname,hostname,ipmask4)))'; + o.placeholder = '0.0.0.0/0'; + o.modalonly = true; + + o = s.taboption('advanced', form.DynamicList, 'masq_dest', _('Restrict Masquerading to given destination subnets')); + o.depends('family', ''); + o.depends('family', 'ipv4'); + o.datatype = 'list(neg(or(uciname,hostname,ipmask4)))'; + o.placeholder = '0.0.0.0/0'; + o.modalonly = true; + + o = s.taboption('advanced', form.Flag, 'conntrack', _('Force connection tracking')); + o.modalonly = true; + + o = s.taboption('advanced', form.Flag, 'log', _('Enable logging on this zone')); + o.modalonly = true; + + o = s.taboption('advanced', form.Value, 'log_limit', _('Limit log messages')); + o.depends('log', '1'); + o.placeholder = '10/minute'; + o.modalonly = true; + + o = s.taboption('general', form.DummyValue, '_forwardinfo'); + o.rawhtml = true; + o.modalonly = true; + o.cfgvalue = function(section_id) { + return _('The options below control the forwarding policies between this zone (%s) and other zones. Destination zones cover forwarded traffic originating from %q. Source zones match forwarded traffic from other zones targeted at %q. The forwarding rule is unidirectional, e.g. a forward from lan to wan does not imply a permission to forward from wan to lan as well.') + .format(uci.get('firewall', section_id, 'name')); + }; + + out = o = s.taboption('general', widgets.ZoneSelect, 'out', _('Allow forward to destination zones:')); + o.nocreate = true; + o.multiple = true; + o.modalonly = true; + o.filter = function(section_id, value) { + return (uci.get('firewall', section_id, 'name') != value); + }; + o.cfgvalue = function(section_id) { + var out = (this.option == 'out'), + zone = this.lookupZone(uci.get('firewall', section_id, 'name')), + fwds = zone.getForwardingsBy(out ? 'src' : 'dest'), + value = []; + + for (var i = 0; i < fwds.length; i++) + value.push(out ? fwds[i].getDestination() : fwds[i].getSource()); + + return value; + }; + o.write = o.remove = function(section_id, formvalue) { + var out = (this.option == 'out'), + zone = this.lookupZone(uci.get('firewall', section_id, 'name')), + fwds = zone.getForwardingsBy(out ? 'src' : 'dest'); + + if (formvalue == null) + formvalue = []; + + if (Array.isArray(formvalue)) { + for (var i = 0; i < fwds.length; i++) { + var cmp = out ? fwds[i].getDestination() : fwds[i].getSource(); + if (!formvalue.filter(function(d) { return d == cmp }).length) + zone.deleteForwarding(fwds[i]); + } + + for (var i = 0; i < formvalue.length; i++) + if (out) + zone.addForwardingTo(formvalue[i]); + else + zone.addForwardingFrom(formvalue[i]); + } + }; + + inp = o = s.taboption('general', widgets.ZoneSelect, 'in', _('Allow forward from source zones:')); + o.nocreate = true; + o.multiple = true; + o.modalonly = true; + o.write = o.remove = out.write; + o.filter = out.filter; + o.cfgvalue = out.cfgvalue; + + return m.render(); + } +}); diff --git a/applications/luci-app-firewall/luasrc/controller/firewall.lua b/applications/luci-app-firewall/luasrc/controller/firewall.lua index 4fe7770ef..58a44c601 100644 --- a/applications/luci-app-firewall/luasrc/controller/firewall.lua +++ b/applications/luci-app-firewall/luasrc/controller/firewall.lua @@ -6,16 +6,13 @@ function index() _("Firewall"), 60) entry({"admin", "network", "firewall", "zones"}, - arcombine(cbi("firewall/zones"), cbi("firewall/zone-details")), - _("General Settings"), 10).leaf = true + view("firewall/zones"), _("General Settings"), 10) entry({"admin", "network", "firewall", "forwards"}, - arcombine(cbi("firewall/forwards"), cbi("firewall/forward-details")), - _("Port Forwards"), 20).leaf = true + view("firewall/forwards"), _("Port Forwards"), 20) entry({"admin", "network", "firewall", "rules"}, - arcombine(cbi("firewall/rules"), cbi("firewall/rule-details")), - _("Traffic Rules"), 30).leaf = true + view("firewall/rules"), _("Traffic Rules"), 30) entry({"admin", "network", "firewall", "custom"}, form("firewall/custom"), diff --git a/applications/luci-app-firewall/luasrc/model/cbi/firewall/forward-details.lua b/applications/luci-app-firewall/luasrc/model/cbi/firewall/forward-details.lua deleted file mode 100644 index d51f8fb79..000000000 --- a/applications/luci-app-firewall/luasrc/model/cbi/firewall/forward-details.lua +++ /dev/null @@ -1,162 +0,0 @@ --- Copyright 2011 Jo-Philipp Wich --- Licensed to the public under the Apache License 2.0. - -local sys = require "luci.sys" -local dsp = require "luci.dispatcher" -local ft = require "luci.tools.firewall" - -local m, s, o - -arg[1] = arg[1] or "" - -m = Map("firewall", - translate("Firewall - Port Forwards"), - translate("This page allows you to change advanced properties of the port \ - forwarding entry. In most cases there is no need to modify \ - those settings.")) - -m.redirect = dsp.build_url("admin/network/firewall/forwards") - -if m.uci:get("firewall", arg[1]) ~= "redirect" then - luci.http.redirect(m.redirect) - return -else - local name = m:get(arg[1], "name") or m:get(arg[1], "_name") - if not name or #name == 0 then - name = translate("(Unnamed Entry)") - end - m.title = "%s - %s" %{ translate("Firewall - Port Forwards"), name } -end - -s = m:section(NamedSection, arg[1], "redirect", "") -s.anonymous = true -s.addremove = false - -ft.opt_enabled(s, Button) -ft.opt_name(s, Value, translate("Name")) - - -o = s:option(Value, "proto", translate("Protocol")) -o:value("tcp udp", "TCP+UDP") -o:value("tcp", "TCP") -o:value("udp", "UDP") -o:value("icmp", "ICMP") - -function o.cfgvalue(...) - local v = Value.cfgvalue(...) - if not v or v == "tcpudp" then - return "tcp udp" - end - return v -end - - -o = s:option(Value, "src", translate("Source zone")) -o.nocreate = true -o.default = "wan" -o.template = "cbi/firewall_zonelist" -o.rmempty = false - - -o = s:option(DynamicList, "src_mac", - translate("Source MAC address"), - translate("Only match incoming traffic from these MACs.")) -o.rmempty = true -o.datatype = "neg(macaddr)" -o.placeholder = translate("any") - -luci.sys.net.mac_hints(function(mac, name) - o:value(mac, "%s (%s)" %{ mac, name }) -end) - - -o = s:option(Value, "src_ip", - translate("Source IP address"), - translate("Only match incoming traffic from this IP or range.")) -o.rmempty = true -o.datatype = "neg(ipmask4)" -o.placeholder = translate("any") - -luci.sys.net.ipv4_hints(function(ip, name) - o:value(ip, "%s (%s)" %{ ip, name }) -end) - - -o = s:option(Value, "src_port", - translate("Source port"), - translate("Only match incoming traffic originating from the given source port or port range on the client host")) -o.rmempty = true -o.datatype = "neg(portrange)" -o.placeholder = translate("any") - -o:depends("proto", "tcp") -o:depends("proto", "udp") -o:depends("proto", "tcp udp") -o:depends("proto", "tcpudp") - -o = s:option(Value, "src_dip", - translate("External IP address"), - translate("Only match incoming traffic directed at the given IP address.")) - -luci.sys.net.ipv4_hints(function(ip, name) - o:value(ip, "%s (%s)" %{ ip, name }) -end) - - -o.rmempty = true -o.datatype = "neg(ipmask4)" -o.placeholder = translate("any") - - -o = s:option(Value, "src_dport", translate("External port"), - translate("Match incoming traffic directed at the given " .. - "destination port or port range on this host")) -o.datatype = "neg(portrange)" - -o:depends("proto", "tcp") -o:depends("proto", "udp") -o:depends("proto", "tcp udp") -o:depends("proto", "tcpudp") - -o = s:option(Value, "dest", translate("Internal zone")) -o.nocreate = true -o.default = "lan" -o.template = "cbi/firewall_zonelist" - - -o = s:option(Value, "dest_ip", translate("Internal IP address"), - translate("Redirect matched incoming traffic to the specified \ - internal host")) -o.datatype = "ipmask4" - -luci.sys.net.ipv4_hints(function(ip, name) - o:value(ip, "%s (%s)" %{ ip, name }) -end) - - -o = s:option(Value, "dest_port", - translate("Internal port"), - translate("Redirect matched incoming traffic to the given port on \ - the internal host")) -o.placeholder = translate("any") -o.datatype = "portrange" - -o:depends("proto", "tcp") -o:depends("proto", "udp") -o:depends("proto", "tcp udp") -o:depends("proto", "tcpudp") - -o = s:option(Flag, "reflection", translate("Enable NAT Loopback")) -o.rmempty = true -o.default = o.enabled -o.cfgvalue = function(...) - return Flag.cfgvalue(...) or "1" -end - - -s:option(Value, "extra", - translate("Extra arguments"), - translate("Passes additional arguments to iptables. Use with care!")) - - -return m diff --git a/applications/luci-app-firewall/luasrc/model/cbi/firewall/forwards.lua b/applications/luci-app-firewall/luasrc/model/cbi/firewall/forwards.lua deleted file mode 100644 index 5d1ffe091..000000000 --- a/applications/luci-app-firewall/luasrc/model/cbi/firewall/forwards.lua +++ /dev/null @@ -1,133 +0,0 @@ --- Copyright 2008 Steven Barth --- Copyright 2010-2012 Jo-Philipp Wich --- Licensed to the public under the Apache License 2.0. - -local ds = require "luci.dispatcher" -local ft = require "luci.tools.firewall" - -m = Map("firewall", translate("Firewall - Port Forwards"), - translate("Port forwarding allows remote computers on the Internet to \ - connect to a specific computer or service within the \ - private LAN.")) - --- --- Port Forwards --- - -s = m:section(TypedSection, "redirect", translate("Port Forwards")) -s.template = "cbi/tblsection" -s.addremove = true -s.anonymous = true -s.sortable = true -s.extedit = ds.build_url("admin/network/firewall/forwards/%s") -s.template_addremove = "firewall/cbi_addforward" - -function s.create(self, section) - local n = m:formvalue("_newfwd.name") - local p = m:formvalue("_newfwd.proto") - local E = m:formvalue("_newfwd.extzone") - local e = m:formvalue("_newfwd.extport") - local I = m:formvalue("_newfwd.intzone") - local a = m:formvalue("_newfwd.intaddr") - local i = m:formvalue("_newfwd.intport") - - if p == "other" or (p and a) then - created = TypedSection.create(self, section) - - self.map:set(created, "target", "DNAT") - self.map:set(created, "src", E or "wan") - self.map:set(created, "dest", I or "lan") - self.map:set(created, "proto", (p ~= "other") and p or "all") - self.map:set(created, "src_dport", e) - self.map:set(created, "dest_ip", a) - self.map:set(created, "dest_port", i) - self.map:set(created, "name", n) - end - - if p ~= "other" then - created = nil - end -end - -function s.parse(self, ...) - TypedSection.parse(self, ...) - if created then - m.uci:save("firewall") - luci.http.redirect(ds.build_url( - "admin/network/firewall/forwards", created - )) - end -end - -function s.filter(self, sid) - return (self.map:get(sid, "target") ~= "SNAT") -end - -function s.sectiontitle(self, sid) - return (self.map:get(sid, "name") or translate("Unnamed forward")) -end - - -local function forward_proto_txt(self, s) - return "%s-%s" %{ - translate("IPv4"), - ft.fmt_proto(self.map:get(s, "proto"), - self.map:get(s, "icmp_type")) or "TCP+UDP" - } -end - -local function forward_src_txt(self, s) - local z = ft.fmt_zone(self.map:get(s, "src"), translate("any zone")) - local a = ft.fmt_ip(self.map:get(s, "src_ip"), translate("any host")) - local p = ft.fmt_port(self.map:get(s, "src_port")) - local m = ft.fmt_mac(self.map:get(s, "src_mac")) - - if p and m then - return translatef("From %s in %s with source %s and %s", a, z, p, m) - elseif p or m then - return translatef("From %s in %s with source %s", a, z, p or m) - else - return translatef("From %s in %s", a, z) - end -end - -local function forward_via_txt(self, s) - local a = ft.fmt_ip(self.map:get(s, "src_dip"), translate("any router IP")) - local p = ft.fmt_port(self.map:get(s, "src_dport")) - - if p then - return translatef("Via %s at %s", a, p) - else - return translatef("Via %s", a) - end -end - -match = s:option(DummyValue, "match", translate("Match")) -match.rawhtml = true -function match.cfgvalue(self, s) - return "%s
%s
%s
" % { - forward_proto_txt(self, s), - forward_src_txt(self, s), - forward_via_txt(self, s) - } -end - - -dest = s:option(DummyValue, "dest", translate("Forward to")) -dest.rawhtml = true -function dest.cfgvalue(self, s) - local z = ft.fmt_zone(self.map:get(s, "dest"), translate("any zone")) - local a = ft.fmt_ip(self.map:get(s, "dest_ip"), translate("any host")) - local p = ft.fmt_port(self.map:get(s, "dest_port")) or - ft.fmt_port(self.map:get(s, "src_dport")) - - if p then - return translatef("%s, %s in %s", a, p, z) - else - return translatef("%s in %s", a, z) - end -end - -ft.opt_enabled(s, Flag, translate("Enable")) - -return m diff --git a/applications/luci-app-firewall/luasrc/model/cbi/firewall/rule-details.lua b/applications/luci-app-firewall/luasrc/model/cbi/firewall/rule-details.lua deleted file mode 100644 index def01c669..000000000 --- a/applications/luci-app-firewall/luasrc/model/cbi/firewall/rule-details.lua +++ /dev/null @@ -1,365 +0,0 @@ --- Copyright 2008 Steven Barth --- Copyright 2010-2012 Jo-Philipp Wich --- Licensed to the public under the Apache License 2.0. -local dsp = require "luci.dispatcher" -local ft = require "luci.tools.firewall" -local nw = require "luci.model.network" -local m, s, o, v, _ - -arg[1] = arg[1] or "" - -m = Map("firewall", - translate("Firewall - Traffic Rules"), - translate("This page allows you to change advanced properties of the \ - traffic rule entry, such as matched source and destination \ - hosts.")) - -m.redirect = dsp.build_url("admin/network/firewall/rules") - -nw.init(m.uci) - -local rule_type = m.uci:get("firewall", arg[1]) -if rule_type == "redirect" and m:get(arg[1], "target") ~= "SNAT" then - rule_type = nil -end - -if not rule_type then - luci.http.redirect(m.redirect) - return - --- --- SNAT --- -elseif rule_type == "redirect" then - - local name = m:get(arg[1], "name") or m:get(arg[1], "_name") - if not name or #name == 0 then - name = translate("(Unnamed SNAT)") - else - name = "SNAT %s" % name - end - - m.title = "%s - %s" %{ translate("Firewall - Traffic Rules"), name } - - s = m:section(NamedSection, arg[1], "redirect", "") - s.anonymous = true - s.addremove = false - - - ft.opt_enabled(s, Button) - ft.opt_name(s, Value, translate("Name")) - - - o = s:option(Value, "proto", - translate("Protocol"), - translate("You may specify multiple by selecting \"-- custom --\" and \ - then entering protocols separated by space.")) - - o:value("all", "All protocols") - o:value("tcp udp", "TCP+UDP") - o:value("tcp", "TCP") - o:value("udp", "UDP") - o:value("icmp", "ICMP") - - function o.cfgvalue(...) - local v = Value.cfgvalue(...) - if not v or v == "tcpudp" then - return "tcp udp" - end - return v - end - - - o = s:option(Value, "src", translate("Source zone")) - o.nocreate = true - o.default = "wan" - o.template = "cbi/firewall_zonelist" - - - o = s:option(Value, "src_ip", translate("Source IP address")) - o.rmempty = true - o.datatype = "neg(ipmask4)" - o.placeholder = translate("any") - - luci.sys.net.ipv4_hints(function(ip, name) - o:value(ip, "%s (%s)" %{ ip, name }) - end) - - - o = s:option(Value, "src_port", - translate("Source port"), - translate("Match incoming traffic originating from the given source \ - port or port range on the client host.")) - o.rmempty = true - o.datatype = "neg(portrange)" - o.placeholder = translate("any") - - o:depends("proto", "tcp") - o:depends("proto", "udp") - o:depends("proto", "tcp udp") - o:depends("proto", "tcpudp") - - o = s:option(Value, "dest", translate("Destination zone")) - o.nocreate = true - o.default = "lan" - o.template = "cbi/firewall_zonelist" - - - o = s:option(Value, "dest_ip", translate("Destination IP address")) - o.datatype = "neg(ipmask4)" - - luci.sys.net.ipv4_hints(function(ip, name) - o:value(ip, "%s (%s)" %{ ip, name }) - end) - - - o = s:option(Value, "dest_port", - translate("Destination port"), - translate("Match forwarded traffic to the given destination port or \ - port range.")) - - o.rmempty = true - o.placeholder = translate("any") - o.datatype = "neg(portrange)" - - o:depends("proto", "tcp") - o:depends("proto", "udp") - o:depends("proto", "tcp udp") - o:depends("proto", "tcpudp") - - o = s:option(Value, "src_dip", - translate("SNAT IP address"), - translate("Rewrite matched traffic to the given address.")) - o.rmempty = false - o.datatype = "ip4addr" - - for _, v in ipairs(nw:get_interfaces()) do - local a - for _, a in ipairs(v:ipaddrs()) do - o:value(a:host():string(), '%s (%s)' %{ - a:host():string(), v:shortname() - }) - end - end - - - o = s:option(Value, "src_dport", translate("SNAT port"), - translate("Rewrite matched traffic to the given source port. May be \ - left empty to only rewrite the IP address.")) - o.datatype = "portrange" - o.rmempty = true - o.placeholder = translate('Do not rewrite') - - o:depends("proto", "tcp") - o:depends("proto", "udp") - o:depends("proto", "tcp udp") - o:depends("proto", "tcpudp") - - s:option(Value, "extra", - translate("Extra arguments"), - translate("Passes additional arguments to iptables. Use with care!")) - - --- --- Rule --- -else - local name = m:get(arg[1], "name") or m:get(arg[1], "_name") - if not name or #name == 0 then - name = translate("(Unnamed Rule)") - end - - m.title = "%s - %s" %{ translate("Firewall - Traffic Rules"), name } - - - s = m:section(NamedSection, arg[1], "rule", "") - s.anonymous = true - s.addremove = false - - ft.opt_enabled(s, Button) - ft.opt_name(s, Value, translate("Name")) - - - o = s:option(ListValue, "family", translate("Restrict to address family")) - o.rmempty = true - o:value("", translate("IPv4 and IPv6")) - o:value("ipv4", translate("IPv4 only")) - o:value("ipv6", translate("IPv6 only")) - - - o = s:option(Value, "proto", translate("Protocol")) - o:value("all", translate("Any")) - o:value("tcp udp", "TCP+UDP") - o:value("tcp", "TCP") - o:value("udp", "UDP") - o:value("icmp", "ICMP") - - function o.cfgvalue(...) - local v = Value.cfgvalue(...) - if not v or v == "tcpudp" then - return "tcp udp" - end - return v - end - - - o = s:option(DropDown, "icmp_type", translate("Match ICMP type")) - o.multiple = true - o.display = 10 - o.dropdown = 10 - o.custom = true - o.cast = "table" - - o:value("", "any") - o:value("echo-reply") - o:value("destination-unreachable") - o:value("network-unreachable") - o:value("host-unreachable") - o:value("protocol-unreachable") - o:value("port-unreachable") - o:value("fragmentation-needed") - o:value("source-route-failed") - o:value("network-unknown") - o:value("host-unknown") - o:value("network-prohibited") - o:value("host-prohibited") - o:value("TOS-network-unreachable") - o:value("TOS-host-unreachable") - o:value("communication-prohibited") - o:value("host-precedence-violation") - o:value("precedence-cutoff") - o:value("source-quench") - o:value("redirect") - o:value("network-redirect") - o:value("host-redirect") - o:value("TOS-network-redirect") - o:value("TOS-host-redirect") - o:value("echo-request") - o:value("router-advertisement") - o:value("router-solicitation") - o:value("time-exceeded") - o:value("ttl-zero-during-transit") - o:value("ttl-zero-during-reassembly") - o:value("parameter-problem") - o:value("ip-header-bad") - o:value("required-option-missing") - o:value("timestamp-request") - o:value("timestamp-reply") - o:value("address-mask-request") - o:value("address-mask-reply") - - o:depends("proto", "icmp") - - - o = s:option(Value, "src", translate("Source zone")) - o.nocreate = true - o.allowany = true - o.allowlocal = "src" - o.template = "cbi/firewall_zonelist" - - - o = s:option(Value, "src_mac", translate("Source MAC address")) - o.datatype = "list(macaddr)" - o.placeholder = translate("any") - - luci.sys.net.mac_hints(function(mac, name) - o:value(mac, "%s (%s)" %{ mac, name }) - end) - - - o = s:option(Value, "src_ip", translate("Source address")) - o.datatype = "list(neg(ipmask))" - o.placeholder = translate("any") - - luci.sys.net.ipv4_hints(function(ip, name) - o:value(ip, "%s (%s)" %{ ip, name }) - end) - - - o = s:option(Value, "src_port", translate("Source port")) - o.datatype = "list(neg(portrange))" - o.placeholder = translate("any") - - o:depends("proto", "tcp") - o:depends("proto", "udp") - o:depends("proto", "tcp udp") - o:depends("proto", "tcpudp") - - o = s:option(Value, "dest_local", translate("Output zone")) - o.nocreate = true - o.allowany = true - o.template = "cbi/firewall_zonelist" - o.alias = "dest" - o:depends("src", "") - - o = s:option(Value, "dest_remote", translate("Destination zone")) - o.nocreate = true - o.allowany = true - o.allowlocal = true - o.template = "cbi/firewall_zonelist" - o.alias = "dest" - o:depends({["src"] = "", ["!reverse"] = true}) - - - o = s:option(Value, "dest_ip", translate("Destination address")) - o.datatype = "list(neg(ipmask))" - o.placeholder = translate("any") - - luci.sys.net.ipv4_hints(function(ip, name) - o:value(ip, "%s (%s)" %{ ip, name }) - end) - - - o = s:option(Value, "dest_port", translate("Destination port")) - o.datatype = "list(neg(portrange))" - o.placeholder = translate("any") - - o:depends("proto", "tcp") - o:depends("proto", "udp") - o:depends("proto", "tcp udp") - o:depends("proto", "tcpudp") - - o = s:option(ListValue, "target", translate("Action")) - o.default = "ACCEPT" - o:value("DROP", translate("drop")) - o:value("ACCEPT", translate("accept")) - o:value("REJECT", translate("reject")) - o:value("NOTRACK", translate("don't track")) - - - s:option(Value, "extra", - translate("Extra arguments"), - translate("Passes additional arguments to iptables. Use with care!")) -end - -o = s:option(DropDown, "weekdays", translate("Week Days")) -o.multiple = true -o.display = 5 -o:value("Sun", translate("Sunday")) -o:value("Mon", translate("Monday")) -o:value("Tue", translate("Tuesday")) -o:value("Wed", translate("Wednesday")) -o:value("Thu", translate("Thursday")) -o:value("Fri", translate("Friday")) -o:value("Sat", translate("Saturday")) - -o = s:option(DropDown, "monthdays", translate("Month Days")) -o.multiple = true -o.display = 15 -for i = 1,31 do - o:value(translate(i)) -end - -o = s:option(Value, "start_time", translate("Start Time (hh:mm:ss)")) -o.datatype = "timehhmmss" -o = s:option(Value, "stop_time", translate("Stop Time (hh:mm:ss)")) -o.datatype = "timehhmmss" -o = s:option(Value, "start_date", translate("Start Date (yyyy-mm-dd)")) -o.datatype = "dateyyyymmdd" -o = s:option(Value, "stop_date", translate("Stop Date (yyyy-mm-dd)")) -o.datatype = "dateyyyymmdd" - -o = s:option(Flag, "utc_time", translate("Time in UTC")) -o.default = o.disabled - -return m diff --git a/applications/luci-app-firewall/luasrc/model/cbi/firewall/rules.lua b/applications/luci-app-firewall/luasrc/model/cbi/firewall/rules.lua deleted file mode 100644 index f4b6b2a92..000000000 --- a/applications/luci-app-firewall/luasrc/model/cbi/firewall/rules.lua +++ /dev/null @@ -1,273 +0,0 @@ --- Copyright 2008 Steven Barth --- Copyright 2010-2012 Jo-Philipp Wich --- Licensed to the public under the Apache License 2.0. - -local ds = require "luci.dispatcher" -local ft = require "luci.tools.firewall" - -m = Map("firewall", - translate("Firewall - Traffic Rules"), - translate("Traffic rules define policies for packets traveling between \ - different zones, for example to reject traffic between certain hosts \ - or to open WAN ports on the router.")) - --- --- Rules --- - -s = m:section(TypedSection, "rule", translate("Traffic Rules")) -s.addremove = true -s.anonymous = true -s.sortable = true -s.template = "cbi/tblsection" -s.extedit = ds.build_url("admin/network/firewall/rules/%s") -s.defaults.target = "ACCEPT" -s.template_addremove = "firewall/cbi_addrule" - - -function s.create(self, section) - created = TypedSection.create(self, section) -end - -function s.parse(self, ...) - TypedSection.parse(self, ...) - - local i_n = m:formvalue("_newopen.name") - local i_p = m:formvalue("_newopen.proto") - local i_e = m:formvalue("_newopen.extport") - local i_x = m:formvalue("_newopen.submit") - - local f_n = m:formvalue("_newfwd.name") - local f_s = m:formvalue("_newfwd.src") - local f_d = m:formvalue("_newfwd.dest") - local f_x = m:formvalue("_newfwd.submit") - - if i_x then - created = TypedSection.create(self, section) - - self.map:set(created, "target", "ACCEPT") - self.map:set(created, "src", "wan") - self.map:set(created, "proto", (i_p ~= "other") and i_p or "all") - self.map:set(created, "dest_port", i_e) - self.map:set(created, "name", i_n) - - if i_p ~= "other" and i_e and #i_e > 0 then - created = nil - end - - elseif f_x then - created = TypedSection.create(self, section) - - self.map:set(created, "target", "ACCEPT") - self.map:set(created, "src", f_s) - self.map:set(created, "dest", f_d) - self.map:set(created, "name", f_n) - end - - if created then - m.uci:save("firewall") - luci.http.redirect(ds.build_url( - "admin/network/firewall/rules", created - )) - end -end - -function s.sectiontitle(self, sid) - return (self.map:get(sid, "name") or translate("Unnamed rule")) -end - -local function rule_proto_txt(self, s) - local f = self.map:get(s, "family") - local p = ft.fmt_proto(self.map:get(s, "proto"), - self.map:get(s, "icmp_type")) or translate("traffic") - - if f and f:match("4") then - return "%s-%s" %{ translate("IPv4"), p } - elseif f and f:match("6") then - return "%s-%s" %{ translate("IPv6"), p } - else - return "%s %s" %{ translate("Any"), p } - end -end - -local function rule_src_txt(self, s) - local z = ft.fmt_zone(self.map:get(s, "src")) - local p = ft.fmt_port(self.map:get(s, "src_port")) - local m = ft.fmt_mac(self.map:get(s, "src_mac")) - - -- Forward/Input - if z and #z > 0 then - local a = ft.fmt_ip(self.map:get(s, "src_ip"), translate("any host")) - if p and m then - return translatef("From %s in %s with source %s and %s", a, z, p, m) - elseif p or m then - return translatef("From %s in %s with source %s", a, z, p or m) - else - return translatef("From %s in %s", a, z) - end - - -- Output - else - local a = ft.fmt_ip(self.map:get(s, "src_ip"), translate("any router IP")) - if p and m then - return translatef("From %s on this device with source %s and %s", a, p, m) - elseif p or m then - return translatef("From %s on this device with source %s", a, p or m) - else - return translatef("From %s on this device", a) - end - end -end - -local function rule_dest_txt(self, s) - local z = ft.fmt_zone(self.map:get(s, "dest")) - local p = ft.fmt_port(self.map:get(s, "dest_port")) - - -- Forward - if z then - local a = ft.fmt_ip(self.map:get(s, "dest_ip"), translate("any host")) - if p then - return translatef("To %s, %s in %s", a, p, z) - else - return translatef("To %s in %s", a, z) - end - - -- Input - else - local a = ft.fmt_ip(self.map:get(s, "dest_ip"), - translate("any router IP")) - - if p then - return translatef("To %s at %s on this device", a, p) - else - return translatef("To %s on this device", a) - end - end -end - -local function snat_dest_txt(self, s) - local z = ft.fmt_zone(self.map:get(s, "dest"), translate("any zone")) - local a = ft.fmt_ip(self.map:get(s, "dest_ip"), translate("any host")) - local p = ft.fmt_port(self.map:get(s, "dest_port")) or - ft.fmt_port(self.map:get(s, "src_dport")) - - if p then - return translatef("To %s, %s in %s", a, p, z) - else - return translatef("To %s in %s", a, z) - end -end - - -match = s:option(DummyValue, "match", translate("Match")) -match.rawhtml = true -function match.cfgvalue(self, s) - return "%s
%s
%s
" % { - rule_proto_txt(self, s), - rule_src_txt(self, s), - rule_dest_txt(self, s) - } -end - -target = s:option(DummyValue, "target", translate("Action")) -target.rawhtml = true -function target.cfgvalue(self, s) - local t = ft.fmt_target(self.map:get(s, "target"), self.map:get(s, "src"), self.map:get(s, "dest")) - local l = ft.fmt_limit(self.map:get(s, "limit"), - self.map:get(s, "limit_burst")) - - if l then - return translatef("%s and limit to %s", t, l) - else - return "%s" % t - end -end - -ft.opt_enabled(s, Flag, translate("Enable")) - - --- --- SNAT --- - -s = m:section(TypedSection, "redirect", - translate("Source NAT"), - translate("Source NAT is a specific form of masquerading which allows \ - fine grained control over the source IP used for outgoing traffic, \ - for example to map multiple WAN addresses to internal subnets.")) -s.template = "cbi/tblsection" -s.addremove = true -s.anonymous = true -s.sortable = true -s.extedit = ds.build_url("admin/network/firewall/rules/%s") -s.template_addremove = "firewall/cbi_addsnat" - -function s.create(self, section) - created = TypedSection.create(self, section) -end - -function s.parse(self, ...) - TypedSection.parse(self, ...) - - local n = m:formvalue("_newsnat.name") - local s = m:formvalue("_newsnat.src") - local d = m:formvalue("_newsnat.dest") - local a = m:formvalue("_newsnat.dip") - local p = m:formvalue("_newsnat.dport") - local x = m:formvalue("_newsnat.submit") - - if x and a and #a > 0 then - created = TypedSection.create(self, section) - - self.map:set(created, "target", "SNAT") - self.map:set(created, "src", s) - self.map:set(created, "dest", d) - self.map:set(created, "proto", "all") - self.map:set(created, "src_dip", a) - self.map:set(created, "src_dport", p) - self.map:set(created, "name", n) - end - - if created then - m.uci:save("firewall") - luci.http.redirect(ds.build_url( - "admin/network/firewall/rules", created - )) - end -end - -function s.filter(self, sid) - return (self.map:get(sid, "target") == "SNAT") -end - -function s.sectiontitle(self, sid) - return (self.map:get(sid, "name") or translate("Unnamed SNAT")) -end - -match = s:option(DummyValue, "match", translate("Match")) -match.rawhtml = true -function match.cfgvalue(self, s) - return "%s
%s
%s
" % { - rule_proto_txt(self, s), - rule_src_txt(self, s), - snat_dest_txt(self, s) - } -end - -snat = s:option(DummyValue, "via", translate("Action")) -snat.rawhtml = true -function snat.cfgvalue(self, s) - local a = ft.fmt_ip(self.map:get(s, "src_dip")) - local p = ft.fmt_port(self.map:get(s, "src_dport")) - - if a and p then - return translatef("Rewrite to source %s, %s", a, p) - else - return translatef("Rewrite to source %s", a or p) - end -end - -ft.opt_enabled(s, Flag, translate("Enable")) - - -return m diff --git a/applications/luci-app-firewall/luasrc/model/cbi/firewall/zone-details.lua b/applications/luci-app-firewall/luasrc/model/cbi/firewall/zone-details.lua deleted file mode 100644 index e168c3c60..000000000 --- a/applications/luci-app-firewall/luasrc/model/cbi/firewall/zone-details.lua +++ /dev/null @@ -1,229 +0,0 @@ --- Copyright 2008 Steven Barth --- Copyright 2010-2011 Jo-Philipp Wich --- Licensed to the public under the Apache License 2.0. - -local nw = require "luci.model.network" -local fw = require "luci.model.firewall" -local ds = require "luci.dispatcher" -local ut = require "luci.util" - -local m, p, i, v -local s, name, net, family, msrc, mdest, log, lim -local s2, out, inp - - -m = Map("firewall", translate("Firewall - Zone Settings")) -m.redirect = luci.dispatcher.build_url("admin/network/firewall/zones") - -fw.init(m.uci) -nw.init(m.uci) - - -local zone = fw:get_zone(arg[1]) -if not zone then - luci.http.redirect(ds.build_url("admin/network/firewall/zones")) - return -else - m.title = "%s - %s" %{ - translate("Firewall - Zone Settings"), - translatef("Zone %q", zone:name() or "?") - } -end - - -s = m:section(NamedSection, zone.sid, "zone", - translatef("Zone %q", zone:name()), - translatef("This section defines common properties of %q. \ - The input and output options set the default \ - policies for traffic entering and leaving this zone while the \ - forward option describes the policy for forwarded traffic \ - between different networks within the zone. \ - Covered networks specifies which available networks are \ - members of this zone.", zone:name())) - -s.anonymous = true -s.addremove = false - -m.on_commit = function(map) - local zone = fw:get_zone(arg[1]) - if zone then - s.section = zone.sid - s2.section = zone.sid - end -end - - -s:tab("general", translate("General Settings")) -s:tab("advanced", translate("Advanced Settings")) - - -name = s:taboption("general", Value, "name", translate("Name")) -name.optional = false -name.forcewrite = true -name.datatype = "and(uciname,maxlength(11))" - -function name.write(self, section, value) - if zone:name() ~= value then - fw:rename_zone(zone:name(), value) - out.exclude = value - inp.exclude = value - end -end - -p = { - s:taboption("general", ListValue, "input", translate("Input")), - s:taboption("general", ListValue, "output", translate("Output")), - s:taboption("general", ListValue, "forward", translate("Forward")) -} - -for i, v in ipairs(p) do - v:value("REJECT", translate("reject")) - v:value("DROP", translate("drop")) - v:value("ACCEPT", translate("accept")) -end - -s:taboption("general", Flag, "masq", translate("Masquerading")) -s:taboption("general", Flag, "mtu_fix", translate("MSS clamping")) - -net = s:taboption("general", Value, "network", translate("Covered networks")) -net.template = "cbi/network_netlist" -net.widget = "checkbox" -net.cast = "string" - -function net.formvalue(self, section) - return Value.formvalue(self, section) or "-" -end - -function net.cfgvalue(self, section) - return Value.cfgvalue(self, section) or name:cfgvalue(section) -end - -function net.write(self, section, value) - zone:clear_networks() - - local net - for net in ut.imatch(value) do - local n = nw:get_network(net) or nw:add_network(net, { proto = "none" }) - if n then - zone:add_network(n:name()) - end - end -end - - -family = s:taboption("advanced", ListValue, "family", - translate("Restrict to address family")) - -family.rmempty = true -family:value("", translate("IPv4 and IPv6")) -family:value("ipv4", translate("IPv4 only")) -family:value("ipv6", translate("IPv6 only")) - -msrc = s:taboption("advanced", DynamicList, "masq_src", - translate("Restrict Masquerading to given source subnets")) - -msrc.optional = true -msrc.datatype = "list(neg(or(uciname,hostname,ipmask4)))" -msrc.placeholder = "0.0.0.0/0" -msrc:depends("family", "") -msrc:depends("family", "ipv4") - -mdest = s:taboption("advanced", DynamicList, "masq_dest", - translate("Restrict Masquerading to given destination subnets")) - -mdest.optional = true -mdest.datatype = "list(neg(or(uciname,hostname,ipmask4)))" -mdest.placeholder = "0.0.0.0/0" -mdest:depends("family", "") -mdest:depends("family", "ipv4") - -s:taboption("advanced", Flag, "conntrack", - translate("Force connection tracking")) - -log = s:taboption("advanced", Flag, "log", - translate("Enable logging on this zone")) - -log.rmempty = true -log.enabled = "1" - -lim = s:taboption("advanced", Value, "log_limit", - translate("Limit log messages")) - -lim.placeholder = "10/minute" -lim:depends("log", "1") - - -s2 = m:section(NamedSection, zone.sid, "fwd_out", - translate("Inter-Zone Forwarding"), - translatef("The options below control the forwarding policies between \ - this zone (%s) and other zones. Destination zones cover \ - forwarded traffic originating from %q. \ - Source zones match forwarded traffic from other zones \ - targeted at %q. The forwarding rule is \ - unidirectional, e.g. a forward from lan to wan does \ - not imply a permission to forward from wan to lan as well.", - zone:name(), zone:name(), zone:name() - - )) - -out = s2:option(Value, "out", - translate("Allow forward to destination zones:")) - -out.nocreate = true -out.widget = "checkbox" -out.exclude = zone:name() -out.template = "cbi/firewall_zonelist" - -inp = s2:option(Value, "in", - translate("Allow forward from source zones:")) - -inp.nocreate = true -inp.widget = "checkbox" -inp.exclude = zone:name() -inp.template = "cbi/firewall_zonelist" - -function out.cfgvalue(self, section) - local v = { } - local f - for _, f in ipairs(zone:get_forwardings_by("src")) do - v[#v+1] = f:dest() - end - return table.concat(v, " ") -end - -function inp.cfgvalue(self, section) - local v = { } - local f - for _, f in ipairs(zone:get_forwardings_by("dest")) do - v[#v+1] = f:src() - end - return v -end - -function out.formvalue(self, section) - return Value.formvalue(self, section) or "-" -end - -function inp.formvalue(self, section) - return Value.formvalue(self, section) or "-" -end - -function out.write(self, section, value) - zone:del_forwardings_by("src") - - local f - for f in ut.imatch(value) do - zone:add_forwarding_to(f) - end -end - -function inp.write(self, section, value) - zone:del_forwardings_by("dest") - - local f - for f in ut.imatch(value) do - zone:add_forwarding_from(f) - end -end - -return m diff --git a/applications/luci-app-firewall/luasrc/model/cbi/firewall/zones.lua b/applications/luci-app-firewall/luasrc/model/cbi/firewall/zones.lua deleted file mode 100644 index 46402a8fc..000000000 --- a/applications/luci-app-firewall/luasrc/model/cbi/firewall/zones.lua +++ /dev/null @@ -1,104 +0,0 @@ --- Copyright 2008 Steven Barth --- Licensed to the public under the Apache License 2.0. - -local ds = require "luci.dispatcher" -local fw = require "luci.model.firewall" -local fs = require "nixio.fs" - -local m, s, o, p, i, v - -m = Map("firewall", - translate("Firewall - Zone Settings"), - translate("The firewall creates zones over your network interfaces to control network traffic flow.")) - -fw.init(m.uci) - -s = m:section(TypedSection, "defaults", translate("General Settings")) -s.anonymous = true -s.addremove = false - -s:option(Flag, "syn_flood", translate("Enable SYN-flood protection")) - -o = s:option(Flag, "drop_invalid", translate("Drop invalid packets")) - -p = { - s:option(ListValue, "input", translate("Input")), - s:option(ListValue, "output", translate("Output")), - s:option(ListValue, "forward", translate("Forward")) -} - -for i, v in ipairs(p) do - v:value("REJECT", translate("reject")) - v:value("DROP", translate("drop")) - v:value("ACCEPT", translate("accept")) -end - --- Netfilter flow offload support - -local offload = fs.access("/sys/module/xt_FLOWOFFLOAD/refcnt") - -if offload then - s:option(DummyValue, "offload_advice", - translate("Routing/NAT Offloading"), - translate("Experimental feature. Not fully compatible with QoS/SQM.")) - - o = s:option(Flag, "flow_offloading", - translate("Software flow offloading"), - translate("Software based offloading for routing/NAT")) - o.optional = true - - o = s:option(Flag, "flow_offloading_hw", - translate("Hardware flow offloading"), - translate("Requires hardware NAT support. Implemented at least for mt7621")) - o.optional = true - o:depends( "flow_offloading", 1) -end - --- Firewall zones - -s = m:section(TypedSection, "zone", translate("Zones")) -s.template = "cbi/tblsection" -s.anonymous = true -s.addremove = true -s.extedit = ds.build_url("admin", "network", "firewall", "zones", "%s") - -function s.sectiontitle(self, sid) - local z = fw:get_zone(sid) - return z:name() -end - -function s.create(self) - local z = fw:new_zone() - if z then - luci.http.redirect( - ds.build_url("admin", "network", "firewall", "zones", z.sid) - ) - end -end - -function s.remove(self, section) - return fw:del_zone(section) -end - -o = s:option(DummyValue, "_info", translate("Zone ⇒ Forwardings")) -o.template = "cbi/firewall_zoneforwards" -o.cfgvalue = function(self, section) - return self.map:get(section, "name") -end - -p = { - s:option(ListValue, "input", translate("Input")), - s:option(ListValue, "output", translate("Output")), - s:option(ListValue, "forward", translate("Forward")) -} - -for i, v in ipairs(p) do - v:value("REJECT", translate("reject")) - v:value("DROP", translate("drop")) - v:value("ACCEPT", translate("accept")) -end - -s:option(Flag, "masq", translate("Masquerading")) -s:option(Flag, "mtu_fix", translate("MSS clamping")) - -return m -- 2.25.1