Merge pull request #2917 from castillofrancodamian/banip
[oweals/luci.git] / applications / luci-app-firewall / htdocs / luci-static / resources / view / firewall / forwards.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 forward_src_txt(s) {
52         var z = fwtool.fmt_zone(uci.get('firewall', s, 'src'), _('any zone')),
53             a = fwtool.fmt_ip(uci.get('firewall', s, 'src_ip'), _('any host')),
54             p = fwtool.fmt_port(uci.get('firewall', s, 'src_port')),
55             m = fwtool.fmt_mac(uci.get('firewall', s, 'src_mac'));
56
57         if (p && m)
58                 return fmt(_('From %s in %s with source %s and %s'), a, z, p, m);
59         else if (p || m)
60                 return fmt(_('From %s in %s with source %s'), a, z, p || m);
61         else
62                 return fmt(_('From %s in %s'), a, z);
63 }
64
65 function forward_via_txt(s) {
66         var a = fwtool.fmt_ip(uci.get('firewall', s, 'src_dip'), _('any router IP')),
67             p = fwtool.fmt_port(uci.get('firewall', s, 'src_dport'));
68
69         if (p)
70                 return fmt(_('Via %s at %s'), a, p);
71         else
72                 return fmt(_('Via %s'), a);
73 }
74
75 return L.view.extend({
76         callHostHints: rpc.declare({
77                 object: 'luci',
78                 method: 'host_hints'
79         }),
80
81         load: function() {
82                 return Promise.all([
83                         this.callHostHints()
84                 ]);
85         },
86
87         render: function(data) {
88                 var hosts = data[0],
89                     m, s, o;
90
91                 m = new form.Map('firewall', _('Firewall - Port Forwards'),
92                         _('Port forwarding allows remote computers on the Internet to connect to a specific computer or service within the private LAN.'));
93
94                 s = m.section(form.GridSection, 'redirect', _('Port Forwards'));
95                 s.addremove = true;
96                 s.anonymous = true;
97                 s.sortable  = true;
98
99                 s.tab('general', _('General Settings'));
100                 s.tab('advanced', _('Advanced Settings'));
101
102                 s.filter = function(section_id) {
103                         return (uci.get('firewall', section_id, 'target') != 'SNAT');
104                 };
105
106                 s.sectiontitle = function(section_id) {
107                         return uci.get('firewall', section_id, 'name') || _('Unnamed forward');
108                 };
109
110                 s.handleAdd = function(ev) {
111                         var config_name = this.uciconfig || this.map.config,
112                             section_id = uci.add(config_name, this.sectiontype);
113
114                         uci.set(config_name, section_id, 'target', 'DNAT');
115
116                         this.addedSection = section_id;
117                         this.renderMoreOptionsModal(section_id);
118                 };
119
120                 o = s.taboption('general', form.Value, 'name', _('Name'));
121                 o.placeholder = _('Unnamed forward');
122                 o.modalonly = true;
123
124                 o = s.option(form.DummyValue, '_match', _('Match'));
125                 o.modalonly = false;
126                 o.textvalue = function(s) {
127                         return E('small', [
128                                 forward_proto_txt(s), E('br'),
129                                 forward_src_txt(s), E('br'),
130                                 forward_via_txt(s)
131                         ]);
132                 };
133
134                 o = s.option(form.ListValue, '_dest', _('Forward to'));
135                 o.modalonly = false;
136                 o.textvalue = function(s) {
137                         var z = fwtool.fmt_zone(uci.get('firewall', s, 'dest'), _('any zone')),
138                             a = fwtool.fmt_ip(uci.get('firewall', s, 'dest_ip'), _('any host')),
139                             p = fwtool.fmt_port(uci.get('firewall', s, 'dest_port')) ||
140                                 fwtool.fmt_port(uci.get('firewall', s, 'src_dport'));
141
142                         if (p)
143                                 return fmt(_('%s, %s in %s'), a, p, z);
144                         else
145                                 return fmt(_('%s in %s'), a, z);
146                 };
147
148                 o = s.option(form.Flag, 'enabled', _('Enable'));
149                 o.modalonly = false;
150                 o.default = o.enabled;
151                 o.editable = true;
152
153                 o = s.taboption('general', form.Value, 'proto', _('Protocol'));
154                 o.modalonly = true;
155                 o.default = 'tcp udp';
156                 o.value('tcp udp', 'TCP+UDP');
157                 o.value('tcp', 'TCP');
158                 o.value('udp', 'UDP');
159                 o.value('icmp', 'ICMP');
160
161                 o.cfgvalue = function(/* ... */) {
162                         var v = this.super('cfgvalue', arguments);
163                         return (v == 'tcpudp') ? 'tcp udp' : v;
164                 };
165
166                 o = s.taboption('general', widgets.ZoneSelect, 'src', _('Source zone'));
167                 o.modalonly = true;
168                 o.rmempty = false;
169                 o.nocreate = true;
170                 o.default = 'wan';
171
172                 o = s.taboption('advanced', form.Value, 'src_mac', _('Source MAC address'),
173                         _('Only match incoming traffic from these MACs.'));
174                 o.modalonly = true;
175                 o.rmempty = true;
176                 o.datatype = 'neg(macaddr)';
177                 o.placeholder = E('em', _('any'));
178                 L.sortedKeys(hosts).forEach(function(mac) {
179                         o.value(mac, '%s (%s)'.format(
180                                 mac,
181                                 hosts[mac].name || hosts[mac].ipv4 || hosts[mac].ipv6 || '?'
182                         ));
183                 });
184
185                 o = s.taboption('advanced', form.Value, 'src_ip', _('Source IP address'),
186                         _('Only match incoming traffic from this IP or range.'));
187                 o.modalonly = true;
188                 o.rmempty = true;
189                 o.datatype = 'neg(ipmask4)';
190                 o.placeholder = E('em', _('any'));
191                 L.sortedKeys(hosts, 'ipv4', 'addr').forEach(function(mac) {
192                         o.value(hosts[mac].ipv4, '%s (%s)'.format(
193                                 hosts[mac].ipv4,
194                                 hosts[mac].name || mac
195                         ));
196                 });
197
198                 o = s.taboption('advanced', form.Value, 'src_port', _('Source port'),
199                         _('Only match incoming traffic originating from the given source port or port range on the client host'));
200                 o.modalonly = true;
201                 o.rmempty = true;
202                 o.datatype = 'neg(portrange)';
203                 o.placeholder = _('any');
204                 o.depends('proto', 'tcp');
205                 o.depends('proto', 'udp');
206                 o.depends('proto', 'tcp udp');
207                 o.depends('proto', 'tcpudp');
208
209                 o = s.taboption('advanced', form.Value, 'src_dip', _('External IP address'),
210                         _('Only match incoming traffic directed at the given IP address.'));
211                 o.modalonly = true;
212                 o.rmempty = true;
213                 o.datatype = 'neg(ipmask4)';
214                 o.placeholder = E('em', _('any'));
215                 L.sortedKeys(hosts, 'ipv4', 'addr').forEach(function(mac) {
216                         o.value(hosts[mac].ipv4, '%s (%s)'.format(
217                                 hosts[mac].ipv4,
218                                 hosts[mac].name || mac
219                         ));
220                 });
221
222                 o = s.taboption('general', form.Value, 'src_dport', _('External port'),
223                         _('Match incoming traffic directed at the given destination port or port range on this host'));
224                 o.modalonly = true;
225                 o.rmempty = false;
226                 o.datatype = 'neg(portrange)';
227                 o.depends('proto', 'tcp');
228                 o.depends('proto', 'udp');
229                 o.depends('proto', 'tcp udp');
230                 o.depends('proto', 'tcpudp');
231
232                 o = s.taboption('general', widgets.ZoneSelect, 'dest', _('Internal zone'));
233                 o.modalonly = true;
234                 o.rmempty = true;
235                 o.nocreate = true;
236                 o.default = 'lan';
237
238                 o = s.taboption('general', form.Value, 'dest_ip', _('Internal IP address'),
239                         _('Redirect matched incoming traffic to the specified internal host'));
240                 o.modalonly = true;
241                 o.rmempty = true;
242                 o.datatype = 'ipmask4';
243                 L.sortedKeys(hosts, 'ipv4', 'addr').forEach(function(mac) {
244                         o.value(hosts[mac].ipv4, '%s (%s)'.format(
245                                 hosts[mac].ipv4,
246                                 hosts[mac].name || mac
247                         ));
248                 });
249
250                 o = s.taboption('general', form.Value, 'dest_port', _('Internal port'),
251                         _('Redirect matched incoming traffic to the given port on the internal host'));
252                 o.modalonly = true;
253                 o.rmempty = true;
254                 o.placeholder = _('any');
255                 o.datatype = 'portrange';
256                 o.depends('proto', 'tcp');
257                 o.depends('proto', 'udp');
258                 o.depends('proto', 'tcp udp');
259                 o.depends('proto', 'tcpudp');
260
261                 o = s.taboption('advanced', form.Flag, 'reflection', _('Enable NAT Loopback'));
262                 o.modalonly = true;
263                 o.rmempty = true;
264                 o.default = o.enabled;
265
266                 o = s.taboption('advanced', form.Value, 'extra', _('Extra arguments'),
267                         _('Passes additional arguments to iptables. Use with care!'));
268                 o.modalonly = true;
269                 o.rmempty = true;
270
271                 return m.render();
272         }
273 });