'use strict';'require view';'require poll';'require fs';'require ui';const table_names=['Filter','NAT','Mangle','Raw'];const raw_style='font-family:monospace;font-size:smaller;text-align:right';return view.extend({load(){return L.resolveDefault(fs.stat('/usr/sbin/ip6tables'));},createTableSection(is_ipv6,table){const idiv=document.querySelector('div[data-tab="%s"]'.format(is_ipv6?'ip6tables':'iptables'));let tdiv=idiv.querySelector('[data-table="%s-%s"]'.format(is_ipv6?'ipv6':'ipv4',table));const title='%s: %s'.format(_('Table'),table);if(!tdiv){tdiv=E('div',{'data-table':'%s-%s'.format(is_ipv6?'ipv6':'ipv4',table)},[E('h3',{},title),E('div')]);if(idiv.firstElementChild.nodeName.toLowerCase()==='p')
idiv.removeChild(idiv.firstElementChild);let added=false,thisIdx=table_names.indexOf(table);idiv.querySelectorAll('[data-table]').forEach(function(child){const childIdx=table_names.indexOf(child.getAttribute('data-table').split(/-/)[1]);if(added===false&&childIdx>thisIdx){idiv.insertBefore(tdiv,child);added=true;}});if(added===false)
idiv.appendChild(tdiv);}
return tdiv.lastElementChild;},createChainSection(is_ipv6,table,chain,policy,packets,bytes,references){const tdiv=this.createTableSection(is_ipv6,table);let cdiv=tdiv.querySelector('[data-chain="%s"]'.format(chain));let title;if(policy)
title='%s <em>%s</em> <span>(%s: <em>%s</em>, %d %s, %.2mB %s)</span>'.format(_('Chain'),chain,_('Policy'),policy,packets,_('Packets'),bytes,_('Traffic'));else
title='%s <em>%s</em> <span class="references">(%d %s)</span>'.format(_('Chain'),chain,references,_('References'));if(!cdiv){cdiv=E('div',{'data-chain':chain},[E('h4',{'id':'rule_%s-%s_%s'.format(is_ipv6?'ipv6':'ipv4',table.toLowerCase(),chain)},title),E('table',{'class':'table'},[E('tr',{'class':'tr table-titles'},[E('th',{'class':'th'},_('Pkts.')),E('th',{'class':'th'},_('Traffic')),E('th',{'class':'th'},_('Target')),E('th',{'class':'th'},_('Prot.')),E('th',{'class':'th'},_('In')),E('th',{'class':'th'},_('Out')),E('th',{'class':'th'},_('Source')),E('th',{'class':'th'},_('Destination')),E('th',{'class':'th'},_('Options')),E('th',{'class':'th'},_('Comment'))])])]);tdiv.appendChild(cdiv);}
else{cdiv.firstElementChild.innerHTML=title;}
return cdiv.lastElementChild;},updateChainSection(chaintable,rows){if(!chaintable)
return;cbi_update_table(chaintable,rows,_('No rules in this chain.'));if(rows.length===0&&document.querySelector('[data-hide-empty="true"]'))
chaintable.parentNode.style.display='none';else
chaintable.parentNode.style.display='';chaintable.parentNode.setAttribute('data-empty',rows.length===0);},parseIptablesDump(is_ipv6,table,s){let current_chain=null;let current_rules=[];const seen_chains={};const chain_refs={};const re=/([^\n]*)\n/g;let m,m2;const raw=document.querySelector('[data-raw-counters="true"]');while((m=re.exec(s))!=null){if(m[1].match(/^Chain (.+) \(policy (\w+) (\d+) packets, (\d+) bytes\)$/)){const chain=RegExp.$1;const policy=RegExp.$2;const packets=+RegExp.$3;const bytes=+RegExp.$4;this.updateChainSection(current_chain,current_rules);seen_chains[chain]=true;current_chain=this.createChainSection(is_ipv6,table,chain,policy,packets,bytes);current_rules=[];}
else if(m[1].match(/^Chain (.+) \((\d+) references\)$/)){const chain=RegExp.$1;const references=+RegExp.$2;this.updateChainSection(current_chain,current_rules);seen_chains[chain]=true;current_chain=this.createChainSection(is_ipv6,table,chain,null,null,null,references);current_rules=[];}
else if(m[1].match(/^num /)){continue;}
else if((m2=m[1].match(/^(\d+) +(\d+) +(\d+) +(.*?) +(\S+) +(\S*) +(\S+) +(\S+) +(!?[a-f0-9:.]+(?:\/[a-f0-9:.]+)?) +(!?[a-f0-9:.]+(?:\/[a-f0-9:.]+)?) +(.+)$/))!==null){const num=+m2[1];const pkts=+m2[2];const bytes=+m2[3];const target=m2[4];const proto=m2[5];const indev=m2[7];const outdev=m2[8];const srcnet=m2[9];const dstnet=m2[10];let options=m2[11]||'-';let comment='-';options=options.trim().replace(/(?:^| )\/\* (.+) \*\//,function(m1,m2){comment=m2.replace(/^!fw3(: |$)/,'').trim()||'-';return'';})||'-';current_rules.push([E('div',{'class':'nowrap','style':raw?raw_style:null,'data-format':'%.2m','data-value':pkts},(raw?'%d':'%.2m').format(pkts)),E('div',{'class':'nowrap','style':raw?raw_style:null,'data-format':'%.2mB','data-value':bytes},(raw?'%d':'%.2mB').format(bytes)),target?'<span class="target">%s</span>'.format(target):'-',proto,(indev!=='*')?'<span class="ifacebadge nowrap">%s</span>'.format(indev):'*',(outdev!=='*')?'<span class="ifacebadge nowrap">%s</span>'.format(outdev):'*',srcnet,dstnet,options,[comment,'%h'.format(comment)]]);if(target){chain_refs[target]=chain_refs[target]||[];chain_refs[target].push([current_chain,num]);}}}
this.updateChainSection(current_chain,current_rules);document.querySelectorAll('[data-table="%s-%s"] [data-chain]'.format(is_ipv6?'ipv6':'ipv4',table)).forEach(L.bind(function(cdiv){if(!seen_chains[cdiv.getAttribute('data-chain')]){cdiv.parentNode.removeChild(cdiv);return;}
cdiv.querySelectorAll('.target').forEach(L.bind(function(tspan){if(seen_chains[tspan.textContent]){tspan.classList.add('jump');tspan.addEventListener('click',this.handleJumpTarget);}},this));cdiv.querySelectorAll('.references').forEach(L.bind(function(rspan){const refs=chain_refs[cdiv.getAttribute('data-chain')];if(refs&&refs.length){rspan.classList.add('cbi-tooltip-container');rspan.appendChild(E('small',{'class':'cbi-tooltip ifacebadge','style':'top:1em; left:auto'},[E('ul')]));refs.forEach(L.bind(function(ref){const chain=ref[0].parentNode.getAttribute('data-chain');const num=ref[1];rspan.lastElementChild.lastElementChild.appendChild(E('li',{},[_('Chain'),' ',E('span',{'class':'jump','data-num':num,'click':this.handleJumpTarget},chain),', %s #%d'.format(_('Rule'),num)]));},this));}},this));},this));},pollFirewallLists(has_ip6tables){const cmds=['/usr/sbin/iptables'];if(has_ip6tables)
cmds.push('/usr/sbin/ip6tables');poll.add(L.bind(function(){const tasks=[];for(let i=0;i<cmds.length;i++){for(let tn of table_names){tasks.push(L.resolveDefault(fs.exec_direct(cmds[i],['--line-numbers','-w','-nvxL','-t',tn.toLowerCase()]).then(this.parseIptablesDump.bind(this,i>0,tn))));}}
return Promise.all(tasks);},this));},handleJumpTarget(ev){const link=ev.target;const table=findParent(link,'[data-table]').getAttribute('data-table');const chain=link.textContent;const num=+link.getAttribute('data-num');const elem=document.getElementById('rule_%s_%s'.format(table.toLowerCase(),chain));if(elem){if(elem.scrollIntoView){elem.scrollIntoView();}else{(document.documentElement||document.body.parentNode||document.body).scrollTop=elem.offsetTop-40;}
elem.classList.remove('flash');void elem.offsetWidth;elem.classList.add('flash');if(num){const rule=elem.nextElementSibling.childNodes[num];if(rule){rule.classList.remove('flash');void rule.offsetWidth;rule.classList.add('flash');}}}},handleRawCounters(ev){const btn=ev.currentTarget;const raw=(btn.getAttribute('data-raw-counters')==='false');btn.setAttribute('data-raw-counters',raw);btn.firstChild.data=raw?_('Human-readable counters'):_('Show raw counters');btn.blur();document.querySelectorAll('[data-value]').forEach(function(div){const fmt=raw?'%d':div.getAttribute('data-format');div.style=raw?raw_style:'';div.innerText=fmt.format(div.getAttribute('data-value'));});},handleHideEmpty(ev){const btn=ev.currentTarget;const hide=(btn.getAttribute('data-hide-empty')==='false');btn.setAttribute('data-hide-empty',hide);btn.firstChild.data=hide?_('Show empty chains'):_('Hide empty chains');btn.blur();document.querySelectorAll('[data-chain][data-empty="true"]').forEach(function(chaintable){chaintable.style.display=hide?'none':'';});},handleCounterReset(has_ip6tables,ev){return Promise.all([fs.exec('/usr/sbin/iptables',['-Z']).catch(function(err){ui.addNotification(null,E('p',{},_('Unable to reset iptables counters: %s').format(err.message)))}),has_ip6tables?fs.exec('/usr/sbin/ip6tables',['-Z']).catch(function(err){ui.addNotification(null,E('p',{},_('Unable to reset ip6tables counters: %s').format(err.message)))}):null]);},handleRestart(ev){return fs.exec_direct('/etc/init.d/firewall',['restart']).catch(function(err){ui.addNotification(null,E('p',{},_('Unable to restart firewall: %s').format(err.message)))});},render(has_ip6tables){const view=E([],[E('style',{'type':'text/css'},['.cbi-tooltip-container, span.jump { border-bottom:1px dotted #00f;cursor:pointer }','ul { list-style:none }','.references { position:relative }','.references .cbi-tooltip { left:0!important;top:1.5em!important }','h4>span { font-size:90% }']),E('h2',{},[_('Firewall Status')]),E('div',{'class':'right','style':'margin-bottom:-1.5em'},[E('button',{'class':'cbi-button','data-hide-empty':false,'click':ui.createHandlerFn(this,'handleHideEmpty')},[_('Hide empty chains')]),' ',E('button',{'class':'cbi-button','data-raw-counters':false,'click':ui.createHandlerFn(this,'handleRawCounters')},[_('Show raw counters')]),' ',E('button',{'class':'cbi-button','click':ui.createHandlerFn(this,'handleCounterReset',has_ip6tables)},[_('Reset Counters')]),' ',E('button',{'class':'cbi-button','click':ui.createHandlerFn(this,'handleRestart')},[_('Restart Firewall')])]),E('div',{},[E('div',{'data-tab':'iptables','data-tab-title':has_ip6tables?_('IPv4 Firewall'):null,'data-tab-active':has_ip6tables?null:true},[E('p',{},E('em',{'class':'spinning'},[_('Collecting data...')]))]),has_ip6tables?E('div',{'data-tab':'ip6tables','data-tab-title':_('IPv6 Firewall')},[E('p',{},E('em',{'class':'spinning'},[_('Collecting data...')]))]):E([])])]);if(has_ip6tables)
ui.tabs.initTabGroup(view.lastElementChild.childNodes);this.pollFirewallLists(has_ip6tables);return view;},handleSaveApply:null,handleSave:null,handleReset:null});