Files
mucas-central/mikrotik/arp-monitor.rsc

145 lines
5.4 KiB
Plaintext

# ARP Table Monitor Script for MikroTik RouterOS
# This script monitors ARP table and sends REST API notifications for new MAC+IP combinations
# Configuration variables
:local apiEndpoint "http://10.10.10.6:8500/mikrotik-389210-instant"
:local monitorInterfaces {"vlan-guest"; "vlan-iot"; "vlan-home"}
# Create global variable to store known MAC+IP combinations if it doesn't exist
:global arpKnownDevices
:if ([:typeof $arpKnownDevices] = "nothing") do={
:set arpKnownDevices [:toarray ""]
}
# Uncomment while testing, comment for production
# :set arpKnownDevices [:toarray ""]
# Get current ARP entries
:local currentArpEntries [:toarray ""]
:local arpEntries
# Get ARP entries - filter by interface if specified
:if ([:len $monitorInterfaces] > 0) do={
:set arpEntries [:toarray ""]
:foreach iface in=$monitorInterfaces do={
:do {
:local ifaceEntries [/ip arp find interface=$iface]
:foreach entry in=$ifaceEntries do={
:if ([:len $arpEntries] = 0) do={
:set arpEntries $entry
} else={
:set arpEntries ($arpEntries, $entry)
}
}
} on-error={
:log warning "Could not access interface: $iface"
}
}
:if ([:len $arpEntries] > 0) do={
:set arpEntries [:toarray $arpEntries]
}
} else={
# Monitor all interfaces
:set arpEntries [/ip arp find]
}
# Check for new MAC+IP combinations
:local newDevicesFound false
:local requestBody ""
:if ([:len $arpEntries] > 0) do={
:foreach arpEntry in=$arpEntries do={
:local arpInfo [/ip arp get $arpEntry]
# Skip incomplete, invalid, or dynamic entries if desired
:local arpStatus ($arpInfo->"status")
:if ($arpStatus = "reachable" || $arpStatus = "stale" || $arpStatus = "delay") do={
:local macAddress ($arpInfo->"mac-address")
:local ipAddress ($arpInfo->"address")
:local interface ($arpInfo->"interface")
# Create unique identifier for MAC+IP combination
:local deviceId ($macAddress . "-" . $ipAddress)
# Check if this MAC+IP combination is already known
:local isKnown false
:if ([:len $arpKnownDevices] > 0) do={
:if ([:find $arpKnownDevices $deviceId] >= 0) do={
:set isKnown true
}
}
# If not known, process as new device
:if (!$isKnown) do={
:set newDevicesFound true
# Get additional info
:local arpComment ""
:if ([:typeof ($arpInfo->"comment")] != "nothing") do={
:set arpComment ($arpInfo->"comment")
} else={
:set arpComment "N/A"
}
# Try to get hostname from DHCP lease table (if available)
:local hostname "Unknown"
:do {
:local dhcpLease [/ip dhcp-server lease find address=$ipAddress]
:if ([:len $dhcpLease] > 0) do={
:local leaseInfo [/ip dhcp-server lease get [:pick $dhcpLease 0]]
:if ([:typeof ($leaseInfo->"host-name")] != "nothing") do={
:set hostname ($leaseInfo->"host-name")
}
}
} on-error={
# DHCP lookup failed, keep hostname as "Unknown"
}
# Build notification body
:set requestBody ($requestBody . "MAC+IP Address: " . $deviceId . "\n")
:set requestBody ($requestBody . "Interface: " . $interface . "\n")
:set requestBody ($requestBody . "ARP Status: " . $arpStatus . "\n")
:set requestBody ($requestBody . "Hostname: " . $hostname . "\n")
:set requestBody ($requestBody . "----------------------------------------\n")
# Add to known devices
:if ([:len $arpKnownDevices] = 0) do={
:set arpKnownDevices $deviceId
} else={
:set arpKnownDevices ($arpKnownDevices . "," . $deviceId)
}
:log info "New ARP entry detected: $macAddress at $ipAddress on $interface"
}
}
}
}
# Send REST API notification for new devices
:if ($newDevicesFound) do={
:do {
/tool fetch \
url=$apiEndpoint \
http-method=post \
http-header-field="Priority: 3,Title: New device detected in network,Tags: warning" \
http-data=$requestBody \
keep-result=no
:log info "ARP monitoring notification API request sent"
} on-error={
:log error "Failed to send ARP monitoring notification API request"
}
} else={
:log info "No new mac/ip combinations in ARP"
}
# Clean up known devices list if it gets too large
:local knownCount 0
:if ([:len $arpKnownDevices] > 0) do={
:set knownCount [:len [:toarray $arpKnownDevices]]
}
:if ($knownCount > 2000) do={
:log warning "Known ARP devices list is getting large ($knownCount entries), consider resetting it"
# Uncomment the next line to auto-reset when list gets too large
# :global arpKnownDevices ""
}