Support Forum
The Forums are a place to find answers on a range of Fortinet products from peers and product experts.
Dannу
New Contributor III

FortiGate WebUI Tools > System info

Comment for more tool ideas!
Let's extend the FortiGate WebUI
Tested on FortiOS v7.0, 7.2

 

Installation:

  1. Login to your FortiGate's WebUI
  2. Create a new bookmark in your web browser and copy the JavaScript code below into the URL field.
  3. Click the bookmark and enjoy the Tools extension

Result:

image.png

Copy & paste into a bookmark:
javascript:(async function(){document.contains(document.getElementById("tools"))&&document.getElementById("tools").remove();let e="_cliWS",t="",s=["get system status","get system global","get system settings"],l=["get system arp","diag ip arp list"],n=window[e],i=!1,r;function a(e){n.send(`${e}\r`)}function o(e,t){let s=document.querySelector(`table[data-command="${r}"]`);if(s)switch(t){case"arp_cmd1":let[l,n,i,a]=e.replace(/\s+/g," ").split(" ");s.innerHTML+=`<tr><td style="border:1px solid grey;">${l}</td><td style="border:1px solid grey;text-align:center">${n}</td><td style="border:1px solid grey;text-align:center">${i}</td><td style="border:1px solid grey;text-align:center">${a}</td></tr>`;break;case"arp_cmd2":let[o,d,c,$,p,y,g,_,f]=e.replace(/\s+/g," ").split(" ");p=p.replace("00000000",'<span title="Pseudo state used while an ARP entry is initially created or just before it is removed"><f-icon class="fa-connected"></f-icon>&nbsp;NONE<span>'),p=p.replace("00000001",'<span title="First ARP request sent"><f-icon class="fa-connected"></f-icon>&nbsp;INCOMPLETE</span>'),p=p.replace("00000002",'<span title="ARP response is received"><f-icon class="fa-connected"></f-icon>&nbsp;REACHABLE</span>'),p=p.replace("00000004",'<span title="ARP response is not received within expected time"><f-icon class="fa-custom-action"></f-icon>&nbsp;STALE</span>'),p=p.replace("00000008",'<span title="Schedule ARP request"><f-icon class="fa-clock-plus"></f-icon>&nbsp;DELAY</span>'),p=p.replace("00000010",'<span title="Actively sending ARP requests to try and resolve the address"><f-icon class="fa-clock-plus"></f-icon>&nbsp;PROBE</span>'),p=p.replace("00000020",'<span title="Not managed to resolve ARP within max configured number of probes"><f-icon class="fa-cancel"></f-icon>&nbsp;FAILED</span>'),p=p.replace("00000040",'<span title="Device does not support ARP e.g. IPsec Interface"><f-icon class="fa-dismiss"></f-icon>&nbsp;NOARP</span>'),p=p.replace("00000080",'<span title="Statically configured ARP entry">PERMANENT</span>'),s.innerHTML+=`<tr><td style="border:1px solid grey;text-align:center">${d.substring(d.indexOf("=")+1)}</td><td style="border:1px solid grey">${c}</td><td style="border:1px solid grey;text-align:center">${$}</td><td style="border:1px solid grey">${p.substring(p.indexOf("=")+1)}</td><td style="border:1px solid grey;text-align:center">${y.substring(y.indexOf("=")+1)}</td><td style="border:1px solid grey;text-align:center">${g.substring(g.indexOf("=")+1)}</td><td style="border:1px solid grey;text-align:center">${_.substring(_.indexOf("=")+1)}</td><td style="border:1px solid grey;text-align:center">${f.substring(f.indexOf("=")+1)}</td></tr>`;break;default:let[m,b]=e.split(/:(.*)/s);b=b.replace(/[dD]isable/g,'<f-icon class="fa-disabled"></f-icon>&nbsp;<span style="color:silver">Disabled</span>'),b=b.replace(/[nN]ot [aV]vailable/g,'<f-icon class="fa-disabled"></f-icon>&nbsp;<span style="color:silver">Not available</span>'),b=b.replace(/[eE]nable/g,'<f-icon class="fa-enabled"></f-icon>&nbsp;<span>Enabled</span>'),b=b.replace(/[cC]ertified/g,'<f-icon class="fa-enabled"></f-icon>&nbsp;<span>Certified</span>'),s.innerHTML+=`<tr><td style="border: 1px solid grey;">${m}</td><td style="border: 1px solid grey;">${b}</td></tr>`}else{switch((s=document.createElement("table")).dataset.command=r,s.dataset.active="active",s.style.margin="1rem",t){case"arp_cmd1":s.innerHTML='<tr><th style="border:1px solid grey;text-align:left">IP Address</th><th style="border:1px solid grey">Age(min)</th><th style="border:1px solid grey">MAC Address</th><th style="border:1px solid grey">Interface</th></tr>';break;case"arp_cmd2":s.innerHTML='<tr><th style="border:1px solid grey">Interface</th><th style="border:1px solid grey;text-align:left">IP Address</th><th style="border:1px solid grey">MAC Address</th><th style="border:1px solid grey;text-align:left">Status</th><th style="border:1px solid grey">Use</th><th style="border:1px solid grey">Confirm</th><th style="border:1px solid grey">Update</th><th style="border:1px solid grey">Ref</th></tr>';break;default:s.innerHTML='<tr><th style="border:1px solid grey;">Key</th><th style="border:1px solid grey;">Value</th></tr>'}let x=document.querySelector(`li[data-command="${r}"]`);!function e(t,s){s.parentNode.insertBefore(t,s.nextSibling)}(s,x)}}let d="";async function c(e){let s=await e.data.text();if(i){let l="";for(let n in s){let r=s[n];"\r"===l?"\n"===r&&d.length>0?(o(d,t),d=""):"\0"===r&&(d=""):"\r"!==r&&(d+=r),l=r}}else i=!0,a("")}function $(){let t="https:"===location.protocol?"wss:":"ws:",s=`${t}//${location.hostname}:${location.port}/ws/cli/open?cols=500&rows=500`;window[e]=n=new WebSocket(s),n.addEventListener("message",c),n.addEventListener("close",()=>window[e]=null)}let p=[{label:"System info",content:"",script:function(e){n||$();let l=document.createElement("ul");l.id="system-info-command-list",s.forEach(e=>{let s=document.createElement("li");s.style.marginBottom="1rem",s.style.color="green",s.style.cursor="pointer",s.dataset.command=e,s.innerHTML=`&nbsp;${e}<nu-icon class="icon" style="margin-left:auto;width:18px;height:14px;transform:rotate(0deg)"><svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg" style="width: 18px; height: 18px;"><path d="m12.01 9.531-4.25 4.25a.747.747 0 0 1-1.06 0l-.706-.706a.747.747 0 0 1 0-1.06l3.012-3.012-3.012-3.012a.747.747 0 0 1 0-1.06l.703-.712a.747.747 0 0 1 1.06 0l4.25 4.25a.748.748 0 0 1 .002 1.062z"></path></svg></nu-icon>`,s.onclick=function(){if(t="sys_cmd",n){let e=this.nextSibling&&"TABLE"===this.nextSibling.nodeName?this.nextSibling:null,l=this.querySelector(".icon");if(e)"active"===e.dataset.active?(e.dataset.active="",e.style.display="none",l.style.transform="rotate(0deg)"):(e.dataset.active="active",e.style.display="block",l.style.transform="rotate(90deg)");else{i=!0;let o=s.dataset.command;a(o),r=o,l.style.transform="rotate(90deg)"}}else $()},l.appendChild(s)}),e.innerHTML="",e.style.overflow="auto",e.style.padding="1.5rem",e.appendChild(l)}},{label:"ARP info",content:"",script:function(e){n||$();let s=document.createElement("ul");s.id="system-arp-command-list",l.forEach(e=>{let l=document.createElement("li");l.style.marginBottom="1rem",l.style.color="green",l.style.cursor="pointer",l.dataset.command=e,l.innerHTML=`&nbsp;${e}<nu-icon class="icon" style="margin-left:auto;width:18px;height:14px;transform:rotate(0deg)"><svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg" style="width: 18px; height: 18px;"><path d="m12.01 9.531-4.25 4.25a.747.747 0 0 1-1.06 0l-.706-.706a.747.747 0 0 1 0-1.06l3.012-3.012-3.012-3.012a.747.747 0 0 1 0-1.06l.703-.712a.747.747 0 0 1 1.06 0l4.25 4.25a.748.748 0 0 1 .002 1.062z"></path></svg></nu-icon>`,l.onclick=function(){if(t="arp_cmd1","diag"==this.innerHTML.substr(6,4)&&(t="arp_cmd2"),n){let e=this.nextSibling&&"TABLE"===this.nextSibling.nodeName?this.nextSibling:null,s=this.querySelector(".icon");if(e)"active"===e.dataset.active?(e.dataset.active="",e.style.display="none",s.style.transform="rotate(0deg)"):(e.dataset.active="active",e.style.display="block",s.style.transform="rotate(90deg)");else{i=!0;let o=l.dataset.command;a(o),r=o,s.style.transform="rotate(90deg)"}}else $()},s.appendChild(l)}),e.innerHTML="",e.style.overflow="auto",e.style.padding="1.5rem",e.appendChild(s)}}],y=document.querySelector("nu-nav-entry"),g=document.createElement("li"),_='<svg version="1.1" id="L4" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="100" viewBox="0 0 100 100" enable-background="new 0 0 0 0" xml:space="preserve"><circle fill="#555" stroke="none" cx="6" cy="50" r="6"><animate attributeName="opacity" dur="1s" values="0;1;0" repeatCount="indefinite" begin="0.1"/></circle><circle fill="#555" stroke="none" cx="26" cy="50" r="6"><animate attributeName="opacity" dur="1s" values="0;1;0" repeatCount="indefinite" begin="0.2"/></circle>circle fill="#555" stroke="none" cx="46" cy="50" r="6"><animate attributeName="opacity" dur="1s" values="0;1;0" repeatCount="indefinite" begin="0.3"/></circle></svg>';g.style.listStyle="none",g.id="tools",g.innerHTML='<div id="menu-toggle" style="color:#000;background-color:goldenrod;margin:0;padding:4px 0 1px 5px;border-left:3px solid #ffd700; display: flex;"><f-icon class="ftnt-webhook icon-lg"></f-icon>&nbsp;Tools<nu-icon class="icon" style="margin-left:auto;width:18px;height:18px;transform:rotate(90deg)"><svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg" style="width:18px;height:18px"><path d="m12.01 9.531-4.25 4.25a.747.747 0 0 1-1.06 0l-.706-.706a.747.747 0 0 1 0-1.06l3.012-3.012-3.012-3.012a.747.747 0 0 1 0-1.06l.703-.712a.747.747 0 0 1 1.06 0l4.25 4.25a.748.748 0 0 1 .002 1.062z"></path></svg></nu-icon></div>',y.before(g);let f=!0,m=document.createElement("ul");async function b(e){let t,s=document.getElementById("ng1-app").getElementsByTagName("div")[0];s.innerHTML=`<div style="position:relative;overflow-y:auto"><pre style="padding:1em;margin:0;display:flex"><code style="width:100%; display:flex; justify-content:center;">${_}</code></pre></div>`,t=e.content,m.querySelectorAll("li").forEach(e=>{e.style["background-color"]="#ffd700",e.style.color="black",e.dataset.active=""}),s.style.width="100%",s.innerHTML=`<div style="position:relative;overflow-y:auto"><pre style="padding:1em;margin:0;display:flex"><code style="width:100%; display:flex; justify-content:center;">${t??_}</code></pre></div>`,e.script?.(s)}m.style.margin=0,m.style.padding=0,p.forEach((e,t)=>{let s=document.createElement("li");s.innerText=e.label,s.style.listStyle="none",s.style.color="black",s.style.backgroundColor="#FFD700",s.style.margin=0,s.style.padding="6px 0 5px 35px",s.style.cursor="pointer",s.style.fontWeight="normal",s.onmouseover=function(){this.style["background-color"]="#FFE86D"},s.onmouseout=function(){"active"!==this.dataset.active&&(this.style["background-color"]="#FFD700"),s.onclick=async function(){this.dataset.active="active",await b(e)}},m.appendChild(s)});let x=document.querySelector("#tools #menu-toggle"),u=x.querySelector(".icon");x.after(m),x.onclick=()=>{f?(m.style.display="none",u.style.transform="rotate(0deg)",f=!1):(m.style.display="block",u.style.transform="rotate(90deg)",f=!0)}})();

Roadmap (planned):

  • ARP info  Done
  • VPN diagnostics
  • FortiGate health check / audit / security assessment
  • FortiOS v7.4 support
12 REPLIES 12
jkfortinet
Staff
Staff

This is super helpful, can't wait to see what else is coming.

torenhof
New Contributor III

Very useful tool, keep up the good work!

torenhof
New Contributor III

hi Danny,

 

Maybe a good possible feature to add is if you are able to see the 'critical' system events for the last 7 days or so. System degradation etc. can sometimes show some hints/clues over there.

 

Thanks

Dannу
New Contributor III

@torenhof : The FortiGate WebUI let's you filter for critical system events under Log & Report:
image.png

torenhof
New Contributor III

@Dannу, you're right, it's already there, overlooked that.

I'll be thinking of something else that could be useful, thx.

mgoswami
Staff
Staff

This will be very helpful. Thanks!

yusif_hasanzada
New Contributor

Helpful feature. Thanks Danny!

JoeTorres
New Contributor

Very Useful Tool. Amazing!!!

El_Craic
New Contributor

Nice work Danny, helpful tool to have, great job! Eoin