Files
Mikrotik-arpwatch/arpwatch.rsc
T
Evgeny 264f05d503 first
2025-12-15 06:13:59 +03:00

112 lines
3.5 KiB
Plaintext

# ARPWATCH — simple & reliable version with per-MAC files in "arpwatch" folder
:local folder "arpwatch"
:local dbFile ($folder . "/arpwatch.csv")
:local sendTo "svetloe@koronovonoe-pivo.ru"
:local emailSubjectPrefix "ARPWatch"
:local date [/system clock get date]
:local time [/system clock get time]
:local now ($date . " " . $time)
:log info ("arpwatch: starting run at " . $now)
# Ensure folder exists
:if ([:len [/file find name=$folder]] = 0) do={
/file make-directory $folder
:log info ("arpwatch: created folder " . $folder)
}
# Ensure CSV exists
:if ([:len [/file find name=$dbFile]] = 0) do={
/file add name=$dbFile contents="mac,ip,first_seen,vendor"
:log info ("arpwatch: created database file " . $dbFile)
}
# Read current CSV for in-memory append
:local oldCSV [/file get [/file find name=$dbFile] contents]
# Buffers/counters
:local newRows ""
:local newCount 0
:local arpCount 0
# Count ARP entries
:foreach id in=[/ip arp find] do={ :set arpCount ($arpCount + 1) }
:log info ("arpwatch: ARP entries found: " . $arpCount)
# Iterate through ARP table
:foreach id in=[/ip arp find] do={
:local mac [/ip arp get $id mac-address]
:local ip [/ip arp get $id address]
:local iface [/ip arp get $id interface]
# Skip empty
:if ([:len $mac] = 0) do={
:log info ("arpwatch: skipping, empty MAC (iface=" . $iface . " ip=" . $ip . ")")
} else={
:if ([:len $ip] = 0) do={
:log info ("arpwatch: skipping, empty IP for MAC " . $mac)
} else={
# Normalize MAC and filename
# :local mac_up [$mac]
:local macFileCore ""
:local i 0
:local maclen [:len $mac]
:for i from=0 to=($maclen - 1) do={
:local ch [:pick $mac $i ($i + 1)]
:if ($ch = ":") do={ :set macFileCore ($macFileCore . "-") } else={ :set macFileCore ($macFileCore . $ch) }
}
:local macFile ($folder . "/mac-" . $macFileCore)
:log info ("arpwatch: checking MAC " . $mac . " at " . $ip . " on " . $iface)
# Check if exists
:if ([:len [/file find name=$macFile]] > 0) do={
:log info ("arpwatch: MAC exists, skip: " . $mac)
} else={
:log info ("arpwatch: NEW MAC detected: " . $mac)
:local row ($mac . "," . $ip . "," . $now . ",https://maclookup.app/search/result?mac=" . $mac)
:if ([:len $newRows] = 0) do={ :set newRows $row } else={ :set newRows ($newRows . "\n" . $row) }
:set oldCSV ($oldCSV . "\n" . $row)
/file add name=$macFile contents=$now
:set newCount ($newCount + 1)
}
}
}
}
:log info ("arpwatch: new MAC count = " . $newCount)
# Update CSV and send mail
:if ($newCount > 0) do={
:do {
/file set [/file find name=$dbFile] contents=$oldCSV
:log info ("arpwatch: database updated, appended " . $newCount . " new row(s)")
} on-error={
:log error "arpwatch: failed to update CSV"
}
:local subject ($emailSubjectPrefix . " - " . $newCount . " new MAC(s)")
:local body ("New MAC addresses detected at " . $now . ":\n\n" . $newRows . "\n\nDatabase: " . $dbFile)
:do {
/tool e-mail send to=$sendTo subject=$subject body=$body
:log info ("arpwatch: e-mail sent to " . $sendTo)
} on-error={
:log error "arpwatch: failed to send e-mail"
}
} else={
:log info "arpwatch: no new MACs found, nothing to update or send"
}
:log info "arpwatch: run finished"