I would like to share a script that I wrote for logging WireGuard peers connect/disconnect events. Due to the nature of WG protocol, there is no logon or logoff events as such. However, the peers constantly perform handshakes and keep track of the time since the last handshake took place.
This makes it possible to determine if a peer is in the “connected” state, meaning the handshake was done recently. The protocol defines 180 seconds as the maximum time before a peer is considered “disconnected”.
Comparing this current peer state information with the previous state from one or several seconds ago, it is possible to detect the state changes like connected=>disconnected or disconnected=>connected. The disconnect event is not extremely precise since 3 minutes must pass before a peer is declared disconnected. Still, it is precise enough for logging purposes.
My script accomplishes everything described above. The only requirement is that the WireGuard peer names are unique. You need to add this script to System - Scripts and then schedule it to run every X seconds in System - Scheduler. How often you want to run it depends on how precise you want the logging (mostly applies to the connect events precision). It’s not a heavy script and can be run every second if needed.
Example:
Tested on RouterOS 7.19.
# Peer names must be unique.
:global wgpeers
/interface/wireguard/peers
:foreach p in=[find] do={
:local name [get $p name]
:local ip [get $p current-endpoint-address]
:local last [:tonsec [get $p last-handshake]]
# WG session is 180s max.
:if ($last > 180000000000 or [:len $last] = 0) do={
# The peer is disconnected (false). If changed from connected:
:if ([:typeof ($wgpeers->$name)] = "bool" and ($wgpeers->$name) = true) do={
:log info "WireGuard peer $name disconnected"
}
:set ($wgpeers->$name) false
} else {
# The peer is connected (true). If changed from disconnected:
:local connmsg "WireGuard peer $name connected from IP $ip"
:if ([:typeof ($wgpeers->$name)] = "bool" and ($wgpeers->$name) = false) do={
:log info $connmsg
}
:if ([:typeof ($wgpeers->$name)] != "bool") do={
:log info ($connmsg . " (previous state was not stored)")
}
:set ($wgpeers->$name) true
}
}