4 'require tools.prng as random';
7 function initFirewallState() {
8 return uci.load('firewall');
11 function parseEnum(s, values) {
15 s = String(s).toUpperCase();
20 for (var i = 0; i < values.length; i++)
21 if (values[i].toUpperCase().indexOf(s) == 0)
27 function parsePolicy(s, defaultValue) {
28 return parseEnum(s, ['DROP', 'REJECT', 'ACCEPT']) || (arguments.length < 2 ? null : defaultValue);
32 var Firewall, AbstractFirewallItem, Defaults, Zone, Forwarding, Redirect, Rule;
34 function lookupZone(name) {
35 var z = uci.get('firewall', name);
37 if (z != null && z['.type'] == 'zone')
38 return new Zone(z['.name']);
40 var sections = uci.sections('firewall', 'zone');
42 for (var i = 0; i < sections.length; i++) {
43 if (sections[i].name != name)
46 return new Zone(sections[i]['.name']);
52 function getColorForName(forName) {
55 else if (forName == 'lan')
57 else if (forName == 'wan')
60 random.seed(parseInt(sfh(forName), 16));
62 var r = random.get(128),
72 var b = min + Math.floor(random.get() * (max - min));
74 return '#%02x%02x%02x'.format(0xff - r, 0xff - g, 0xff - b);
78 Firewall = L.Class.extend({
79 getDefaults: function() {
80 return initFirewallState().then(function() {
81 return new Defaults();
86 return initFirewallState().then(L.bind(function() {
90 while (this.getZone(name) != null)
91 name = 'newzone%d'.format(++count);
93 return this.addZone(name);
97 addZone: function(name) {
98 return initFirewallState().then(L.bind(function() {
99 if (name == null || !/^[a-zA-Z0-9_]+$/.test(name))
102 if (lookupZone(name) != null)
105 var d = new Defaults(),
106 z = uci.add('firewall', 'zone');
108 uci.set('firewall', z, 'name', name);
109 uci.set('firewall', z, 'network', ' ');
110 uci.set('firewall', z, 'input', d.getInput() || 'DROP');
111 uci.set('firewall', z, 'output', d.getOutput() || 'DROP');
112 uci.set('firewall', z, 'forward', d.getForward() || 'DROP');
118 getZone: function(name) {
119 return initFirewallState().then(function() {
120 return lookupZone(name);
124 getZones: function() {
125 return initFirewallState().then(function() {
126 var sections = uci.sections('firewall', 'zone'),
129 for (var i = 0; i < sections.length; i++)
130 zones.push(new Zone(sections[i]['.name']));
132 zones.sort(function(a, b) { return a.getName() > b.getName() });
138 getZoneByNetwork: function(network) {
139 return initFirewallState().then(function() {
140 var sections = uci.sections('firewall', 'zone');
142 for (var i = 0; i < sections.length; i++)
143 if (L.toArray(sections[i].network || sections[i].name).indexOf(network) != -1)
144 return new Zone(sections[i]['.name']);
150 deleteZone: function(name) {
151 return initFirewallState().then(function() {
152 var section = uci.get('firewall', name),
155 if (section != null && section['.type'] == 'zone') {
158 uci.remove('firewall', section['.name']);
160 else if (name != null) {
161 var sections = uci.sections('firewall', 'zone');
163 for (var i = 0; i < sections.length; i++) {
164 if (sections[i].name != name)
168 uci.remove('firewall', sections[i]['.name']);
173 sections = uci.sections('firewall');
175 for (var i = 0; i < sections.length; i++) {
176 if (sections[i]['.type'] != 'rule' &&
177 sections[i]['.type'] != 'redirect' &&
178 sections[i]['.type'] != 'forwarding')
181 if (sections[i].src == name || sections[i].dest == name)
182 uci.remove('firewall', sections[i]['.name']);
190 renameZone: function(oldName, newName) {
191 return initFirewallState().then(L.bind(function() {
192 if (oldName == null || newName == null || !/^[a-zA-Z0-9_]+$/.test(newName))
195 if (lookupZone(newName) != null)
198 var sections = uci.sections('firewall', 'zone'),
201 for (var i = 0; i < sections.length; i++) {
202 if (sections[i].name != oldName)
205 if (L.toArray(sections[i].network).length == 0)
206 uci.set('firewall', sections[i]['.name'], 'network', oldName);
208 uci.set('firewall', sections[i]['.name'], 'name', newName);
213 sections = uci.sections('firewall');
215 for (var i = 0; i < sections.length; i++) {
216 if (sections[i]['.type'] != 'rule' &&
217 sections[i]['.type'] != 'redirect' &&
218 sections[i]['.type'] != 'forwarding')
221 if (sections[i].src == oldName)
222 uci.set('firewall', sections[i]['.name'], 'src', newName);
224 if (sections[i].dest == oldName)
225 uci.set('firewall', sections[i]['.name'], 'dest', newName);
233 deleteNetwork: function(network) {
234 return this.getZones().then(L.bind(function(zones) {
237 for (var i = 0; i < zones.length; i++)
238 if (zones[i].deleteNetwork(network))
245 getColorForName: getColorForName
249 AbstractFirewallItem = L.Class.extend({
250 get: function(option) {
251 return uci.get('firewall', this.sid, option);
254 set: function(option, value) {
255 return uci.set('firewall', this.sid, option, value);
260 Defaults = AbstractFirewallItem.extend({
261 __init__: function() {
262 var sections = uci.sections('firewall', 'defaults');
264 for (var i = 0; i < sections.length; i++) {
265 this.sid = sections[i]['.name'];
269 if (this.sid == null)
270 this.sid = uci.add('firewall', 'defaults');
273 isSynFlood: function() {
274 return (this.get('syn_flood') == '1');
277 isDropInvalid: function() {
278 return (this.get('drop_invalid') == '1');
281 getInput: function() {
282 return parsePolicy(this.get('input'), 'DROP');
285 getOutput: function() {
286 return parsePolicy(this.get('output'), 'DROP');
289 getForward: function() {
290 return parsePolicy(this.get('forward'), 'DROP');
295 Zone = AbstractFirewallItem.extend({
296 __init__: function(name) {
297 var section = uci.get('firewall', name);
299 if (section != null && section['.type'] == 'zone') {
303 else if (name != null) {
304 var sections = uci.get('firewall', 'zone');
306 for (var i = 0; i < sections.length; i++) {
307 if (sections[i].name != name)
310 this.sid = sections[i]['.name'];
311 this.data = sections[i];
317 isMasquerade: function() {
318 return (this.get('masq') == '1');
321 getName: function() {
322 return this.get('name');
325 getNetwork: function() {
326 return this.get('network');
329 getInput: function() {
330 return parsePolicy(this.get('input'), (new Defaults()).getInput());
333 getOutput: function() {
334 return parsePolicy(this.get('output'), (new Defaults()).getOutput());
337 getForward: function() {
338 return parsePolicy(this.get('forward'), (new Defaults()).getForward());
341 addNetwork: function(network) {
342 var section = uci.get('network', network);
344 if (section == null || section['.type'] != 'interface')
347 var newNetworks = this.getNetworks();
349 if (newNetworks.filter(function(net) { return net == network }).length)
352 newNetworks.push(network);
353 this.set('network', newNetworks.join(' '));
358 deleteNetwork: function(network) {
359 var oldNetworks = this.getNetworks(),
360 newNetworks = oldNetworks.filter(function(net) { return net != network });
362 if (newNetworks.length > 0)
363 this.set('network', newNetworks.join(' '));
365 this.set('network', null);
367 return (newNetworks.length < oldNetworks.length);
370 getNetworks: function() {
371 return L.toArray(this.get('network'));
374 clearNetworks: function() {
375 this.set('network', ' ');
378 getDevices: function() {
379 return L.toArray(this.get('device'));
382 getSubnets: function() {
383 return L.toArray(this.get('subnet'));
386 getForwardingsBy: function(what) {
387 var sections = uci.sections('firewall', 'forwarding'),
390 for (var i = 0; i < sections.length; i++) {
391 if (sections[i].src == null || sections[i].dest == null)
394 if (sections[i][what] != this.getName())
397 forwards.push(new Forwarding(sections[i]['.name']));
403 addForwardingTo: function(dest) {
404 var forwards = this.getForwardingsBy('src'),
405 zone = lookupZone(dest);
407 if (zone == null || zone.getName() == this.getName())
410 for (var i = 0; i < forwards.length; i++)
411 if (forwards[i].getDestination() == zone.getName())
414 var sid = uci.add('firewall', 'forwarding');
416 uci.set('firewall', sid, 'src', this.getName());
417 uci.set('firewall', sid, 'dest', zone.getName());
419 return new Forwarding(sid);
422 addForwardingFrom: function(src) {
423 var forwards = this.getForwardingsBy('dest'),
424 zone = lookupZone(src);
426 if (zone == null || zone.getName() == this.getName())
429 for (var i = 0; i < forwards.length; i++)
430 if (forwards[i].getSource() == zone.getName())
433 var sid = uci.add('firewall', 'forwarding');
435 uci.set('firewall', sid, 'src', zone.getName());
436 uci.set('firewall', sid, 'dest', this.getName());
438 return new Forwarding(sid);
441 deleteForwardingsBy: function(what) {
442 var sections = uci.sections('firewall', 'forwarding'),
445 for (var i = 0; i < sections.length; i++) {
446 if (sections[i].src == null || sections[i].dest == null)
449 if (sections[i][what] != this.getName())
452 uci.remove('firewall', sections[i]['.name']);
459 deleteForwarding: function(forwarding) {
460 if (!(forwarding instanceof Forwarding))
463 var section = uci.get('firewall', forwarding.sid);
465 if (!section || section['.type'] != 'forwarding')
468 uci.remove('firewall', section['.name']);
473 addRedirect: function(options) {
474 var sid = uci.add('firewall', 'redirect');
476 if (options != null && typeof(options) == 'object')
477 for (var key in options)
478 if (options.hasOwnProperty(key))
479 uci.set('firewall', sid, key, options[key]);
481 uci.set('firewall', sid, 'src', this.getName());
483 return new Redirect(sid);
486 addRule: function(options) {
487 var sid = uci.add('firewall', 'rule');
489 if (options != null && typeof(options) == 'object')
490 for (var key in options)
491 if (options.hasOwnProperty(key))
492 uci.set('firewall', sid, key, options[key]);
494 uci.set('firewall', sid, 'src', this.getName());
496 return new Redirect(sid);
499 getColor: function(forName) {
500 var name = (arguments.length > 0 ? forName : this.getName());
502 return getColorForName(name);
507 Forwarding = AbstractFirewallItem.extend({
508 __init__: function(sid) {
512 getSource: function() {
513 return this.get('src');
516 getDestination: function() {
517 return this.get('dest');
520 getSourceZone: function() {
521 return lookupZone(this.getSource());
524 getDestinationZone: function() {
525 return lookupZone(this.getDestination());
530 Rule = AbstractFirewallItem.extend({
531 getSource: function() {
532 return this.get('src');
535 getDestination: function() {
536 return this.get('dest');
539 getSourceZone: function() {
540 return lookupZone(this.getSource());
543 getDestinationZone: function() {
544 return lookupZone(this.getDestination());
549 Redirect = AbstractFirewallItem.extend({
550 getSource: function() {
551 return this.get('src');
554 getDestination: function() {
555 return this.get('dest');
558 getSourceZone: function() {
559 return lookupZone(this.getSource());
562 getDestinationZone: function() {
563 return lookupZone(this.getDestination());