How to get the result of dns query in lua script. #15726
-
Hi, I want to use a lua script to log the query include result into the sqlite3. The following code is generated and modified via chatgpt. But it couldn't fix the Here is the lua script I use, dnslog.lua. -- pdns-recursor/dnslog.lua
pdnslog("pdns-recursor Lua script starting!", pdns.loglevels.Warning)
-- dnslog.lua for PowerDNS Recursor
-- https://doc.powerdns.com/recursor/lua-scripting/hooks.html
function log_to_pipe(line)
local f = io.open("/var/log/pdns/dnslog.pipe", "a")
if f then f:write(line .. "\n"); f:close() end
pdnslog("[dnslog] " .. line, pdns.loglevels.Info)
end
function preresolve(dq)
pdnslog("[dnslog] preresolve called", pdns.loglevels.Info)
local event = {
os.date("!%Y-%m-%dT%H:%M:%SZ"),
dq.qname:toString(),
dq.qtype,
dq.remoteaddr:toString(),
"?",
"",
"recursor"
}
log_to_pipe(table.concat(event, "|"))
return false
end
function postresolve(dq)
pdnslog("[dnslog] postresolve called", pdns.loglevels.Info)
local answerStr = ""
local status, err = pcall(function()
for _, rec in ipairs(dq:getRecords() or {}) do
local rrtype = pdns.rrtype2string and pdns.rrtype2string(rec.qtype or 0) or tostring(rec.qtype or "?")
local content = rec.content or "[no content]"
answerStr = answerStr .. dq.qname:toString() .. " " .. rrtype .. " " .. content .. "; "
end
end)
if not status then
answerStr = "[error parsing answer: " .. tostring(err) .. "]"
pdnslog("[dnslog error] " .. answerStr, pdns.loglevels.Error)
end
local event = {
os.date("!%Y-%m-%dT%H:%M:%SZ"),
dq.qname:toString(),
dq.qtype,
dq.remoteaddr:toString(),
dq.rcode,
answerStr,
"recursor"
}
log_to_pipe(table.concat(event, "|"))
return true
end But the record in database is something like the following.
And here is the logserver.py used to pipe the result to sqlite3. # dnslog-collector/logserver.py
import sqlite3, os, time, sys
pipe_path = "/var/log/pdns/dnslog.pipe"
db_path = "/var/log/pdns/dnslog.db"
def init_db():
conn = sqlite3.connect(db_path, check_same_thread=False)
cur = conn.cursor()
cur.execute("""CREATE TABLE IF NOT EXISTS dns_logs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT,
qname TEXT,
qtype TEXT,
remote_ip TEXT,
response_code TEXT,
answer TEXT,
source TEXT
)""")
conn.commit()
return conn, cur
def wait_for_pipe(path):
while not os.path.exists(path):
print(f"Waiting for pipe {path}...")
time.sleep(1)
def main():
if not os.path.exists(pipe_path):
os.mkfifo(pipe_path)
conn, cur = init_db()
wait_for_pipe(pipe_path)
print("Logserver is running, waiting for input...")
while True:
with open(pipe_path, 'r') as pipe:
for line in pipe:
line = line.strip()
if not line:
continue
print(f"[LOG] {line}")
parts = line.split('|')
if len(parts) == 7:
try:
cur.execute("INSERT INTO dns_logs (timestamp, qname, qtype, remote_ip, response_code, answer, source) VALUES (?, ?, ?, ?, ?, ?, ?)", parts)
conn.commit()
except Exception as e:
print(f"[ERROR] Failed to insert: {e}")
else:
print(f"[WARN] Invalid line: {line}")
if __name__ == "__main__":
main() |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
I have find some solutions from https://stackoverflow.com/questions/75107667/i-want-to-use-lua-in-pdns-recursor-to-log-the-responses-answers. The updated code is: pdnslog("pdns-recursor Lua script starting!", pdns.loglevels.Warning)
-- dnslog.lua for PowerDNS Recursor
-- https://doc.powerdns.com/recursor/lua-scripting/hooks.html
function log_to_pipe(line)
local f = io.open("/var/log/pdns/dnslog.pipe", "a")
if f then f:write(line .. "\n"); f:close() end
pdnslog("[dnslog] " .. line, pdns.loglevels.Info)
end
function preresolve(dq)
pdnslog("[dnslog] preresolve called", pdns.loglevels.Info)
local event = {
os.date("!%Y-%m-%dT%H:%M:%SZ"),
dq.qname:toString(),
dq.qtype,
dq.remoteaddr:toString(),
"?",
"",
"recursor"
}
log_to_pipe(table.concat(event, "|"))
return false
end
local recordTypeStrings = {
[1] = "A",
[5] = "CNAME",
}
function postresolve(dq)
pdnslog("[dnslog] postresolve called", pdns.loglevels.Info)
local answerStr = ""
local records = dq:getRecords()
for k,v in pairs(records) do
local recordTypeString = recordTypeStrings[v.type] or tostring(v.type)
answerStr = k .. " " .. v.name:toString() .. " " .. recordTypeString .. " " .. v:getContent()
end
local event = {
os.date("!%Y-%m-%dT%H:%M:%SZ"),
dq.qname:toString(),
dq.qtype,
dq.remoteaddr:toString(),
dq.rcode,
answerStr,
"recursor"
}
log_to_pipe(table.concat(event, "|"))
return true
end
And there is a problem when using FIFO pipe, only one consumer can get the updates. |
Beta Was this translation helpful? Give feedback.
I have find some solutions from https://stackoverflow.com/questions/75107667/i-want-to-use-lua-in-pdns-recursor-to-log-the-responses-answers.
The updated code is: