Comment for more tool ideas!
Let's extend the FortiGate WebUI
Tested on FortiOS v7.0, 7.2
Installation:
Result:
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> NONE<span>'),p=p.replace("00000001",'<span title="First ARP request sent"><f-icon class="fa-connected"></f-icon> INCOMPLETE</span>'),p=p.replace("00000002",'<span title="ARP response is received"><f-icon class="fa-connected"></f-icon> REACHABLE</span>'),p=p.replace("00000004",'<span title="ARP response is not received within expected time"><f-icon class="fa-custom-action"></f-icon> STALE</span>'),p=p.replace("00000008",'<span title="Schedule ARP request"><f-icon class="fa-clock-plus"></f-icon> 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> 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> FAILED</span>'),p=p.replace("00000040",'<span title="Device does not support ARP e.g. IPsec Interface"><f-icon class="fa-dismiss"></f-icon> 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> <span style="color:silver">Disabled</span>'),b=b.replace(/[nN]ot [aV]vailable/g,'<f-icon class="fa-disabled"></f-icon> <span style="color:silver">Not available</span>'),b=b.replace(/[eE]nable/g,'<f-icon class="fa-enabled"></f-icon> <span>Enabled</span>'),b=b.replace(/[cC]ertified/g,'<f-icon class="fa-enabled"></f-icon> <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=` ${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=` ${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> 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):
This is super helpful, can't wait to see what else is coming.
Very useful tool, keep up the good work!
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
Created on 05-02-2023 06:35 AM Edited on 05-02-2023 06:35 AM
@torenhof : The FortiGate WebUI let's you filter for critical system events under Log & Report:
@Dannу, you're right, it's already there, overlooked that.
I'll be thinking of something else that could be useful, thx.
This will be very helpful. Thanks!
Helpful feature. Thanks Danny!
Very Useful Tool. Amazing!!!
Nice work Danny, helpful tool to have, great job! Eoin
The Fortinet Security Fabric brings together the concepts of convergence and consolidation to provide comprehensive cybersecurity protection for all users, devices, and applications and across all network edges.
Copyright 2023 Fortinet, Inc. All Rights Reserved.