[Dnsmasq-discuss] Scripting with lua
Geert Stappers
stappers at stappers.nl
Wed May 15 05:25:04 UTC 2024
On Tue, May 14, 2024 at 10:09:12PM +0100, White, Phil via Dnsmasq-discuss wrote:
> Hi All,
>
> Feeling inquisitive about the options --dhcp-luascript, script-arp,
> and script-on-renewal, I've been exploring what possibilities this
> brings. Knowing absolutely nothing about lua, I have pulled together a
> simple logging script that works -- but I've run up against a problem
> in accessing the stored variables. Therefore, this is probably more of
> a query about lua than it is about dnsmasq.
>
> The man page states that the environment inherits a number of
> variables (example: DNSMASQ_TAGS) which I am trying to retrieve -- but
> my current approach is returning nil (eg. tags =
> os.getenv("DNSMASQ_TAGS"))
>
> Questions:
> * How can I retrieve the contents of the DNSMASQ_ variables (if set)
> * Does the dnsmasq log the return status if there is an error?
> * and (tentatively / hypothetically), could the actions taken by
> dnsmasq in granting/renewing a lease be modified following the results
> of running the lua script? For example, if the lua script modified the
> DNSMASQ_TAGS variable.
>
> Note: This is NOT a feature request -- purely thinking about what
> might be possible...
>
> I've uploaded my current test script to:
> https://github.com/whitepj/dnsmasq-lua if this makes anything clearer.
I've followed that URL and had to click deeper.
Now sharing the output of
$ curl --silent https://raw.githubusercontent.com/whitepj/dnsmasq-lua/main/dhcp.lua
--[[
LUA script for dnsmasq DHCP leases. Modified from original source at:
http://lists.thekelleys.org/pipermail/dnsmasq-discuss/2012q1/005425.html
This script is principally a boilerplate example, to show what is possible...
Tested using dnsmasq v2.90
Run when:
- Startup (existing leases are invoked with 'old' event
- SIGHUP ?
- dhcp lease created, renewed, changed, or destroyed.
- tftp file transfer completes (not tested)
WHY?
====
Gives us another way to monitor dhcp leases.
ENVIRONMENT VARIABLES
=====================
- DNSMASQ_DOMAIN
- DNSMASQ_SUPPLIED_HOSTNAME
- DNSMASQ_USER_CLASS0 ... _CLASSn
- DNSMASQ_LEASE_LENGTH / DNSMASQ_LEASE_EXPIRES
- DNSMASQ_TIME_REMAINING
- DNSMASQ_DATA_MISSING
- DNSMASQ_INTERFACE
- DNSMASQ_RELAY_ADDRESS
- DNSMASQ_TAGS
- DNSMASQ_REQUESTED_OPTIONS
- DNSMASQ_MUD_URL
- IPv4 Only
- DNSMASQ_CLIENT_ID
- DNSMASQ_CIRCUIT_ID
- DNSMASQ_SUBSCRIBER_ID
- DNSMASQ_REMOTE_ID
- DNSMASQ_VENDOR_CLASS
- IPv6 Only
- DNSMASQ_VENDOR_CLASS_ID
- DNSMASQ_VENDOR_CLASS0 ... _CLASSn
- DNSMASQ_SERVER_DUID
- DNSMASQ_IAID
- DNSMASQ_MAC
FUNCTIONS & ARGUMENTS
=====================
- init
- shutdown
- lease
- add
- old
- del
- arp
- arp-add
- arp-del
- relay-snoop ??? or is this relay(arg), where arg='snoop'?
- tftp ??? not yet tested
dnsmasq CONFIGURATION
=====================
dhcp-scriptuser = WHATEVER
dhcp-luascript = /usr/local/etc/dnsmasq.d/THIS_SCRIPT.lua
script-on-renewal
script-arp
--]]
DBI = require "DBI" -- The ONLY external dependency. On gentoo, use emerge dev-lua/luadbi (or use luarocks)
-- Variable Declarations
counter = 0
file = nil -- writing to a normal file
dbh = nil -- our database connection
dbinsert = nil -- preprepared call to write to a database
local function myenv() -- For testing. How do we retrieve the contents of the environment variables?
a = (os.getenv("DNSMASQ_TIME_REMAINING") or "blank") -- Help. Always blank.
return a
end
local function myerrorhandler(err)
print("ERROR: " .. err)
end
function init(a)
a = (a or "------------------------------\n")
-- MOST of this function will need to be deleted or commented out, depending on what functionality is required.
local ok, err, code = os.rename("/tmp/ilua.db","/tmp/ilua.db")
if not ok then
if code == 13 then
print("DB File exists, but we can't open it! Please fix (or delete).")
os.exit()
else
print("No DB file found. Creating...")
os.execute('sqlite3 --line /tmp/ilua.db "CREATE TABLE table1(\"a\");"')
end
end
print(a .. "Starting dnsmasq lua script...\n==============================\n")
file = assert(io.open("/tmp/test.log", "a+"))
-- dbh = assert(DBI.Connect('PostgreSQL', 'db', 'user', 'password' )) -- Alternative
dbh = assert(DBI.Connect('SQLite3','/tmp/ilua.db'))
dbh:autocommit(true)
-- dbinsert = assert(dbh:prepare('INSERT INTO table1(a) values ($1)')) -- PostgreSQL
end
local function output(mystring)
print(mystring) -- In production, I see little point in this. Left for testing.
file:write(mystring) -- We write our data to a standard file...
file:flush()
DBI.Do(dbh, "INSERT INTO table1(a) VALUES ('" .. mystring .. "');") -- ... or a SQLite3 file ...
-- dbinsert:execute(mystring) -- ... or a database (if using postgreSQL)
-- See: http:jpmens.net/2013/10/21/tracking-dhcp-leases-with-dnsmasq/
local cmd = 'mosquitto_pub -h 192.168.1.2 -t "' .. "topic" .. '" -m "' .. "payload" .. '" -r'
print(cmd .. "\n") -- Edit, and change 'print' to 'os.execute'
-- What else might we like to do?
-- Possibly look at a hook for collectd.
end
function shutdown()
file:write("Stopping dnsmasq lua script..!\n==============================\n")
file:close()
-- dbinsert:close() -- only needed if we have a prepared SQL insert function.
dbh:close()
end
local function tabletostring(table)
local k,v
local line = ""
for k,v in pairs(table) do line = line .. "\n" .. k .. " = " .. v end
return line
end
function lease(action, lease_desc)
counter = counter + 1
-- status = xpcall(myenv, myerrorhandler)
-- print(status)
local line = "Lua: " .. counter .. " " .. action .. " "
for k,v in pairs(lease_desc) do line = line .. "\n" .. k .. " " .. v end
line = line .. "\n"
output(line)
end
function arp(a, b, c) -- expected, but not tested: Action (string), Args (table)
--b = type(b)
c = type(c)
local line = "-- arp " .. a .. " / " .. tabletostring(b) .. "\n" .. c .. "\n"
output(line)
end
function tftp(a, b, c) -- expected, but not tested: Action, table{destination addr, file name, file size}
a = (a or '-')
b = type(b)
c = type(c)
line = "-- tftp " .. a .. " / " .. b .. " / " .. c .. "\n"
output(line)
end
-- Exit Codes: Does dnsmask log these anywhere?
-- 0: Success
-- 1: Configuration problem
-- 2: Network access problem
-- 3: Filesystem error (missing dir/file, incorrect permissions)
-- 4: Memory allocation failure
-- 5: Other (miscellaneous) problem
--[[
-- Used only for testing. REMOVE the third hyphen above when calling via dnsmasq.
table = {}
table["Example"] = "NOT accurate representation of data in real life!"
table["domain"] = "test.com"
table["hostname"] = "laptop"
table["mac_address"] = "01:23:45:67:89:ab"
table["ip_address"] = "192.168.1.14"
init()
lease("old", table)
lease("add", table)
lease("del", table)
arp("arp-add", table)
arp("arp-del", table)
--tftp("test")
-- no other calls seen in a working environment. this appears to be the lot.
shutdown()
--]]
--[[ Ideas
lua-cjson vs luajson
luasocket
toluapp
What's in the DB?
IP / Lease status / Start / End / MAC / DNS Name / WINS name
Subnet / Router
--]]
--[[
+-----+-----+-----------------+
| arp | lease |
+-----+-----+-----+-----+-----+
| add | old | add | old | del |
================+=====+=====+=====+=====+=====+=====+
mac_address | y | y | y | y | y |
client_address | y | y | | | | Either IPv4 addr or ?IPv6? address
client_id | | | * | * | * | derived from MAC addr. Not always present
lease_expires | | | y | y | y |
time_remaining | | | y | y | | If present, always '3600.0'
ip_address | | | y | y | y |
hostname | | | y | y | y |
domain | | | y | y | y |
interface | | | y | y | |
data_missing | | | y | y | | if present, always '1.0'
| | | | | |
----------------+-----+-----+-----+-----+-----+-----+
--]]
> Many thanks,
> Phil
Groeten
Geert Stappers
--
Silence is hard to parse
More information about the Dnsmasq-discuss
mailing list