Accepts full MAC or first 3 octets · any separator ( : - space ) or none
▶ Bulk / Multi-MAC Lookup
Dynamic ARP entries are read-only — comments cannot be set on them.
Use DHCP leases instead: they cover every network automatically and support comments.
For static-IP devices use the ARP scan script below.
► MikroTik — DHCP leases all networks
RouterOS 6.45+ · Winbox Terminal or /system scripts
Quick load (paste in terminal)
A — fetch & run once:
{
/tool fetch url="https://mac.techbg.net/scripts/mac-dhcp.rsc" dst-path=mac-dhcp.rsc
:delay 2
/import mac-dhcp.rsc
}
B — fetch & save as script (next time:
/system script run mac-dhcp):
{
/tool fetch url="https://mac.techbg.net/scripts/mac-dhcp.rsc" dst-path=mac-dhcp.rsc
:delay 2
:local src [/file get [/file find name="mac-dhcp.rsc"] contents]
/system script remove [/system script find name="mac-dhcp"]
/system script add name=mac-dhcp source=$src
/system script run mac-dhcp
}
# MAC Vendor Lookup -- DHCP leases (batch mode) # - ONE HTTP call for all leases (fast) # - Preserves existing comments, appends {v:Vendor} as marker # - Safe to run multiple times -- skips leases already tagged # - Covers ALL DHCP servers (all networks) in one pass # - Requires RouterOS 6.45+ with outbound HTTPS # # IMPORTANT: paste the whole block including { } into the terminal, # or add it to System -> Scripts and run from there. { :local batchBase "https://mac.techbg.net/api/batch/" :local ouiList "" :local cache "" :local count 0 # Step 1: collect unique OUIs from untagged leases :foreach lease in=[/ip dhcp-server lease find] do={ :local mac [/ip dhcp-server lease get $lease mac-address] :local current [/ip dhcp-server lease get $lease comment] :if ([:len $mac] = 17 && [:find $current "{v:"] < 0) do={ :local oui ([:pick $mac 0 2] . [:pick $mac 3 5] . [:pick $mac 6 8]) :if ([:find $ouiList $oui] < 0) do={ :if ($ouiList != "") do={ :set ouiList ($ouiList . ",") } :set ouiList ($ouiList . $oui) } } } :if ($ouiList = "") do={ :log info "mac-vendor: all leases already tagged, nothing to do." :return } # Step 2: ONE batch HTTP call for all unique OUIs :do { :local res [/tool fetch url=($batchBase . $ouiList) output=user as-value] :set cache ($res->"data") } on-error={ :log warning "mac-vendor: batch lookup failed" } # Step 3: apply vendor tags using cache :foreach lease in=[/ip dhcp-server lease find] do={ :local mac [/ip dhcp-server lease get $lease mac-address] :local current [/ip dhcp-server lease get $lease comment] :if ([:len $mac] = 17 && [:find $current "{v:"] < 0) do={ :local oui ([:pick $mac 0 2] . [:pick $mac 3 5] . [:pick $mac 6 8]) :local vendor "" :local cPos [:find $cache ($oui . "~")] :if ($cPos >= 0) do={ :local sfx [:pick $cache ($cPos + 7) [:len $cache]] :local vEnd [:find $sfx ";"] :if ($vEnd < 0) do={ :set vEnd [:len $sfx] } :set vendor [:pick $sfx 0 $vEnd] } :if ($vendor != "" && $vendor != "Unknown") do={ :local tag ("{v:" . $vendor . "}") :if ($current != "") do={ :set tag ($current . " {v:" . $vendor . "}") } /ip dhcp-server lease set $lease comment=$tag :set count ($count + 1) :log info ($mac . " = " . $tag) } } } :log info ("Done. Tagged " . $count . " leases.") }
► MikroTik — DHCP cleanup remove vendor tags
Restores comments to original state before vendor tagging
Quick load (paste in terminal)
A — fetch & run once:
{
/tool fetch url="https://mac.techbg.net/scripts/mac-cleanup.rsc" dst-path=mac-cleanup.rsc
:delay 2
/import mac-cleanup.rsc
}
B — fetch & save as script (next time:
/system script run mac-cleanup):
{
/tool fetch url="https://mac.techbg.net/scripts/mac-cleanup.rsc" dst-path=mac-cleanup.rsc
:delay 2
:local src [/file get [/file find name="mac-cleanup.rsc"] contents]
/system script remove [/system script find name="mac-cleanup"]
/system script add name=mac-cleanup source=$src
/system script run mac-cleanup
}
# DHCP Vendor Cleanup -- removes {v:...} tags added by the annotate script # - If lease had original comment: restores it (removes only our tag) # - If lease had no comment: clears it entirely # # IMPORTANT: paste the whole block including { } into the terminal, # or add it to System -> Scripts and run from there. { :local count 0 :foreach lease in=[/ip dhcp-server lease find] do={ :local comment [/ip dhcp-server lease get $lease comment] :local tagPos [:find $comment "{v:"] :if ($tagPos >= 0) do={ :local original "" :if ($tagPos > 0) do={ # Original comment existed -- restore it (strip trailing space) :set original [:pick $comment 0 ($tagPos - 1)] } /ip dhcp-server lease set $lease comment=$original :set count ($count + 1) } } :log info ("Cleanup done. Removed tags from " . $count . " leases.") }
► MikroTik — IP scan full network → log IP + MAC + Vendor
Auto-detects /24 subnets ·
/log print where topics~"script"
Quick load (paste in terminal)
A — fetch & run once:
{
/tool fetch url="https://mac.techbg.net/scripts/mac-scan.rsc" dst-path=mac-scan.rsc
:delay 2
/import mac-scan.rsc
}
B — fetch & save as script (next time:
/system script run mac-scan):
{
/tool fetch url="https://mac.techbg.net/scripts/mac-scan.rsc" dst-path=mac-scan.rsc
:delay 2
:local src [/file get [/file find name="mac-scan.rsc"] contents]
/system script remove [/system script find name="mac-scan"]
/system script add name=mac-scan source=$src
/system script run mac-scan
}
# Network ARP Scan -- logs IP | MAC | Vendor for all active hosts # Reads the live ARP table across ALL interfaces (no ping sweep needed). # Active devices appear automatically from normal network traffic. # For devices that haven't communicated recently, ping them manually first. # # View results: /log print where topics~"script" # Requires RouterOS 6.45+, outbound HTTPS to mac.techbg.net # # IMPORTANT: paste the whole block including { } into the terminal, # or add it to System -> Scripts and run from there. { :local found 0 :local ouiList "" :local cache "" :log info "===== Network Scan Start =====" # Step 1: collect unique OUIs from ARP table (all interfaces) :foreach entry in=[/ip arp find] do={ :local mac [/ip arp get $entry mac-address] :if ([:len $mac] = 17) do={ :local oui ([:pick $mac 0 2] . [:pick $mac 3 5] . [:pick $mac 6 8]) :if ([:find $ouiList $oui] < 0) do={ :if ($ouiList != "") do={ :set ouiList ($ouiList . ",") } :set ouiList ($ouiList . $oui) } } } # Step 3: ONE batch HTTP call for all unique OUIs :if ($ouiList != "") do={ :do { :local res [/tool fetch url=("https://mac.techbg.net/api/batch/" . $ouiList) output=user as-value] :set cache ($res->"data") } on-error={ :log warning "Batch vendor lookup failed" } } # Step 4: log results from cache (no more HTTP calls) :log info "IP MAC Vendor" :log info "-----------------------------------------------------" :foreach entry in=[/ip arp find] do={ :local mac [/ip arp get $entry mac-address] :local ip [/ip arp get $entry address] :local vendor "Unknown" :if ([:len $mac] = 17) do={ :local oui ([:pick $mac 0 2] . [:pick $mac 3 5] . [:pick $mac 6 8]) :local cPos [:find $cache ($oui . "~")] :if ($cPos >= 0) do={ :local sfx [:pick $cache ($cPos + 7) [:len $cache]] :local vEnd [:find $sfx ";"] :if ($vEnd < 0) do={ :set vEnd [:len $sfx] } :set vendor [:pick $sfx 0 $vEnd] } } :log info ($ip . " | " . $mac . " | " . $vendor) :set found ($found + 1) } :log info ("===== Scan done -- " . $found . " hosts =====") }
► MikroTik — ARP table current snapshot → log IP + MAC + Vendor
Edit
$scanIface · /log print where topics~"script"
Quick load (paste in terminal)
A — fetch & run once:
{
/tool fetch url="https://mac.techbg.net/scripts/mac-arp.rsc" dst-path=mac-arp.rsc
:delay 2
/import mac-arp.rsc
}
B — fetch & save as script (next time:
/system script run mac-arp):
{
/tool fetch url="https://mac.techbg.net/scripts/mac-arp.rsc" dst-path=mac-arp.rsc
:delay 2
:local src [/file get [/file find name="mac-arp.rsc"] contents]
/system script remove [/system script find name="mac-arp"]
/system script add name=mac-arp source=$src
/system script run mac-arp
}
# ARP table snapshot -- logs IP | MAC | Vendor for a single interface. # No ping sweep -- reads whatever is currently in the ARP table. # Change "bridge" to your actual interface name before running. # View results: /log print where topics~"script" # # IMPORTANT: paste the whole block including { } into the terminal, # or add it to System -> Scripts and run from there. { :local apiBase "https://mac.techbg.net/api/" :local scanIface "bridge" :local found 0 :local ouiList "" :local cache "" # Pass 1: collect unique OUIs :foreach entry in=[/ip arp find interface=$scanIface] do={ :local mac [/ip arp get $entry mac-address] :if ([:len $mac] = 17) do={ :local oui ([:pick $mac 0 2] . [:pick $mac 3 5] . [:pick $mac 6 8]) :if ([:find $ouiList $oui] < 0) do={ :if ($ouiList != "") do={ :set ouiList ($ouiList . ",") } :set ouiList ($ouiList . $oui) } } } # ONE batch HTTP call for all unique OUIs :if ($ouiList != "") do={ :do { :local res [/tool fetch url=("https://mac.techbg.net/api/batch/" . $ouiList) output=user as-value] :set cache ($res->"data") } on-error={ :log warning "Batch vendor lookup failed" } } # Pass 2: log from cache (no HTTP calls) :log info ("===== ARP Snapshot: " . $scanIface . " =====") :log info "IP MAC Vendor" :log info "-----------------------------------------------------" :foreach entry in=[/ip arp find interface=$scanIface] do={ :local mac [/ip arp get $entry mac-address] :local ip [/ip arp get $entry address] :local vendor "Unknown" :if ([:len $mac] = 17) do={ :local oui ([:pick $mac 0 2] . [:pick $mac 3 5] . [:pick $mac 6 8]) :local cPos [:find $cache ($oui . "~")] :if ($cPos >= 0) do={ :local sfx [:pick $cache ($cPos + 7) [:len $cache]] :local vEnd [:find $sfx ";"] :if ($vEnd < 0) do={ :set vEnd [:len $sfx] } :set vendor [:pick $sfx 0 $vEnd] } } :log info ($ip . " | " . $mac . " | " . $vendor) :set found ($found + 1) } :log info ("===== Done -- " . $found . " entries =====") }
► MikroTik — Static IP detector ARP ping sweep → add missing devices as static DHCP leases
All variables auto-detected · optionally override
$dhcpServer / $scanIface / $poolStart / $poolEnd
Quick load (paste in terminal)
A — fetch & run once:
{
/tool fetch url="https://mac.techbg.net/scripts/mac-static.rsc" dst-path=mac-static.rsc
:delay 2
/import file-name=mac-static.rsc
}
B — fetch & save as script (next time:
/system script run mac-static):
{
/tool fetch url="https://mac.techbg.net/scripts/mac-static.rsc" dst-path=mac-static.rsc
:delay 2
/system script add name=mac-static source=[/file get mac-static.rsc contents]
/system script run mac-static
}
{
:local srv ""
:local ifc ""
:local pS ""
:local pE ""
:local gw ""
:local bb "https://mac.techbg.net/api/batch/"
:if ($srv = "") do={
:local sl [/ip dhcp-server find]
:if ([:len $sl] = 0) do={ :log error "ms: no DHCP server"; :error "abort" }
:set srv [/ip dhcp-server get ($sl->0) name]
}
:if ($ifc = "") do={
:set ifc [/ip dhcp-server get [/ip dhcp-server find name=$srv] interface]
}
:if ($pS = "") do={
:local ia [/ip address get [/ip address find interface=$ifc] address]
:local sp [:find $ia "/"]
:set gw [:tostr [:toip [:pick $ia 0 $sp]]]
:local d1 [:find $gw "."]
:local d2 [:find $gw "." ($d1+1)]
:local d3 [:find $gw "." ($d2+1)]
:local lo [:tonum [:pick $gw ($d3+1) [:len $gw]]]
:local b [:toip $gw]
:set pS [:tostr ($b - $lo + 1)]
:set pE [:tostr ($b - $lo + 254)]
}
:if ($gw = "") do={ :set gw $pS }
:log info ("ms: " . $pS . ".." . $pE . " gw=" . $gw)
:local cur [:toip $pS]
:local end [:toip $pE]
:local gwip [:toip $gw]
:local tot [:tonum ($end - $cur + 1)]
:log info ("ms: sweep " . $tot . " addr (~2-3 min)")
:local sc $cur
:local sn 0
:local cy 0
:while ($sc <= $end) do={
:if ($sc != $gwip) do={
:local d [/ping address=$sc arp-ping=yes interface=$ifc count=1]
}
:set sn ($sn + 1)
:set sc ($sc + 1)
:if (($sn % 20) = 0) do={
:set cy ($cy + 1)
:log info ("ms: cycle " . $cy . " (" . $sn . "/" . $tot . ")")
}
}
:log info ("ms: sweep done - " . $sn . " scanned")
:local ia []
:local ma []
:local ol ""
:set sc $cur
:while ($sc <= $end) do={
:if ($sc != $gwip) do={
:if ([:len [/ip dhcp-server lease find address=$sc server=$srv]] = 0) do={
:local ae [/ip arp find address=$sc]
:if ([:len $ae] > 0) do={
:local m [/ip arp get ($ae->0) mac-address]
:if ([:len $m] = 17) do={
:if ([:len [/ip dhcp-server lease find mac-address=$m]] = 0) do={
:set ia ($ia, $sc)
:set ma ($ma, $m)
:local o ([:pick $m 0 2] . [:pick $m 3 5] . [:pick $m 6 8])
:if ([:find $ol $o] < 0) do={
:if ($ol != "") do={ :set ol ($ol . ",") }
:set ol ($ol . $o)
}
:log info ("ms: found " . $sc . " " . $m)
}
}
}
}
}
:set sc ($sc + 1)
}
:local n [:len $ia]
:if ($n = 0) do={
:log info "ms: done - nothing to add"
} else={
:local ca ""
:if ($ol != "") do={
:do {
:local r [/tool fetch url=($bb . $ol) output=user as-value]
:set ca ($r->"data")
} on-error={ :log warning "ms: vendor lookup failed" }
}
:local added 0
:for i from=0 to=($n - 1) do={
:local ip ($ia->i)
:local m ($ma->i)
:local vd "Unknown"
:local o ([:pick $m 0 2] . [:pick $m 3 5] . [:pick $m 6 8])
:local cp [:find $ca ($o . "~")]
:if ($cp >= 0) do={
:local sx [:pick $ca ($cp + 7) [:len $ca]]
:local ve [:find $sx ";"]
:if ($ve < 0) do={ :set ve [:len $sx] }
:set vd [:pick $sx 0 $ve]
}
/ip dhcp-server lease add address=$ip mac-address=$m server=$srv comment=("static {v:" . $vd . "}")
:log info ("ms: + " . $ip . " " . $m . " {v:" . $vd . "}")
:set added ($added + 1)
}
:log info ("ms: done - " . $added . " lease(s) added")
}
}