dnsdist: Unable to access `until` property from DynBlock
- [x] This is not a support question, I have read about opensource and will send support questions to the IRC channel, Github Discussions or the mailing list.
- [x] I have read and understood the 'out in the open' support policy
- Program: dnsdist
- Issue type: Bug report
Short description
When trying to access the until property of a DynBlock object from Lua, a userdata object is returned.
Environment
- Operating system: AlmaLinux 9
- Software version: 1.9.6
- Software source: PowerDNS EL9 repository
Steps to reproduce
- Setup dynamic blocking with a
dynblockRulesGroup() - Trigger blocking by querying dnsdist
- Try to access the
untilproperty from theDynBlockobject viagetDynamicBlocks()orgetDynamicBlocksSMT()
See below for a minimal test setup.
Expected behaviour
You should be able to obtain the epoch timestamp in seconds until the dynamic block will expire.
Actual behaviour
You get a userdata 0x7f6020024e50.
Other information
until is actually a reserved word in Lua, which makes it more difficult to access this property, i.e.: you can't do dynblock.until. Looking at pdns/dnsdistdist/dnsdist-dynblocks.cc, it seems as if until is assigned a timespec struct: https://en.cppreference.com/w/c/chrono/timespec You can access the tv_sec property on the userdata, however the data returned appears to be invalid. In my case 2336458 is returned, which is about 55 years in the past, would it have been an epoch timestamp.
dnsdist.conf
setLocal('127.0.0.1:53')
newServer({name="cf1", address="1.1.1.1"})
newServer({name="cf2", address="1.0.0.1"})
setRingBuffersSize(1000000, 100)
local dbr = dynBlockRulesGroup()
dbr:setRCodeRate(DNSRCode.NXDOMAIN, 2, 1, "Exceeded NXDomain rate", 60, DNSAction.Drop, 1)
dbr:setRCodeRate(DNSRCode.SERVFAIL, 2, 1, "Exceeded ServFail rate", 60, DNSAction.Drop, 1)
dbr:setQTypeRate(DNSQType.ANY, 2, 1, "Exceeded ANY rate", 60, DNSAction.Drop, 1)
dbr:setResponseByteRate(1024, 1, "Exceeded resp BW rate", 60, DNSAction.Drop, 512)
function maintenance()
dbr:apply()
end
perform queries
while :; do dig example.com ns @127.0.0.1; sleep .03; done
access dynamic block details
As soon as a dynamic block is triggered:
-- works, but prints 127.0.0.1/32 userdata 0x7f6020024e50
for key, details in pairs(getDynamicBlocks()) do print(key, details["until"]) end
-- fails with: invalid value (userdata)
for key, details in pairs(getDynamicBlocks()) do
print(key, table.concat({ details.action, details.blocks, tostring(details.bpf), details["until"], details.reason }, ' '))
end
-- works, but prints an invalid epoch timestamp
for key, details in pairs(getDynamicBlocks()) do
print(key, table.concat({ details.action, details.blocks, tostring(details.bpf), details["until"].tv_sec, details.reason }, ' '))
end
So it's slightly more complicated than that: your third attempt actually works! But, for performance reasons, the timestamp we are using for the dynamic block is obtained via CLOCK_MONOTONIC, and thus is a bit harder to use than a normal unix timestamp. I'm not sure how we can improve the situation, as I don't want to move away from CLOCK_MONOTONIC. I guess we could convert the value to a unix timestamp in the Lua accessor, I'll see what I can do.
Maybe it is an idea to do the same as is done with DynBlockRulesGroup:setNewBlockInsertedHook(), which actually just passes in the duration of the dynamic block in seconds? I actually found out about setNewBlockInsertedHook() later on, so I am already not depending on getDynamicBlocks() and getDynamicBlocksSMT() anymore. It does however make sense to then also provide the time when the block was inserted, if possible.
I'm not sure I understand what you mean, because the callback passed to DynBlockRulesGroup:setNewBlockInsertedHook() will be invoked right after a dynamic block has been added, so the time when the block was inserted is pretty much now, give or take a few microseconds.
I'm not sure I understand what you mean, because the callback passed to
DynBlockRulesGroup:setNewBlockInsertedHook()will be invoked right after a dynamic block has been added, so the time when the block was inserted is pretty much now, give or take a few microseconds.
What I meant was opting for replacing the until property from a DynBlock object with a duration property, just like what is being used for DynBlockRulesGroup:setNewBlockInsertedHook(). But since getDynamicBlocks() and getDynamicBlocksSMT() can be called at any time after a dynamic block becomes active, you would need the time at which the dynamic block became active for a duration property on a DynBlock to be useful. For example, an extra since property. I hope this makes more sense.
I am in no position to judge what makes most sense from a code perspective though, I'm just looking at it from a user perspective.
And thanks for taking the time to look into this. :smile:
Right, I see what you meant now, thanks! I understand the use-case, but it would require adding a new field to the internal DynBlock structure to store the initial duration, and given that we can have a huge number of dynamic blocks structures in memory at a given point I'm not sure I want to increase the size of that structure.