@{
var views = EffectiveConfigViews.GetViewsForContext(Context);
- var descriptorsBySection = EffectiveConfigViews.GetDescriptorsBySection(Status, views);
+ var descriptorsBySection = EffectiveConfigViews.GetDescriptorsBySection(Status, views, RenderFragmentRegistry);
var hasSearch = !string.IsNullOrWhiteSpace(_searchTerm);
var term = _searchTerm?.Trim() ?? "";
}
@@ -48,7 +51,6 @@
[Parameter] public DnsmasqServiceStatus? Status { get; set; }
[Parameter] public EffectiveConfigContext Context { get; set; } = EffectiveConfigContext.All;
[Parameter] public bool ShowSearchBox { get; set; } = true;
- ///
View = read-only; Edit = editable (future). Cascaded to field displays.
[Parameter] public EffectiveConfigDisplayMode DisplayMode { get; set; } = EffectiveConfigDisplayMode.View;
private string _searchTerm = "";
diff --git a/src/DnsmasqWebUI/Infrastructure/Helpers/Config/EffectiveConfigFieldBuilder.cs b/src/DnsmasqWebUI/Infrastructure/Helpers/Config/EffectiveConfigFieldBuilder.cs
index 71f7dae..66bc3b0 100644
--- a/src/DnsmasqWebUI/Infrastructure/Helpers/Config/EffectiveConfigFieldBuilder.cs
+++ b/src/DnsmasqWebUI/Infrastructure/Helpers/Config/EffectiveConfigFieldBuilder.cs
@@ -1,5 +1,6 @@
using DnsmasqWebUI.Models.Dnsmasq;
using DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig;
+using DnsmasqWebUI.Infrastructure.Services.Abstractions;
namespace DnsmasqWebUI.Infrastructure.Helpers.Config;
@@ -11,7 +12,7 @@ public static class EffectiveConfigFieldBuilder
private static EffectiveDnsmasqConfig? Config(DnsmasqServiceStatus? s) => s?.EffectiveConfig;
private static EffectiveConfigSources? Sources(DnsmasqServiceStatus? s) => s?.EffectiveConfigSources;
- ///
Builds getItems from config/source list selectors; used by Multi() for fields that have both.
+ ///
Builds getItems from config/source list selectors; used by AddDescriptor for multi-value fields that have both config and source lists.
private static Func
?> Items(
Func?> getValues,
Func?> getWithSource)
@@ -37,7 +38,7 @@ public static class EffectiveConfigFieldBuilder
public static string SectionCache => EffectiveConfigSections.SectionCache;
public static string SectionProcess => EffectiveConfigSections.SectionProcess;
- public static IReadOnlyList BuildFieldDescriptors(DnsmasqServiceStatus? status)
+ public static IReadOnlyList BuildFieldDescriptors(DnsmasqServiceStatus? status, IEffectiveConfigRenderFragmentRegistry? registry = null)
{
if (status == null || status.EffectiveConfig == null)
return Array.Empty();
@@ -45,142 +46,158 @@ public static class EffectiveConfigFieldBuilder
var list = new List();
// Hosts
- list.Add(Single(DnsmasqConfKeys.NoHosts, status, s => Config(s)?.NoHosts, s => Sources(s)?.NoHosts, null));
- list.Add(Multi(DnsmasqConfKeys.AddnHosts, status, s => ToValueWithSourceList(s?.AddnHostsPaths, Sources(s)?.AddnHostsPaths)));
- list.Add(Single(DnsmasqConfKeys.Hostsdir, status, s => Config(s)?.HostsdirPath, s => Sources(s)?.HostsdirPath, null));
- list.Add(Single(DnsmasqConfKeys.ReadEthers, status, s => Config(s)?.ReadEthers, s => Sources(s)?.ReadEthers, null));
+ list.AddDescriptor(registry, DnsmasqConfKeys.NoHosts, status, s => Config(s)?.NoHosts, s => Sources(s)?.NoHosts, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.AddnHosts, status, null, null, s => ToValueWithSourceList(s?.AddnHostsPaths, Sources(s)?.AddnHostsPaths));
+ list.AddDescriptor(registry, DnsmasqConfKeys.Hostsdir, status, s => Config(s)?.HostsdirPath, s => Sources(s)?.HostsdirPath, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.ReadEthers, status, s => Config(s)?.ReadEthers, s => Sources(s)?.ReadEthers, null);
// Resolver / DNS
- list.Add(Multi(DnsmasqOptionTooltips.ServerLocalLabel, status, Items(ec => ec?.ServerLocalValues, src => src?.ServerLocalValues)));
- list.Add(Multi(DnsmasqConfKeys.RevServer, status, Items(ec => ec?.RevServerValues, src => src?.RevServerValues)));
- list.Add(Multi(DnsmasqConfKeys.Address, status, Items(ec => ec?.AddressValues, src => src?.AddressValues)));
- list.Add(Multi(DnsmasqConfKeys.ResolvFile, status, Items(ec => ec?.ResolvFiles, src => src?.ResolvFiles)));
- list.Add(Single(DnsmasqConfKeys.NoResolv, status, s => Config(s)?.NoResolv, s => Sources(s)?.NoResolv, null));
- list.Add(Single(DnsmasqConfKeys.DomainNeeded, status, s => Config(s)?.DomainNeeded, s => Sources(s)?.DomainNeeded, null));
- list.Add(Single(DnsmasqConfKeys.Port, status, s => Config(s)?.Port, s => Sources(s)?.Port, null));
- list.Add(Single(DnsmasqConfKeys.LogQueries, status, s => Config(s)?.LogQueries, s => Sources(s)?.LogQueries, null));
- list.Add(Single(DnsmasqConfKeys.StrictOrder, status, s => Config(s)?.StrictOrder, s => Sources(s)?.StrictOrder, null));
- list.Add(Single(DnsmasqConfKeys.AllServers, status, s => Config(s)?.AllServers, s => Sources(s)?.AllServers, null));
- list.Add(Single(DnsmasqConfKeys.AuthTtl, status, s => Config(s)?.AuthTtl, s => Sources(s)?.AuthTtl, null));
- list.Add(Single(DnsmasqConfKeys.EdnsPacketMax, status, s => Config(s)?.EdnsPacketMax, s => Sources(s)?.EdnsPacketMax, null));
- list.Add(Single(DnsmasqConfKeys.QueryPort, status, s => Config(s)?.QueryPort, s => Sources(s)?.QueryPort, null));
- list.Add(Single(DnsmasqConfKeys.PortLimit, status, s => Config(s)?.PortLimit, s => Sources(s)?.PortLimit, null));
- list.Add(Single(DnsmasqConfKeys.MinPort, status, s => Config(s)?.MinPort, s => Sources(s)?.MinPort, null));
- list.Add(Single(DnsmasqConfKeys.MaxPort, status, s => Config(s)?.MaxPort, s => Sources(s)?.MaxPort, null));
- list.Add(Single(DnsmasqConfKeys.DnsLoopDetect, status, s => Config(s)?.DnsLoopDetect, s => Sources(s)?.DnsLoopDetect, null));
- list.Add(Single(DnsmasqConfKeys.StopDnsRebind, status, s => Config(s)?.StopDnsRebind, s => Sources(s)?.StopDnsRebind, null));
- list.Add(Single(DnsmasqConfKeys.RebindLocalhostOk, status, s => Config(s)?.RebindLocalhostOk, s => Sources(s)?.RebindLocalhostOk, null));
- list.Add(Single(DnsmasqConfKeys.ClearOnReload, status, s => Config(s)?.ClearOnReload, s => Sources(s)?.ClearOnReload, null));
- list.Add(Single(DnsmasqConfKeys.ExpandHosts, status, s => Config(s)?.ExpandHosts, s => Sources(s)?.ExpandHosts, null));
- list.Add(Single(DnsmasqConfKeys.BogusPriv, status, s => Config(s)?.BogusPriv, s => Sources(s)?.BogusPriv, null));
- list.Add(Multi(DnsmasqConfKeys.RebindDomainOk, status, Items(ec => ec?.RebindDomainOkValues, src => src?.RebindDomainOkValues)));
- list.Add(Multi(DnsmasqConfKeys.BogusNxdomain, status, Items(ec => ec?.BogusNxdomainValues, src => src?.BogusNxdomainValues)));
- list.Add(Multi(DnsmasqConfKeys.IgnoreAddress, status, Items(ec => ec?.IgnoreAddressValues, src => src?.IgnoreAddressValues)));
- list.Add(Multi(DnsmasqConfKeys.Alias, status, Items(ec => ec?.AliasValues, src => src?.AliasValues)));
- list.Add(Multi(DnsmasqConfKeys.FilterRr, status, Items(ec => ec?.FilterRrValues, src => src?.FilterRrValues)));
- list.Add(Single(DnsmasqConfKeys.Filterwin2k, status, s => Config(s)?.Filterwin2k, s => Sources(s)?.Filterwin2k, null));
- list.Add(Single(DnsmasqConfKeys.FilterA, status, s => Config(s)?.FilterA, s => Sources(s)?.FilterA, null));
- list.Add(Single(DnsmasqConfKeys.FilterAaaa, status, s => Config(s)?.FilterAaaa, s => Sources(s)?.FilterAaaa, null));
- list.Add(Single(DnsmasqConfKeys.LocaliseQueries, status, s => Config(s)?.LocaliseQueries, s => Sources(s)?.LocaliseQueries, null));
- list.Add(Single(DnsmasqConfKeys.FastDnsRetry, status, s => Config(s)?.FastDnsRetry, s => Sources(s)?.FastDnsRetry, null));
- list.Add(Multi(DnsmasqConfKeys.Ipset, status, Items(ec => ec?.IpsetValues, src => src?.IpsetValues)));
- list.Add(Multi(DnsmasqConfKeys.Nftset, status, Items(ec => ec?.NftsetValues, src => src?.NftsetValues)));
+ list.AddDescriptor(registry, DnsmasqOptionTooltips.ServerLocalLabel, status, null, null, Items(ec => ec?.ServerLocalValues, src => src?.ServerLocalValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.RevServer, status, null, null, Items(ec => ec?.RevServerValues, src => src?.RevServerValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.Address, status, null, null, Items(ec => ec?.AddressValues, src => src?.AddressValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.ResolvFile, status, null, null, Items(ec => ec?.ResolvFiles, src => src?.ResolvFiles));
+ list.AddDescriptor(registry, DnsmasqConfKeys.NoResolv, status, s => Config(s)?.NoResolv, s => Sources(s)?.NoResolv, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.DomainNeeded, status, s => Config(s)?.DomainNeeded, s => Sources(s)?.DomainNeeded, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.Port, status, s => Config(s)?.Port, s => Sources(s)?.Port, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.LogQueries, status, s => Config(s)?.LogQueries, s => Sources(s)?.LogQueries, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.StrictOrder, status, s => Config(s)?.StrictOrder, s => Sources(s)?.StrictOrder, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.AllServers, status, s => Config(s)?.AllServers, s => Sources(s)?.AllServers, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.AuthTtl, status, s => Config(s)?.AuthTtl, s => Sources(s)?.AuthTtl, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.EdnsPacketMax, status, s => Config(s)?.EdnsPacketMax, s => Sources(s)?.EdnsPacketMax, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.QueryPort, status, s => Config(s)?.QueryPort, s => Sources(s)?.QueryPort, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.PortLimit, status, s => Config(s)?.PortLimit, s => Sources(s)?.PortLimit, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.MinPort, status, s => Config(s)?.MinPort, s => Sources(s)?.MinPort, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.MaxPort, status, s => Config(s)?.MaxPort, s => Sources(s)?.MaxPort, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.DnsLoopDetect, status, s => Config(s)?.DnsLoopDetect, s => Sources(s)?.DnsLoopDetect, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.StopDnsRebind, status, s => Config(s)?.StopDnsRebind, s => Sources(s)?.StopDnsRebind, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.RebindLocalhostOk, status, s => Config(s)?.RebindLocalhostOk, s => Sources(s)?.RebindLocalhostOk, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.ClearOnReload, status, s => Config(s)?.ClearOnReload, s => Sources(s)?.ClearOnReload, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.ExpandHosts, status, s => Config(s)?.ExpandHosts, s => Sources(s)?.ExpandHosts, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.BogusPriv, status, s => Config(s)?.BogusPriv, s => Sources(s)?.BogusPriv, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.RebindDomainOk, status, null, null, Items(ec => ec?.RebindDomainOkValues, src => src?.RebindDomainOkValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.BogusNxdomain, status, null, null, Items(ec => ec?.BogusNxdomainValues, src => src?.BogusNxdomainValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.IgnoreAddress, status, null, null, Items(ec => ec?.IgnoreAddressValues, src => src?.IgnoreAddressValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.Alias, status, null, null, Items(ec => ec?.AliasValues, src => src?.AliasValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.FilterRr, status, null, null, Items(ec => ec?.FilterRrValues, src => src?.FilterRrValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.Filterwin2k, status, s => Config(s)?.Filterwin2k, s => Sources(s)?.Filterwin2k, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.FilterA, status, s => Config(s)?.FilterA, s => Sources(s)?.FilterA, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.FilterAaaa, status, s => Config(s)?.FilterAaaa, s => Sources(s)?.FilterAaaa, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.LocaliseQueries, status, s => Config(s)?.LocaliseQueries, s => Sources(s)?.LocaliseQueries, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.FastDnsRetry, status, s => Config(s)?.FastDnsRetry, s => Sources(s)?.FastDnsRetry, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.Ipset, status, null, null, Items(ec => ec?.IpsetValues, src => src?.IpsetValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.Nftset, status, null, null, Items(ec => ec?.NftsetValues, src => src?.NftsetValues));
// DNS records
- list.Add(Multi(DnsmasqConfKeys.Domain, status, Items(ec => ec?.DomainValues, src => src?.DomainValues)));
- list.Add(Multi(DnsmasqConfKeys.Cname, status, Items(ec => ec?.CnameValues, src => src?.CnameValues)));
- list.Add(Multi(DnsmasqConfKeys.MxHost, status, Items(ec => ec?.MxHostValues, src => src?.MxHostValues)));
- list.Add(Multi(DnsmasqConfKeys.Srv, status, Items(ec => ec?.SrvValues, src => src?.SrvValues)));
- list.Add(Multi(DnsmasqConfKeys.PtrRecord, status, Items(ec => ec?.PtrRecordValues, src => src?.PtrRecordValues)));
- list.Add(Multi(DnsmasqConfKeys.TxtRecord, status, Items(ec => ec?.TxtRecordValues, src => src?.TxtRecordValues)));
- list.Add(Multi(DnsmasqConfKeys.NaptrRecord, status, Items(ec => ec?.NaptrRecordValues, src => src?.NaptrRecordValues)));
- list.Add(Multi(DnsmasqConfKeys.HostRecord, status, Items(ec => ec?.HostRecordValues, src => src?.HostRecordValues)));
- list.Add(Multi(DnsmasqConfKeys.DynamicHost, status, Items(ec => ec?.DynamicHostValues, src => src?.DynamicHostValues)));
- list.Add(Multi(DnsmasqConfKeys.InterfaceName, status, Items(ec => ec?.InterfaceNameValues, src => src?.InterfaceNameValues)));
- list.Add(Single(DnsmasqConfKeys.MxTarget, status, s => Config(s)?.MxTarget, s => Sources(s)?.MxTarget, null));
- list.Add(Single(DnsmasqConfKeys.Localmx, status, s => Config(s)?.Localmx, s => Sources(s)?.Localmx, null));
- list.Add(Single(DnsmasqConfKeys.Selfmx, status, s => Config(s)?.Selfmx, s => Sources(s)?.Selfmx, null));
+ list.AddDescriptor(registry, DnsmasqConfKeys.Domain, status, null, null, Items(ec => ec?.DomainValues, src => src?.DomainValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.Cname, status, null, null, Items(ec => ec?.CnameValues, src => src?.CnameValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.MxHost, status, null, null, Items(ec => ec?.MxHostValues, src => src?.MxHostValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.Srv, status, null, null, Items(ec => ec?.SrvValues, src => src?.SrvValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.PtrRecord, status, null, null, Items(ec => ec?.PtrRecordValues, src => src?.PtrRecordValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.TxtRecord, status, null, null, Items(ec => ec?.TxtRecordValues, src => src?.TxtRecordValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.NaptrRecord, status, null, null, Items(ec => ec?.NaptrRecordValues, src => src?.NaptrRecordValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.HostRecord, status, null, null, Items(ec => ec?.HostRecordValues, src => src?.HostRecordValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.DynamicHost, status, null, null, Items(ec => ec?.DynamicHostValues, src => src?.DynamicHostValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.InterfaceName, status, null, null, Items(ec => ec?.InterfaceNameValues, src => src?.InterfaceNameValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.MxTarget, status, s => Config(s)?.MxTarget, s => Sources(s)?.MxTarget, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.Localmx, status, s => Config(s)?.Localmx, s => Sources(s)?.Localmx, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.Selfmx, status, s => Config(s)?.Selfmx, s => Sources(s)?.Selfmx, null);
// DHCP
- list.Add(Single(DnsmasqConfKeys.DhcpAuthoritative, status, s => Config(s)?.DhcpAuthoritative, s => Sources(s)?.DhcpAuthoritative, null));
- list.Add(Single(DnsmasqConfKeys.DhcpRapidCommit, status, s => Config(s)?.DhcpRapidCommit, s => Sources(s)?.DhcpRapidCommit, null));
- list.Add(Single(DnsmasqConfKeys.LeasefileRo, status, s => Config(s)?.LeasefileRo, s => Sources(s)?.LeasefileRo, null));
- list.Add(Single(DnsmasqConfKeys.DhcpScript, status, s => Config(s)?.DhcpScriptPath, s => Sources(s)?.DhcpScriptPath, null));
- list.Add(Single(DnsmasqConfKeys.DhcpLeasefile, status, s => Config(s)?.DhcpLeaseFilePath, s => Sources(s)?.DhcpLeaseFilePath, null));
- list.Add(Single(DnsmasqConfKeys.DhcpLeaseMax, status, s => Config(s)?.DhcpLeaseMax, s => Sources(s)?.DhcpLeaseMax, null));
- list.Add(Single(DnsmasqConfKeys.DhcpTtl, status, s => Config(s)?.DhcpTtl, s => Sources(s)?.DhcpTtl, null));
- list.Add(Multi(DnsmasqConfKeys.DhcpRange, status, Items(ec => ec?.DhcpRanges, src => src?.DhcpRanges)));
- list.Add(Multi(DnsmasqConfKeys.DhcpHost, status, Items(ec => ec?.DhcpHostLines, src => src?.DhcpHostLines)));
- list.Add(Multi(DnsmasqConfKeys.DhcpOption, status, Items(ec => ec?.DhcpOptionLines, src => src?.DhcpOptionLines)));
- list.Add(Multi(DnsmasqConfKeys.DhcpOptionForce, status, Items(ec => ec?.DhcpOptionForceLines, src => src?.DhcpOptionForceLines)));
- list.Add(Multi(DnsmasqConfKeys.DhcpMatch, status, Items(ec => ec?.DhcpMatchValues, src => src?.DhcpMatchValues)));
- list.Add(Multi(DnsmasqConfKeys.DhcpMac, status, Items(ec => ec?.DhcpMacValues, src => src?.DhcpMacValues)));
- list.Add(Multi(DnsmasqConfKeys.DhcpNameMatch, status, Items(ec => ec?.DhcpNameMatchValues, src => src?.DhcpNameMatchValues)));
- list.Add(Multi(DnsmasqConfKeys.DhcpIgnoreNames, status, Items(ec => ec?.DhcpIgnoreNamesValues, src => src?.DhcpIgnoreNamesValues)));
- list.Add(Multi(DnsmasqConfKeys.DhcpHostsfile, status, Items(ec => ec?.DhcpHostsfilePaths, src => src?.DhcpHostsfilePaths)));
- list.Add(Multi(DnsmasqConfKeys.DhcpOptsfile, status, Items(ec => ec?.DhcpOptsfilePaths, src => src?.DhcpOptsfilePaths)));
- list.Add(Multi(DnsmasqConfKeys.DhcpHostsdir, status, Items(ec => ec?.DhcpHostsdirPaths, src => src?.DhcpHostsdirPaths)));
- list.Add(Multi(DnsmasqConfKeys.DhcpBoot, status, Items(ec => ec?.DhcpBootValues, src => src?.DhcpBootValues)));
- list.Add(Multi(DnsmasqConfKeys.DhcpIgnore, status, Items(ec => ec?.DhcpIgnoreValues, src => src?.DhcpIgnoreValues)));
- list.Add(Multi(DnsmasqConfKeys.DhcpVendorclass, status, Items(ec => ec?.DhcpVendorclassValues, src => src?.DhcpVendorclassValues)));
- list.Add(Multi(DnsmasqConfKeys.DhcpUserclass, status, Items(ec => ec?.DhcpUserclassValues, src => src?.DhcpUserclassValues)));
- list.Add(Multi(DnsmasqConfKeys.RaParam, status, Items(ec => ec?.RaParamValues, src => src?.RaParamValues)));
- list.Add(Multi(DnsmasqConfKeys.Slaac, status, Items(ec => ec?.SlaacValues, src => src?.SlaacValues)));
+ list.AddDescriptor(registry, DnsmasqConfKeys.DhcpAuthoritative, status, s => Config(s)?.DhcpAuthoritative, s => Sources(s)?.DhcpAuthoritative, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.DhcpRapidCommit, status, s => Config(s)?.DhcpRapidCommit, s => Sources(s)?.DhcpRapidCommit, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.LeasefileRo, status, s => Config(s)?.LeasefileRo, s => Sources(s)?.LeasefileRo, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.DhcpScript, status, s => Config(s)?.DhcpScriptPath, s => Sources(s)?.DhcpScriptPath, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.DhcpLeasefile, status, s => Config(s)?.DhcpLeaseFilePath, s => Sources(s)?.DhcpLeaseFilePath, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.DhcpLeaseMax, status, s => Config(s)?.DhcpLeaseMax, s => Sources(s)?.DhcpLeaseMax, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.DhcpTtl, status, s => Config(s)?.DhcpTtl, s => Sources(s)?.DhcpTtl, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.DhcpRange, status, null, null, Items(ec => ec?.DhcpRanges, src => src?.DhcpRanges));
+ list.AddDescriptor(registry, DnsmasqConfKeys.DhcpHost, status, null, null, Items(ec => ec?.DhcpHostLines, src => src?.DhcpHostLines));
+ list.AddDescriptor(registry, DnsmasqConfKeys.DhcpOption, status, null, null, Items(ec => ec?.DhcpOptionLines, src => src?.DhcpOptionLines));
+ list.AddDescriptor(registry, DnsmasqConfKeys.DhcpOptionForce, status, null, null, Items(ec => ec?.DhcpOptionForceLines, src => src?.DhcpOptionForceLines));
+ list.AddDescriptor(registry, DnsmasqConfKeys.DhcpMatch, status, null, null, Items(ec => ec?.DhcpMatchValues, src => src?.DhcpMatchValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.DhcpMac, status, null, null, Items(ec => ec?.DhcpMacValues, src => src?.DhcpMacValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.DhcpNameMatch, status, null, null, Items(ec => ec?.DhcpNameMatchValues, src => src?.DhcpNameMatchValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.DhcpIgnoreNames, status, null, null, Items(ec => ec?.DhcpIgnoreNamesValues, src => src?.DhcpIgnoreNamesValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.DhcpHostsfile, status, null, null, Items(ec => ec?.DhcpHostsfilePaths, src => src?.DhcpHostsfilePaths));
+ list.AddDescriptor(registry, DnsmasqConfKeys.DhcpOptsfile, status, null, null, Items(ec => ec?.DhcpOptsfilePaths, src => src?.DhcpOptsfilePaths));
+ list.AddDescriptor(registry, DnsmasqConfKeys.DhcpHostsdir, status, null, null, Items(ec => ec?.DhcpHostsdirPaths, src => src?.DhcpHostsdirPaths));
+ list.AddDescriptor(registry, DnsmasqConfKeys.DhcpBoot, status, null, null, Items(ec => ec?.DhcpBootValues, src => src?.DhcpBootValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.DhcpIgnore, status, null, null, Items(ec => ec?.DhcpIgnoreValues, src => src?.DhcpIgnoreValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.DhcpVendorclass, status, null, null, Items(ec => ec?.DhcpVendorclassValues, src => src?.DhcpVendorclassValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.DhcpUserclass, status, null, null, Items(ec => ec?.DhcpUserclassValues, src => src?.DhcpUserclassValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.RaParam, status, null, null, Items(ec => ec?.RaParamValues, src => src?.RaParamValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.Slaac, status, null, null, Items(ec => ec?.SlaacValues, src => src?.SlaacValues));
// TFTP / PXE
- list.Add(Single(DnsmasqConfKeys.EnableTftp, status, s => Config(s)?.EnableTftp, s => Sources(s)?.EnableTftp, null));
- list.Add(Single(DnsmasqConfKeys.TftpSecure, status, s => Config(s)?.TftpSecure, s => Sources(s)?.TftpSecure, null));
- list.Add(Single(DnsmasqConfKeys.TftpNoFail, status, s => Config(s)?.TftpNoFail, s => Sources(s)?.TftpNoFail, null));
- list.Add(Single(DnsmasqConfKeys.TftpNoBlocksize, status, s => Config(s)?.TftpNoBlocksize, s => Sources(s)?.TftpNoBlocksize, null));
- list.Add(Single(DnsmasqConfKeys.TftpRoot, status, s => Config(s)?.TftpRootPath, s => Sources(s)?.TftpRootPath, null));
- list.Add(Single(DnsmasqConfKeys.PxePrompt, status, s => Config(s)?.PxePrompt, s => Sources(s)?.PxePrompt, null));
- list.Add(Multi(DnsmasqConfKeys.PxeService, status, Items(ec => ec?.PxeServiceValues, src => src?.PxeServiceValues)));
+ list.AddDescriptor(registry, DnsmasqConfKeys.EnableTftp, status, s => Config(s)?.EnableTftp, s => Sources(s)?.EnableTftp, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.TftpSecure, status, s => Config(s)?.TftpSecure, s => Sources(s)?.TftpSecure, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.TftpNoFail, status, s => Config(s)?.TftpNoFail, s => Sources(s)?.TftpNoFail, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.TftpNoBlocksize, status, s => Config(s)?.TftpNoBlocksize, s => Sources(s)?.TftpNoBlocksize, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.TftpRoot, status, s => Config(s)?.TftpRootPath, s => Sources(s)?.TftpRootPath, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.PxePrompt, status, s => Config(s)?.PxePrompt, s => Sources(s)?.PxePrompt, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.PxeService, status, null, null, Items(ec => ec?.PxeServiceValues, src => src?.PxeServiceValues));
// DNSSEC
- list.Add(Single(DnsmasqConfKeys.Dnssec, status, s => Config(s)?.Dnssec, s => Sources(s)?.Dnssec, null));
- list.Add(Single(DnsmasqConfKeys.DnssecCheckUnsigned, status, s => Config(s)?.DnssecCheckUnsigned, s => Sources(s)?.DnssecCheckUnsigned, null));
- list.Add(Single(DnsmasqConfKeys.ProxyDnssec, status, s => Config(s)?.ProxyDnssec, s => Sources(s)?.ProxyDnssec, null));
- list.Add(Multi(DnsmasqConfKeys.TrustAnchor, status, Items(ec => ec?.TrustAnchorValues, src => src?.TrustAnchorValues)));
+ list.AddDescriptor(registry, DnsmasqConfKeys.Dnssec, status, s => Config(s)?.Dnssec, s => Sources(s)?.Dnssec, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.DnssecCheckUnsigned, status, s => Config(s)?.DnssecCheckUnsigned, s => Sources(s)?.DnssecCheckUnsigned, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.ProxyDnssec, status, s => Config(s)?.ProxyDnssec, s => Sources(s)?.ProxyDnssec, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.TrustAnchor, status, null, null, Items(ec => ec?.TrustAnchorValues, src => src?.TrustAnchorValues));
// Cache
- list.Add(Multi(DnsmasqConfKeys.CacheRr, status, Items(ec => ec?.CacheRrValues, src => src?.CacheRrValues)));
- list.Add(Single(DnsmasqConfKeys.CacheSize, status, s => Config(s)?.CacheSize, s => Sources(s)?.CacheSize, null));
- list.Add(Single(DnsmasqConfKeys.LocalTtl, status, s => Config(s)?.LocalTtl, s => Sources(s)?.LocalTtl, null));
- list.Add(Single(DnsmasqConfKeys.NoNegcache, status, s => Config(s)?.NoNegcache, s => Sources(s)?.NoNegcache, null));
- list.Add(Single(DnsmasqConfKeys.NegTtl, status, s => Config(s)?.NegTtl, s => Sources(s)?.NegTtl, null));
- list.Add(Single(DnsmasqConfKeys.MaxTtl, status, s => Config(s)?.MaxTtl, s => Sources(s)?.MaxTtl, null));
- list.Add(Single(DnsmasqConfKeys.MaxCacheTtl, status, s => Config(s)?.MaxCacheTtl, s => Sources(s)?.MaxCacheTtl, null));
- list.Add(Single(DnsmasqConfKeys.MinCacheTtl, status, s => Config(s)?.MinCacheTtl, s => Sources(s)?.MinCacheTtl, null));
+ list.AddDescriptor(registry, DnsmasqConfKeys.CacheRr, status, null, null, Items(ec => ec?.CacheRrValues, src => src?.CacheRrValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.CacheSize, status, s => Config(s)?.CacheSize, s => Sources(s)?.CacheSize, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.LocalTtl, status, s => Config(s)?.LocalTtl, s => Sources(s)?.LocalTtl, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.NoNegcache, status, s => Config(s)?.NoNegcache, s => Sources(s)?.NoNegcache, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.NegTtl, status, s => Config(s)?.NegTtl, s => Sources(s)?.NegTtl, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.MaxTtl, status, s => Config(s)?.MaxTtl, s => Sources(s)?.MaxTtl, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.MaxCacheTtl, status, s => Config(s)?.MaxCacheTtl, s => Sources(s)?.MaxCacheTtl, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.MinCacheTtl, status, s => Config(s)?.MinCacheTtl, s => Sources(s)?.MinCacheTtl, null);
// Process & networking
- list.Add(Single(DnsmasqConfKeys.NoPoll, status, s => Config(s)?.NoPoll, s => Sources(s)?.NoPoll, null));
- list.Add(Single(DnsmasqConfKeys.BindInterfaces, status, s => Config(s)?.BindInterfaces, s => Sources(s)?.BindInterfaces, null));
- list.Add(Single(DnsmasqConfKeys.BindDynamic, status, s => Config(s)?.BindDynamic, s => Sources(s)?.BindDynamic, null));
- list.Add(Single(DnsmasqConfKeys.LogDebug, status, s => Config(s)?.LogDebug, s => Sources(s)?.LogDebug, null));
- list.Add(Single(DnsmasqConfKeys.LogAsync, status, s => Config(s)?.LogAsync, s => Sources(s)?.LogAsync, null));
- list.Add(Single(DnsmasqConfKeys.LocalService, status, s => Config(s)?.LocalService, s => Sources(s)?.LocalService, null));
- list.Add(Multi(DnsmasqConfKeys.Interface, status, Items(ec => ec?.Interfaces, src => src?.Interfaces)));
- list.Add(Multi(DnsmasqConfKeys.ListenAddress, status, Items(ec => ec?.ListenAddresses, src => src?.ListenAddresses)));
- list.Add(Multi(DnsmasqConfKeys.ExceptInterface, status, Items(ec => ec?.ExceptInterfaces, src => src?.ExceptInterfaces)));
- list.Add(Multi(DnsmasqConfKeys.AuthServer, status, Items(ec => ec?.AuthServerValues, src => src?.AuthServerValues)));
- list.Add(Multi(DnsmasqConfKeys.NoDhcpInterface, status, Items(ec => ec?.NoDhcpInterfaceValues, src => src?.NoDhcpInterfaceValues)));
- list.Add(Multi(DnsmasqConfKeys.NoDhcpv4Interface, status, Items(ec => ec?.NoDhcpv4InterfaceValues, src => src?.NoDhcpv4InterfaceValues)));
- list.Add(Multi(DnsmasqConfKeys.NoDhcpv6Interface, status, Items(ec => ec?.NoDhcpv6InterfaceValues, src => src?.NoDhcpv6InterfaceValues)));
- list.Add(Single(DnsmasqConfKeys.PidFile, status, s => Config(s)?.PidFilePath, s => Sources(s)?.PidFilePath, null));
- list.Add(Single(DnsmasqConfKeys.User, status, s => Config(s)?.User, s => Sources(s)?.User, null));
- list.Add(Single(DnsmasqConfKeys.Group, status, s => Config(s)?.Group, s => Sources(s)?.Group, null));
- list.Add(Single(DnsmasqConfKeys.LogFacility, status, s => Config(s)?.LogFacility, s => Sources(s)?.LogFacility, null));
- list.Add(Single(DnsmasqConfKeys.EnableDbus, status, s => Config(s)?.EnableDbus, s => Sources(s)?.EnableDbus, null));
- list.Add(Single(DnsmasqConfKeys.EnableUbus, status, s => Config(s)?.EnableUbus, s => Sources(s)?.EnableUbus, null));
- list.Add(Single(DnsmasqConfKeys.EnableRa, status, s => Config(s)?.EnableRa, s => Sources(s)?.EnableRa, null));
- list.Add(Single(DnsmasqConfKeys.LogDhcp, status, s => Config(s)?.LogDhcp, s => Sources(s)?.LogDhcp, null));
- list.Add(Single(DnsmasqConfKeys.KeepInForeground, status, s => Config(s)?.KeepInForeground, s => Sources(s)?.KeepInForeground, null));
- list.Add(Single(DnsmasqConfKeys.NoDaemon, status, s => Config(s)?.NoDaemon, s => Sources(s)?.NoDaemon, null));
- list.Add(Single(DnsmasqConfKeys.Conntrack, status, s => Config(s)?.Conntrack, s => Sources(s)?.Conntrack, null));
+ list.AddDescriptor(registry, DnsmasqConfKeys.NoPoll, status, s => Config(s)?.NoPoll, s => Sources(s)?.NoPoll, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.BindInterfaces, status, s => Config(s)?.BindInterfaces, s => Sources(s)?.BindInterfaces, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.BindDynamic, status, s => Config(s)?.BindDynamic, s => Sources(s)?.BindDynamic, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.LogDebug, status, s => Config(s)?.LogDebug, s => Sources(s)?.LogDebug, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.LogAsync, status, s => Config(s)?.LogAsync, s => Sources(s)?.LogAsync, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.LocalService, status, s => Config(s)?.LocalService, s => Sources(s)?.LocalService, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.Interface, status, null, null, Items(ec => ec?.Interfaces, src => src?.Interfaces));
+ list.AddDescriptor(registry, DnsmasqConfKeys.ListenAddress, status, null, null, Items(ec => ec?.ListenAddresses, src => src?.ListenAddresses));
+ list.AddDescriptor(registry, DnsmasqConfKeys.ExceptInterface, status, null, null, Items(ec => ec?.ExceptInterfaces, src => src?.ExceptInterfaces));
+ list.AddDescriptor(registry, DnsmasqConfKeys.AuthServer, status, null, null, Items(ec => ec?.AuthServerValues, src => src?.AuthServerValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.NoDhcpInterface, status, null, null, Items(ec => ec?.NoDhcpInterfaceValues, src => src?.NoDhcpInterfaceValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.NoDhcpv4Interface, status, null, null, Items(ec => ec?.NoDhcpv4InterfaceValues, src => src?.NoDhcpv4InterfaceValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.NoDhcpv6Interface, status, null, null, Items(ec => ec?.NoDhcpv6InterfaceValues, src => src?.NoDhcpv6InterfaceValues));
+ list.AddDescriptor(registry, DnsmasqConfKeys.PidFile, status, s => Config(s)?.PidFilePath, s => Sources(s)?.PidFilePath, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.User, status, s => Config(s)?.User, s => Sources(s)?.User, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.Group, status, s => Config(s)?.Group, s => Sources(s)?.Group, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.LogFacility, status, s => Config(s)?.LogFacility, s => Sources(s)?.LogFacility, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.EnableDbus, status, s => Config(s)?.EnableDbus, s => Sources(s)?.EnableDbus, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.EnableUbus, status, s => Config(s)?.EnableUbus, s => Sources(s)?.EnableUbus, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.EnableRa, status, s => Config(s)?.EnableRa, s => Sources(s)?.EnableRa, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.LogDhcp, status, s => Config(s)?.LogDhcp, s => Sources(s)?.LogDhcp, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.KeepInForeground, status, s => Config(s)?.KeepInForeground, s => Sources(s)?.KeepInForeground, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.NoDaemon, status, s => Config(s)?.NoDaemon, s => Sources(s)?.NoDaemon, null);
+ list.AddDescriptor(registry, DnsmasqConfKeys.Conntrack, status, s => Config(s)?.Conntrack, s => Sources(s)?.Conntrack, null);
return list;
}
+ /// Creates a single-value descriptor; uses registry factory when registered (e.g. integer), otherwise a plain descriptor. Used by .
+ public static EffectiveConfigFieldDescriptor GetSingleDescriptor(
+ IEffectiveConfigRenderFragmentRegistry? registry,
+ string optionName,
+ DnsmasqServiceStatus? status,
+ Func? getValue,
+ Func? getSource,
+ Func?>? getItems)
+ {
+ var sectionId = EffectiveConfigSections.GetSectionId(optionName);
+ var factory = registry?.GetDescriptorFactory(sectionId, optionName);
+ if (factory != null)
+ return (EffectiveConfigFieldDescriptor)factory(sectionId, optionName, status, getValue, getSource, getItems);
+ return Single(optionName, status, getValue, getSource, getItems);
+ }
+
private static EffectiveConfigFieldDescriptor Single(string optionName, DnsmasqServiceStatus? status,
Func? getValue,
Func? getSource,
@@ -197,11 +214,4 @@ public static class EffectiveConfigFieldBuilder
? withSource.Select(p => new ValueWithSource(p.Path, p.Source)).ToList()
: paths.Select(p => new ValueWithSource(p, null)).ToList();
}
-
- private static EffectiveConfigFieldDescriptor Multi(string optionName, DnsmasqServiceStatus? status,
- Func?>? getItems)
- {
- var sectionId = EffectiveConfigSections.GetSectionId(optionName);
- return new EffectiveConfigFieldDescriptor(sectionId, optionName, true, status, null, null, getItems);
- }
}
diff --git a/src/DnsmasqWebUI/Infrastructure/Helpers/Config/EffectiveConfigFieldDescriptorListExtensions.cs b/src/DnsmasqWebUI/Infrastructure/Helpers/Config/EffectiveConfigFieldDescriptorListExtensions.cs
new file mode 100644
index 0000000..deef2ff
--- /dev/null
+++ b/src/DnsmasqWebUI/Infrastructure/Helpers/Config/EffectiveConfigFieldDescriptorListExtensions.cs
@@ -0,0 +1,57 @@
+using DnsmasqWebUI.Models.Dnsmasq;
+using DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig;
+using DnsmasqWebUI.Infrastructure.Services.Abstractions;
+
+namespace DnsmasqWebUI.Infrastructure.Helpers.Config;
+
+///
+/// Extension methods for building lists of effective-config field descriptors. Keeps the field builder readable.
+///
+public static class EffectiveConfigFieldDescriptorListExtensions
+{
+ ///
+ /// Adds a field descriptor; single vs multi is determined by for the given option name.
+ ///
+ public static void AddDescriptor(
+ this List list,
+ IEffectiveConfigRenderFragmentRegistry? registry,
+ string optionName,
+ DnsmasqServiceStatus? status,
+ Func? getValue,
+ Func? getSource,
+ Func?>? getItems)
+ {
+ if (EffectiveConfigOptionKindMap.GetKind(optionName) == EffectiveConfigFieldKind.Multi)
+ list.AddMultiDescriptor(optionName, status, getItems);
+ else
+ list.AddSingleDescriptor(registry, optionName, status, getValue, getSource, getItems);
+ }
+
+ ///
+ /// Adds a single-value field descriptor. Uses the registry's factory when registered (e.g. integer options), otherwise a plain descriptor.
+ ///
+ public static void AddSingleDescriptor(
+ this List list,
+ IEffectiveConfigRenderFragmentRegistry? registry,
+ string optionName,
+ DnsmasqServiceStatus? status,
+ Func? getValue,
+ Func? getSource,
+ Func?>? getItems)
+ {
+ list.Add(EffectiveConfigFieldBuilder.GetSingleDescriptor(registry, optionName, status, getValue, getSource, getItems));
+ }
+
+ ///
+ /// Adds a multi-value field descriptor (e.g. server, address, dhcp-range).
+ ///
+ public static void AddMultiDescriptor(
+ this List list,
+ string optionName,
+ DnsmasqServiceStatus? status,
+ Func?>? getItems)
+ {
+ var sectionId = EffectiveConfigSections.GetSectionId(optionName);
+ list.Add(new EffectiveConfigFieldDescriptor(sectionId, optionName, true, status, null, null, getItems));
+ }
+}
diff --git a/src/DnsmasqWebUI/Infrastructure/Helpers/Config/EffectiveConfigOptionKindMap.cs b/src/DnsmasqWebUI/Infrastructure/Helpers/Config/EffectiveConfigOptionKindMap.cs
new file mode 100644
index 0000000..8b2a996
--- /dev/null
+++ b/src/DnsmasqWebUI/Infrastructure/Helpers/Config/EffectiveConfigOptionKindMap.cs
@@ -0,0 +1,292 @@
+using System.Collections.Generic;
+
+namespace DnsmasqWebUI.Infrastructure.Helpers.Config;
+
+///
+/// Whether an effective-config option has a single value (or flag) or multiple values.
+/// Single source of truth for descriptor building and UI; flags are treated as single-value.
+///
+public enum EffectiveConfigFieldKind
+{
+ Single,
+ Multi,
+}
+
+///
+/// How to parse an option from config files: last occurrence wins, key-only flag, or collect all values.
+/// Used by ConfigSetCache to choose GetLastValue / GetFlag / GetMultiValue without hard-coding per option.
+///
+public enum EffectiveConfigParserBehavior
+{
+ LastWins,
+ Flag,
+ Multi,
+}
+
+///
+/// Maps dnsmasq option names to single vs multi-value kind. Used by the field builder so call sites
+/// do not choose AddSingleDescriptor vs AddMultiDescriptor explicitly.
+///
+public static class EffectiveConfigOptionKindMap
+{
+ private static readonly IReadOnlyDictionary KindByOptionName =
+ new Dictionary(System.StringComparer.Ordinal)
+ {
+ [DnsmasqConfKeys.NoHosts] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.AddnHosts] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.Hostsdir] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.ReadEthers] = EffectiveConfigFieldKind.Single,
+ [DnsmasqOptionTooltips.ServerLocalLabel] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.RevServer] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.Address] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.ResolvFile] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.NoResolv] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.DomainNeeded] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.Port] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.LogQueries] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.StrictOrder] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.AllServers] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.AuthTtl] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.EdnsPacketMax] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.QueryPort] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.PortLimit] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.MinPort] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.MaxPort] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.DnsLoopDetect] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.StopDnsRebind] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.RebindLocalhostOk] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.ClearOnReload] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.ExpandHosts] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.BogusPriv] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.RebindDomainOk] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.BogusNxdomain] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.IgnoreAddress] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.Alias] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.FilterRr] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.Filterwin2k] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.FilterA] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.FilterAaaa] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.LocaliseQueries] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.FastDnsRetry] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.Ipset] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.Nftset] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.Domain] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.Cname] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.MxHost] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.Srv] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.PtrRecord] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.TxtRecord] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.NaptrRecord] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.HostRecord] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.DynamicHost] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.InterfaceName] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.MxTarget] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.Localmx] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.Selfmx] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.DhcpAuthoritative] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.DhcpRapidCommit] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.LeasefileRo] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.DhcpScript] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.DhcpLeasefile] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.DhcpLeaseMax] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.DhcpTtl] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.DhcpRange] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.DhcpHost] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.DhcpOption] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.DhcpOptionForce] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.DhcpMatch] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.DhcpMac] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.DhcpNameMatch] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.DhcpIgnoreNames] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.DhcpHostsfile] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.DhcpOptsfile] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.DhcpHostsdir] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.DhcpBoot] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.DhcpIgnore] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.DhcpVendorclass] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.DhcpUserclass] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.RaParam] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.Slaac] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.EnableTftp] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.TftpSecure] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.TftpNoFail] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.TftpNoBlocksize] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.TftpRoot] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.PxePrompt] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.PxeService] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.Dnssec] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.DnssecCheckUnsigned] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.ProxyDnssec] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.TrustAnchor] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.CacheRr] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.CacheSize] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.LocalTtl] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.NoNegcache] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.NegTtl] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.MaxTtl] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.MaxCacheTtl] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.MinCacheTtl] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.NoPoll] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.BindInterfaces] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.BindDynamic] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.LogDebug] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.LogAsync] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.LocalService] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.Interface] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.ListenAddress] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.ExceptInterface] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.AuthServer] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.NoDhcpInterface] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.NoDhcpv4Interface] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.NoDhcpv6Interface] = EffectiveConfigFieldKind.Multi,
+ [DnsmasqConfKeys.PidFile] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.User] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.Group] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.LogFacility] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.EnableDbus] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.EnableUbus] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.EnableRa] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.LogDhcp] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.KeepInForeground] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.NoDaemon] = EffectiveConfigFieldKind.Single,
+ [DnsmasqConfKeys.Conntrack] = EffectiveConfigFieldKind.Single,
+ };
+
+ /// Returns Single or Multi for the given option name; defaults to Single if unknown.
+ public static EffectiveConfigFieldKind GetKind(string optionName) =>
+ KindByOptionName.TryGetValue(optionName, out var kind) ? kind : EffectiveConfigFieldKind.Single;
+}
+
+///
+/// Maps dnsmasq option names to parser behavior (LastWins / Flag / Multi). Used by ConfigSetCache so it
+/// dispatches to GetLastValue, GetFlag, or GetMultiValue from one place. Special cases (NoHosts value,
+/// AddnHosts, server/local keys array, DhcpLeaseFilePath) remain explicit in the cache.
+///
+public static class EffectiveConfigParserBehaviorMap
+{
+ private static readonly IReadOnlyDictionary BehaviorByOptionName =
+ new Dictionary(System.StringComparer.Ordinal)
+ {
+ [DnsmasqConfKeys.NoHosts] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.AddnHosts] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.Hostsdir] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.ReadEthers] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.RevServer] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.Address] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.ResolvFile] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.NoResolv] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.DomainNeeded] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.Port] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.LogQueries] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.StrictOrder] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.AllServers] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.AuthTtl] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.EdnsPacketMax] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.QueryPort] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.PortLimit] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.MinPort] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.MaxPort] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.DnsLoopDetect] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.StopDnsRebind] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.RebindLocalhostOk] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.ClearOnReload] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.ExpandHosts] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.BogusPriv] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.RebindDomainOk] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.BogusNxdomain] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.IgnoreAddress] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.Alias] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.FilterRr] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.Filterwin2k] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.FilterA] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.FilterAaaa] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.LocaliseQueries] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.FastDnsRetry] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.Ipset] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.Nftset] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.Domain] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.Cname] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.MxHost] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.Srv] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.PtrRecord] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.TxtRecord] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.NaptrRecord] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.HostRecord] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.DynamicHost] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.InterfaceName] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.MxTarget] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.Localmx] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.Selfmx] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.DhcpAuthoritative] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.DhcpRapidCommit] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.LeasefileRo] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.DhcpScript] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.DhcpLeasefile] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.DhcpLeaseMax] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.DhcpTtl] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.DhcpRange] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.DhcpHost] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.DhcpOption] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.DhcpOptionForce] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.DhcpMatch] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.DhcpMac] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.DhcpNameMatch] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.DhcpIgnoreNames] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.DhcpHostsfile] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.DhcpOptsfile] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.DhcpHostsdir] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.DhcpBoot] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.DhcpIgnore] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.DhcpVendorclass] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.DhcpUserclass] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.RaParam] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.Slaac] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.EnableTftp] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.TftpSecure] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.TftpNoFail] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.TftpNoBlocksize] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.TftpRoot] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.PxePrompt] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.PxeService] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.Dnssec] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.DnssecCheckUnsigned] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.ProxyDnssec] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.TrustAnchor] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.CacheRr] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.CacheSize] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.LocalTtl] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.NoNegcache] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.NegTtl] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.MaxTtl] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.MaxCacheTtl] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.MinCacheTtl] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.NoPoll] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.BindInterfaces] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.BindDynamic] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.LogDebug] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.LogAsync] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.LocalService] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.Interface] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.ListenAddress] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.ExceptInterface] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.AuthServer] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.NoDhcpInterface] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.NoDhcpv4Interface] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.NoDhcpv6Interface] = EffectiveConfigParserBehavior.Multi,
+ [DnsmasqConfKeys.PidFile] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.User] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.Group] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.LogFacility] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.EnableDbus] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.EnableUbus] = EffectiveConfigParserBehavior.LastWins,
+ [DnsmasqConfKeys.EnableRa] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.LogDhcp] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.KeepInForeground] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.NoDaemon] = EffectiveConfigParserBehavior.Flag,
+ [DnsmasqConfKeys.Conntrack] = EffectiveConfigParserBehavior.LastWins,
+ };
+
+ /// Returns LastWins, Flag, or Multi for the given option name; defaults to LastWins if unknown.
+ public static EffectiveConfigParserBehavior GetBehavior(string optionName) =>
+ BehaviorByOptionName.TryGetValue(optionName, out var b) ? b : EffectiveConfigParserBehavior.LastWins;
+}
diff --git a/src/DnsmasqWebUI/Infrastructure/Helpers/Config/EffectiveConfigViews.cs b/src/DnsmasqWebUI/Infrastructure/Helpers/Config/EffectiveConfigViews.cs
index 36b58a0..66d4dd5 100644
--- a/src/DnsmasqWebUI/Infrastructure/Helpers/Config/EffectiveConfigViews.cs
+++ b/src/DnsmasqWebUI/Infrastructure/Helpers/Config/EffectiveConfigViews.cs
@@ -1,5 +1,6 @@
using DnsmasqWebUI.Models.Dnsmasq;
using DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig;
+using DnsmasqWebUI.Infrastructure.Services.Abstractions;
namespace DnsmasqWebUI.Infrastructure.Helpers.Config;
@@ -50,14 +51,16 @@ public static class EffectiveConfigViews
/// For each section in the view, returns the context-visible descriptors for that section.
/// Does not apply search; component applies search to each section's list and hides sections with no matches.
///
+ /// When provided, used to create the correct descriptor type per field (e.g. integer options).
public static IReadOnlyDictionary> GetDescriptorsBySection(
DnsmasqServiceStatus? status,
- IReadOnlyList views)
+ IReadOnlyList views,
+ IEffectiveConfigRenderFragmentRegistry? registry = null)
{
if (status == null || views.Count == 0)
return new Dictionary>();
- var allDescriptors = EffectiveConfigFieldBuilder.BuildFieldDescriptors(status);
+ var allDescriptors = EffectiveConfigFieldBuilder.BuildFieldDescriptors(status, registry);
var result = new Dictionary>(StringComparer.OrdinalIgnoreCase);
foreach (var view in views)
diff --git a/src/DnsmasqWebUI/Infrastructure/Services/Abstractions/IEffectiveConfigRenderFragmentRegistry.cs b/src/DnsmasqWebUI/Infrastructure/Services/Abstractions/IEffectiveConfigRenderFragmentRegistry.cs
index f47c024..de52e99 100644
--- a/src/DnsmasqWebUI/Infrastructure/Services/Abstractions/IEffectiveConfigRenderFragmentRegistry.cs
+++ b/src/DnsmasqWebUI/Infrastructure/Services/Abstractions/IEffectiveConfigRenderFragmentRegistry.cs
@@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Components;
using DnsmasqWebUI.Models.Dnsmasq;
using DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig;
+using DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig.Abstractions;
namespace DnsmasqWebUI.Infrastructure.Services.Abstractions;
@@ -12,7 +13,12 @@ namespace DnsmasqWebUI.Infrastructure.Services.Abstractions;
public interface IEffectiveConfigRenderFragmentRegistry : IApplicationSingleton
{
///
- /// Returns a fragment that renders the custom value UI for this field, or null to use default rendering.
+ /// Builds a fragment that renders the custom value component for this field, or null to use default rendering.
///
- RenderFragment? GetDisplayFragment(string sectionId, string optionName);
+ RenderFragment? BuildFieldComponentFragment(string sectionId, string optionName);
+
+ ///
+ /// Returns a factory that creates the correct descriptor type for this field (e.g. ), or null to use the default.
+ ///
+ EffectiveConfigDescriptorFactory? GetDescriptorFactory(string sectionId, string optionName);
}
diff --git a/src/DnsmasqWebUI/Infrastructure/Services/ConfigSetCache.cs b/src/DnsmasqWebUI/Infrastructure/Services/ConfigSetCache.cs
index 2672eeb..1457f4a 100644
--- a/src/DnsmasqWebUI/Infrastructure/Services/ConfigSetCache.cs
+++ b/src/DnsmasqWebUI/Infrastructure/Services/ConfigSetCache.cs
@@ -214,159 +214,183 @@ public sealed class ConfigSetCache : IConfigSetCache, IDisposable
return dict;
}
+ /// Dispatches to GetFlag, GetLastValue, or GetMultiValue based on .
+ private static object ParseOptionValue(IReadOnlyList paths, IReadOnlyDictionary pathToLines, string optionName)
+ {
+ return EffectiveConfigParserBehaviorMap.GetBehavior(optionName) switch
+ {
+ EffectiveConfigParserBehavior.Flag => DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, optionName),
+ EffectiveConfigParserBehavior.LastWins => DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, optionName),
+ EffectiveConfigParserBehavior.Multi => DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, optionName),
+ _ => DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, optionName),
+ };
+ }
+
+ /// Dispatches to GetFlag/GetLastValue/GetMultiValue WithSource based on .
+ private static object ParseOptionWithSource(IReadOnlyList paths, IReadOnlyDictionary pathToLines, string optionName, string? managedFilePath)
+ {
+ return EffectiveConfigParserBehaviorMap.GetBehavior(optionName) switch
+ {
+ EffectiveConfigParserBehavior.Flag => DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, optionName, managedFilePath),
+ EffectiveConfigParserBehavior.LastWins => DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, optionName, managedFilePath),
+ EffectiveConfigParserBehavior.Multi => DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, optionName, managedFilePath),
+ _ => DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, optionName, managedFilePath),
+ };
+ }
+
private static EffectiveDnsmasqConfig BuildEffectiveConfig(IReadOnlyList paths, IReadOnlyDictionary pathToLines)
{
var noHosts = DnsmasqConfIncludeParser.GetNoHostsFromConfigFiles(paths, pathToLines);
var addnHosts = DnsmasqConfIncludeParser.GetAddnHostsPathsFromConfigFiles(paths, pathToLines);
- var (hostsdirVal, hostsdirDir) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.Hostsdir);
+ var (hostsdirVal, hostsdirDir) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.Hostsdir);
var hostsdirPath = string.IsNullOrWhiteSpace(hostsdirVal) ? null : DnsmasqConfIncludeParser.ResolvePath(hostsdirVal?.Trim(), hostsdirDir);
var serverLocal = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.ServerLocalKeys);
- var revServer = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.RevServer);
- var addressValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.Address);
- var interfaces = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.Interface);
- var listenAddresses = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.ListenAddress);
- var exceptInterfaces = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.ExceptInterface);
- var dhcpRanges = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DhcpRange);
- var dhcpHostLines = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DhcpHost);
- var dhcpOptionLines = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DhcpOption);
- var dhcpMatchValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DhcpMatch);
- var dhcpBootValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DhcpBoot);
- var dhcpIgnoreValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DhcpIgnore);
- var dhcpVendorclassValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DhcpVendorclass);
- var dhcpUserclassValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DhcpUserclass);
- var raParamValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.RaParam);
- var slaacValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.Slaac);
- var pxeServiceValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.PxeService);
- var trustAnchorValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.TrustAnchor);
- var resolvFiles = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.ResolvFile);
- var rebindDomainOk = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.RebindDomainOk);
- var bogusNxdomain = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.BogusNxdomain);
- var ignoreAddress = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.IgnoreAddress);
- var alias = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.Alias);
- var filterRr = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.FilterRr);
- var cacheRr = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.CacheRr);
- var authServer = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.AuthServer);
- var noDhcpInterface = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.NoDhcpInterface);
- var noDhcpv4Interface = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.NoDhcpv4Interface);
- var noDhcpv6Interface = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.NoDhcpv6Interface);
- var domainValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.Domain);
- var cnameValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.Cname);
- var mxHostValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.MxHost);
- var srvValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.Srv);
- var ptrRecordValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.PtrRecord);
- var txtRecordValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.TxtRecord);
- var naptrRecordValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.NaptrRecord);
- var hostRecordValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.HostRecord);
- var dynamicHostValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DynamicHost);
- var interfaceNameValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.InterfaceName);
- var dhcpOptionForceLines = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DhcpOptionForce);
- var ipsetValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.Ipset);
- var nftsetValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.Nftset);
- var dhcpMacValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DhcpMac);
- var dhcpNameMatchValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DhcpNameMatch);
- var dhcpIgnoreNamesValues = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DhcpIgnoreNames);
- var dhcpHostsfilePaths = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DhcpHostsfile);
- var dhcpOptsfilePaths = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DhcpOptsfile);
- var dhcpHostsdirPaths = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DhcpHostsdir);
+ var revServer = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.RevServer);
+ var addressValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.Address);
+ var interfaces = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.Interface);
+ var listenAddresses = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.ListenAddress);
+ var exceptInterfaces = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.ExceptInterface);
+ var dhcpRanges = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.DhcpRange);
+ var dhcpHostLines = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.DhcpHost);
+ var dhcpOptionLines = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.DhcpOption);
+ var dhcpMatchValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.DhcpMatch);
+ var dhcpBootValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.DhcpBoot);
+ var dhcpIgnoreValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.DhcpIgnore);
+ var dhcpVendorclassValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.DhcpVendorclass);
+ var dhcpUserclassValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.DhcpUserclass);
+ var raParamValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.RaParam);
+ var slaacValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.Slaac);
+ var pxeServiceValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.PxeService);
+ var trustAnchorValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.TrustAnchor);
+ var resolvFiles = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.ResolvFile);
+ var rebindDomainOk = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.RebindDomainOk);
+ var bogusNxdomain = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.BogusNxdomain);
+ var ignoreAddress = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.IgnoreAddress);
+ var alias = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.Alias);
+ var filterRr = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.FilterRr);
+ var cacheRr = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.CacheRr);
+ var authServer = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.AuthServer);
+ var noDhcpInterface = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.NoDhcpInterface);
+ var noDhcpv4Interface = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.NoDhcpv4Interface);
+ var noDhcpv6Interface = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.NoDhcpv6Interface);
+ var domainValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.Domain);
+ var cnameValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.Cname);
+ var mxHostValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.MxHost);
+ var srvValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.Srv);
+ var ptrRecordValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.PtrRecord);
+ var txtRecordValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.TxtRecord);
+ var naptrRecordValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.NaptrRecord);
+ var hostRecordValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.HostRecord);
+ var dynamicHostValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.DynamicHost);
+ var interfaceNameValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.InterfaceName);
+ var dhcpOptionForceLines = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.DhcpOptionForce);
+ var ipsetValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.Ipset);
+ var nftsetValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.Nftset);
+ var dhcpMacValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.DhcpMac);
+ var dhcpNameMatchValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.DhcpNameMatch);
+ var dhcpIgnoreNamesValues = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.DhcpIgnoreNames);
+ var dhcpHostsfilePaths = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.DhcpHostsfile);
+ var dhcpOptsfilePaths = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.DhcpOptsfile);
+ var dhcpHostsdirPaths = (IReadOnlyList)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.DhcpHostsdir);
- var expandHosts = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.ExpandHosts);
- var bogusPriv = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.BogusPriv);
- var strictOrder = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.StrictOrder);
- var allServers = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.AllServers);
- var noResolv = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.NoResolv);
- var domainNeeded = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DomainNeeded);
- var noPoll = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.NoPoll);
- var bindInterfaces = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.BindInterfaces);
- var bindDynamic = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.BindDynamic);
- var noNegcache = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.NoNegcache);
- var dnsLoopDetect = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DnsLoopDetect);
- var stopDnsRebind = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.StopDnsRebind);
- var rebindLocalhostOk = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.RebindLocalhostOk);
- var clearOnReload = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.ClearOnReload);
- var filterwin2k = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.Filterwin2k);
- var filterA = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.FilterA);
- var filterAaaa = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.FilterAaaa);
- var localiseQueries = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.LocaliseQueries);
- var logDebug = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.LogDebug);
- var dhcpAuthoritative = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DhcpAuthoritative);
- var leasefileRo = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.LeasefileRo);
- var enableTftp = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.EnableTftp);
- var tftpSecure = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.TftpSecure);
- var dnssec = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.Dnssec);
- var dnssecCheckUnsigned = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DnssecCheckUnsigned);
- var readEthers = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.ReadEthers);
- var dhcpRapidCommit = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DhcpRapidCommit);
- var tftpNoFail = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.TftpNoFail);
- var tftpNoBlocksize = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.TftpNoBlocksize);
- var localmx = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.Localmx);
- var selfmx = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.Selfmx);
- var enableRa = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.EnableRa);
- var logDhcp = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.LogDhcp);
- var keepInForeground = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.KeepInForeground);
- var noDaemon = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.NoDaemon);
- var proxyDnssec = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.ProxyDnssec);
+ var expandHosts = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.ExpandHosts);
+ var bogusPriv = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.BogusPriv);
+ var strictOrder = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.StrictOrder);
+ var allServers = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.AllServers);
+ var noResolv = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.NoResolv);
+ var domainNeeded = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.DomainNeeded);
+ var noPoll = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.NoPoll);
+ var bindInterfaces = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.BindInterfaces);
+ var bindDynamic = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.BindDynamic);
+ var noNegcache = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.NoNegcache);
+ var dnsLoopDetect = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.DnsLoopDetect);
+ var stopDnsRebind = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.StopDnsRebind);
+ var rebindLocalhostOk = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.RebindLocalhostOk);
+ var clearOnReload = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.ClearOnReload);
+ var filterwin2k = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.Filterwin2k);
+ var filterA = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.FilterA);
+ var filterAaaa = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.FilterAaaa);
+ var localiseQueries = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.LocaliseQueries);
+ var logDebug = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.LogDebug);
+ var dhcpAuthoritative = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.DhcpAuthoritative);
+ var leasefileRo = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.LeasefileRo);
+ var enableTftp = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.EnableTftp);
+ var tftpSecure = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.TftpSecure);
+ var dnssec = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.Dnssec);
+ var dnssecCheckUnsigned = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.DnssecCheckUnsigned);
+ var readEthers = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.ReadEthers);
+ var dhcpRapidCommit = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.DhcpRapidCommit);
+ var tftpNoFail = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.TftpNoFail);
+ var tftpNoBlocksize = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.TftpNoBlocksize);
+ var localmx = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.Localmx);
+ var selfmx = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.Selfmx);
+ var enableRa = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.EnableRa);
+ var logDhcp = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.LogDhcp);
+ var keepInForeground = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.KeepInForeground);
+ var noDaemon = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.NoDaemon);
+ var proxyDnssec = (bool)ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.ProxyDnssec);
var dhcpLeaseFilePath = DnsmasqConfIncludeParser.GetDhcpLeaseFilePathFromConfigFiles(paths, pathToLines);
- var (cacheVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.CacheSize);
+ var (cacheVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.CacheSize);
var cacheSize = TryParseInt(cacheVal);
- var (portVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.Port);
+ var (portVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.Port);
var port = TryParseInt(portVal);
- var (localTtlVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.LocalTtl);
+ var (localTtlVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.LocalTtl);
var localTtl = TryParseInt(localTtlVal);
- var (pidVal, pidDir) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.PidFile);
+ var (pidVal, pidDir) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.PidFile);
var pidFilePath = DnsmasqConfIncludeParser.ResolvePath(pidVal, pidDir);
- var (userVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.User);
+ var (userVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.User);
var user = string.IsNullOrWhiteSpace(userVal) ? null : userVal.Trim();
- var (groupVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.Group);
+ var (groupVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.Group);
var group = string.IsNullOrWhiteSpace(groupVal) ? null : groupVal.Trim();
- var (logFacVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.LogFacility);
+ var (logFacVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.LogFacility);
var logFacility = string.IsNullOrWhiteSpace(logFacVal) ? null : logFacVal.Trim();
- var (logQueriesVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.LogQueries);
+ var (logQueriesVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.LogQueries);
var logQueries = string.IsNullOrWhiteSpace(logQueriesVal) ? null : logQueriesVal.Trim();
- var (authTtlVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.AuthTtl);
+ var (authTtlVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.AuthTtl);
var authTtl = TryParseInt(authTtlVal);
- var (ednsPacketMaxVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.EdnsPacketMax);
+ var (ednsPacketMaxVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.EdnsPacketMax);
var ednsPacketMax = TryParseInt(ednsPacketMaxVal);
- var (queryPortVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.QueryPort);
+ var (queryPortVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.QueryPort);
var queryPort = TryParseInt(queryPortVal);
- var (portLimitVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.PortLimit);
+ var (portLimitVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.PortLimit);
var portLimit = TryParseInt(portLimitVal);
- var (minPortVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.MinPort);
+ var (minPortVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.MinPort);
var minPort = TryParseInt(minPortVal);
- var (maxPortVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.MaxPort);
+ var (maxPortVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.MaxPort);
var maxPort = TryParseInt(maxPortVal);
- var (logAsyncVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.LogAsync);
+ var (logAsyncVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.LogAsync);
var logAsync = string.IsNullOrWhiteSpace(logAsyncVal) ? null : logAsyncVal.Trim();
- var (localServiceVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.LocalService);
+ var (localServiceVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.LocalService);
var localService = string.IsNullOrWhiteSpace(localServiceVal) ? null : localServiceVal.Trim();
- var (leaseMaxVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DhcpLeaseMax);
+ var (leaseMaxVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.DhcpLeaseMax);
var dhcpLeaseMax = TryParseInt(leaseMaxVal);
- var (negTtlVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.NegTtl);
+ var (negTtlVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.NegTtl);
var negTtl = TryParseInt(negTtlVal);
- var (maxTtlVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.MaxTtl);
+ var (maxTtlVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.MaxTtl);
var maxTtl = TryParseInt(maxTtlVal);
- var (maxCacheTtlVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.MaxCacheTtl);
+ var (maxCacheTtlVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.MaxCacheTtl);
var maxCacheTtl = TryParseInt(maxCacheTtlVal);
- var (minCacheTtlVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.MinCacheTtl);
+ var (minCacheTtlVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.MinCacheTtl);
var minCacheTtl = TryParseInt(minCacheTtlVal);
- var (dhcpTtlVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DhcpTtl);
+ var (dhcpTtlVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.DhcpTtl);
var dhcpTtl = TryParseInt(dhcpTtlVal);
- var (tftpRootVal, tftpRootDir) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.TftpRoot);
+ var (tftpRootVal, tftpRootDir) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.TftpRoot);
var tftpRootPath = string.IsNullOrWhiteSpace(tftpRootVal) ? null : DnsmasqConfIncludeParser.ResolvePath(tftpRootVal?.Trim(), tftpRootDir);
- var (pxePromptVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.PxePrompt);
+ var (pxePromptVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.PxePrompt);
var pxePrompt = string.IsNullOrWhiteSpace(pxePromptVal) ? null : pxePromptVal.Trim();
- var (enableDbusVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.EnableDbus);
+ var (enableDbusVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.EnableDbus);
var enableDbus = string.IsNullOrWhiteSpace(enableDbusVal) ? null : enableDbusVal.Trim();
- var (enableUbusVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.EnableUbus);
+ var (enableUbusVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.EnableUbus);
var enableUbus = string.IsNullOrWhiteSpace(enableUbusVal) ? null : enableUbusVal.Trim();
- var (fastDnsRetryVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.FastDnsRetry);
+ var (fastDnsRetryVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.FastDnsRetry);
var fastDnsRetry = string.IsNullOrWhiteSpace(fastDnsRetryVal) ? null : fastDnsRetryVal.Trim();
- var (dhcpScriptVal, dhcpScriptDir) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DhcpScript);
+ var (dhcpScriptVal, dhcpScriptDir) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.DhcpScript);
var dhcpScriptPath = string.IsNullOrWhiteSpace(dhcpScriptVal) ? null : DnsmasqConfIncludeParser.ResolvePath(dhcpScriptVal?.Trim(), dhcpScriptDir);
- var (mxTargetVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.MxTarget);
+ var (mxTargetVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.MxTarget);
var mxTarget = string.IsNullOrWhiteSpace(mxTargetVal) ? null : mxTargetVal.Trim();
- var (conntrackVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.Conntrack);
+ var (conntrackVal, _) = ((string?, string?))ParseOptionValue(paths, pathToLines, DnsmasqConfKeys.Conntrack);
var conntrack = string.IsNullOrWhiteSpace(conntrackVal) ? null : conntrackVal.Trim();
return new EffectiveDnsmasqConfig(
@@ -390,126 +414,126 @@ public sealed class ConfigSetCache : IConfigSetCache, IDisposable
private static EffectiveConfigSources BuildEffectiveConfigSources(IReadOnlyList paths, IReadOnlyDictionary pathToLines, string? managedFilePath)
{
- var (_, noHostsSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.NoHosts, managedFilePath);
+ var (_, noHostsSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.NoHosts, managedFilePath);
var addnHostsWithSource = DnsmasqConfIncludeParser.GetAddnHostsPathsFromConfigFilesWithSource(paths, pathToLines, managedFilePath);
- var (_, hostsdirPathSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.Hostsdir, managedFilePath);
+ var (_, hostsdirPathSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.Hostsdir, managedFilePath);
var serverLocalWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.ServerLocalKeys, managedFilePath);
- var revServerWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.RevServer, managedFilePath);
- var addressWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.Address, managedFilePath);
- var interfacesWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.Interface, managedFilePath);
- var listenAddressesWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.ListenAddress, managedFilePath);
- var exceptInterfacesWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.ExceptInterface, managedFilePath);
- var dhcpRangesWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpRange, managedFilePath);
- var dhcpHostLinesWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpHost, managedFilePath);
- var dhcpOptionLinesWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpOption, managedFilePath);
- var dhcpMatchWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpMatch, managedFilePath);
- var dhcpBootWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpBoot, managedFilePath);
- var dhcpIgnoreWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpIgnore, managedFilePath);
- var dhcpVendorclassWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpVendorclass, managedFilePath);
- var dhcpUserclassWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpUserclass, managedFilePath);
- var raParamWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.RaParam, managedFilePath);
- var slaacWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.Slaac, managedFilePath);
- var pxeServiceWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.PxeService, managedFilePath);
- var trustAnchorWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.TrustAnchor, managedFilePath);
- var resolvFilesWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.ResolvFile, managedFilePath);
- var rebindDomainOkWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.RebindDomainOk, managedFilePath);
- var bogusNxdomainWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.BogusNxdomain, managedFilePath);
- var ignoreAddressWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.IgnoreAddress, managedFilePath);
- var aliasWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.Alias, managedFilePath);
- var filterRrWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.FilterRr, managedFilePath);
- var cacheRrWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.CacheRr, managedFilePath);
- var authServerWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.AuthServer, managedFilePath);
- var noDhcpInterfaceWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.NoDhcpInterface, managedFilePath);
- var noDhcpv4InterfaceWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.NoDhcpv4Interface, managedFilePath);
- var noDhcpv6InterfaceWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.NoDhcpv6Interface, managedFilePath);
- var domainWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.Domain, managedFilePath);
- var cnameWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.Cname, managedFilePath);
- var mxHostWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.MxHost, managedFilePath);
- var srvWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.Srv, managedFilePath);
- var ptrRecordWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.PtrRecord, managedFilePath);
- var txtRecordWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.TxtRecord, managedFilePath);
- var naptrRecordWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.NaptrRecord, managedFilePath);
- var hostRecordWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.HostRecord, managedFilePath);
- var dynamicHostWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.DynamicHost, managedFilePath);
- var interfaceNameWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.InterfaceName, managedFilePath);
- var dhcpOptionForceWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpOptionForce, managedFilePath);
- var ipsetWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.Ipset, managedFilePath);
- var nftsetWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.Nftset, managedFilePath);
- var dhcpMacWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpMac, managedFilePath);
- var dhcpNameMatchWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpNameMatch, managedFilePath);
- var dhcpIgnoreNamesWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpIgnoreNames, managedFilePath);
- var dhcpHostsfileWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpHostsfile, managedFilePath);
- var dhcpOptsfileWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpOptsfile, managedFilePath);
- var dhcpHostsdirWithSource = DnsmasqConfIncludeParser.GetMultiValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpHostsdir, managedFilePath);
+ var revServerWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.RevServer, managedFilePath);
+ var addressWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.Address, managedFilePath);
+ var interfacesWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.Interface, managedFilePath);
+ var listenAddressesWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.ListenAddress, managedFilePath);
+ var exceptInterfacesWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.ExceptInterface, managedFilePath);
+ var dhcpRangesWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpRange, managedFilePath);
+ var dhcpHostLinesWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpHost, managedFilePath);
+ var dhcpOptionLinesWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpOption, managedFilePath);
+ var dhcpMatchWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpMatch, managedFilePath);
+ var dhcpBootWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpBoot, managedFilePath);
+ var dhcpIgnoreWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpIgnore, managedFilePath);
+ var dhcpVendorclassWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpVendorclass, managedFilePath);
+ var dhcpUserclassWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpUserclass, managedFilePath);
+ var raParamWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.RaParam, managedFilePath);
+ var slaacWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.Slaac, managedFilePath);
+ var pxeServiceWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.PxeService, managedFilePath);
+ var trustAnchorWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.TrustAnchor, managedFilePath);
+ var resolvFilesWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.ResolvFile, managedFilePath);
+ var rebindDomainOkWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.RebindDomainOk, managedFilePath);
+ var bogusNxdomainWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.BogusNxdomain, managedFilePath);
+ var ignoreAddressWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.IgnoreAddress, managedFilePath);
+ var aliasWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.Alias, managedFilePath);
+ var filterRrWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.FilterRr, managedFilePath);
+ var cacheRrWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.CacheRr, managedFilePath);
+ var authServerWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.AuthServer, managedFilePath);
+ var noDhcpInterfaceWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.NoDhcpInterface, managedFilePath);
+ var noDhcpv4InterfaceWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.NoDhcpv4Interface, managedFilePath);
+ var noDhcpv6InterfaceWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.NoDhcpv6Interface, managedFilePath);
+ var domainWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.Domain, managedFilePath);
+ var cnameWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.Cname, managedFilePath);
+ var mxHostWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.MxHost, managedFilePath);
+ var srvWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.Srv, managedFilePath);
+ var ptrRecordWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.PtrRecord, managedFilePath);
+ var txtRecordWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.TxtRecord, managedFilePath);
+ var naptrRecordWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.NaptrRecord, managedFilePath);
+ var hostRecordWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.HostRecord, managedFilePath);
+ var dynamicHostWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.DynamicHost, managedFilePath);
+ var interfaceNameWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.InterfaceName, managedFilePath);
+ var dhcpOptionForceWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpOptionForce, managedFilePath);
+ var ipsetWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.Ipset, managedFilePath);
+ var nftsetWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.Nftset, managedFilePath);
+ var dhcpMacWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpMac, managedFilePath);
+ var dhcpNameMatchWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpNameMatch, managedFilePath);
+ var dhcpIgnoreNamesWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpIgnoreNames, managedFilePath);
+ var dhcpHostsfileWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpHostsfile, managedFilePath);
+ var dhcpOptsfileWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpOptsfile, managedFilePath);
+ var dhcpHostsdirWithSource = (IReadOnlyList<(string Value, ConfigValueSource Source)>)ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpHostsdir, managedFilePath);
- var (_, expandHostsSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.ExpandHosts, managedFilePath);
- var (_, bogusPrivSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.BogusPriv, managedFilePath);
- var (_, strictOrderSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.StrictOrder, managedFilePath);
- var (_, allServersSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.AllServers, managedFilePath);
- var (_, noResolvSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.NoResolv, managedFilePath);
- var (_, domainNeededSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.DomainNeeded, managedFilePath);
- var (_, noPollSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.NoPoll, managedFilePath);
- var (_, bindInterfacesSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.BindInterfaces, managedFilePath);
- var (_, bindDynamicSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.BindDynamic, managedFilePath);
- var (_, noNegcacheSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.NoNegcache, managedFilePath);
- var (_, dnsLoopDetectSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.DnsLoopDetect, managedFilePath);
- var (_, stopDnsRebindSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.StopDnsRebind, managedFilePath);
- var (_, rebindLocalhostOkSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.RebindLocalhostOk, managedFilePath);
- var (_, clearOnReloadSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.ClearOnReload, managedFilePath);
- var (_, filterwin2kSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.Filterwin2k, managedFilePath);
- var (_, filterASource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.FilterA, managedFilePath);
- var (_, filterAaaaSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.FilterAaaa, managedFilePath);
- var (_, localiseQueriesSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.LocaliseQueries, managedFilePath);
- var (_, logDebugSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.LogDebug, managedFilePath);
- var (_, dhcpAuthoritativeSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpAuthoritative, managedFilePath);
- var (_, leasefileRoSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.LeasefileRo, managedFilePath);
- var (_, enableTftpSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.EnableTftp, managedFilePath);
- var (_, tftpSecureSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.TftpSecure, managedFilePath);
- var (_, dnssecSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.Dnssec, managedFilePath);
- var (_, dnssecCheckUnsignedSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.DnssecCheckUnsigned, managedFilePath);
- var (_, readEthersSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.ReadEthers, managedFilePath);
- var (_, dhcpRapidCommitSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpRapidCommit, managedFilePath);
- var (_, tftpNoFailSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.TftpNoFail, managedFilePath);
- var (_, tftpNoBlocksizeSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.TftpNoBlocksize, managedFilePath);
- var (_, localmxSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.Localmx, managedFilePath);
- var (_, selfmxSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.Selfmx, managedFilePath);
- var (_, enableRaSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.EnableRa, managedFilePath);
- var (_, logDhcpSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.LogDhcp, managedFilePath);
- var (_, keepInForegroundSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.KeepInForeground, managedFilePath);
- var (_, noDaemonSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.NoDaemon, managedFilePath);
- var (_, proxyDnssecSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.ProxyDnssec, managedFilePath);
+ var (_, expandHostsSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.ExpandHosts, managedFilePath);
+ var (_, bogusPrivSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.BogusPriv, managedFilePath);
+ var (_, strictOrderSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.StrictOrder, managedFilePath);
+ var (_, allServersSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.AllServers, managedFilePath);
+ var (_, noResolvSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.NoResolv, managedFilePath);
+ var (_, domainNeededSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.DomainNeeded, managedFilePath);
+ var (_, noPollSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.NoPoll, managedFilePath);
+ var (_, bindInterfacesSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.BindInterfaces, managedFilePath);
+ var (_, bindDynamicSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.BindDynamic, managedFilePath);
+ var (_, noNegcacheSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.NoNegcache, managedFilePath);
+ var (_, dnsLoopDetectSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.DnsLoopDetect, managedFilePath);
+ var (_, stopDnsRebindSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.StopDnsRebind, managedFilePath);
+ var (_, rebindLocalhostOkSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.RebindLocalhostOk, managedFilePath);
+ var (_, clearOnReloadSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.ClearOnReload, managedFilePath);
+ var (_, filterwin2kSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.Filterwin2k, managedFilePath);
+ var (_, filterASource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.FilterA, managedFilePath);
+ var (_, filterAaaaSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.FilterAaaa, managedFilePath);
+ var (_, localiseQueriesSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.LocaliseQueries, managedFilePath);
+ var (_, logDebugSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.LogDebug, managedFilePath);
+ var (_, dhcpAuthoritativeSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpAuthoritative, managedFilePath);
+ var (_, leasefileRoSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.LeasefileRo, managedFilePath);
+ var (_, enableTftpSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.EnableTftp, managedFilePath);
+ var (_, tftpSecureSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.TftpSecure, managedFilePath);
+ var (_, dnssecSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.Dnssec, managedFilePath);
+ var (_, dnssecCheckUnsignedSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.DnssecCheckUnsigned, managedFilePath);
+ var (_, readEthersSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.ReadEthers, managedFilePath);
+ var (_, dhcpRapidCommitSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpRapidCommit, managedFilePath);
+ var (_, tftpNoFailSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.TftpNoFail, managedFilePath);
+ var (_, tftpNoBlocksizeSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.TftpNoBlocksize, managedFilePath);
+ var (_, localmxSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.Localmx, managedFilePath);
+ var (_, selfmxSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.Selfmx, managedFilePath);
+ var (_, enableRaSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.EnableRa, managedFilePath);
+ var (_, logDhcpSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.LogDhcp, managedFilePath);
+ var (_, keepInForegroundSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.KeepInForeground, managedFilePath);
+ var (_, noDaemonSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.NoDaemon, managedFilePath);
+ var (_, proxyDnssecSource) = ((bool, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.ProxyDnssec, managedFilePath);
var (_, dhcpLeaseFilePathSource) = DnsmasqConfIncludeParser.GetDhcpLeaseFilePathFromConfigFilesWithSource(paths, pathToLines, managedFilePath);
- var (_, cacheSizeSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.CacheSize, managedFilePath);
- var (_, portSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.Port, managedFilePath);
- var (_, localTtlSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.LocalTtl, managedFilePath);
- var (_, pidFilePathSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.PidFile, managedFilePath);
- var (_, userSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.User, managedFilePath);
- var (_, groupSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.Group, managedFilePath);
- var (_, logFacilitySource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.LogFacility, managedFilePath);
- var (_, logQueriesSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.LogQueries, managedFilePath);
- var (_, authTtlSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.AuthTtl, managedFilePath);
- var (_, ednsPacketMaxSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.EdnsPacketMax, managedFilePath);
- var (_, queryPortSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.QueryPort, managedFilePath);
- var (_, portLimitSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.PortLimit, managedFilePath);
- var (_, minPortSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.MinPort, managedFilePath);
- var (_, maxPortSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.MaxPort, managedFilePath);
- var (_, logAsyncSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.LogAsync, managedFilePath);
- var (_, localServiceSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.LocalService, managedFilePath);
- var (_, dhcpLeaseMaxSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpLeaseMax, managedFilePath);
- var (_, negTtlSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.NegTtl, managedFilePath);
- var (_, maxTtlSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.MaxTtl, managedFilePath);
- var (_, maxCacheTtlSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.MaxCacheTtl, managedFilePath);
- var (_, minCacheTtlSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.MinCacheTtl, managedFilePath);
- var (_, dhcpTtlSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpTtl, managedFilePath);
- var (_, tftpRootPathSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.TftpRoot, managedFilePath);
- var (_, pxePromptSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.PxePrompt, managedFilePath);
- var (_, enableDbusSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.EnableDbus, managedFilePath);
- var (_, enableUbusSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.EnableUbus, managedFilePath);
- var (_, fastDnsRetrySource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.FastDnsRetry, managedFilePath);
- var (_, dhcpScriptPathSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpScript, managedFilePath);
- var (_, mxTargetSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.MxTarget, managedFilePath);
- var (_, conntrackSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.Conntrack, managedFilePath);
+ var (_, cacheSizeSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.CacheSize, managedFilePath);
+ var (_, portSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.Port, managedFilePath);
+ var (_, localTtlSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.LocalTtl, managedFilePath);
+ var (_, pidFilePathSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.PidFile, managedFilePath);
+ var (_, userSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.User, managedFilePath);
+ var (_, groupSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.Group, managedFilePath);
+ var (_, logFacilitySource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.LogFacility, managedFilePath);
+ var (_, logQueriesSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.LogQueries, managedFilePath);
+ var (_, authTtlSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.AuthTtl, managedFilePath);
+ var (_, ednsPacketMaxSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.EdnsPacketMax, managedFilePath);
+ var (_, queryPortSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.QueryPort, managedFilePath);
+ var (_, portLimitSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.PortLimit, managedFilePath);
+ var (_, minPortSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.MinPort, managedFilePath);
+ var (_, maxPortSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.MaxPort, managedFilePath);
+ var (_, logAsyncSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.LogAsync, managedFilePath);
+ var (_, localServiceSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.LocalService, managedFilePath);
+ var (_, dhcpLeaseMaxSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpLeaseMax, managedFilePath);
+ var (_, negTtlSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.NegTtl, managedFilePath);
+ var (_, maxTtlSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.MaxTtl, managedFilePath);
+ var (_, maxCacheTtlSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.MaxCacheTtl, managedFilePath);
+ var (_, minCacheTtlSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.MinCacheTtl, managedFilePath);
+ var (_, dhcpTtlSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpTtl, managedFilePath);
+ var (_, tftpRootPathSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.TftpRoot, managedFilePath);
+ var (_, pxePromptSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.PxePrompt, managedFilePath);
+ var (_, enableDbusSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.EnableDbus, managedFilePath);
+ var (_, enableUbusSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.EnableUbus, managedFilePath);
+ var (_, fastDnsRetrySource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.FastDnsRetry, managedFilePath);
+ var (_, dhcpScriptPathSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.DhcpScript, managedFilePath);
+ var (_, mxTargetSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.MxTarget, managedFilePath);
+ var (_, conntrackSource) = ((string?, ConfigValueSource?))ParseOptionWithSource(paths, pathToLines, DnsmasqConfKeys.Conntrack, managedFilePath);
return new EffectiveConfigSources(
noHostsSource, addnHostsWithSource.Select(t => new PathWithSource(t.Path, t.Source)).ToList(), hostsdirPathSource,
diff --git a/src/DnsmasqWebUI/Infrastructure/Services/EffectiveConfigRenderFragmentRegistry.cs b/src/DnsmasqWebUI/Infrastructure/Services/EffectiveConfigRenderFragmentRegistry.cs
index 10ecada..585615a 100644
--- a/src/DnsmasqWebUI/Infrastructure/Services/EffectiveConfigRenderFragmentRegistry.cs
+++ b/src/DnsmasqWebUI/Infrastructure/Services/EffectiveConfigRenderFragmentRegistry.cs
@@ -2,23 +2,41 @@ using Microsoft.AspNetCore.Components;
using DnsmasqWebUI.Infrastructure.Helpers.Config;
using DnsmasqWebUI.Models.Dnsmasq;
using DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig;
+using DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig.Abstractions;
using DnsmasqWebUI.Infrastructure.Services.Abstractions;
using DnsmasqWebUI.Components.Dnsmasq.EffectiveConfig.CustomDisplays;
namespace DnsmasqWebUI.Infrastructure.Services;
///
-/// Maps (sectionId, optionName) to custom effective-config value display component types and builds
-/// RenderFragments that render those components with the descriptor.
+/// Maps (sectionId, optionName) to custom effective-config value display component types and descriptor factories.
+/// Builds RenderFragments that render those components with the descriptor.
///
public class EffectiveConfigRenderFragmentRegistry : IEffectiveConfigRenderFragmentRegistry
{
private readonly Dictionary<(string SectionId, string OptionName), Type> _displayComponents = new();
+ private readonly Dictionary<(string SectionId, string OptionName), EffectiveConfigDescriptorFactory> _descriptorFactories = new();
public EffectiveConfigRenderFragmentRegistry()
{
// Port: single-field display (e.g. "53 (default DNS port)").
- _displayComponents[(EffectiveConfigFieldBuilder.SectionResolver, DnsmasqConfKeys.Port)] = typeof(PortValueDisplay);
+ RegisterComponent(EffectiveConfigFieldBuilder.SectionResolver, DnsmasqConfKeys.Port, typeof(PortValueDisplay));
+
+ // Integer single-value options: component type + factory that creates EffectiveIntegerConfigFieldDescriptor.
+ RegisterInteger(EffectiveConfigFieldBuilder.SectionResolver, DnsmasqConfKeys.AuthTtl, unit: "seconds");
+ RegisterInteger(EffectiveConfigFieldBuilder.SectionResolver, DnsmasqConfKeys.EdnsPacketMax, max: 65535);
+ RegisterInteger(EffectiveConfigFieldBuilder.SectionResolver, DnsmasqConfKeys.QueryPort, max: 65535, defaultValue: 0);
+ RegisterInteger(EffectiveConfigFieldBuilder.SectionResolver, DnsmasqConfKeys.PortLimit, max: 65535);
+ RegisterInteger(EffectiveConfigFieldBuilder.SectionResolver, DnsmasqConfKeys.MinPort, min: 1, max: 65535);
+ RegisterInteger(EffectiveConfigFieldBuilder.SectionResolver, DnsmasqConfKeys.MaxPort, min: 1, max: 65535);
+ RegisterInteger(EffectiveConfigFieldBuilder.SectionCache, DnsmasqConfKeys.CacheSize, min: 0);
+ RegisterInteger(EffectiveConfigFieldBuilder.SectionCache, DnsmasqConfKeys.LocalTtl, unit: "seconds");
+ RegisterInteger(EffectiveConfigFieldBuilder.SectionCache, DnsmasqConfKeys.NegTtl, unit: "seconds");
+ RegisterInteger(EffectiveConfigFieldBuilder.SectionCache, DnsmasqConfKeys.MaxTtl, unit: "seconds");
+ RegisterInteger(EffectiveConfigFieldBuilder.SectionCache, DnsmasqConfKeys.MaxCacheTtl, unit: "seconds");
+ RegisterInteger(EffectiveConfigFieldBuilder.SectionCache, DnsmasqConfKeys.MinCacheTtl, unit: "seconds");
+ RegisterInteger(EffectiveConfigFieldBuilder.SectionDhcp, DnsmasqConfKeys.DhcpLeaseMax, min: 0);
+ RegisterInteger(EffectiveConfigFieldBuilder.SectionDhcp, DnsmasqConfKeys.DhcpTtl);
// Boolean flags: shared display ("Enabled" / "Disabled") for all flag options.
RegisterFlag(EffectiveConfigFieldBuilder.SectionHosts, DnsmasqConfKeys.NoHosts);
@@ -58,6 +76,17 @@ public class EffectiveConfigRenderFragmentRegistry : IEffectiveConfigRenderFragm
RegisterFlag(EffectiveConfigFieldBuilder.SectionProcess, DnsmasqConfKeys.KeepInForeground);
RegisterFlag(EffectiveConfigFieldBuilder.SectionProcess, DnsmasqConfKeys.NoDaemon);
RegisterFlag(EffectiveConfigFieldBuilder.SectionDnssec, DnsmasqConfKeys.ProxyDnssec);
+
+ // log-queries: dropdown (Off / On / extra / proto / auth).
+ RegisterComponent(EffectiveConfigFieldBuilder.SectionResolver, DnsmasqConfKeys.LogQueries, typeof(LogQueriesDisplay));
+
+ // local-service: dropdown (not set / net / host).
+ RegisterComponent(EffectiveConfigFieldBuilder.SectionProcess, DnsmasqConfKeys.LocalService, typeof(LocalServiceDisplay));
+ }
+
+ private void RegisterComponent(string sectionId, string optionName, Type componentType)
+ {
+ _displayComponents[(sectionId, optionName)] = componentType;
}
private void RegisterFlag(string sectionId, string optionName)
@@ -65,8 +94,22 @@ public class EffectiveConfigRenderFragmentRegistry : IEffectiveConfigRenderFragm
_displayComponents[(sectionId, optionName)] = typeof(FlagValueDisplay);
}
+ private void RegisterInteger(string sectionId, string optionName,
+ string? viewSuffix = null, string? unit = null, int min = 0, int max = int.MaxValue, int? defaultValue = null)
+ {
+ _displayComponents[(sectionId, optionName)] = typeof(IntegerValueDisplay);
+ _descriptorFactories[(sectionId, optionName)] = (sectionId, optionName, status, getValue, getSource, getItems) =>
+ new EffectiveIntegerConfigFieldDescriptor(sectionId, optionName, false, status, getValue, getSource, getItems, viewSuffix, unit, min, max, defaultValue);
+ }
+
///
- public RenderFragment? GetDisplayFragment(string sectionId, string optionName)
+ public EffectiveConfigDescriptorFactory? GetDescriptorFactory(string sectionId, string optionName)
+ {
+ return _descriptorFactories.TryGetValue((sectionId, optionName), out var factory) ? factory : null;
+ }
+
+ ///
+ public RenderFragment? BuildFieldComponentFragment(string sectionId, string optionName)
{
if (!_displayComponents.TryGetValue((sectionId, optionName), out var componentType))
return null;
diff --git a/src/DnsmasqWebUI/Models/Dnsmasq/EffectiveConfig/Abstractions/EffectiveConfigDescriptorFactory.cs b/src/DnsmasqWebUI/Models/Dnsmasq/EffectiveConfig/Abstractions/EffectiveConfigDescriptorFactory.cs
new file mode 100644
index 0000000..99d223f
--- /dev/null
+++ b/src/DnsmasqWebUI/Models/Dnsmasq/EffectiveConfig/Abstractions/EffectiveConfigDescriptorFactory.cs
@@ -0,0 +1,16 @@
+using DnsmasqWebUI.Models.Dnsmasq;
+using DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig;
+
+namespace DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig.Abstractions;
+
+///
+/// Creates an for a single-value field given section, option, status, and resolve delegates.
+/// Used by the registry so the builder can request the correct concrete descriptor type per registration (e.g. integer options).
+///
+public delegate IEffectiveConfigFieldDescriptor EffectiveConfigDescriptorFactory(
+ string sectionId,
+ string optionName,
+ DnsmasqServiceStatus? status,
+ Func? getValue,
+ Func? getSource,
+ Func?>? getItems);
diff --git a/src/DnsmasqWebUI/Models/Dnsmasq/EffectiveConfig/Abstractions/IEffectiveConfigFieldDescriptor.cs b/src/DnsmasqWebUI/Models/Dnsmasq/EffectiveConfig/Abstractions/IEffectiveConfigFieldDescriptor.cs
new file mode 100644
index 0000000..5e2c383
--- /dev/null
+++ b/src/DnsmasqWebUI/Models/Dnsmasq/EffectiveConfig/Abstractions/IEffectiveConfigFieldDescriptor.cs
@@ -0,0 +1,16 @@
+using DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig;
+
+namespace DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig.Abstractions;
+
+///
+/// Contract for one effective-config field: metadata (section, option name) and resolution of value, source, and items at render time.
+///
+public interface IEffectiveConfigFieldDescriptor
+{
+ string SectionId { get; }
+ string OptionName { get; }
+ bool IsMultiValue { get; }
+ object? GetValue();
+ ConfigValueSource? GetSource();
+ IReadOnlyList? GetItems();
+}
diff --git a/src/DnsmasqWebUI/Models/Dnsmasq/EffectiveConfig/EffectiveConfigFieldDescriptor.cs b/src/DnsmasqWebUI/Models/Dnsmasq/EffectiveConfig/EffectiveConfigFieldDescriptor.cs
index 00d6c6a..11d8cd1 100644
--- a/src/DnsmasqWebUI/Models/Dnsmasq/EffectiveConfig/EffectiveConfigFieldDescriptor.cs
+++ b/src/DnsmasqWebUI/Models/Dnsmasq/EffectiveConfig/EffectiveConfigFieldDescriptor.cs
@@ -1,4 +1,5 @@
using DnsmasqWebUI.Models.Dnsmasq;
+using DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig.Abstractions;
namespace DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig;
@@ -13,7 +14,7 @@ public record EffectiveConfigFieldDescriptor(
Func? ResolveValue,
Func? ResolveSource,
Func?>? ResolveItems
-)
+) : IEffectiveConfigFieldDescriptor
{
public object? GetValue() => ResolveValue?.Invoke(Status);
public ConfigValueSource? GetSource() => ResolveSource?.Invoke(Status);
diff --git a/src/DnsmasqWebUI/Models/Dnsmasq/EffectiveConfig/EffectiveIntegerConfigFieldDescriptor.cs b/src/DnsmasqWebUI/Models/Dnsmasq/EffectiveConfig/EffectiveIntegerConfigFieldDescriptor.cs
new file mode 100644
index 0000000..5363cb2
--- /dev/null
+++ b/src/DnsmasqWebUI/Models/Dnsmasq/EffectiveConfig/EffectiveIntegerConfigFieldDescriptor.cs
@@ -0,0 +1,21 @@
+using DnsmasqWebUI.Models.Dnsmasq;
+
+namespace DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig;
+
+///
+/// Descriptor for integer single-value options. Extends the base descriptor with display/validation metadata for number inputs.
+///
+public record EffectiveIntegerConfigFieldDescriptor(
+ string SectionId,
+ string OptionName,
+ bool IsMultiValue,
+ DnsmasqServiceStatus? Status,
+ Func? ResolveValue,
+ Func? ResolveSource,
+ Func?>? ResolveItems,
+ string? ViewSuffix = null,
+ string? Unit = null,
+ int Min = 0,
+ int Max = int.MaxValue,
+ int? DefaultValue = null
+) : EffectiveConfigFieldDescriptor(SectionId, OptionName, IsMultiValue, Status, ResolveValue, ResolveSource, ResolveItems);