luci-app-firewall: rules: sort ICMP types alphabetically
[project/luci.git] / applications / luci-app-firewall / htdocs / luci-static / resources / view / firewall / rules.js
1 'use strict';
2 'require ui';
3 'require rpc';
4 'require uci';
5 'require form';
6 'require tools.firewall as fwtool';
7 'require tools.widgets as widgets';
8
9 function fmt(fmt /*, ...*/) {
10 var repl = [], wrap = false;
11
12 for (var i = 1; i < arguments.length; i++) {
13 if (L.dom.elem(arguments[i])) {
14 switch (arguments[i].nodeType) {
15 case 1:
16 repl.push(arguments[i].outerHTML);
17 wrap = true;
18 break;
19
20 case 3:
21 repl.push(arguments[i].data);
22 break;
23
24 case 11:
25 var span = E('span');
26 span.appendChild(arguments[i]);
27 repl.push(span.innerHTML);
28 wrap = true;
29 break;
30
31 default:
32 repl.push('');
33 }
34 }
35 else {
36 repl.push(arguments[i]);
37 }
38 }
39
40 var rv = fmt.format.apply(fmt, repl);
41 return wrap ? E('span', rv) : rv;
42 }
43
44 function forward_proto_txt(s) {
45 return fmt('%s-%s',
46 fwtool.fmt_family(uci.get('firewall', s, 'family')),
47 fwtool.fmt_proto(uci.get('firewall', s, 'proto'),
48 uci.get('firewall', s, 'icmp_type')) || 'TCP+UDP');
49 }
50
51 function rule_src_txt(s) {
52 var z = fwtool.fmt_zone(uci.get('firewall', s, 'src')),
53 p = fwtool.fmt_port(uci.get('firewall', s, 'src_port')),
54 m = fwtool.fmt_mac(uci.get('firewall', s, 'src_mac'));
55
56 // Forward/Input
57 if (z) {
58 var a = fwtool.fmt_ip(uci.get('firewall', s, 'src_ip'), _('any host'));
59 if (p && m)
60 return fmt(_('From %s in %s with source %s and %s'), a, z, p, m);
61 else if (p || m)
62 return fmt(_('From %s in %s with source %s'), a, z, p || m);
63 else
64 return fmt(_('From %s in %s'), a, z);
65 }
66
67 // Output
68 else {
69 var a = fwtool.fmt_ip(uci.get('firewall', s, 'src_ip'), _('any router IP'));
70 if (p && m)
71 return fmt(_('From %s on <var>this device</var> with source %s and %s'), a, p, m);
72 else if (p || m)
73 return fmt(_('From %s on <var>this device</var> with source %s'), a, p || m);
74 else
75 return fmt(_('From %s on <var>this device</var>'), a);
76 }
77 }
78
79 function rule_dest_txt(s) {
80 var z = fwtool.fmt_zone(uci.get('firewall', s, 'dest')),
81 p = fwtool.fmt_port(uci.get('firewall', s, 'dest_port'));
82
83 // Forward
84 if (z) {
85 var a = fwtool.fmt_ip(uci.get('firewall', s, 'dest_ip'), _('any host'));
86 if (p)
87 return fmt(_('To %s, %s in %s'), a, p, z);
88 else
89 return fmt(_('To %s in %s'), a, z);
90 }
91
92 // Input
93 else {
94 var a = fwtool.fmt_ip(uci.get('firewall', s, 'dest_ip'), _('any router IP'));
95 if (p)
96 return fmt(_('To %s at %s on <var>this device</var>'), a, p);
97 else
98 return fmt(_('To %s on <var>this device</var>'), a);
99 }
100 }
101
102 function rule_target_txt(s) {
103 var t = fwtool.fmt_target(uci.get('firewall', s, 'target'), uci.get('firewall', s, 'src'), uci.get('firewall', s, 'dest')),
104 l = fwtool.fmt_limit(uci.get('firewall', s, 'limit'), uci.get('firewall', s, 'limit_burst'));
105
106 if (l)
107 return fmt(_('<var>%s</var> and limit to %s'), t, l);
108 else
109 return fmt('<var>%s</var>', t);
110 }
111
112 return L.view.extend({
113 callHostHints: rpc.declare({
114 object: 'luci',
115 method: 'host_hints'
116 }),
117
118 load: function() {
119 return this.callHostHints().catch(function(e) {
120 console.debug('load fail', e);
121 });
122 },
123
124 render: function(hosts) {
125 var m, s, o;
126
127 m = new form.Map('firewall', _('Firewall - Traffic Rules'),
128 _('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.'));
129
130 s = m.section(form.GridSection, 'rule', _('Traffic Rules'));
131 s.addremove = true;
132 s.anonymous = true;
133 s.sortable = true;
134
135 s.tab('general', _('General Settings'));
136 s.tab('advanced', _('Advanced Settings'));
137 s.tab('timed', _('Time Restrictions'));
138
139 s.filter = function(section_id) {
140 return (uci.get('firewall', section_id, 'target') != 'SNAT');
141 };
142
143 s.sectiontitle = function(section_id) {
144 return uci.get('firewall', section_id, 'name') || _('Unnamed rule');
145 };
146
147 s.handleAdd = function(ev) {
148 var config_name = this.uciconfig || this.map.config,
149 section_id = uci.add(config_name, this.sectiontype),
150 opt1, opt2;
151
152 for (var i = 0; i < this.children.length; i++)
153 if (this.children[i].option == 'src')
154 opt1 = this.children[i];
155 else if (this.children[i].option == 'dest')
156 opt2 = this.children[i];
157
158 opt1.default = 'wan';
159 opt2.default = 'lan';
160
161 this.addedSection = section_id;
162 this.renderMoreOptionsModal(section_id);
163
164 delete opt1.default;
165 delete opt2.default;
166 };
167
168 o = s.taboption('general', form.Value, 'name', _('Name'));
169 o.placeholder = _('Unnamed rule');
170 o.modalonly = true;
171
172 o = s.option(form.DummyValue, '_match', _('Match'));
173 o.modalonly = false;
174 o.textvalue = function(s) {
175 return E('small', [
176 forward_proto_txt(s), E('br'),
177 rule_src_txt(s), E('br'),
178 rule_dest_txt(s)
179 ]);
180 };
181
182 o = s.option(form.ListValue, '_target', _('Action'));
183 o.modalonly = false;
184 o.textvalue = function(s) {
185 return rule_target_txt(s);
186 };
187
188 o = s.option(form.Flag, 'enabled', _('Enable'));
189 o.modalonly = false;
190 o.default = o.enabled;
191 o.editable = true;
192
193 //ft.opt_enabled(s, Button);
194 //ft.opt_name(s, Value, _('Name'));
195
196
197 o = s.taboption('advanced', form.ListValue, 'family', _('Restrict to address family'));
198 o.modalonly = true;
199 o.rmempty = true;
200 o.value('', _('IPv4 and IPv6'));
201 o.value('ipv4', _('IPv4 only'));
202 o.value('ipv6', _('IPv6 only'));
203
204 o = s.taboption('general', form.Value, 'proto', _('Protocol'));
205 o.modalonly = true;
206 o.default = 'tcp udp';
207 o.value('all', _('Any'));
208 o.value('tcp udp', 'TCP+UDP');
209 o.value('tcp', 'TCP');
210 o.value('udp', 'UDP');
211 o.value('icmp', 'ICMP');
212 o.cfgvalue = function(/* ... */) {
213 var v = this.super('cfgvalue', arguments);
214 return (v == 'tcpudp') ? 'tcp udp' : v;
215 };
216
217 o = s.taboption('advanced', form.MultiValue, 'icmp_type', _('Match ICMP type'));
218 o.modalonly = true;
219 o.multiple = true;
220 o.custom = true;
221 o.cast = 'table';
222 o.placeholder = _('any');
223 o.value('', 'any');
224 o.value('address-mask-reply');
225 o.value('address-mask-request');
226 o.value('communication-prohibited');
227 o.value('destination-unreachable');
228 o.value('echo-reply');
229 o.value('echo-request');
230 o.value('fragmentation-needed');
231 o.value('host-precedence-violation');
232 o.value('host-prohibited');
233 o.value('host-redirect');
234 o.value('host-unknown');
235 o.value('host-unreachable');
236 o.value('ip-header-bad');
237 o.value('neighbour-advertisement');
238 o.value('neighbour-solicitation');
239 o.value('network-prohibited');
240 o.value('network-redirect');
241 o.value('network-unknown');
242 o.value('network-unreachable');
243 o.value('parameter-problem');
244 o.value('port-unreachable');
245 o.value('precedence-cutoff');
246 o.value('protocol-unreachable');
247 o.value('redirect');
248 o.value('required-option-missing');
249 o.value('router-advertisement');
250 o.value('router-solicitation');
251 o.value('source-quench');
252 o.value('source-route-failed');
253 o.value('time-exceeded');
254 o.value('timestamp-reply');
255 o.value('timestamp-request');
256 o.value('TOS-host-redirect');
257 o.value('TOS-host-unreachable');
258 o.value('TOS-network-redirect');
259 o.value('TOS-network-unreachable');
260 o.value('ttl-zero-during-reassembly');
261 o.value('ttl-zero-during-transit');
262 o.depends('proto', 'icmp');
263
264 o = s.taboption('general', widgets.ZoneSelect, 'src', _('Source zone'));
265 o.modalonly = true;
266 o.nocreate = true;
267 o.allowany = true;
268 o.allowlocal = 'src';
269
270 o = s.taboption('advanced', form.Value, 'src_mac', _('Source MAC address'));
271 o.modalonly = true;
272 o.datatype = 'list(macaddr)';
273 o.placeholder = _('any');
274 L.sortedKeys(hosts).forEach(function(mac) {
275 o.value(mac, '%s (%s)'.format(
276 mac,
277 hosts[mac].name || hosts[mac].ipv4 || hosts[mac].ipv6 || '?'
278 ));
279 });
280
281 o = s.taboption('general', form.Value, 'src_ip', _('Source address'));
282 o.modalonly = true;
283 o.datatype = 'list(neg(ipmask))';
284 o.placeholder = _('any');
285 L.sortedKeys(hosts, 'ipv4', 'addr').forEach(function(mac) {
286 o.value(hosts[mac].ipv4, '%s (%s)'.format(
287 hosts[mac].ipv4,
288 hosts[mac].name || mac
289 ));
290 });
291
292 o = s.taboption('general', form.Value, 'src_port', _('Source port'));
293 o.modalonly = true;
294 o.datatype = 'list(neg(portrange))';
295 o.placeholder = _('any');
296 o.depends('proto', 'tcp');
297 o.depends('proto', 'udp');
298 o.depends('proto', 'tcp udp');
299 o.depends('proto', 'tcpudp');
300
301 o = s.taboption('general', widgets.ZoneSelect, 'dest', _('Destination zone'));
302 o.modalonly = true;
303 o.nocreate = true;
304 o.allowany = true;
305 o.allowlocal = true;
306
307 o = s.taboption('general', form.Value, 'dest_ip', _('Destination address'));
308 o.modalonly = true;
309 o.datatype = 'list(neg(ipmask))';
310 o.placeholder = _('any');
311 L.sortedKeys(hosts, 'ipv4', 'addr').forEach(function(mac) {
312 o.value(hosts[mac].ipv4, '%s (%s)'.format(
313 hosts[mac].ipv4,
314 hosts[mac].name || mac
315 ));
316 });
317
318 o = s.taboption('general', form.Value, 'dest_port', _('Destination port'));
319 o.modalonly = true;
320 o.datatype = 'list(neg(portrange))';
321 o.placeholder = _('any');
322 o.depends('proto', 'tcp');
323 o.depends('proto', 'udp');
324 o.depends('proto', 'tcp udp');
325 o.depends('proto', 'tcpudp');
326
327 o = s.taboption('general', form.ListValue, 'target', _('Action'));
328 o.modalonly = true;
329 o.default = 'ACCEPT';
330 o.value('DROP', _('drop'));
331 o.value('ACCEPT', _('accept'));
332 o.value('REJECT', _('reject'));
333 o.value('NOTRACK', _("don't track"));
334
335 o = s.taboption('advanced', form.Value, 'extra', _('Extra arguments'),
336 _('Passes additional arguments to iptables. Use with care!'));
337 o.modalonly = true;
338
339 o = s.taboption('timed', form.MultiValue, 'weekdays', _('Week Days'));
340 o.modalonly = true;
341 o.multiple = true;
342 o.display = 5;
343 o.placeholder = _('Any day');
344 o.value('Sun', _('Sunday'));
345 o.value('Mon', _('Monday'));
346 o.value('Tue', _('Tuesday'));
347 o.value('Wed', _('Wednesday'));
348 o.value('Thu', _('Thursday'));
349 o.value('Fri', _('Friday'));
350 o.value('Sat', _('Saturday'));
351
352 o = s.taboption('timed', form.MultiValue, 'monthdays', _('Month Days'));
353 o.modalonly = true;
354 o.multiple = true;
355 o.display_size = 15;
356 o.placeholder = _('Any day');
357 for (var i = 1; i <= 31; i++)
358 o.value(i);
359
360 o = s.taboption('timed', form.Value, 'start_time', _('Start Time (hh.mm.ss)'));
361 o.modalonly = true;
362 o.datatype = 'timehhmmss';
363
364 o = s.taboption('timed', form.Value, 'stop_time', _('Stop Time (hh.mm.ss)'));
365 o.modalonly = true;
366 o.datatype = 'timehhmmss';
367
368 o = s.taboption('timed', form.Value, 'start_date', _('Start Date (yyyy-mm-dd)'));
369 o.modalonly = true;
370 o.datatype = 'dateyyyymmdd';
371
372 o = s.taboption('timed', form.Value, 'stop_date', _('Stop Date (yyyy-mm-dd)'));
373 o.modalonly = true;
374 o.datatype = 'dateyyyymmdd';
375
376 o = s.taboption('timed', form.Flag, 'utc_time', _('Time in UTC'));
377 o.modalonly = true;
378 o.default = o.disabled;
379
380 return m.render();
381 }
382 });