From 7a4e5c5134a2b072fe5f5e9090429b8dcca9b115 Mon Sep 17 00:00:00 2001 From: Paul Banks Date: Mon, 27 Apr 2026 20:10:20 +0200 Subject: [PATCH] Config corruption fix on Linux The write-to-temp and then rename is a valid pattern but for crash safety you should flush the file before renaming. This is a fix for observed behavior where my docker host was rebooted and then it had corrupted this file. (I fsync'd and then copied one from another cluster node to fix it.) Searched for other instances - I think I got them. --- DnsServerCore/Auth/AuthManager.cs | 1 + DnsServerCore/Cluster/ClusterManager.cs | 1 + DnsServerCore/Dhcp/DhcpServer.cs | 1 + DnsServerCore/Dns/Applications/DnsApplication.cs | 8 +++++++- DnsServerCore/Dns/DnsServer.cs | 1 + DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs | 1 + DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs | 1 + DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs | 1 + DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs | 1 + DnsServerCore/DnsWebService.cs | 1 + DnsServerCore/LogManager.cs | 1 + 11 files changed, 17 insertions(+), 1 deletion(-) diff --git a/DnsServerCore/Auth/AuthManager.cs b/DnsServerCore/Auth/AuthManager.cs index ae7023134..0494a2627 100644 --- a/DnsServerCore/Auth/AuthManager.cs +++ b/DnsServerCore/Auth/AuthManager.cs @@ -337,6 +337,7 @@ private void SaveConfigFileInternal() using (FileStream fS = new FileStream(tmpConfigFile, FileMode.Create, FileAccess.Write)) { mS.CopyTo(fS); + fS.Flush(flushToDisk: true); } } diff --git a/DnsServerCore/Cluster/ClusterManager.cs b/DnsServerCore/Cluster/ClusterManager.cs index f70d0679b..1579c1499 100644 --- a/DnsServerCore/Cluster/ClusterManager.cs +++ b/DnsServerCore/Cluster/ClusterManager.cs @@ -296,6 +296,7 @@ private void SaveConfigFileInternal() using (FileStream fS = new FileStream(tmpConfigFile, FileMode.Create, FileAccess.Write)) { mS.CopyTo(fS); + fS.Flush(flushToDisk: true); } } diff --git a/DnsServerCore/Dhcp/DhcpServer.cs b/DnsServerCore/Dhcp/DhcpServer.cs index f63e31ee7..686d1376b 100644 --- a/DnsServerCore/Dhcp/DhcpServer.cs +++ b/DnsServerCore/Dhcp/DhcpServer.cs @@ -1282,6 +1282,7 @@ private void SaveScopeFile(Scope scope) using (FileStream fS = new FileStream(tmpScopeFile, FileMode.Create, FileAccess.Write)) { mS.CopyTo(fS); + fS.Flush(flushToDisk: true); } } diff --git a/DnsServerCore/Dns/Applications/DnsApplication.cs b/DnsServerCore/Dns/Applications/DnsApplication.cs index ebc554063..c916cf567 100644 --- a/DnsServerCore/Dns/Applications/DnsApplication.cs +++ b/DnsServerCore/Dns/Applications/DnsApplication.cs @@ -243,7 +243,13 @@ public async Task SetConfigAsync(string config) { string tmpConfigFile = Path.Combine(_dnsServer.ApplicationFolder, "dnsApp.tmp"); - await File.WriteAllTextAsync(tmpConfigFile, config); + await using (FileStream fS = new FileStream(tmpConfigFile, FileMode.Create, FileAccess.Write)) + { + byte[] configBytes = System.Text.Encoding.UTF8.GetBytes(config); + await fS.WriteAsync(configBytes); + await fS.FlushAsync(); + fS.Flush(flushToDisk: true); + } File.Move(tmpConfigFile, configFile, true); } diff --git a/DnsServerCore/Dns/DnsServer.cs b/DnsServerCore/Dns/DnsServer.cs index c79a00e97..21bd48a70 100644 --- a/DnsServerCore/Dns/DnsServer.cs +++ b/DnsServerCore/Dns/DnsServer.cs @@ -619,6 +619,7 @@ internal void SaveConfigFileInternal() using (FileStream fS = new FileStream(tmpConfigFile, FileMode.Create, FileAccess.Write)) { mS.CopyTo(fS); + fS.Flush(flushToDisk: true); } } diff --git a/DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs index 295caaf56..004fc13fb 100644 --- a/DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/AllowedZoneManager.cs @@ -168,6 +168,7 @@ private void SaveZoneFileInternal() using (FileStream fS = new FileStream(tmpAllowedZoneFile, FileMode.Create, FileAccess.Write)) { WriteConfigTo(fS); + fS.Flush(flushToDisk: true); } File.Move(tmpAllowedZoneFile, allowedZoneFile, true); diff --git a/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs index 352ea6c0d..1f02c69a1 100644 --- a/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs @@ -303,6 +303,7 @@ private void SaveZoneFileInternal(string zoneName) using (FileStream fS = new FileStream(tmpZoneFile, FileMode.Create, FileAccess.Write)) { mS.CopyTo(fS); + fS.Flush(flushToDisk: true); } } diff --git a/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs index d61856491..62cf01e18 100644 --- a/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/BlockListZoneManager.cs @@ -206,6 +206,7 @@ private void SaveConfigFileInternal() using (FileStream fS = new FileStream(tmpBlockListConfigFile, FileMode.Create, FileAccess.Write)) { mS.CopyTo(fS); + fS.Flush(flushToDisk: true); } } diff --git a/DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs b/DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs index 5c64574b2..5ec10031a 100644 --- a/DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs +++ b/DnsServerCore/Dns/ZoneManagers/BlockedZoneManager.cs @@ -184,6 +184,7 @@ private void SaveZoneFileInternal() using (FileStream fS = new FileStream(tmpBlockedZoneFile, FileMode.Create, FileAccess.Write)) { WriteConfigTo(fS); + fS.Flush(flushToDisk: true); } File.Move(tmpBlockedZoneFile, blockedZoneFile, true); diff --git a/DnsServerCore/DnsWebService.cs b/DnsServerCore/DnsWebService.cs index df5ad6ca8..73d6c5d30 100644 --- a/DnsServerCore/DnsWebService.cs +++ b/DnsServerCore/DnsWebService.cs @@ -379,6 +379,7 @@ private void SaveConfigFileInternal() using (FileStream fS = new FileStream(tmpConfigFile, FileMode.Create, FileAccess.Write)) { mS.CopyTo(fS); + fS.Flush(flushToDisk: true); } } diff --git a/DnsServerCore/LogManager.cs b/DnsServerCore/LogManager.cs index 85c48f139..9810e9699 100644 --- a/DnsServerCore/LogManager.cs +++ b/DnsServerCore/LogManager.cs @@ -330,6 +330,7 @@ private void SaveConfigFileInternal() using (FileStream fS = new FileStream(tmpLogConfigFile, FileMode.Create, FileAccess.Write)) { mS.CopyTo(fS); + fS.Flush(flushToDisk: true); } }