luci-app-firewall: drop usage of getOffloadSupport()
[oweals/luci.git] / applications / luci-app-firewall / htdocs / luci-static / resources / view / firewall / zones.js
1 'use strict';
2 'require rpc';
3 'require uci';
4 'require form';
5 'require network';
6 'require firewall';
7 'require tools.widgets as widgets';
8
9 return L.view.extend({
10         callConntrackHelpers: rpc.declare({
11                 object: 'luci',
12                 method: 'conntrack_helpers',
13                 expect: { helpers: [] }
14         }),
15
16         load: function() {
17                 return Promise.all([
18                         this.callConntrackHelpers()
19                 ]);
20         },
21
22         render: function(data) {
23                 var ctHelpers = data[0],
24                     m, s, o, inp, out;
25
26                 m = new form.Map('firewall', _('Firewall - Zone Settings'),
27                         _('The firewall creates zones over your network interfaces to control network traffic flow.'));
28
29                 s = m.section(form.TypedSection, 'defaults', _('General Settings'));
30                 s.anonymous = true;
31                 s.addremove = false;
32
33                 o = s.option(form.Flag, 'syn_flood', _('Enable SYN-flood protection'));
34                 o = s.option(form.Flag, 'drop_invalid', _('Drop invalid packets'));
35
36                 var p = [
37                         s.option(form.ListValue, 'input', _('Input')),
38                         s.option(form.ListValue, 'output', _('Output')),
39                         s.option(form.ListValue, 'forward', _('Forward'))
40                 ];
41
42                 for (var i = 0; i < p.length; i++) {
43                         p[i].value('REJECT', _('reject'));
44                         p[i].value('DROP', _('drop'));
45                         p[i].value('ACCEPT', _('accept'));
46                 }
47
48                 /* Netfilter flow offload support */
49
50                 if (L.hasSystemFeature('offloading')) {
51                         s = m.section(form.TypedSection, 'defaults', _('Routing/NAT Offloading'),
52                                 _('Experimental feature. Not fully compatible with QoS/SQM.'));
53
54                         s.anonymous = true;
55                         s.addremove = false;
56
57                         o = s.option(form.Flag, 'flow_offloading',
58                                 _('Software flow offloading'),
59                                 _('Software based offloading for routing/NAT'));
60                         o.optional = true;
61
62                         o = s.option(form.Flag, 'flow_offloading_hw',
63                                 _('Hardware flow offloading'),
64                                 _('Requires hardware NAT support. Implemented at least for mt7621'));
65                         o.optional = true;
66                         o.depends('flow_offloading', '1');
67                 }
68
69
70                 s = m.section(form.GridSection, 'zone', _('Zones'));
71                 s.addremove = true;
72                 s.anonymous = true;
73                 s.sortable  = true;
74
75                 s.tab('general', _('General Settings'));
76                 s.tab('advanced', _('Advanced Settings'));
77                 s.tab('conntrack', _('Conntrack Settings'));
78                 s.tab('extra', _('Extra iptables arguments'));
79
80                 o = s.taboption('general', form.DummyValue, '_generalinfo');
81                 o.rawhtml = true;
82                 o.modalonly = true;
83                 o.cfgvalue = function(section_id) {
84                         var name = uci.get('firewall', section_id, 'name');
85
86                         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.')
87                                 .replace(/%s/g, name).replace(/%q/g, '"' + name + '"');
88                 };
89
90                 o = s.taboption('general', form.Value, 'name', _('Name'));
91                 o.placeholder = _('Unnamed zone');
92                 o.modalonly = true;
93                 o.datatype = 'and(uciname,maxlength(11))';
94                 o.write = function(section_id, formvalue) {
95                         var cfgvalue = this.cfgvalue(section_id);
96
97                         if (cfgvalue != formvalue)
98                                 return firewall.renameZone(cfgvalue, formvalue);
99                 };
100
101                 o = s.option(widgets.ZoneForwards, '_info', _('Zone ⇒ Forwardings'));
102                 o.editable = true;
103                 o.modalonly = false;
104                 o.cfgvalue = function(section_id) {
105                         return uci.get('firewall', section_id, 'name');
106                 };
107
108                 var p = [
109                         s.taboption('general', form.ListValue, 'input', _('Input')),
110                         s.taboption('general', form.ListValue, 'output', _('Output')),
111                         s.taboption('general', form.ListValue, 'forward', _('Forward'))
112                 ];
113
114                 for (var i = 0; i < p.length; i++) {
115                         p[i].value('REJECT', _('reject'));
116                         p[i].value('DROP', _('drop'));
117                         p[i].value('ACCEPT', _('accept'));
118                         p[i].editable = true;
119                 }
120
121                 o = s.taboption('general', form.Flag, 'masq', _('Masquerading'));
122                 o.editable = true;
123
124                 o = s.taboption('general', form.Flag, 'mtu_fix', _('MSS clamping'));
125                 o.modalonly = true;
126
127                 o = s.taboption('general', widgets.NetworkSelect, 'network', _('Covered networks'));
128                 o.modalonly = true;
129                 o.multiple = true;
130                 o.write = function(section_id, formvalue) {
131                         var name = uci.get('firewall', section_id, 'name'),
132                             cfgvalue = this.cfgvalue(section_id);
133
134                         if (typeof(cfgvalue) == 'string' && Array.isArray(formvalue) && (cfgvalue == formvalue.join(' ')))
135                                 return;
136
137                         var tasks = [ firewall.getZone(name) ];
138
139                         if (Array.isArray(formvalue))
140                                 for (var i = 0; i < formvalue.length; i++) {
141                                         var netname = formvalue[i];
142                                         tasks.push(network.getNetwork(netname).then(function(net) {
143                                                 return net || network.addNetwork(netname, { 'proto': 'none' });
144                                         }));
145                                 }
146
147                         return Promise.all(tasks).then(function(zone_networks) {
148                                 if (zone_networks[0])
149                                         for (var i = 1; i < zone_networks.length; i++)
150                                                 zone_networks[0].addNetwork(zone_networks[i].getName());
151                         });
152                 };
153                 o.remove = function(section_id) {
154                         return uci.set('firewall', section_id, 'network', ' ');
155                 };
156
157                 o = s.taboption('advanced', form.DummyValue, '_advancedinfo');
158                 o.rawhtml = true;
159                 o.modalonly = true;
160                 o.cfgvalue = function(section_id) {
161                         var name = uci.get('firewall', section_id, 'name');
162
163                         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.')
164                                 .format(name);
165                 };
166
167                 o = s.taboption('advanced', widgets.DeviceSelect, 'device', _('Covered devices'), _('Use this option to classify zone traffic by raw, non-<em>uci</em> managed network devices.'));
168                 o.modalonly = true;
169                 o.multiple = true;
170
171                 o = s.taboption('advanced', form.DynamicList, 'subnet', _('Covered subnets'), _('Use this option to classify zone traffic by source or destination subnet instead of networks or devices.'));
172                 o.datatype = 'neg(cidr)';
173                 o.modalonly = true;
174                 o.multiple = true;
175
176                 o = s.taboption('advanced', form.ListValue, 'family', _('Restrict to address family'));
177                 o.value('', _('IPv4 and IPv6'));
178                 o.value('ipv4', _('IPv4 only'));
179                 o.value('ipv6', _('IPv6 only'));
180                 o.modalonly = true;
181
182                 o = s.taboption('advanced', form.DynamicList, 'masq_src', _('Restrict Masquerading to given source subnets'));
183                 o.depends('family', '');
184                 o.depends('family', 'ipv4');
185                 o.datatype = 'list(neg(or(uciname,hostname,ipmask4)))';
186                 o.placeholder = '0.0.0.0/0';
187                 o.modalonly = true;
188
189                 o = s.taboption('advanced', form.DynamicList, 'masq_dest', _('Restrict Masquerading to given destination subnets'));
190                 o.depends('family', '');
191                 o.depends('family', 'ipv4');
192                 o.datatype = 'list(neg(or(uciname,hostname,ipmask4)))';
193                 o.placeholder = '0.0.0.0/0';
194                 o.modalonly = true;
195
196                 o = s.taboption('conntrack', form.Flag, 'conntrack', _('Force connection tracking'), _('Prevent the installation of <em>NOTRACK</em> rules which would bypass connection tracking.'));
197                 o.modalonly = true;
198
199                 o = s.taboption('conntrack', form.Flag, 'masq_allow_invalid', _('Allow "invalid" traffic'), _('Do not install extra rules to reject forwarded traffic with conntrack state <em>invalid</em>. This may be required for complex asymmetric route setups.'));
200                 o.modalonly = true;
201
202                 o = s.taboption('conntrack', form.Flag, 'auto_helper', _('Automatic helper assignment'), _('Automatically assign conntrack helpers based on traffic protocol and port'));
203                 o.default = o.enabled;
204                 o.modalonly = true;
205
206                 o = s.taboption('conntrack', form.MultiValue, 'helper', _('Conntrack helpers'), _('Explicitly choses allowed connection tracking helpers for zone traffic'));
207                 o.depends('auto_helper', '0');
208                 o.modalonly = true;
209                 for (var i = 0; i < ctHelpers.length; i++)
210                         o.value(ctHelpers[i].name, '<span class="hide-close">%s (%s)</span><span class="hide-open">%s</span>'.format(ctHelpers[i].description, ctHelpers[i].name.toUpperCase(), ctHelpers[i].name.toUpperCase()));
211
212                 o = s.taboption('advanced', form.Flag, 'log', _('Enable logging on this zone'));
213                 o.modalonly = true;
214
215                 o = s.taboption('advanced', form.Value, 'log_limit', _('Limit log messages'));
216                 o.depends('log', '1');
217                 o.placeholder = '10/minute';
218                 o.modalonly = true;
219
220                 o = s.taboption('extra', form.DummyValue, '_extrainfo');
221                 o.rawhtml = true;
222                 o.modalonly = true;
223                 o.cfgvalue = function(section_id) {
224                         return _('Passing raw iptables arguments to source and destination traffic classification rules allows to match packets based on other criteria than interfaces or subnets. These options should be used with extreme care as invalid values could render the firewall ruleset broken, completely exposing all services.');
225                 };
226
227                 o = s.taboption('extra', form.Value, 'extra_src', _('Extra source arguments'), _('Additional raw <em>iptables</em> arguments to classify zone source traffic, e.g. <code>-p tcp --sport 443</code> to only match inbound HTTPS traffic.'));
228                 o.modalonly = true;
229                 o.cfgvalue = function(section_id) {
230                         return uci.get('firewall', section_id, 'extra_src') || uci.get('firewall', section_id, 'extra');
231                 };
232                 o.write = function(section_id, value) {
233                         uci.unset('firewall', section_id, 'extra');
234                         uci.set('firewall', section_id, 'extra_src', value);
235                 };
236
237                 o = s.taboption('extra', form.Value, 'extra_dest', _('Extra destination arguments'), _('Additional raw <em>iptables</em> arguments to classify zone destination traffic, e.g. <code>-p tcp --dport 443</code> to only match outbound HTTPS traffic.'));
238                 o.modalonly = true;
239                 o.cfgvalue = function(section_id) {
240                         return uci.get('firewall', section_id, 'extra_dest') || uci.get('firewall', section_id, 'extra_src') || uci.get('firewall', section_id, 'extra');
241                 };
242                 o.write = function(section_id, value) {
243                         uci.unset('firewall', section_id, 'extra');
244                         uci.set('firewall', section_id, 'extra_dest', value);
245                 };
246
247                 o = s.taboption('general', form.DummyValue, '_forwardinfo');
248                 o.rawhtml = true;
249                 o.modalonly = true;
250                 o.cfgvalue = function(section_id) {
251                         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.')
252                                 .format(uci.get('firewall', section_id, 'name'));
253                 };
254
255                 out = o = s.taboption('general', widgets.ZoneSelect, 'out', _('Allow forward to <em>destination zones</em>:'));
256                 o.nocreate = true;
257                 o.multiple = true;
258                 o.modalonly = true;
259                 o.filter = function(section_id, value) {
260                         return (uci.get('firewall', section_id, 'name') != value);
261                 };
262                 o.cfgvalue = function(section_id) {
263                         var out = (this.option == 'out'),
264                             zone = this.lookupZone(uci.get('firewall', section_id, 'name')),
265                             fwds = zone.getForwardingsBy(out ? 'src' : 'dest'),
266                             value = [];
267
268                         for (var i = 0; i < fwds.length; i++)
269                                 value.push(out ? fwds[i].getDestination() : fwds[i].getSource());
270
271                         return value;
272                 };
273                 o.write = o.remove = function(section_id, formvalue) {
274                         var out = (this.option == 'out'),
275                             zone = this.lookupZone(uci.get('firewall', section_id, 'name')),
276                             fwds = zone.getForwardingsBy(out ? 'src' : 'dest');
277
278                         if (formvalue == null)
279                                 formvalue = [];
280
281                         if (Array.isArray(formvalue)) {
282                                 for (var i = 0; i < fwds.length; i++) {
283                                         var cmp = out ? fwds[i].getDestination() : fwds[i].getSource();
284                                         if (!formvalue.filter(function(d) { return d == cmp }).length)
285                                                 zone.deleteForwarding(fwds[i]);
286                                 }
287
288                                 for (var i = 0; i < formvalue.length; i++)
289                                         if (out)
290                                                 zone.addForwardingTo(formvalue[i]);
291                                         else
292                                                 zone.addForwardingFrom(formvalue[i]);
293                         }
294                 };
295
296                 inp = o = s.taboption('general', widgets.ZoneSelect, 'in', _('Allow forward from <em>source zones</em>:'));
297                 o.nocreate = true;
298                 o.multiple = true;
299                 o.modalonly = true;
300                 o.write = o.remove = out.write;
301                 o.filter = out.filter;
302                 o.cfgvalue = out.cfgvalue;
303
304                 return m.render();
305         }
306 });