7 'require tools.widgets as widgets';
10 callConntrackHelpers: rpc.declare({
12 method: 'getConntrackHelpers',
13 expect: { result: [] }
18 this.callConntrackHelpers(),
19 firewall.getDefaults()
23 render: function(data) {
24 var ctHelpers = data[0],
28 m = new form.Map('firewall', _('Firewall - Zone Settings'),
29 _('The firewall creates zones over your network interfaces to control network traffic flow.'));
31 s = m.section(form.TypedSection, 'defaults', _('General Settings'));
35 o = s.option(form.Flag, 'syn_flood', _('Enable SYN-flood protection'));
36 o = s.option(form.Flag, 'drop_invalid', _('Drop invalid packets'));
39 s.option(form.ListValue, 'input', _('Input')),
40 s.option(form.ListValue, 'output', _('Output')),
41 s.option(form.ListValue, 'forward', _('Forward'))
44 for (var i = 0; i < p.length; i++) {
45 p[i].value('REJECT', _('reject'));
46 p[i].value('DROP', _('drop'));
47 p[i].value('ACCEPT', _('accept'));
50 /* Netfilter flow offload support */
52 if (L.hasSystemFeature('offloading')) {
53 s = m.section(form.TypedSection, 'defaults', _('Routing/NAT Offloading'),
54 _('Experimental feature. Not fully compatible with QoS/SQM.'));
59 o = s.option(form.Flag, 'flow_offloading',
60 _('Software flow offloading'),
61 _('Software based offloading for routing/NAT'));
64 o = s.option(form.Flag, 'flow_offloading_hw',
65 _('Hardware flow offloading'),
66 _('Requires hardware NAT support. Implemented at least for mt7621'));
68 o.depends('flow_offloading', '1');
72 s = m.section(form.GridSection, 'zone', _('Zones'));
77 s.tab('general', _('General Settings'));
78 s.tab('advanced', _('Advanced Settings'));
79 s.tab('conntrack', _('Conntrack Settings'));
80 s.tab('extra', _('Extra iptables arguments'));
82 o = s.taboption('general', form.DummyValue, '_generalinfo');
85 o.cfgvalue = function(section_id) {
86 var name = uci.get('firewall', section_id, 'name');
88 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.')
89 .replace(/%s/g, name).replace(/%q/g, '"' + name + '"');
92 o = s.taboption('general', form.Value, 'name', _('Name'));
93 o.placeholder = _('Unnamed zone');
96 o.datatype = 'and(uciname,maxlength(11))';
97 o.write = function(section_id, formvalue) {
98 var cfgvalue = this.cfgvalue(section_id);
100 if (cfgvalue == null || cfgvalue == '')
101 return uci.set('firewall', section_id, 'name', formvalue);
102 else if (cfgvalue != formvalue)
103 return firewall.renameZone(cfgvalue, formvalue);
106 o = s.option(widgets.ZoneForwards, '_info', _('Zone ⇒ Forwardings'));
109 o.cfgvalue = function(section_id) {
110 return uci.get('firewall', section_id, 'name');
114 s.taboption('general', form.ListValue, 'input', _('Input')),
115 s.taboption('general', form.ListValue, 'output', _('Output')),
116 s.taboption('general', form.ListValue, 'forward', _('Forward'))
119 for (var i = 0; i < p.length; i++) {
120 p[i].value('REJECT', _('reject'));
121 p[i].value('DROP', _('drop'));
122 p[i].value('ACCEPT', _('accept'));
123 p[i].editable = true;
126 p[0].default = fwDefaults.getInput();
127 p[1].default = fwDefaults.getOutput();
128 p[2].default = fwDefaults.getForward();
130 o = s.taboption('general', form.Flag, 'masq', _('Masquerading'));
133 o = s.taboption('general', form.Flag, 'mtu_fix', _('MSS clamping'));
136 o = s.taboption('general', widgets.NetworkSelect, 'network', _('Covered networks'));
139 o.write = function(section_id, formvalue) {
140 var name = uci.get('firewall', section_id, 'name'),
141 cfgvalue = this.cfgvalue(section_id);
143 if (typeof(cfgvalue) == 'string' && Array.isArray(formvalue) && (cfgvalue == formvalue.join(' ')))
146 var tasks = [ firewall.getZone(name) ];
148 if (Array.isArray(formvalue))
149 for (var i = 0; i < formvalue.length; i++) {
150 var netname = formvalue[i];
151 tasks.push(network.getNetwork(netname).then(function(net) {
152 return net || network.addNetwork(netname, { 'proto': 'none' });
156 return Promise.all(tasks).then(function(zone_networks) {
157 if (zone_networks[0])
158 for (var i = 1; i < zone_networks.length; i++)
159 zone_networks[0].addNetwork(zone_networks[i].getName());
162 o.remove = function(section_id) {
163 return uci.set('firewall', section_id, 'network', ' ');
166 o = s.taboption('advanced', form.DummyValue, '_advancedinfo');
169 o.cfgvalue = function(section_id) {
170 var name = uci.get('firewall', section_id, 'name');
172 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.')
176 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.'));
181 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.'));
182 o.datatype = 'neg(cidr)';
186 o = s.taboption('advanced', form.ListValue, 'family', _('Restrict to address family'));
187 o.value('', _('IPv4 and IPv6'));
188 o.value('ipv4', _('IPv4 only'));
189 o.value('ipv6', _('IPv6 only'));
192 o = s.taboption('advanced', form.DynamicList, 'masq_src', _('Restrict Masquerading to given source subnets'));
193 o.depends('family', '');
194 o.depends('family', 'ipv4');
195 o.datatype = 'list(neg(or(uciname,hostname,ipmask4)))';
196 o.placeholder = '0.0.0.0/0';
199 o = s.taboption('advanced', form.DynamicList, 'masq_dest', _('Restrict Masquerading to given destination subnets'));
200 o.depends('family', '');
201 o.depends('family', 'ipv4');
202 o.datatype = 'list(neg(or(uciname,hostname,ipmask4)))';
203 o.placeholder = '0.0.0.0/0';
206 o = s.taboption('conntrack', form.Flag, 'conntrack', _('Force connection tracking'), _('Prevent the installation of <em>NOTRACK</em> rules which would bypass connection tracking.'));
209 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.'));
212 o = s.taboption('conntrack', form.Flag, 'auto_helper', _('Automatic helper assignment'), _('Automatically assign conntrack helpers based on traffic protocol and port'));
213 o.default = o.enabled;
216 o = s.taboption('conntrack', form.MultiValue, 'helper', _('Conntrack helpers'), _('Explicitly choses allowed connection tracking helpers for zone traffic'));
217 o.depends('auto_helper', '0');
219 for (var i = 0; i < ctHelpers.length; i++)
220 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()));
222 o = s.taboption('advanced', form.Flag, 'log', _('Enable logging on this zone'));
225 o = s.taboption('advanced', form.Value, 'log_limit', _('Limit log messages'));
226 o.depends('log', '1');
227 o.placeholder = '10/minute';
230 o = s.taboption('extra', form.DummyValue, '_extrainfo');
233 o.cfgvalue = function(section_id) {
234 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.');
237 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.'));
239 o.cfgvalue = function(section_id) {
240 return uci.get('firewall', section_id, 'extra_src') || uci.get('firewall', section_id, 'extra');
242 o.write = function(section_id, value) {
243 uci.unset('firewall', section_id, 'extra');
244 uci.set('firewall', section_id, 'extra_src', value);
247 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.'));
249 o.cfgvalue = function(section_id) {
250 return uci.get('firewall', section_id, 'extra_dest') || uci.get('firewall', section_id, 'extra_src') || uci.get('firewall', section_id, 'extra');
252 o.write = function(section_id, value) {
253 uci.unset('firewall', section_id, 'extra');
254 uci.set('firewall', section_id, 'extra_dest', value);
257 o = s.taboption('general', form.DummyValue, '_forwardinfo');
260 o.cfgvalue = function(section_id) {
261 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.')
262 .format(uci.get('firewall', section_id, 'name'));
265 out = o = s.taboption('general', widgets.ZoneSelect, 'out', _('Allow forward to <em>destination zones</em>:'));
269 o.filter = function(section_id, value) {
270 return (uci.get('firewall', section_id, 'name') != value);
272 o.cfgvalue = function(section_id) {
273 var out = (this.option == 'out'),
274 zone = this.lookupZone(uci.get('firewall', section_id, 'name')),
275 fwds = zone ? zone.getForwardingsBy(out ? 'src' : 'dest') : [],
278 for (var i = 0; i < fwds.length; i++)
279 value.push(out ? fwds[i].getDestination() : fwds[i].getSource());
283 o.write = o.remove = function(section_id, formvalue) {
284 var out = (this.option == 'out'),
285 zone = this.lookupZone(uci.get('firewall', section_id, 'name')),
286 fwds = zone ? zone.getForwardingsBy(out ? 'src' : 'dest') : [];
288 if (formvalue == null)
291 if (Array.isArray(formvalue)) {
292 for (var i = 0; i < fwds.length; i++) {
293 var cmp = out ? fwds[i].getDestination() : fwds[i].getSource();
294 if (!formvalue.filter(function(d) { return d == cmp }).length)
295 zone.deleteForwarding(fwds[i]);
298 for (var i = 0; i < formvalue.length; i++)
300 zone.addForwardingTo(formvalue[i]);
302 zone.addForwardingFrom(formvalue[i]);
306 inp = o = s.taboption('general', widgets.ZoneSelect, 'in', _('Allow forward from <em>source zones</em>:'));
310 o.write = o.remove = out.write;
311 o.filter = out.filter;
312 o.cfgvalue = out.cfgvalue;