Anatomy of the DLZ transaction issue in Bind9
The call flow for a Dynamic DNS update to a Bind 9 DLZ module is:
- add/subtract records
- closeversion (commit flag)
which maps nicely to a database transaction; new version starts the transaction and has a user supplied ‘version’ parameter, in which you can pass a structure to identify the db connection in use.
Adds/subtracts have the same ‘version’ parameter, so get processed with the same db connection that started the transaction, so integrity is fine.
When closeversion is called, the ‘version' parameter is again available, and can be used to call ‘ROLLBACK’ or ‘COMMIT’ as appropriate.
The problem is the following:
- transaction gets started
- the delete is processed within the scope of the transaction
- the ‘add’ is processed but the add_rr_prepare_action function calls a DNS lookup outside of the scope of the transaction, so the database record still exists as the transaction is still open.
- The ‘add_rr_prepare_action’ function assumes it can silently ignore the add as the record exists.
- The commit then happens, and the ‘delete’ is now applied to the database.
End result, is that the new ‘A’ record is not added during the update request.
What this looks like in reality,
- The ‘A’ record is added first time through (when the database doesn't have a record for the client).
- When the client renews it’s lease, the DDNS update removes the ‘A’ record, only leaving the ‘TXT’ record behind.
- next time it renews, the ‘A’ record is added again;
- next time it renews, it’s deleted...
Repeat until you bash your head against a wall as sometimes you can
resolve your IP address, sometimes you can’t…
We have submitted patches to ISC to allow the ‘versionp’ structure to be visible through the ‘clientinfo’, which is passed to dlz_lookup.
This means that DLZ authors can take the option of picking up that variable to let you query against the right version of the database.
We are guessing that anyone else that’s played with DLZ and DDNS has
either just applied changes to the DB directly and then tracked
those changes should they need to be rolled back; or maybe nobody
has really played with DLZ, DDNS and implemented the transactions