dnsmasq options: dhcp-optsdir, key-only-or-value semantics, capability detection

- Add dhcp-optsdir support (model, sections, parser, UI multi-value).
- Model leasequery, connmark-allowlist-enable, dhcp-generate-names, dhcp-broadcast,
  bootp-dynamic, dnssec-check-unsigned as key-only-or-value with validation.
- Parse compile-time capabilities from dnsmasq --version (DHCP, TFTP, DNSSEC, DBus).
- Expose capabilities via DnsmasqVersionInfo and status API (DnsmasqSupports*).
- Map options to required features; disable unsupported option editors with badge + tooltip.
- Save guard: reject changes for unsupported options; use UnsupportedCapabilities error code.
- MultiKeyOnlyOrValue write path: filter out readonly values to avoid duplicating in managed file.
- User-friendly tooltips for disabled options; dedicated UnsupportedCapabilities vs WriteFailed.
This commit is contained in:
2026-03-10 02:23:14 +10:00
parent 4c1c19b792
commit 214d6c686e
38 changed files with 970 additions and 91 deletions
@@ -1,3 +1,4 @@
using DnsmasqWebUI.Infrastructure.Helpers.Config;
using DnsmasqWebUI.Infrastructure.Services.Dnsmasq.Config.Abstractions;
using DnsmasqWebUI.Infrastructure.Services.Dnsmasq.Reload.Abstractions;
using DnsmasqWebUI.Infrastructure.Services.Dnsmasq.Validation.Abstractions;
@@ -94,6 +95,38 @@ public sealed class EffectiveConfigSaveService : IEffectiveConfigSaveService
var managedPath = set.ManagedFilePath!;
var backupPath = BuildBackupPath(managedPath);
// Reject changes for options not supported by this dnsmasq build (e.g. DNSSEC when built without DNSSEC).
var unsupported = changes
.Where(c => !EffectiveConfigFeatureRequirements.IsSupportedByCapabilities(c.OptionName, version.Capabilities))
.Select(c => c.OptionName)
.Distinct(StringComparer.Ordinal)
.ToList();
if (unsupported.Count > 0)
{
var firstReason = EffectiveConfigFeatureRequirements.GetRequiredFeature(unsupported[0]) is { } f
? EffectiveConfigFeatureRequirements.GetUnsupportedReason(f)
: "This option isn't available with your current dnsmasq build.";
var optionList = string.Join(", ", unsupported);
_logger.LogWarning("Save rejected: unsupported options in pending changes: {Options}", optionList);
var userMessage = unsupported.Count == 1
? firstReason
: $"Some of the options you changed aren't supported by your dnsmasq build. Options not saved: {optionList}.";
return new EffectiveConfigSaveResult(
BackupCreated: false,
BackupPath: null,
Saved: false,
Validated: false,
ValidationExitCode: -1,
ValidationStdOut: null,
ValidationStdErr: null,
Restarted: false,
RestartExitCode: -1,
RestartStdOut: null,
RestartStdErr: null,
ErrorCode: EffectiveConfigSaveResult.ErrorCodes.UnsupportedCapabilities,
UserMessage: userMessage);
}
try
{
CreateBackupIfSourceExists(managedPath, backupPath);