MAC Vendor Lookup

Find the manufacturer of any network device by its MAC address

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")
}
}