'use strict';'require baseclass';'require dom';'require ui';'require uci';'require form';'require network';'require firewall';'require tools.prng as random';var protocols=['ip',0,'IP','hopopt',0,'HOPOPT','icmp',1,'ICMP','igmp',2,'IGMP','ggp',3,'GGP','ipencap',4,'IP-ENCAP','st',5,'ST','tcp',6,'TCP','egp',8,'EGP','igp',9,'IGP','pup',12,'PUP','udp',17,'UDP','hmp',20,'HMP','xns-idp',22,'XNS-IDP','rdp',27,'RDP','iso-tp4',29,'ISO-TP4','dccp',33,'DCCP','xtp',36,'XTP','ddp',37,'DDP','idpr-cmtp',38,'IDPR-CMTP','ipv6',41,'IPv6','ipv6-route',43,'IPv6-Route','ipv6-frag',44,'IPv6-Frag','idrp',45,'IDRP','rsvp',46,'RSVP','gre',47,'GRE','esp',50,'IPSEC-ESP','ah',51,'IPSEC-AH','skip',57,'SKIP','icmpv6',58,'IPv6-ICMP','ipv6-icmp',58,'IPv6-ICMP','ipv6-nonxt',59,'IPv6-NoNxt','ipv6-opts',60,'IPv6-Opts','rspf',73,'RSPF','rspf',73,'CPHB','vmtp',81,'VMTP','eigrp',88,'EIGRP','ospf',89,'OSPFIGP','ax.25',93,'AX.25','ipip',94,'IPIP','etherip',97,'ETHERIP','encap',98,'ENCAP','pim',103,'PIM','ipcomp',108,'IPCOMP','vrrp',112,'VRRP','l2tp',115,'L2TP','isis',124,'ISIS','sctp',132,'SCTP','fc',133,'FC','mh',135,'Mobility-Header','ipv6-mh',135,'Mobility-Header','mobility-header',135,'Mobility-Header','udplite',136,'UDPLite','mpls-in-ip',137,'MPLS-in-IP','manet',138,'MANET','hip',139,'HIP','shim6',140,'Shim6','wesp',141,'WESP','rohc',142,'ROHC',];function lookupProto(x){if(x==null||x==='')
return null;var s=String(x).toLowerCase();for(var i=0;i<protocols.length;i+=3)
if(s==protocols[i]||s==protocols[i+1])
return[protocols[i+1],protocols[i+2],protocols[i]];return[-1,x,x];}
return baseclass.extend({fmt:function(fmtstr,args,values){var repl=[],wrap=false,tokens=[];if(values==null){values=[];wrap=true;}
var get=function(args,key){var names=key.trim().split(/\./),obj=args,ctx=obj;for(var i=0;i<names.length;i++){if(!L.isObject(obj))
return null;ctx=obj;obj=obj[names[i]];}
if(typeof(obj)=='function')
return obj.call(ctx);return obj;};var isset=function(val){if(L.isObject(val)&&!dom.elem(val)){for(var k in val)
if(val.hasOwnProperty(k))
return true;return false;}
else if(Array.isArray(val)){return(val.length>0);}
else{return(val!==null&&val!==undefined&&val!==''&&val!==false);}};var parse=function(tokens,text){if(dom.elem(text)){tokens.push('<span data-fmt-placeholder="%d"></span>'.format(values.length));values.push(text);}
else{tokens.push(String(text).replace(/\\(.)/g,'$1'));}};for(var i=0,last=0;i<=fmtstr.length;i++){if(fmtstr.charAt(i)=='%'&&fmtstr.charAt(i+1)=='{'){if(i>last)
parse(tokens,fmtstr.substring(last,i));var j=i+1,nest=0;var subexpr=[];for(var off=j+1,esc=false;j<=fmtstr.length;j++){var ch=fmtstr.charAt(j);if(esc){esc=false;}
else if(ch=='\\'){esc=true;}
else if(ch=='{'){nest++;}
else if(ch=='}'){if(--nest==0){subexpr.push(fmtstr.substring(off,j));break;}}
else if(ch=='?'||ch==':'||ch=='#'){if(nest==1){subexpr.push(fmtstr.substring(off,j));subexpr.push(ch);off=j+1;}}}
var varname=subexpr[0].trim(),op1=(subexpr[1]!=null)?subexpr[1]:'?',if_set=(subexpr[2]!=null&&subexpr[2]!='')?subexpr[2]:'%{'+varname+'}',op2=(subexpr[3]!=null)?subexpr[3]:':',if_unset=(subexpr[4]!=null)?subexpr[4]:'';if(nest!=0||subexpr.length>5||varname==''){return fmtstr;}
else if(op1=='#'&&subexpr.length==3){var items=L.toArray(get(args,varname));for(var k=0;k<items.length;k++){tokens.push.apply(tokens,this.fmt(if_set,Object.assign({},args,{first:k==0,next:k>0,last:(k+1)==items.length,item:items[k]}),values));}}
else if(op1=='?'&&op2==':'&&(subexpr.length==1||subexpr.length==3||subexpr.length==5)){var val=get(args,varname);if(subexpr.length==1)
parse(tokens,isset(val)?val:'');else if(isset(val))
tokens.push.apply(tokens,this.fmt(if_set,args,values));else
tokens.push.apply(tokens,this.fmt(if_unset,args,values));}
else{return fmtstr;}
last=j+1;i=j;}
else if(i>=fmtstr.length){if(i>last)
parse(tokens,fmtstr.substring(last,i));}}
if(wrap){var node=E('span',{},tokens.join('')),repl=node.querySelectorAll('span[data-fmt-placeholder]');for(var i=0;i<repl.length;i++)
repl[i].parentNode.replaceChild(values[repl[i].getAttribute('data-fmt-placeholder')],repl[i]);return node;}
else{return tokens;}},map_invert:function(v,fn){return L.toArray(v).map(function(v){v=String(v);if(fn!=null&&typeof(v[fn])=='function')
v=v[fn].call(v);return{ival:v,inv:v.charAt(0)=='!',val:v.replace(/^!\s*/,'')};});},lookupProto:lookupProto,addDSCPOption:function(s,is_target){var o=s.taboption(is_target?'general':'advanced',form.Value,is_target?'set_dscp':'dscp',is_target?_('DSCP mark'):_('Match DSCP'),is_target?_('Apply the given DSCP class or value to established connections.'):_('Matches traffic carrying the specified DSCP marking.'));o.modalonly=true;o.rmempty=!is_target;o.placeholder=_('any');if(is_target)
o.depends('target','DSCP');o.value('CS0');o.value('CS1');o.value('CS2');o.value('CS3');o.value('CS4');o.value('CS5');o.value('CS6');o.value('CS7');o.value('BE');o.value('AF11');o.value('AF12');o.value('AF13');o.value('AF21');o.value('AF22');o.value('AF23');o.value('AF31');o.value('AF32');o.value('AF33');o.value('AF41');o.value('AF42');o.value('AF43');o.value('EF');o.validate=function(section_id,value){if(value=='')
return is_target?_('DSCP mark required'):true;if(!is_target)
value=String(value).replace(/^!\s*/,'');var m=value.match(/^(?:CS[0-7]|BE|AF[1234][123]|EF|(0x[0-9a-f]{1,2}|[0-9]{1,2}))$/);if(!m||(m[1]!=null&&+m[1]>0x3f))
return _('Invalid DSCP mark');return true;};return o;},addMarkOption:function(s,is_target){var o=s.taboption(is_target?'general':'advanced',form.Value,(is_target>1)?'set_xmark':(is_target?'set_mark':'mark'),(is_target>1)?_('XOR mark'):(is_target?_('Set mark'):_('Match mark')),(is_target>1)?_('Apply a bitwise XOR of the given value and the existing mark value on established connections. Format is value[/mask]. If a mask is specified then those bits set in the mask are zeroed out.'):(is_target?_('Set the given mark value on established connections. Format is value[/mask]. If a mask is specified then only those bits set in the mask are modified.'):_('Matches a specific firewall mark or a range of different marks.')));o.modalonly=true;o.rmempty=true;if(is_target>1)
o.depends('target','MARK_XOR');else if(is_target)
o.depends('target','MARK_SET');o.validate=function(section_id,value){if(value=='')
return is_target?_('Valid firewall mark required'):true;if(!is_target)
value=String(value).replace(/^!\s*/,'');var m=value.match(/^(0x[0-9a-f]{1,8}|[0-9]{1,10})(?:\/(0x[0-9a-f]{1,8}|[0-9]{1,10}))?$/i);if(!m||+m[1]>0xffffffff||(m[2]!=null&&+m[2]>0xffffffff))
return _('Expecting: %s').format(_('valid firewall mark'));return true;};return o;},addLimitOption:function(s){var o=s.taboption('advanced',form.Value,'limit',_('Limit matching'),_('Limits traffic matching to the specified rate.'));o.modalonly=true;o.rmempty=true;o.placeholder=_('unlimited');o.value('10/second');o.value('60/minute');o.value('3/hour');o.value('500/day');o.validate=function(section_id,value){if(value=='')
return true;var m=String(value).toLowerCase().match(/^(?:0x[0-9a-f]{1,8}|[0-9]{1,10})\/([a-z]+)$/),u=['second','minute','hour','day'],i=0;if(m)
for(i=0;i<u.length;i++)
if(u[i].indexOf(m[1])==0)
break;if(!m||i>=u.length)
return _('Invalid limit value');return true;};return o;},addLimitBurstOption:function(s){var o=s.taboption('advanced',form.Value,'limit_burst',_('Limit burst'),_('Maximum initial number of packets to match: this number gets recharged by one every time the limit specified above is not reached, up to this number.'));o.modalonly=true;o.rmempty=true;o.placeholder='5';o.datatype='uinteger';o.depends({limit:null,'!reverse':true});return o;},transformHostHints:function(family,hosts){var choice_values=[],choice_labels={},ip6addrs={},ipaddrs={};for(var mac in hosts){L.toArray(hosts[mac].ipaddrs||hosts[mac].ipv4).forEach(function(ip){ipaddrs[ip]=mac;});L.toArray(hosts[mac].ip6addrs||hosts[mac].ipv6).forEach(function(ip){ip6addrs[ip]=mac;});}
if(!family||family=='ipv4'){L.sortedKeys(ipaddrs,null,'addr').forEach(function(ip){var val=ip,txt=hosts[ipaddrs[ip]].name||ipaddrs[ip];choice_values.push(val);choice_labels[val]=E([],[val,' (',E('strong',{},[txt]),')']);});}
if(!family||family=='ipv6'){L.sortedKeys(ip6addrs,null,'addr').forEach(function(ip){var val=ip,txt=hosts[ip6addrs[ip]].name||ip6addrs[ip];choice_values.push(val);choice_labels[val]=E([],[val,' (',E('strong',{},[txt]),')']);});}
return[choice_values,choice_labels];},updateHostHints:function(map,section_id,option,family,hosts){var opt=map.lookupOption(option,section_id)[0].getUIElement(section_id),choices=this.transformHostHints(family,hosts);opt.clearChoices();opt.addChoices(choices[0],choices[1]);},CBIDynamicMultiValueList:form.DynamicList.extend({renderWidget:function(){var dl=form.DynamicList.prototype.renderWidget.apply(this,arguments),inst=dom.findClassInstance(dl);inst.addItem=function(dl,value,text,flash){var values=L.toArray(value);for(var i=0;i<values.length;i++)
ui.DynamicList.prototype.addItem.call(this,dl,values[i],null,true);};return dl;}}),addIPOption:function(s,tab,name,label,description,family,hosts,multiple){var o=s.taboption(tab,multiple?this.CBIDynamicMultiValueList:form.Value,name,label,description);o.modalonly=true;o.datatype='list(neg(ipmask("true")))';o.placeholder=multiple?_('-- add IP --'):_('any');if(family!=null){var choices=this.transformHostHints(family,hosts);for(var i=0;i<choices[0].length;i++)
o.value(choices[0][i],choices[1][choices[0][i]]);}
o.transformChoices=function(){return this.super('transformChoices',[])||{};};return o;},addLocalIPOption:function(s,tab,name,label,description,devices){var o=s.taboption(tab,form.Value,name,label,description);o.modalonly=true;o.datatype='ip4addr("nomask")';o.placeholder=_('any');L.sortedKeys(devices,'name').forEach(function(dev){var ip4addrs=devices[dev].ipaddrs;if(!L.isObject(devices[dev].flags)||!Array.isArray(ip4addrs)||devices[dev].flags.loopback)
return;for(var i=0;i<ip4addrs.length;i++){if(!L.isObject(ip4addrs[i])||!ip4addrs[i].address)
continue;o.value(ip4addrs[i].address,E([],[ip4addrs[i].address,' (',E('strong',{},[dev]),')']));}});return o;},addMACOption:function(s,tab,name,label,description,hosts){var o=s.taboption(tab,this.CBIDynamicMultiValueList,name,label,description);o.modalonly=true;o.datatype='list(macaddr)';o.placeholder=_('-- add MAC --');L.sortedKeys(hosts).forEach(function(mac){o.value(mac,E([],[mac,' (',E('strong',{},[hosts[mac].name||L.toArray(hosts[mac].ipaddrs||hosts[mac].ipv4)[0]||L.toArray(hosts[mac].ip6addrs||hosts[mac].ipv6)[0]||'?']),')']));});return o;},CBIProtocolSelect:form.MultiValue.extend({__name__:'CBI.ProtocolSelect',addChoice:function(value,label){if(!Array.isArray(this.keylist)||this.keylist.indexOf(value)==-1)
this.value(value,label);},load:function(section_id){var cfgvalue=L.toArray(this.super('load',[section_id])||this.default).sort();['all','tcp','udp','icmp'].concat(cfgvalue).forEach(L.bind(function(value){switch(value){case'all':case'any':case'*':this.addChoice('all',_('Any'));break;case'tcpudp':this.addChoice('tcp','TCP');this.addChoice('udp','UDP');break;default:var m=value.match(/^(0x[0-9a-f]{1,2}|[0-9]{1,3})$/),p=lookupProto(m?+m[1]:value);this.addChoice(p[2],p[1]);break;}},this));if(cfgvalue=='*'||cfgvalue=='any'||cfgvalue=='all')
cfgvalue='all';return cfgvalue;},renderWidget:function(section_id,option_index,cfgvalue){var value=(cfgvalue!=null)?cfgvalue:this.default,choices=this.transformChoices();var widget=new ui.Dropdown(L.toArray(value),choices,{id:this.cbid(section_id),sort:this.keylist,multiple:true,optional:false,display_items:10,dropdown_items:-1,create:true,disabled:(this.readonly!=null)?this.readonly:this.map.readonly,validate:function(value){var v=L.toArray(value);for(var i=0;i<v.length;i++){if(v[i]=='all')
continue;var m=v[i].match(/^(0x[0-9a-f]{1,2}|[0-9]{1,3})$/);if(m?(+m[1]>255):(lookupProto(v[i])[0]==-1))
return _('Unrecognized protocol');}
return true;}});widget.createChoiceElement=function(sb,value){var p=lookupProto(value);return ui.Dropdown.prototype.createChoiceElement.call(this,sb,p[2],p[1]);};widget.createItems=function(sb,value){var values=L.toArray(value).map(function(value){var m=value.match(/^(0x[0-9a-f]{1,2}|[0-9]{1,3})$/),p=lookupProto(m?+m[1]:value);return(p[0]>-1)?p[2]:p[1];});values.sort();return ui.Dropdown.prototype.createItems.call(this,sb,values.join(' '));};widget.toggleItem=function(sb,li){var value=li.getAttribute('data-value'),toggleFn=ui.Dropdown.prototype.toggleItem;toggleFn.call(this,sb,li);if(value=='all'){var items=li.parentNode.querySelectorAll('li[data-value]');for(var j=0;j<items.length;j++)
if(items[j]!==li)
toggleFn.call(this,sb,items[j],false);}
else{toggleFn.call(this,sb,li.parentNode.querySelector('li[data-value="all"]'),false);}};return widget.render();}}),checkLegacySNAT:function(){var redirects=uci.sections('firewall','redirect');for(var i=0;i<redirects.length;i++)
if((redirects[i]['target']||'').toLowerCase()=='snat')
return true;return false;},handleMigration:function(ev){var redirects=uci.sections('firewall','redirect'),tasks=[];var mapping={dest:'src',reflection:null,reflection_src:null,src_dip:'snat_ip',src_dport:'snat_port',src:null};for(var i=0;i<redirects.length;i++){if((redirects[i]['target']||'').toLowerCase()!='snat')
continue;var sid=uci.add('firewall','nat');for(var opt in redirects[i]){if(opt.charAt(0)=='.')
continue;if(mapping[opt]===null)
continue;uci.set('firewall',sid,mapping[opt]||opt,redirects[i][opt]);}
uci.remove('firewall',redirects[i]['.name']);}
return uci.save().then(L.bind(ui.changes.init,ui.changes)).then(L.bind(ui.changes.apply,ui.changes));},renderMigration:function(){ui.showModal(_('Firewall configuration migration'),[E('p',_('The existing firewall configuration needs to be changed for LuCI to function properly.')),E('p',_('Upon pressing "Continue", "redirect" sections with target "SNAT" will be converted to "nat" sections and the firewall will be restarted to apply the updated configuration.')),E('div',{'class':'right'},E('button',{'class':'btn cbi-button-action important','click':ui.createHandlerFn(this,'handleMigration')},_('Continue')))]);},});