Three classes of silent-failure bugs were leaving Web UI actions in
limbo without telling the operator:
1. record_add / record_delete:
- The file was already mutated + serial bumped before named-checkzone
ran. If checkzone failed, the user saw an error flash but the
half-applied record was on disk + serial had advanced. Re-running
would create duplicates.
- bind_reload() return value was discarded, so an rndc SERVFAIL was
silently logged as '添加成功'.
2. zone_create / zone_delete:
- Same bind_reload() silent-discard bug.
3. config_options_save / config_upstream_save:
- 'named-checkconf /tmp/named_check.tmp' treated the tmp file as
the master config, which refuses options-only directives
(0.0.0.0 / dnssec-validation / listen-on-v6) at the top level →
false-positive 'unknown option' validation failures that left
the user unable to save any options change.
- Auto-wrap logic re-wrapped already-valid options blocks, creating
'options { options { ... }; };' which named-checkconf rejected.
- No rollback: failures left the live file in whatever state the
tmp had mutated it to.
Fixes:
- append_record_to_file / delete_record_from_file now return the
original content; callers pass it to rollback_zone_file() on
checkzone failure.
- record_delete now runs named-checkzone (was missing entirely).
- All four write paths (record add/delete, zone create/delete)
surface rndc reload failures instead of always flashing '成功'.
- config_options_save and config_upstream_save now validate via
'named-checkconf' (whole config) after writing BIND_CONF_OPTIONS,
with .bak-based rollback on failure — no more /tmp/tmpfile tricks.
Verified end-to-end on prod: bad named.conf.options content triggers
HTTP 302 + '已恢复备份' flash, live file untouched, named-checkconf
remains OK; good content saves + reloads cleanly.
- Flask + SQLite web app with user authentication
- Zone management: create/delete zones, edit raw zone files
- Record management: add/delete A/AAAA/CNAME/MX/TXT/NS/PTR/SRV/CAA records
- Service control: start/stop/restart/reload BIND via systemctl/rndc
- Configuration editor: edit named.conf.options/local with syntax validation
- DNS query testing: online dig tool
- Audit log: all operations logged with user/timestamp
- BIND9 backend, listening on port 53