My problem was that I whanted to know, when devices connect and disconnect to individual lan ports on my router. This is not possible to do via scripts in /etc/hotplug.d/iface because it can only track entire bridge to lan go down or up, it does not track individual ports. I have found out, that netifd demon is populating events to ubus when this happens. It is possible to create a lua script that will subscribe to such events. Before you can do that, you need to install lua itself and packages libubus-lua, libubox-lua. After that you need to create file subscriber.lua with following content:
#!/usr/bin/env lua
require "ubus"
require "uloop"
uloop.init()
local conn = ubus.connect()
if not conn then
error("Failed to connect to ubus")
end
local sub = {
notify = function( msg, name )
print("name:", name)
print(" port name:", msg["name"])
print(" auth_status:", msg["auth_status"])
print(" present:", msg["present"])
print(" active:", msg["active"])
print(" link_active:", msg["link_active"])
end,
}
conn:subscribe( "network.device", sub )
uloop.run()
You can run it like this lua subscriber.lua and the output will be something like this:
#!/usr/bin/env lua
ubus = require("ubus")
uloop = require("uloop")
log = require("posix.syslog")
socket = require("socket")
smtp = require("socket.smtp")
ssl = require("ssl")
function info(msg)
log.syslog(log.LOG_INFO, "NAS Monitor: " .. msg)
end
function error(msg)
log.syslog(log.LOG_ERROR, "NAS Monitor: " .. msg)
end
function sslCreate()
local sock = socket.tcp()
return setmetatable({
connect = function(_, host, port)
local r, e = sock:connect(host, port)
if not r then
return r, e
end
sock = ssl.wrap(sock, {mode = 'client', protocol = 'tlsv1_2'})
return sock:dohandshake()
end
}, {
__index = function(t, n)
return function(_, ...)
return sock[n](sock, ...)
end
end
})
end
function sendMessage(status, text)
from = "<iot@example.com>"
rcpt = "<admin@example.com>"
messageText = {
headers = {
to = "Admin " .. rcpt,
from = "Router " .. from,
subject = "NAS is " .. status
},
body = text
}
local ok, err = smtp.send {
from = from,
rcpt = rcpt,
source = smtp.message(messageText),
user = 'iot@example.com',
password = 'change_me',
server = 'smtp.example.com',
port = 465,
create = sslCreate
}
if not ok then
error("Mail send failed " .. err)
else
info("Mail \"NAS is " .. status .. "\" was sent")
end
end
info("Startup")
uloop.init()
local conn = ubus.connect()
if not conn then
error("Failed to connect to ubus")
end
local lastSeen = os.time()
local notificationTimeout = 40
local sub = {
notify = function( msg, name )
if (msg["name"] == "lan3") and (os.time() - lastSeen > notificationTimeout) then
lastSeen = os.time()
if name == "link_down" then
sendMessage("Down", "NAS server on lan3 is down, probably because of power outage");
else
sendMessage("Up", "NAS server on lan3 is back online");
end
end
end
}
conn:subscribe("network.device", sub)
uloop.run()
Additional required packages are: luaposix, luasocket and luasec.