IPFire uses a Python script located at /usr/lib/python2.7/site-packages/ddns/providers.py to handle interfacing with many of the dynamic DNS providers that the project supports. The script and the web UI from which it’s normally launched try to provide as generic of an interface as possible for the administrator of the firewall to input the DDNS configuration stuffs. Getting it right for your particular provider can take several attempts as some DDNS providers expect a username and password in the request, some just a password, yet others may expect some weird combination of the username and password into an obfuscated string in either the username or password field. Unfortunately, IPFire will only attempt to update a record twice (from what I can tell in the logs) before marking it as “failed” and then preventing any further attempts for 16 hours. My guess is that this is to prevent you from potentially inundating your DDNS provider with failed update attempts.
Sep 16 19:55:00 myipfire ddns: An update has not been performed because earlier updates failed for my-broken-site.net Sep 16 19:55:00 myipfire ddns: Last failure message: Sep 16 19:55:00 myipfire ddns: DDNSRequestError: Request error Sep 16 19:55:00 myipfire ddns: Further updates will be withheld until 2015-09-17 11:55:00.086977
The fact that the script was able to track state immediately tipped me off to the presence of a state file in the form of either a CSV file or a SQLite database. Since only a masochist would want to track state in a CSV file, I assumed SQLite was in play. Tracking down the SQLite database in question took me a few minutes as I’m not particularly fluent in Python and IPFire doesn’t ship with
strace. In hindsight, I could have used
lsof to assist me. At any rate, the SQLite database is located at
There were only 2 tables in the database: “settings” and “updates”:
# sqlite3 /var/lib/ddns.db SQLite version 18.104.22.168 2014-12-09 01:34:36 Enter ".help" for usage hints. sqlite> .tables settings updates
And after examining the schema, I knew “updates” was my target:
sqlite> .schema updates CREATE TABLE updates ( hostname TEXT NOT NULL, status TEXT NOT NULL, message TEXT, timestamp timestamp NOT NULL ); CREATE INDEX idx_updates_hostname ON updates(hostname);
Some success, some failure
sqlite> SELECT * FROM updates; my-site.org|success||2015-09-17 00:52:56.718985 my-other-site.com|success||2015-09-17 00:52:56.718985 my-broken-site.net|failure|DDNSUpdateError: The update could not be performed|2015-09-17 11:55:00.086977
Breaking the chains
sqlite> DELETE FROM updates WHERE status = 'failure'; sqlite> .quit
Now go back into the web UI: “Services” -> “Dynamic DNS” and click “Instant Update”.