diff options
11 files changed, 1262 insertions, 1272 deletions
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('<span>' + + _('<var>%d</var> pkts. per <var>%s</var>, burst <var>%d</var> pkts.').format(l, u, b) + + '</span>'); + else + return E('<span>' + + _('<var>%d</var> pkts. per <var>%s</var>').format(l, u) + + '</span>'); + } + }, + + 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 <var>this device</var> with source %s and %s'), a, p, m); + else if (p || m) + return fmt(_('From %s on <var>this device</var> with source %s'), a, p || m); + else + return fmt(_('From %s on <var>this device</var>'), 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 <var>this device</var>'), a, p); + else + return fmt(_('To %s on <var>this device</var>'), 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(_('<var>%s</var> and limit to %s'), t, l); + else + return fmt('<var>%s</var>', 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 <em>input</em> and <em>output</em> options set the default policies for traffic entering and leaving this zone while the <em>forward</em> option describes the policy for forwarded traffic between different networks within the zone. <em>Covered networks</em> 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. <em>Destination zones</em> cover forwarded traffic <strong>originating from %q</strong>. <em>Source zones</em> match forwarded traffic from other zones <strong>targeted at %q</strong>. The forwarding rule is <em>unidirectional</em>, e.g. a forward from lan to wan does <em>not</em> 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. <em>Destination zones</em> cover forwarded traffic <strong>originating from %q</strong>. <em>Source zones</em> match forwarded traffic from other zones <strong>targeted at %q</strong>. The forwarding rule is <em>unidirectional</em>, e.g. a forward from lan to wan does <em>not</em> 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 <em>destination zones</em>:')); + 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 <em>source zones</em>:')); + 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 <jow@openwrt.org> --- 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 <steven@midlink.org> --- Copyright 2010-2012 Jo-Philipp Wich <jow@openwrt.org> --- 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 "<small>%s<br />%s<br />%s</small>" % { - 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 <steven@midlink.org> --- Copyright 2010-2012 Jo-Philipp Wich <jow@openwrt.org> --- 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 <steven@midlink.org> --- Copyright 2010-2012 Jo-Philipp Wich <jow@openwrt.org> --- 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 <var>this device</var> with source %s and %s", a, p, m) - elseif p or m then - return translatef("From %s on <var>this device</var> with source %s", a, p or m) - else - return translatef("From %s on <var>this device</var>", 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 <var>this device</var>", a, p) - else - return translatef("To %s on <var>this device</var>", 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 "<small>%s<br />%s<br />%s</small>" % { - 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("<var>%s</var> and limit to %s", t, l) - else - return "<var>%s</var>" % 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 "<small>%s<br />%s<br />%s</small>" % { - 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 <steven@midlink.org> --- Copyright 2010-2011 Jo-Philipp Wich <jow@openwrt.org> --- 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 <em>input</em> and <em>output</em> options set the default \ - policies for traffic entering and leaving this zone while the \ - <em>forward</em> option describes the policy for forwarded traffic \ - between different networks within the zone. \ - <em>Covered networks</em> 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. <em>Destination zones</em> cover \ - forwarded traffic <strong>originating from %q</strong>. \ - <em>Source zones</em> match forwarded traffic from other zones \ - <strong>targeted at %q</strong>. The forwarding rule is \ - <em>unidirectional</em>, e.g. a forward from lan to wan does \ - <em>not</em> 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 <em>destination zones</em>:")) - -out.nocreate = true -out.widget = "checkbox" -out.exclude = zone:name() -out.template = "cbi/firewall_zonelist" - -inp = s2:option(Value, "in", - translate("Allow forward from <em>source zones</em>:")) - -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 <steven@midlink.org> --- 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 |