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 > ARP 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 flush
  • ARP delete selected entries
  • table sort
  • FortiOS v7.4 support
5 REPLIES 5
parteeksharma

Hi Danny,
Thankyou for sharing the information!!!

Regards,
Parteek

jkfortinet
Staff
Staff

Another great tool, keep them coming!!!

Sabin_Shahi
New Contributor

Hi Danny,

 

It will be a great tool for troubleshooting.

Thanks


Regards

Sabin

Sabin
YannicS
New Contributor II

Great tool!
Does this also work with FortiOS 7.4?

martinsd
Staff
Staff

Hey Danny,

 

I find myself using this almost everyday, even in v7.4.0. Thank you very much for sharing your script.

 

Regards,

Diogo Martins