mirror of
https://github.com/alexhopeoconnor/dnsmasq-webui.git
synced 2026-10-04 04:18:13 +10:00
Add 16 dnsmasq options, fix srv→srv-host, expand tests
- DnsmasqConfKeys: add ReadEthers, DhcpOptionForce, DhcpMac, DhcpNameMatch, DhcpIgnoreNames, Ipset, Nftset, MxTarget, TftpNoFail, TftpNoBlocksize, DhcpRapidCommit, Localmx, Selfmx, EnableRa, LogDhcp, DhcpScript. Fix SRV option key: srv → srv-host (dnsmasq uses srv-host). - Effective config: new multi-value, flags, single-value fields and sources; ConfigSetCache, EffectiveConfigFieldBuilder, Registry, Tooltips updated. - Tests: split DnsmasqConfIncludeParserTests into focused classes (CoreBehaviour, Include, HostsAndLease, SingleValue, Records, Interfaces, ServerAndResolv, DhcpTftpDnssec, Flags, OfficialExample, NewOptions). Rename *_ParsesRealExample to *_WhenSet_ReturnsValue(s). Add DnsmasqConfIncludeParserOfficialExampleTests (dnsmasq.official.conf.example). Add DnsmasqConfIncludeParserNewOptionsTests (positive tests for 16 options). EffectiveDnsmasqConfigTests: extend CreateConfig for new constructor params. - Testdata: add dnsmasq.official.conf.example; update README.
This commit is contained in:
@@ -70,4 +70,24 @@ public class DnsmasqConfDirectiveParserTests
|
||||
Assert.Equal(DnsmasqConfKeys.Port, kv!.Value.key);
|
||||
Assert.Equal(value, kv.Value.value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryParseKeyValue_ValueContainsEquals_ParsesFirstEqualsAsKeyValueSeparator()
|
||||
{
|
||||
var line = "server=/local/1.2.3.4";
|
||||
var kv = DnsmasqConfDirectiveParser.TryParseKeyValue(line);
|
||||
Assert.NotNull(kv);
|
||||
Assert.Equal("server", kv!.Value.key);
|
||||
Assert.Equal("/local/1.2.3.4", kv.Value.value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TryParseKeyValue_ErrorOverload_InvalidLine_ReturnsFalseAndSetsError()
|
||||
{
|
||||
// KeyValueLine requires at least one key character before '='; "=no-key" has no key and fails.
|
||||
var ok = DnsmasqConfDirectiveParser.TryParseKeyValue("=no-key", out var kv, out var error, out var errorPosition);
|
||||
Assert.False(ok);
|
||||
Assert.NotNull(error);
|
||||
Assert.True(errorPosition.Absolute >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,329 @@
|
||||
using DnsmasqWebUI.Infrastructure.Helpers.Config;
|
||||
using DnsmasqWebUI.Models.Dnsmasq;
|
||||
using DnsmasqWebUI.Infrastructure.Parsers;
|
||||
|
||||
namespace DnsmasqWebUI.Tests;
|
||||
|
||||
|
||||
/// <summary>Parser semantics: flags (option present/absent/with value), last-wins, case-sensitive, path order.</summary>
|
||||
public class DnsmasqConfIncludeParserCoreBehaviourTests
|
||||
{
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_OptionPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-flag-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
try
|
||||
{
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
File.WriteAllText(conf, "expand-hosts\nno-resolv\n");
|
||||
var result = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.ExpandHosts);
|
||||
Assert.True(result);
|
||||
Assert.True(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.NoResolv));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_OptionAbsent_ReturnsFalse()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-flag-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
try
|
||||
{
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
File.WriteAllText(conf, "port=53\n");
|
||||
var result = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.NoHosts);
|
||||
Assert.False(result);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_LastWins()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-last-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var f1 = Path.Combine(dir, "01.conf");
|
||||
var f2 = Path.Combine(dir, "02.conf");
|
||||
var firstVal = "100";
|
||||
var secondVal = "200";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(f1, $"cache-size={firstVal}\n");
|
||||
File.WriteAllText(f2, $"cache-size={secondVal}\n");
|
||||
var (value, configDir) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { f1, f2 }, DnsmasqConfKeys.CacheSize);
|
||||
Assert.Equal(secondVal, value);
|
||||
Assert.Equal(dir, configDir);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_LogFacility_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-logfac-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
try
|
||||
{
|
||||
var logPath = "/data/dnsmasq.log";
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
File.WriteAllText(conf, $"log-facility={logPath}\n");
|
||||
var (value, configDir) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.LogFacility);
|
||||
Assert.Equal(logPath, value);
|
||||
Assert.Equal(dir, configDir);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_LogFacility_LastWins()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-logfac2-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var f1 = Path.Combine(dir, "01.conf");
|
||||
var f2 = Path.Combine(dir, "02.conf");
|
||||
var firstLogPath = "/var/log/dnsmasq.log";
|
||||
var secondLogPath = "/data/dnsmasq.log";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(f1, $"log-facility={firstLogPath}\n");
|
||||
File.WriteAllText(f2, $"log-facility={secondLogPath}\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { f1, f2 }, DnsmasqConfKeys.LogFacility);
|
||||
Assert.Equal(secondLogPath, value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResolvePath_Relative_ResolvesAgainstDir()
|
||||
{
|
||||
var dir = Path.GetTempPath();
|
||||
var subDirName = "sub";
|
||||
var fileName = "pid.pid";
|
||||
var relativePath = $"{subDirName}/{fileName}";
|
||||
var result = DnsmasqConfIncludeParser.ResolvePath(relativePath, dir);
|
||||
Assert.Equal(Path.GetFullPath(Path.Combine(dir, subDirName, fileName)), result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResolvePath_Absolute_ReturnsAsIs()
|
||||
{
|
||||
var absPath = Path.Combine(Path.GetTempPath(), "absolute.pid");
|
||||
var result = DnsmasqConfIncludeParser.ResolvePath(absPath, "/some/dir");
|
||||
Assert.Equal(Path.GetFullPath(absPath), result);
|
||||
}
|
||||
|
||||
// --- Tests matching dnsmasq option.c semantics (ARG_ONE = last wins, flags = no value allowed) ---
|
||||
|
||||
/// <summary>dnsmasq option.c: opts[i].has_arg == 0 && arg -> "extraneous parameter"; flag with value is invalid, so we must not count it.</summary>
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_FlagWithValue_ReturnsFalse()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-flag-val-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
try
|
||||
{
|
||||
var invalidValue = "1";
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
File.WriteAllText(conf, $"expand-hosts={invalidValue}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.ExpandHosts);
|
||||
Assert.False(result);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>dnsmasq option.c: strcmp(opts[i].name, start) == 0 — option names are case-sensitive; "Port" is bad option.</summary>
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_CaseSensitive_PortWithCapitalP_ReturnsNull()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-case-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
try
|
||||
{
|
||||
var wrongKey = "Port";
|
||||
var value = "53";
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
File.WriteAllText(conf, $"{wrongKey}={value}\n");
|
||||
var (parsedValue, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.Port);
|
||||
Assert.Null(parsedValue);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Path list is [main, conf-file...]. We read each file entirely in that order, so last port is last occurrence in that stream (main lines then extra). Main has port=53, port=5353; extra has port=54 → last is 54.</summary>
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_TwoFiles_LastOccurrenceInPathOrderWins()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-two-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var main = Path.Combine(dir, "dnsmasq.conf");
|
||||
var extra = Path.Combine(dir, "extra.conf");
|
||||
var port1 = "53";
|
||||
var port2 = "5353";
|
||||
var port3 = "54";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(main, $"port={port1}\nconf-file=extra.conf\nport={port2}\n");
|
||||
File.WriteAllText(extra, $"port={port3}\n");
|
||||
var paths = DnsmasqConfIncludeParser.GetIncludedPaths(main);
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, DnsmasqConfKeys.Port);
|
||||
Assert.Equal(port3, value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
// --- pathToLines overloads: same result as file-based when content is pre-read ---
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_WithPathToLines_ReturnsSameResultAsFileBased()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-ptl-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var lines = new[] { "expand-hosts", "no-resolv" };
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, string.Join("\n", lines) + "\n");
|
||||
var paths = new[] { conf };
|
||||
var pathToLines = new Dictionary<string, string[]>(StringComparer.Ordinal)
|
||||
{
|
||||
[Path.GetFullPath(conf)] = lines
|
||||
};
|
||||
var fromFile = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, DnsmasqConfKeys.ExpandHosts);
|
||||
var fromDict = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.ExpandHosts);
|
||||
Assert.Equal(fromFile, fromDict);
|
||||
Assert.True(fromDict);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_WithPathToLines_ReturnsSameResultAsFileBased()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-ptl-last-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var value = "1000";
|
||||
var lines = new[] { $"cache-size={value}" };
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, lines[0] + "\n");
|
||||
var paths = new[] { conf };
|
||||
var pathToLines = new Dictionary<string, string[]>(StringComparer.Ordinal)
|
||||
{
|
||||
[Path.GetFullPath(conf)] = lines
|
||||
};
|
||||
var (fromFileVal, fromFileDir) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, DnsmasqConfKeys.CacheSize);
|
||||
var (fromDictVal, fromDictDir) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.CacheSize);
|
||||
Assert.Equal(fromFileVal, fromDictVal);
|
||||
Assert.Equal(value, fromDictVal);
|
||||
Assert.Equal(fromFileDir, fromDictDir);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_WithPathToLines_ReturnsSameResultAsFileBased()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-ptl-multi-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var lines = new[] { "server=1.1.1.1", "server=8.8.8.8" };
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, string.Join("\n", lines) + "\n");
|
||||
var paths = new[] { conf };
|
||||
var pathToLines = new Dictionary<string, string[]>(StringComparer.Ordinal)
|
||||
{
|
||||
[Path.GetFullPath(conf)] = lines
|
||||
};
|
||||
var fromFile = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, DnsmasqConfKeys.Server);
|
||||
var fromDict = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.Server);
|
||||
Assert.Equal(fromFile, fromDict);
|
||||
Assert.Equal(2, fromDict.Count);
|
||||
Assert.Equal("1.1.1.1", fromDict[0]);
|
||||
Assert.Equal("8.8.8.8", fromDict[1]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Empty path list ---
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_EmptyPathList_ReturnsNullAndNull()
|
||||
{
|
||||
var (value, configDir) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(Array.Empty<string>(), DnsmasqConfKeys.Port);
|
||||
Assert.Null(value);
|
||||
Assert.Null(configDir);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_EmptyPathList_ReturnsEmptyList()
|
||||
{
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(Array.Empty<string>(), DnsmasqConfKeys.Server);
|
||||
Assert.NotNull(result);
|
||||
Assert.Empty(result);
|
||||
}
|
||||
|
||||
// --- Non-existent file in path list: skipped without throw, last-wins from existing ---
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_NonExistentFileInList_SkipsMissingFileLastWinsFromExisting()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-missing-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var existing = Path.Combine(dir, "existing.conf");
|
||||
var missing = Path.Combine(dir, "missing.conf");
|
||||
var other = Path.Combine(dir, "other.conf");
|
||||
var valueInExisting = "100";
|
||||
var valueInOther = "200";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(existing, $"port={valueInExisting}\n");
|
||||
File.WriteAllText(other, $"port={valueInOther}\n");
|
||||
Assert.False(File.Exists(missing));
|
||||
var paths = new[] { existing, missing, other };
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, DnsmasqConfKeys.Port);
|
||||
Assert.Equal(valueInOther, value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,359 @@
|
||||
using DnsmasqWebUI.Infrastructure.Helpers.Config;
|
||||
using DnsmasqWebUI.Models.Dnsmasq;
|
||||
using DnsmasqWebUI.Infrastructure.Parsers;
|
||||
|
||||
namespace DnsmasqWebUI.Tests;
|
||||
|
||||
|
||||
/// <summary>DHCP advanced, TFTP/PXE, DNSSEC, enable-dbus/ubus, fast-dns-retry.</summary>
|
||||
public class DnsmasqConfIncludeParserDhcpTftpDnssecTests
|
||||
{
|
||||
// --- One test per option: key wired, when set returns value(s) ---
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_DhcpMatch_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-dhcpmatch-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "set:bios,option:client-arch,0";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"dhcp-match={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.DhcpMatch);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_DhcpBoot_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-dhcpboot-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "tag:bios-x86,firmware/ipxe.pxe,192.168.1.1";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"dhcp-boot={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.DhcpBoot);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_DhcpIgnore_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-dhcpignore-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "tag:!known";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"dhcp-ignore={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.DhcpIgnore);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_DhcpVendorclass_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-dhcpvc-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "set:pxe,option:vendor-class-identifier,PXEClient";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"dhcp-vendorclass={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.DhcpVendorclass);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_DhcpUserclass_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-dhcpuc-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "set:ipxe,iPXE";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"dhcp-userclass={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.DhcpUserclass);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_RaParam_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-raparam-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "eth0,high,0";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"ra-param={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.RaParam);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_Slaac_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-slaac-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "eth0,0";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"slaac={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.Slaac);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_EnableTftp_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-tftp-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "enable-tftp\n");
|
||||
var result = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.EnableTftp);
|
||||
Assert.True(result);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_TftpRoot_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-tftproot-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var path = "/var/lib/tftpboot";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"tftp-root={path}\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.TftpRoot);
|
||||
Assert.Equal(path, value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_TftpSecure_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-tftpsec-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "tftp-secure\n");
|
||||
var result = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.TftpSecure);
|
||||
Assert.True(result);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_PxeService_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-pxe-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "x86PC,pxelinux.0";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"pxe-service={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.PxeService);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_PxePrompt_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-pxeprompt-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "timeout,0";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"pxe-prompt={line}\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.PxePrompt);
|
||||
Assert.Equal(line, value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_Dnssec_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-dnssec-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "dnssec\n");
|
||||
var result = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.Dnssec);
|
||||
Assert.True(result);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_TrustAnchor_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-trust-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = ". IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDE32F024E8FC5";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"trust-anchor={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.TrustAnchor);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_DnssecCheckUnsigned_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-dnsseccu-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "dnssec-check-unsigned\n");
|
||||
var result = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.DnssecCheckUnsigned);
|
||||
Assert.True(result);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_EnableDbus_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-dbus-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var svc = "org.freedesktop.NetworkManager";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"enable-dbus={svc}\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.EnableDbus);
|
||||
Assert.Equal(svc, value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_EnableUbus_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-ubus-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var svc = "com.example.dnsmasq";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"enable-ubus={svc}\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.EnableUbus);
|
||||
Assert.Equal(svc, value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_FastDnsRetry_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-fastretry-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "500,5000";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"fast-dns-retry={line}\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.FastDnsRetry);
|
||||
Assert.Equal(line, value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
using DnsmasqWebUI.Infrastructure.Helpers.Config;
|
||||
using DnsmasqWebUI.Models.Dnsmasq;
|
||||
using DnsmasqWebUI.Infrastructure.Parsers;
|
||||
|
||||
namespace DnsmasqWebUI.Tests;
|
||||
|
||||
|
||||
/// <summary>Boolean flags: no-hosts, bogus-priv, strict-order, domain-needed, no-poll, bind-*, rebind-*, clear-on-reload, filter*, localise-queries, log-debug, dhcp-authoritative, leasefile-ro.</summary>
|
||||
public class DnsmasqConfIncludeParserFlagsTests
|
||||
{
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_BogusPriv_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-boguspriv-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "bogus-priv\n");
|
||||
Assert.True(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.BogusPriv));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_StrictOrder_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-strict-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "strict-order\n");
|
||||
Assert.True(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.StrictOrder));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_DomainNeeded_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-domainneed-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "domain-needed\n");
|
||||
Assert.True(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.DomainNeeded));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_NoPoll_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-nopoll-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "no-poll\n");
|
||||
Assert.True(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.NoPoll));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_BindInterfaces_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-bindif-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "bind-interfaces\n");
|
||||
Assert.True(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.BindInterfaces));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_BindDynamic_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-binddyn-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "bind-dynamic\n");
|
||||
Assert.True(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.BindDynamic));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_NoNegcache_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-noneg-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "no-negcache\n");
|
||||
Assert.True(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.NoNegcache));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_DnsLoopDetect_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-loop-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "dns-loop-detect\n");
|
||||
Assert.True(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.DnsLoopDetect));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_StopDnsRebind_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-rebind-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "stop-dns-rebind\n");
|
||||
Assert.True(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.StopDnsRebind));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_RebindLocalhostOk_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-rebindlo-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "rebind-localhost-ok\n");
|
||||
Assert.True(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.RebindLocalhostOk));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_ClearOnReload_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-clear-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "clear-on-reload\n");
|
||||
Assert.True(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.ClearOnReload));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_Filterwin2k_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-filtw2k-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "filterwin2k\n");
|
||||
Assert.True(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.Filterwin2k));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_FilterA_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-filta-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "filter-A\n");
|
||||
Assert.True(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.FilterA));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_FilterAaaa_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-filtaaaa-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "filter-AAAA\n");
|
||||
Assert.True(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.FilterAaaa));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_LocaliseQueries_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-localise-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "localise-queries\n");
|
||||
Assert.True(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.LocaliseQueries));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_LogDebug_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-logdbg-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "log-debug\n");
|
||||
Assert.True(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.LogDebug));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_DhcpAuthoritative_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-dhcpauth-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "dhcp-authoritative\n");
|
||||
Assert.True(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.DhcpAuthoritative));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
using DnsmasqWebUI.Infrastructure.Helpers.Config;
|
||||
using DnsmasqWebUI.Models.Dnsmasq;
|
||||
using DnsmasqWebUI.Infrastructure.Parsers;
|
||||
|
||||
namespace DnsmasqWebUI.Tests;
|
||||
|
||||
|
||||
/// <summary>Hosts (addn-hosts, hostsdir) and DHCP lease file parsing.</summary>
|
||||
public class DnsmasqConfIncludeParserHostsAndLeaseTests
|
||||
{
|
||||
[Fact]
|
||||
public void GetDhcpLeaseFilePathFromConfigFiles_FromTestdata_ReturnsLeasesPath()
|
||||
{
|
||||
var mainPath = TestDataHelper.GetPath("dnsmasq-test.conf");
|
||||
Assert.True(File.Exists(mainPath), "Testdata dnsmasq-test.conf required");
|
||||
var paths = new[] { mainPath };
|
||||
var result = DnsmasqConfIncludeParser.GetDhcpLeaseFilePathFromConfigFiles(paths);
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(Path.GetFullPath("/data/leases"), result);
|
||||
}
|
||||
|
||||
/// <summary>Uses testdata/dnsmasq-test.conf (harness main) to assert multi-value options are collected from testdata.</summary>
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_FromTestdata_ReturnsServerAndAddnHosts()
|
||||
{
|
||||
var mainPath = TestDataHelper.GetPath("dnsmasq-test.conf");
|
||||
Assert.True(File.Exists(mainPath), "Testdata dnsmasq-test.conf required");
|
||||
var paths = new[] { mainPath };
|
||||
var servers = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, DnsmasqConfKeys.ServerLocalKeys);
|
||||
var addnHosts = DnsmasqConfIncludeParser.GetAddnHostsPathsFromConfigFiles(paths);
|
||||
var addresses = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, DnsmasqConfKeys.Address);
|
||||
var listenAddrs = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, DnsmasqConfKeys.ListenAddress);
|
||||
Assert.True(servers.Count >= 2, "testdata dnsmasq-test.conf should have at least 2 server= lines");
|
||||
Assert.Contains("1.1.1.1", servers);
|
||||
Assert.Contains("8.8.8.8", servers);
|
||||
Assert.True(addnHosts.Count >= 2, "testdata should have at least 2 addn-hosts paths");
|
||||
Assert.True(addresses.Count >= 2, "testdata should have at least 2 address= lines");
|
||||
Assert.Single(listenAddrs);
|
||||
Assert.Equal("172.28.0.2", listenAddrs[0]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDhcpLeaseFilePathFromConfigFiles_LastWins()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-lease-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
try
|
||||
{
|
||||
var firstLeasePath = "/var/first.leases";
|
||||
var secondLeasePath = "/var/second.leases";
|
||||
var first = Path.Combine(dir, "first.conf");
|
||||
File.WriteAllText(first, $"dhcp-leasefile={firstLeasePath}\n");
|
||||
var second = Path.Combine(dir, "second.conf");
|
||||
File.WriteAllText(second, $"dhcp-leasefile={secondLeasePath}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetDhcpLeaseFilePathFromConfigFiles(new[] { first, second });
|
||||
Assert.Equal(Path.GetFullPath(secondLeasePath), result);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDhcpLeaseFilePathFromConfigFiles_RelativePath_ResolvedAgainstConfigDir()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-lease-rel-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
try
|
||||
{
|
||||
var subdir = "subdir";
|
||||
var leasesFile = "leases";
|
||||
var relativePath = $"{subdir}/{leasesFile}";
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
File.WriteAllText(conf, $"dhcp-leasefile={relativePath}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetDhcpLeaseFilePathFromConfigFiles(new[] { conf });
|
||||
Assert.Equal(Path.GetFullPath(Path.Combine(dir, subdir, leasesFile)), result);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAddnHostsPathsFromConfigFiles_Empty_ReturnsEmpty()
|
||||
{
|
||||
var result = DnsmasqConfIncludeParser.GetAddnHostsPathsFromConfigFiles(Array.Empty<string>());
|
||||
Assert.Empty(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAddnHostsPathsFromConfigFiles_Cumulative_ReturnsAllInOrder()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-addn-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
try
|
||||
{
|
||||
var path1 = "/etc/hosts.d/first";
|
||||
var path2 = "/data/hosts";
|
||||
var path3 = "/data/extra.hosts";
|
||||
var first = Path.Combine(dir, "first.conf");
|
||||
File.WriteAllText(first, $"addn-hosts={path1}\n");
|
||||
var second = Path.Combine(dir, "second.conf");
|
||||
File.WriteAllText(second, $"addn-hosts={path2}\naddn-hosts={path3}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetAddnHostsPathsFromConfigFiles(new[] { first, second });
|
||||
Assert.Equal(3, result.Count);
|
||||
Assert.Equal(Path.GetFullPath(path1), result[0]);
|
||||
Assert.Equal(Path.GetFullPath(path2), result[1]);
|
||||
Assert.Equal(Path.GetFullPath(path3), result[2]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAddnHostsPathsFromConfigFiles_RelativePath_ResolvedAgainstConfigDir()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-addn-rel-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
try
|
||||
{
|
||||
var pathPart1 = "hosts.d";
|
||||
var pathPart2 = "app.hosts";
|
||||
var addnRelativePath = $"{pathPart1}/{pathPart2}";
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
File.WriteAllText(conf, $"addn-hosts={addnRelativePath}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetAddnHostsPathsFromConfigFiles(new[] { conf });
|
||||
Assert.Single(result);
|
||||
Assert.Equal(Path.GetFullPath(Path.Combine(dir, pathPart1, pathPart2)), result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAddnHostsPathsFromConfigFilesWithSource_ReturnsSourcePerPath()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-addn-src-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var f1 = Path.Combine(dir, "01.conf");
|
||||
var f2 = Path.Combine(dir, "02.conf");
|
||||
var managedPath = Path.Combine(dir, "managed.conf");
|
||||
var path1 = "/etc/hosts.a";
|
||||
var path2 = "/etc/hosts.b";
|
||||
var path3 = "/etc/hosts.c";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(f1, $"addn-hosts={path1}\n");
|
||||
File.WriteAllText(f2, $"addn-hosts={path2}\naddn-hosts={path3}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetAddnHostsPathsFromConfigFilesWithSource(new[] { f1, f2 }, managedPath);
|
||||
Assert.Equal(3, result.Count);
|
||||
Assert.Equal(Path.GetFullPath(path1), result[0].Path);
|
||||
Assert.Equal(Path.GetFileName(f1), result[0].Source.FileName);
|
||||
Assert.False(result[0].Source.IsManaged);
|
||||
Assert.Equal(1, result[0].Source.LineNumber);
|
||||
Assert.Equal(Path.GetFullPath(path2), result[1].Path);
|
||||
Assert.Equal(Path.GetFileName(f2), result[1].Source.FileName);
|
||||
Assert.Equal(1, result[1].Source.LineNumber);
|
||||
Assert.Equal(Path.GetFullPath(path3), result[2].Path);
|
||||
Assert.Equal(2, result[2].Source.LineNumber);
|
||||
Assert.True(result[2].Source.IsReadOnly == !result[2].Source.IsManaged);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAddnHostsPathsFromConfigFilesWithSource_WhenManagedFileInList_IsManagedTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-addn-mgd-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var mainPath = Path.Combine(dir, "dnsmasq.conf");
|
||||
var managedPath = Path.Combine(dir, "zz-managed.conf");
|
||||
var readOnlyPath = "/other/hosts";
|
||||
var managedAddnPath = "/managed/hosts";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(mainPath, $"addn-hosts={readOnlyPath}\n");
|
||||
File.WriteAllText(managedPath, $"addn-hosts={managedAddnPath}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetAddnHostsPathsFromConfigFilesWithSource(new[] { mainPath, managedPath }, managedPath);
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.False(result[0].Source.IsManaged);
|
||||
Assert.Equal(1, result[0].Source.LineNumber);
|
||||
Assert.True(result[1].Source.IsManaged);
|
||||
Assert.Equal(1, result[1].Source.LineNumber);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,289 @@
|
||||
using DnsmasqWebUI.Infrastructure.Helpers.Config;
|
||||
using DnsmasqWebUI.Models.Dnsmasq;
|
||||
using DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig;
|
||||
using DnsmasqWebUI.Infrastructure.Parsers;
|
||||
|
||||
namespace DnsmasqWebUI.Tests;
|
||||
|
||||
|
||||
/// <summary>Config discovery: conf-file=, conf-dir=, GetIncludedPaths, GetFirstConfDir, GetIncludedPathsWithSource, conf-dir suffix.</summary>
|
||||
public class DnsmasqConfIncludeParserIncludeTests
|
||||
{
|
||||
[Fact]
|
||||
public void GetIncludedPaths_MainFileMissing_ReturnsOnlyMainPath()
|
||||
{
|
||||
var main = Path.Combine(Path.GetTempPath(), "nonexistent-dnsmasq-" + Guid.NewGuid().ToString("N") + ".conf");
|
||||
var paths = DnsmasqConfIncludeParser.GetIncludedPaths(main);
|
||||
Assert.Single(paths);
|
||||
Assert.Equal(Path.GetFullPath(main), paths[0]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetIncludedPaths_MainOnly_ReturnsSinglePath()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-main-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
try
|
||||
{
|
||||
var main = Path.Combine(dir, "dnsmasq.conf");
|
||||
File.WriteAllText(main, "domain=local\n");
|
||||
var paths = DnsmasqConfIncludeParser.GetIncludedPaths(main);
|
||||
Assert.Single(paths);
|
||||
Assert.Equal(Path.GetFullPath(main), paths[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetIncludedPaths_OneConfFile_ReturnsMainThenConfFile()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-conffile-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
try
|
||||
{
|
||||
var includeFileName = "extra.conf";
|
||||
var includePath = Path.Combine(dir, includeFileName);
|
||||
File.WriteAllText(includePath, "# extra\n");
|
||||
var main = Path.Combine(dir, "dnsmasq.conf");
|
||||
File.WriteAllText(main, $"conf-file={includeFileName}\n");
|
||||
var paths = DnsmasqConfIncludeParser.GetIncludedPaths(main);
|
||||
Assert.Equal(2, paths.Count);
|
||||
Assert.Equal(Path.GetFullPath(main), paths[0]);
|
||||
Assert.Equal(Path.GetFullPath(includePath), paths[1]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetIncludedPaths_OneConfDir_ReturnsMainThenDirFilesSorted()
|
||||
{
|
||||
var baseDir = Path.Combine(Path.GetTempPath(), "dnsmasq-confdir-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(baseDir);
|
||||
var confDirName = "d";
|
||||
var subDir = Path.Combine(baseDir, confDirName);
|
||||
Directory.CreateDirectory(subDir);
|
||||
var file1 = "aa.conf";
|
||||
var file2 = "zz.conf";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(Path.Combine(subDir, file2), "");
|
||||
File.WriteAllText(Path.Combine(subDir, file1), "");
|
||||
var main = Path.Combine(baseDir, "dnsmasq.conf");
|
||||
File.WriteAllText(main, $"conf-dir={confDirName}\n");
|
||||
var paths = DnsmasqConfIncludeParser.GetIncludedPaths(main);
|
||||
Assert.Equal(3, paths.Count); // main + aa.conf + zz.conf (alphabetical)
|
||||
Assert.Equal(Path.GetFullPath(main), paths[0]);
|
||||
Assert.Equal(Path.GetFullPath(Path.Combine(subDir, file1)), paths[1]);
|
||||
Assert.Equal(Path.GetFullPath(Path.Combine(subDir, file2)), paths[2]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(baseDir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFirstConfDir_NoConfDir_ReturnsNull()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-noconfdir-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
try
|
||||
{
|
||||
var main = Path.Combine(dir, "dnsmasq.conf");
|
||||
File.WriteAllText(main, "domain=local\nconf-file=other.conf\n");
|
||||
var first = DnsmasqConfIncludeParser.GetFirstConfDir(main);
|
||||
Assert.Null(first);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFirstConfDir_HasConfDir_ReturnsResolvedPath()
|
||||
{
|
||||
var baseDir = Path.Combine(Path.GetTempPath(), "dnsmasq-firstdir-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(baseDir);
|
||||
var confDirName = "dnsmasq.d";
|
||||
var subDir = Path.Combine(baseDir, confDirName);
|
||||
Directory.CreateDirectory(subDir);
|
||||
try
|
||||
{
|
||||
var main = Path.Combine(baseDir, "dnsmasq.conf");
|
||||
File.WriteAllText(main, $"conf-dir={confDirName}\n");
|
||||
var first = DnsmasqConfIncludeParser.GetFirstConfDir(main);
|
||||
Assert.NotNull(first);
|
||||
Assert.Equal(Path.GetFullPath(subDir), first);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(baseDir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetIncludedPaths_CommentsAndBlanks_Ignored()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-comments-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
try
|
||||
{
|
||||
var main = Path.Combine(dir, "dnsmasq.conf");
|
||||
File.WriteAllText(main, "# comment\n\n \nconf-file=extra.conf\n");
|
||||
var extra = Path.Combine(dir, "extra.conf");
|
||||
File.WriteAllText(extra, "");
|
||||
var paths = DnsmasqConfIncludeParser.GetIncludedPaths(main);
|
||||
Assert.Equal(2, paths.Count);
|
||||
Assert.Equal(Path.GetFullPath(extra), paths[1]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetIncludedPaths_ConfDirMissing_ReturnsMainOnly()
|
||||
{
|
||||
var baseDir = Path.Combine(Path.GetTempPath(), "dnsmasq-confdir-missing-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(baseDir);
|
||||
try
|
||||
{
|
||||
var main = Path.Combine(baseDir, "dnsmasq.conf");
|
||||
File.WriteAllText(main, "conf-dir=nonexistent-subdir\n");
|
||||
var paths = DnsmasqConfIncludeParser.GetIncludedPaths(main);
|
||||
Assert.Single(paths);
|
||||
Assert.Equal(Path.GetFullPath(main), paths[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(baseDir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Mirrors harness layout: main + conf-dir with multiple files (including lan-dns.conf) + conf-file. Asserts all appear in load order with correct sources.</summary>
|
||||
[Fact]
|
||||
public void GetIncludedPathsWithSource_ConfDirAndConfFile_ReturnsAllFilesInLoadOrderWithSources()
|
||||
{
|
||||
var baseDir = Path.Combine(Path.GetTempPath(), "dnsmasq-harness-layout-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(baseDir);
|
||||
var confDir = Path.Combine(baseDir, "dnsmasq.d");
|
||||
Directory.CreateDirectory(confDir);
|
||||
try
|
||||
{
|
||||
File.WriteAllText(Path.Combine(confDir, "01-other.conf"), "# other\n");
|
||||
File.WriteAllText(Path.Combine(confDir, "02-servers.conf"), "# servers\n");
|
||||
File.WriteAllText(Path.Combine(confDir, "lan-dns.conf"), "# lan dns\n");
|
||||
File.WriteAllText(Path.Combine(baseDir, "zz-dnsmasq-webui.conf"), "# managed\n");
|
||||
var main = Path.Combine(baseDir, "dnsmasq.conf");
|
||||
File.WriteAllText(main, "conf-dir=dnsmasq.d\nconf-file=zz-dnsmasq-webui.conf\n");
|
||||
var withSource = DnsmasqConfIncludeParser.GetIncludedPathsWithSource(main);
|
||||
Assert.Equal(5, withSource.Count);
|
||||
Assert.Equal(Path.GetFullPath(main), withSource[0].Path);
|
||||
Assert.Equal(DnsmasqConfFileSource.Main, withSource[0].Source);
|
||||
Assert.Equal(Path.GetFullPath(Path.Combine(confDir, "01-other.conf")), withSource[1].Path);
|
||||
Assert.Equal(DnsmasqConfFileSource.ConfDir, withSource[1].Source);
|
||||
Assert.Equal(Path.GetFullPath(Path.Combine(confDir, "02-servers.conf")), withSource[2].Path);
|
||||
Assert.Equal(DnsmasqConfFileSource.ConfDir, withSource[2].Source);
|
||||
Assert.Equal(Path.GetFullPath(Path.Combine(confDir, "lan-dns.conf")), withSource[3].Path);
|
||||
Assert.Equal(DnsmasqConfFileSource.ConfDir, withSource[3].Source);
|
||||
Assert.Equal(Path.GetFullPath(Path.Combine(baseDir, "zz-dnsmasq-webui.conf")), withSource[4].Path);
|
||||
Assert.Equal(DnsmasqConfFileSource.ConfFile, withSource[4].Source);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(baseDir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>dnsmasq conf-dir=dir,*.suffix only includes files ending with suffix (option.c match_suffix).</summary>
|
||||
[Fact]
|
||||
public void GetIncludedPaths_ConfDir_WithMatchSuffix_OnlyIncludesMatchingFiles()
|
||||
{
|
||||
var baseDir = Path.Combine(Path.GetTempPath(), "dnsmasq-match-" + Guid.NewGuid().ToString("N"));
|
||||
var subDir = Path.Combine(baseDir, "d");
|
||||
Directory.CreateDirectory(subDir);
|
||||
var fileConf1 = "a.conf";
|
||||
var fileTxt = "b.txt";
|
||||
var fileConf2 = "c.conf";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(Path.Combine(subDir, fileConf1), "");
|
||||
File.WriteAllText(Path.Combine(subDir, fileTxt), "");
|
||||
File.WriteAllText(Path.Combine(subDir, fileConf2), "");
|
||||
var main = Path.Combine(baseDir, "dnsmasq.conf");
|
||||
File.WriteAllText(main, "conf-dir=d,*.conf\n");
|
||||
var paths = DnsmasqConfIncludeParser.GetIncludedPaths(main);
|
||||
Assert.Equal(3, paths.Count);
|
||||
Assert.Contains(paths, p => p.EndsWith(fileConf1, StringComparison.Ordinal));
|
||||
Assert.Contains(paths, p => p.EndsWith(fileConf2, StringComparison.Ordinal));
|
||||
Assert.DoesNotContain(paths, p => p.EndsWith(fileTxt, StringComparison.Ordinal));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(baseDir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>dnsmasq conf-dir=dir,.suffix ignores files ending with suffix (option.c ignore_suffix).</summary>
|
||||
[Fact]
|
||||
public void GetIncludedPaths_ConfDir_WithIgnoreSuffix_ExcludesMatchingFiles()
|
||||
{
|
||||
var baseDir = Path.Combine(Path.GetTempPath(), "dnsmasq-ignore-" + Guid.NewGuid().ToString("N"));
|
||||
var subDir = Path.Combine(baseDir, "d");
|
||||
Directory.CreateDirectory(subDir);
|
||||
var fileIncluded = "a.conf";
|
||||
var fileExcluded = "b.conf.bak";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(Path.Combine(subDir, fileIncluded), "");
|
||||
File.WriteAllText(Path.Combine(subDir, fileExcluded), "");
|
||||
var main = Path.Combine(baseDir, "dnsmasq.conf");
|
||||
File.WriteAllText(main, "conf-dir=d,.bak\n");
|
||||
var paths = DnsmasqConfIncludeParser.GetIncludedPaths(main);
|
||||
Assert.Equal(2, paths.Count);
|
||||
Assert.Contains(paths, p => p.EndsWith(fileIncluded, StringComparison.Ordinal));
|
||||
Assert.DoesNotContain(paths, p => p.EndsWith(fileExcluded, StringComparison.Ordinal));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(baseDir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Direct test for EnumerateConfigLinesInDnsmasqOrder: main has line1, conf-file=extra, line2; extra has extra1. Asserts interleaving order.</summary>
|
||||
[Fact]
|
||||
public void EnumerateConfigLinesInDnsmasqOrder_ConfFileInMiddle_InterleavesMainThenIncludedThenMain()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-enum-order-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var main = Path.Combine(dir, "dnsmasq.conf");
|
||||
var extra = Path.Combine(dir, "extra.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(main, "line1\nconf-file=extra.conf\nline2\n");
|
||||
File.WriteAllText(extra, "extra1\n");
|
||||
var mainFull = Path.GetFullPath(main);
|
||||
var extraFull = Path.GetFullPath(extra);
|
||||
var mainDir = Path.GetDirectoryName(mainFull) ?? "";
|
||||
var seq = DnsmasqConfIncludeParser.EnumerateConfigLinesInDnsmasqOrder(mainFull, mainDir, DnsmasqConfFileSource.Main, null).ToList();
|
||||
Assert.Equal(5, seq.Count);
|
||||
Assert.Equal((mainFull, 0, "", DnsmasqConfFileSource.Main), seq[0]);
|
||||
Assert.Equal((mainFull, 1, "line1", DnsmasqConfFileSource.Main), seq[1]);
|
||||
Assert.Equal((extraFull, 0, "", DnsmasqConfFileSource.ConfFile), seq[2]);
|
||||
Assert.Equal((extraFull, 1, "extra1", DnsmasqConfFileSource.ConfFile), seq[3]);
|
||||
Assert.Equal((mainFull, 3, "line2", DnsmasqConfFileSource.Main), seq[4]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
using DnsmasqWebUI.Infrastructure.Helpers.Config;
|
||||
using DnsmasqWebUI.Models.Dnsmasq;
|
||||
using DnsmasqWebUI.Infrastructure.Parsers;
|
||||
|
||||
namespace DnsmasqWebUI.Tests;
|
||||
|
||||
|
||||
/// <summary>Interfaces, auth-server, DHCP/option/resolv multi-value, rebind/bogus/ignore/alias, filter-rr, cache-rr.</summary>
|
||||
public class DnsmasqConfIncludeParserInterfacesAndFilteringTests
|
||||
{
|
||||
// --- Additional tests: one per conf field so every option has a documented example test ---
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_Interface_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-if-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "interface=eth0\ninterface=wlan0\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.Interface);
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Equal("eth0", result[0]);
|
||||
Assert.Equal("wlan0", result[1]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_ExceptInterface_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-except-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "except-interface=eth1\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.ExceptInterface);
|
||||
Assert.Single(result);
|
||||
Assert.Equal("eth1", result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_NoDhcpInterface_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-nodhcpi-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "no-dhcp-interface=eth2\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.NoDhcpInterface);
|
||||
Assert.Single(result);
|
||||
Assert.Equal("eth2", result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_NoDhcpv4Interface_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-nodhcp4-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "no-dhcpv4-interface=eth0\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.NoDhcpv4Interface);
|
||||
Assert.Single(result);
|
||||
Assert.Equal("eth0", result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_NoDhcpv6Interface_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-nodhcp6-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "no-dhcpv6-interface=eth0\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.NoDhcpv6Interface);
|
||||
Assert.Single(result);
|
||||
Assert.Equal("eth0", result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_AuthServer_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-auth-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "lan,eth0";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"auth-server={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.AuthServer);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_DhcpHost_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-dhcphost-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "00:11:22:33:44:55,192.168.1.100,router,12h";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"dhcp-host={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.DhcpHost);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_DhcpOption_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-dhcpopt-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "option:router,192.168.1.1";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"dhcp-option={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.DhcpOption);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_ResolvFile_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-resolv-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var path = "/etc/resolv.dnsmasq";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"resolv-file={path}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.ResolvFile);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(path, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_RebindDomainOk_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-rebind-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "/local.lan/";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"rebind-domain-ok={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.RebindDomainOk);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_BogusNxdomain_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-bogusnx-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "64.94.110.11";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"bogus-nxdomain={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.BogusNxdomain);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_IgnoreAddress_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-ignoreaddr-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "192.168.1.0/24";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"ignore-address={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.IgnoreAddress);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_Alias_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-alias-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "1.2.3.0,6.7.8.0,255.255.255.0";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"alias={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.Alias);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_FilterRr_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-filterrr-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "TXT,MX";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"filter-rr={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.FilterRr);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_CacheRr_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-cacherr-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "TXT";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"cache-rr={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.CacheRr);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_NoHosts_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-nohosts-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "no-hosts\n");
|
||||
var result = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.NoHosts);
|
||||
Assert.True(result);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
using DnsmasqWebUI.Infrastructure.Helpers.Config;
|
||||
using DnsmasqWebUI.Models.Dnsmasq;
|
||||
using DnsmasqWebUI.Infrastructure.Parsers;
|
||||
|
||||
namespace DnsmasqWebUI.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Positive parser tests for the 16 added options: key wired and "option present" behaviour.
|
||||
/// Ensures key names in DnsmasqConfKeys match what the parser expects (complement to OfficialExampleTests which assert "all commented → false/empty").
|
||||
/// </summary>
|
||||
public class DnsmasqConfIncludeParserNewOptionsTests
|
||||
{
|
||||
// --- Flags (8): key-only line → GetFlag returns true ---
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_ReadEthers_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
WriteFlagAndAssertTrue(DnsmasqConfKeys.ReadEthers);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_DhcpRapidCommit_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
WriteFlagAndAssertTrue(DnsmasqConfKeys.DhcpRapidCommit);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_TftpNoFail_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
WriteFlagAndAssertTrue(DnsmasqConfKeys.TftpNoFail);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_TftpNoBlocksize_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
WriteFlagAndAssertTrue(DnsmasqConfKeys.TftpNoBlocksize);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_Localmx_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
WriteFlagAndAssertTrue(DnsmasqConfKeys.Localmx);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_Selfmx_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
WriteFlagAndAssertTrue(DnsmasqConfKeys.Selfmx);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_EnableRa_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
WriteFlagAndAssertTrue(DnsmasqConfKeys.EnableRa);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_LogDhcp_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
WriteFlagAndAssertTrue(DnsmasqConfKeys.LogDhcp);
|
||||
}
|
||||
|
||||
// --- Multi-value (6): key=value line(s) → GetMultiValue returns value(s) ---
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_DhcpOptionForce_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = CreateTempDir();
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "208,f1:00:74:7e";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"dhcp-option-force={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.DhcpOptionForce);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally { Directory.Delete(dir, recursive: true); }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_Ipset_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = CreateTempDir();
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "/example.com/vpn,search";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"ipset={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.Ipset);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally { Directory.Delete(dir, recursive: true); }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_Nftset_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = CreateTempDir();
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "/example.com/ip#test#vpn";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"nftset={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.Nftset);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally { Directory.Delete(dir, recursive: true); }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_DhcpMac_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = CreateTempDir();
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "set:red,00:60:8C:*:*:*";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"dhcp-mac={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.DhcpMac);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally { Directory.Delete(dir, recursive: true); }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_DhcpNameMatch_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = CreateTempDir();
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "set:wpad-ignore,wpad";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"dhcp-name-match={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.DhcpNameMatch);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally { Directory.Delete(dir, recursive: true); }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_DhcpIgnoreNames_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = CreateTempDir();
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "tag:wpad-ignore";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"dhcp-ignore-names={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.DhcpIgnoreNames);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally { Directory.Delete(dir, recursive: true); }
|
||||
}
|
||||
|
||||
// --- Single-value (2): key=value → GetLastValue returns value ---
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_MxTarget_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = CreateTempDir();
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var value = "mail.example.com";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"mx-target={value}\n");
|
||||
var (result, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.MxTarget);
|
||||
Assert.Equal(value, result);
|
||||
}
|
||||
finally { Directory.Delete(dir, recursive: true); }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_DhcpScript_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = CreateTempDir();
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var value = "/usr/bin/dnsmasq-script";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"dhcp-script={value}\n");
|
||||
var (result, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.DhcpScript);
|
||||
Assert.Equal(value, result);
|
||||
}
|
||||
finally { Directory.Delete(dir, recursive: true); }
|
||||
}
|
||||
|
||||
private static void WriteFlagAndAssertTrue(string key)
|
||||
{
|
||||
var dir = CreateTempDir();
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, key + "\n");
|
||||
Assert.True(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, key));
|
||||
}
|
||||
finally { Directory.Delete(dir, recursive: true); }
|
||||
}
|
||||
|
||||
private static string CreateTempDir()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-newopts-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
return dir;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
using DnsmasqWebUI.Infrastructure.Helpers.Config;
|
||||
using DnsmasqWebUI.Infrastructure.Parsers;
|
||||
|
||||
namespace DnsmasqWebUI.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Tests that the parser correctly handles the official dnsmasq example (testdata/dnsmasq.official.conf.example).
|
||||
/// All options in that file are commented out, so parsing it should yield no active values (single path, empty/false/null).
|
||||
/// </summary>
|
||||
public class DnsmasqConfIncludeParserOfficialExampleTests
|
||||
{
|
||||
private static string GetOfficialExamplePath()
|
||||
{
|
||||
var path = TestDataHelper.GetPath("dnsmasq.official.conf.example");
|
||||
Assert.True(File.Exists(path), "Testdata dnsmasq.official.conf.example required (download from https://github.com/imp/dnsmasq)");
|
||||
return path;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetIncludedPaths_OfficialExample_ReturnsSinglePath()
|
||||
{
|
||||
var mainPath = GetOfficialExamplePath();
|
||||
var paths = DnsmasqConfIncludeParser.GetIncludedPaths(mainPath);
|
||||
Assert.Single(paths);
|
||||
Assert.Equal(Path.GetFullPath(mainPath), paths[0]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_OfficialExample_AllCommented_ReturnsNull()
|
||||
{
|
||||
var mainPath = GetOfficialExamplePath();
|
||||
var paths = new[] { mainPath };
|
||||
var (portVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, DnsmasqConfKeys.Port);
|
||||
var (cacheVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, DnsmasqConfKeys.CacheSize);
|
||||
var (mxTargetVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, DnsmasqConfKeys.MxTarget);
|
||||
var (dhcpScriptVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, DnsmasqConfKeys.DhcpScript);
|
||||
Assert.Null(portVal);
|
||||
Assert.Null(cacheVal);
|
||||
Assert.Null(mxTargetVal);
|
||||
Assert.Null(dhcpScriptVal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_OfficialExample_AllCommented_ReturnsEmpty()
|
||||
{
|
||||
var mainPath = GetOfficialExamplePath();
|
||||
var paths = new[] { mainPath };
|
||||
var servers = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, DnsmasqConfKeys.ServerLocalKeys);
|
||||
var dhcpOptionForce = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, DnsmasqConfKeys.DhcpOptionForce);
|
||||
var ipset = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, DnsmasqConfKeys.Ipset);
|
||||
var nftset = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, DnsmasqConfKeys.Nftset);
|
||||
var dhcpMac = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, DnsmasqConfKeys.DhcpMac);
|
||||
var dhcpNameMatch = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, DnsmasqConfKeys.DhcpNameMatch);
|
||||
var dhcpIgnoreNames = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(paths, DnsmasqConfKeys.DhcpIgnoreNames);
|
||||
Assert.Empty(servers);
|
||||
Assert.Empty(dhcpOptionForce);
|
||||
Assert.Empty(ipset);
|
||||
Assert.Empty(nftset);
|
||||
Assert.Empty(dhcpMac);
|
||||
Assert.Empty(dhcpNameMatch);
|
||||
Assert.Empty(dhcpIgnoreNames);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_OfficialExample_AllCommented_ReturnsFalse()
|
||||
{
|
||||
var mainPath = GetOfficialExamplePath();
|
||||
var paths = new[] { mainPath };
|
||||
Assert.False(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, DnsmasqConfKeys.ExpandHosts));
|
||||
Assert.False(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, DnsmasqConfKeys.ReadEthers));
|
||||
Assert.False(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, DnsmasqConfKeys.DhcpRapidCommit));
|
||||
Assert.False(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, DnsmasqConfKeys.TftpNoFail));
|
||||
Assert.False(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, DnsmasqConfKeys.TftpNoBlocksize));
|
||||
Assert.False(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, DnsmasqConfKeys.Localmx));
|
||||
Assert.False(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, DnsmasqConfKeys.Selfmx));
|
||||
Assert.False(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, DnsmasqConfKeys.EnableRa));
|
||||
Assert.False(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, DnsmasqConfKeys.LogDhcp));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OfficialExample_FileContainsExpectedOptionNames()
|
||||
{
|
||||
var path = GetOfficialExamplePath();
|
||||
var content = File.ReadAllText(path);
|
||||
// Sanity: official example documents the options we support (as commented lines).
|
||||
Assert.Contains("read-ethers", content);
|
||||
Assert.Contains("dhcp-option-force", content);
|
||||
Assert.Contains("dhcp-rapid-commit", content);
|
||||
Assert.Contains("dhcp-script", content);
|
||||
Assert.Contains("tftp-no-fail", content);
|
||||
Assert.Contains("tftp-no-blocksize", content);
|
||||
Assert.Contains("mx-target", content);
|
||||
Assert.Contains("localmx", content);
|
||||
Assert.Contains("selfmx", content);
|
||||
Assert.Contains("enable-ra", content);
|
||||
Assert.Contains("log-dhcp", content);
|
||||
Assert.Contains("ipset=", content);
|
||||
Assert.Contains("nftset=", content);
|
||||
Assert.Contains("dhcp-mac", content);
|
||||
Assert.Contains("dhcp-name-match", content);
|
||||
Assert.Contains("dhcp-ignore-names", content);
|
||||
// SRV records use option name srv-host (not "srv")
|
||||
Assert.Contains("srv-host", content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetAddnHostsPathsFromConfigFiles_OfficialExample_AllCommented_ReturnsEmpty()
|
||||
{
|
||||
var mainPath = GetOfficialExamplePath();
|
||||
var paths = new[] { mainPath };
|
||||
var addnHosts = DnsmasqConfIncludeParser.GetAddnHostsPathsFromConfigFiles(paths);
|
||||
Assert.NotNull(addnHosts);
|
||||
Assert.Empty(addnHosts);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetNoHostsFromConfigFiles_OfficialExample_AllCommented_ReturnsFalse()
|
||||
{
|
||||
var mainPath = GetOfficialExamplePath();
|
||||
var paths = new[] { mainPath };
|
||||
var noHosts = DnsmasqConfIncludeParser.GetNoHostsFromConfigFiles(paths);
|
||||
Assert.False(noHosts);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
using DnsmasqWebUI.Infrastructure.Helpers.Config;
|
||||
using DnsmasqWebUI.Models.Dnsmasq;
|
||||
using DnsmasqWebUI.Infrastructure.Parsers;
|
||||
|
||||
namespace DnsmasqWebUI.Tests;
|
||||
|
||||
|
||||
/// <summary>DNS records and local names: hostsdir, domain, cname, mx-host, srv, ptr/txt/naptr/host-record, dynamic-host, interface-name.</summary>
|
||||
public class DnsmasqConfIncludeParserRecordsTests
|
||||
{
|
||||
// --- One test per option: key wired, when set returns value(s) ---
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_Hostsdir_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-hostsdir-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var path = "/etc/dnsmasq.d/hosts";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"hostsdir={path}\n");
|
||||
var (value, configDir) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.Hostsdir);
|
||||
Assert.Equal(path, value);
|
||||
Assert.Equal(dir, configDir);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_Domain_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-domain-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "home,192.168.1.1";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"domain={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.Domain);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_Cname_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-cname-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "mail.example.com,real.example.com";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"cname={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.Cname);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_MxHost_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-mx-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "example.com,mail.example.com,50";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"mx-host={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.MxHost);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_Srv_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-srv-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "_http._tcp.example.com,server.example.com,80";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"srv-host={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.Srv);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_PtrRecord_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-ptr-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "1.168.192.in-addr.arpa,host.example.com";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"ptr-record={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.PtrRecord);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_TxtRecord_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-txt-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "example.com,v=spf1 include:_spf.example.com";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"txt-record={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.TxtRecord);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_NaptrRecord_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-naptr-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "example.com,100,10,u,sip+E2U,sips:.*@example.com,.";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"naptr-record={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.NaptrRecord);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_HostRecord_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-hostrecord-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "router.example.com,192.168.1.1";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"host-record={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.HostRecord);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_DynamicHost_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-dynamichost-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "hostname,example.com,192.168.1.50";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"dynamic-host={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.DynamicHost);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_InterfaceName_WhenSet_ReturnsValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-ifname-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var line = "eth0,router.local";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"interface-name={line}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.InterfaceName);
|
||||
Assert.Single(result);
|
||||
Assert.Equal(line, result[0]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
using DnsmasqWebUI.Infrastructure.Helpers.Config;
|
||||
using DnsmasqWebUI.Models.Dnsmasq;
|
||||
using DnsmasqWebUI.Infrastructure.Parsers;
|
||||
|
||||
namespace DnsmasqWebUI.Tests;
|
||||
|
||||
|
||||
/// <summary>Server/local, rev-server, dhcp-range, all-servers, log-queries.</summary>
|
||||
public class DnsmasqConfIncludeParserServerAndResolvTests
|
||||
{
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_ServerAndLocal_CollectsBothInOrder()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-multi-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var f1 = Path.Combine(dir, "01.conf");
|
||||
var f2 = Path.Combine(dir, "02.conf");
|
||||
var v1 = "1.1.1.1";
|
||||
var v2 = "/local/";
|
||||
var v3 = "/example.com/192.168.1.1";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(f1, $"server={v1}\nlocal={v2}\n");
|
||||
File.WriteAllText(f2, $"server={v3}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { f1, f2 }, DnsmasqConfKeys.ServerLocalKeys);
|
||||
Assert.Equal(3, result.Count);
|
||||
Assert.Equal(v1, result[0]);
|
||||
Assert.Equal(v2, result[1]);
|
||||
Assert.Equal(v3, result[2]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_DhcpRange_CollectsAllInOrder()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-dhcp-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var range1 = "172.28.0.10,172.28.0.50,12h";
|
||||
var range2 = "192.168.1.10,192.168.1.100,255.255.255.0,24h";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"dhcp-range={range1}\ndhcp-range={range2}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.DhcpRange);
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Equal(range1, result[0]);
|
||||
Assert.Equal(range2, result[1]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_AllServers_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-allsrv-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "all-servers\n");
|
||||
var result = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.AllServers);
|
||||
Assert.True(result);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_LogQueries_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-logq-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "log-queries=extra\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.LogQueries);
|
||||
Assert.Equal("extra", value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetMultiValueFromConfigFiles_RevServer_ReturnsAllValues()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-rev-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var v1 = "1.2.3.0/24,192.168.0.1";
|
||||
var v2 = "10.0.0.0/8,10.0.0.1";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"rev-server={v1}\nrev-server={v2}\n");
|
||||
var result = DnsmasqConfIncludeParser.GetMultiValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.RevServer);
|
||||
Assert.Equal(2, result.Count);
|
||||
Assert.Equal(v1, result[0]);
|
||||
Assert.Equal(v2, result[1]);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,352 @@
|
||||
using DnsmasqWebUI.Infrastructure.Helpers.Config;
|
||||
using DnsmasqWebUI.Models.Dnsmasq;
|
||||
using DnsmasqWebUI.Infrastructure.Parsers;
|
||||
|
||||
namespace DnsmasqWebUI.Tests;
|
||||
|
||||
|
||||
/// <summary>Single-value options (last wins): local-ttl, pid-file, user, group, auth-ttl, edns-packet-max, query-port, port-limit, min/max-port, log-async, local-service, dhcp-lease-max, neg/max/min-cache-ttl, dhcp-ttl.</summary>
|
||||
public class DnsmasqConfIncludeParserSingleValueTests
|
||||
{
|
||||
[Fact]
|
||||
public void GetFlagFromConfigFiles_LeasefileRo_WhenPresent_ReturnsTrue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-leasero-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "leasefile-ro\n");
|
||||
Assert.True(DnsmasqConfIncludeParser.GetFlagFromConfigFiles(new[] { conf }, DnsmasqConfKeys.LeasefileRo));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_LocalTtl_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-localttl-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "local-ttl=300\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.LocalTtl);
|
||||
Assert.Equal("300", value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_PidFile_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-pid-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
var path = "/var/run/dnsmasq.pid";
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, $"pid-file={path}\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.PidFile);
|
||||
Assert.Equal(path, value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_User_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-user-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "user=nobody\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.User);
|
||||
Assert.Equal("nobody", value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_Group_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-group-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "group=dip\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.Group);
|
||||
Assert.Equal("dip", value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_AuthTtl_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-authttl-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "auth-ttl=60\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.AuthTtl);
|
||||
Assert.Equal("60", value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_EdnsPacketMax_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-edns-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "edns-packet-max=1232\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.EdnsPacketMax);
|
||||
Assert.Equal("1232", value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_QueryPort_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-qport-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "query-port=0\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.QueryPort);
|
||||
Assert.Equal("0", value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_PortLimit_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-portlimit-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "port-limit=3\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.PortLimit);
|
||||
Assert.Equal("3", value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_MinPort_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-minport-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "min-port=1024\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.MinPort);
|
||||
Assert.Equal("1024", value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_MaxPort_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-maxport-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "max-port=65535\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.MaxPort);
|
||||
Assert.Equal("65535", value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_LogAsync_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-logasync-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "log-async=25\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.LogAsync);
|
||||
Assert.Equal("25", value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_LocalService_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-localsvc-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "local-service=host\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.LocalService);
|
||||
Assert.Equal("host", value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_DhcpLeaseMax_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-leasemax-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "dhcp-lease-max=150\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.DhcpLeaseMax);
|
||||
Assert.Equal("150", value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_NegTtl_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-negttl-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "neg-ttl=60\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.NegTtl);
|
||||
Assert.Equal("60", value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_MaxTtl_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-maxttl-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "max-ttl=3600\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.MaxTtl);
|
||||
Assert.Equal("3600", value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_MaxCacheTtl_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-maxcttl-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "max-cache-ttl=86400\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.MaxCacheTtl);
|
||||
Assert.Equal("86400", value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_MinCacheTtl_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-mincttl-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "min-cache-ttl=60\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.MinCacheTtl);
|
||||
Assert.Equal("60", value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetLastValueFromConfigFiles_DhcpTtl_WhenSet_ReturnsValue()
|
||||
{
|
||||
var dir = Path.Combine(Path.GetTempPath(), "dnsmasq-dhcpttl-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(dir);
|
||||
var conf = Path.Combine(dir, "dnsmasq.conf");
|
||||
try
|
||||
{
|
||||
File.WriteAllText(conf, "dhcp-ttl=0\n");
|
||||
var (value, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(new[] { conf }, DnsmasqConfKeys.DhcpTtl);
|
||||
Assert.Equal("0", value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Directory.Delete(dir, recursive: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -44,6 +44,12 @@ public class EffectiveDnsmasqConfigTests
|
||||
DomainValues: Array.Empty<string>(), CnameValues: Array.Empty<string>(), MxHostValues: Array.Empty<string>(), SrvValues: Array.Empty<string>(),
|
||||
PtrRecordValues: Array.Empty<string>(), TxtRecordValues: Array.Empty<string>(), NaptrRecordValues: Array.Empty<string>(),
|
||||
HostRecordValues: Array.Empty<string>(), DynamicHostValues: Array.Empty<string>(), InterfaceNameValues: Array.Empty<string>(),
|
||||
DhcpOptionForceLines: Array.Empty<string>(),
|
||||
IpsetValues: Array.Empty<string>(),
|
||||
NftsetValues: Array.Empty<string>(),
|
||||
DhcpMacValues: Array.Empty<string>(),
|
||||
DhcpNameMatchValues: Array.Empty<string>(),
|
||||
DhcpIgnoreNamesValues: Array.Empty<string>(),
|
||||
ExpandHosts: false,
|
||||
BogusPriv: false,
|
||||
StrictOrder: false,
|
||||
@@ -67,8 +73,16 @@ public class EffectiveDnsmasqConfigTests
|
||||
LeasefileRo: false,
|
||||
EnableTftp: false,
|
||||
TftpSecure: false,
|
||||
TftpNoFail: false,
|
||||
TftpNoBlocksize: false,
|
||||
Dnssec: false,
|
||||
DnssecCheckUnsigned: false,
|
||||
ReadEthers: false,
|
||||
DhcpRapidCommit: false,
|
||||
Localmx: false,
|
||||
Selfmx: false,
|
||||
EnableRa: false,
|
||||
LogDhcp: false,
|
||||
DhcpLeaseFilePath: null,
|
||||
CacheSize: null,
|
||||
Port: null,
|
||||
@@ -96,7 +110,9 @@ public class EffectiveDnsmasqConfigTests
|
||||
PxePrompt: null,
|
||||
EnableDbus: null,
|
||||
EnableUbus: null,
|
||||
FastDnsRetry: null
|
||||
FastDnsRetry: null,
|
||||
DhcpScriptPath: null,
|
||||
MxTarget: null
|
||||
);
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -15,6 +15,7 @@ public static class DnsmasqConfKeys
|
||||
public const string NoHosts = "no-hosts";
|
||||
public const string AddnHosts = "addn-hosts";
|
||||
public const string Hostsdir = "hostsdir";
|
||||
public const string ReadEthers = "read-ethers";
|
||||
|
||||
// --- DHCP lease file (last wins) ---
|
||||
public const string DhcpLeasefile = "dhcp-leasefile";
|
||||
@@ -35,7 +36,11 @@ public static class DnsmasqConfKeys
|
||||
public const string DhcpRange = "dhcp-range";
|
||||
public const string DhcpHost = "dhcp-host";
|
||||
public const string DhcpOption = "dhcp-option";
|
||||
public const string DhcpOptionForce = "dhcp-option-force";
|
||||
public const string DhcpMatch = "dhcp-match";
|
||||
public const string DhcpMac = "dhcp-mac";
|
||||
public const string DhcpNameMatch = "dhcp-name-match";
|
||||
public const string DhcpIgnoreNames = "dhcp-ignore-names";
|
||||
public const string DhcpBoot = "dhcp-boot";
|
||||
public const string DhcpIgnore = "dhcp-ignore";
|
||||
public const string DhcpVendorclass = "dhcp-vendorclass";
|
||||
@@ -51,11 +56,14 @@ public static class DnsmasqConfKeys
|
||||
public const string Alias = "alias";
|
||||
public const string FilterRr = "filter-rr";
|
||||
public const string CacheRr = "cache-rr";
|
||||
public const string Ipset = "ipset";
|
||||
public const string Nftset = "nftset";
|
||||
// --- DNS records (authoritative / local) ---
|
||||
public const string Domain = "domain";
|
||||
public const string Cname = "cname";
|
||||
public const string MxHost = "mx-host";
|
||||
public const string Srv = "srv";
|
||||
public const string MxTarget = "mx-target";
|
||||
public const string Srv = "srv-host";
|
||||
public const string PtrRecord = "ptr-record";
|
||||
public const string TxtRecord = "txt-record";
|
||||
public const string NaptrRecord = "naptr-record";
|
||||
@@ -84,9 +92,16 @@ public static class DnsmasqConfKeys
|
||||
public const string LocaliseQueries = "localise-queries";
|
||||
public const string LogDebug = "log-debug";
|
||||
public const string DhcpAuthoritative = "dhcp-authoritative";
|
||||
public const string DhcpRapidCommit = "dhcp-rapid-commit";
|
||||
public const string LeasefileRo = "leasefile-ro";
|
||||
public const string Localmx = "localmx";
|
||||
public const string Selfmx = "selfmx";
|
||||
public const string EnableRa = "enable-ra";
|
||||
public const string LogDhcp = "log-dhcp";
|
||||
public const string EnableTftp = "enable-tftp";
|
||||
public const string TftpSecure = "tftp-secure";
|
||||
public const string TftpNoFail = "tftp-no-fail";
|
||||
public const string TftpNoBlocksize = "tftp-no-blocksize";
|
||||
public const string Dnssec = "dnssec";
|
||||
public const string DnssecCheckUnsigned = "dnssec-check-unsigned";
|
||||
|
||||
@@ -118,6 +133,7 @@ public static class DnsmasqConfKeys
|
||||
public const string EnableDbus = "enable-dbus";
|
||||
public const string EnableUbus = "enable-ubus";
|
||||
public const string FastDnsRetry = "fast-dns-retry";
|
||||
public const string DhcpScript = "dhcp-script";
|
||||
|
||||
/// <summary>Keys collected for effective config "server/local" multi-value (order preserved).</summary>
|
||||
public static readonly string[] ServerLocalKeys = { Server, Local };
|
||||
|
||||
@@ -17,6 +17,7 @@ public static class DnsmasqOptionTooltips
|
||||
[DnsmasqConfKeys.NoHosts] = "Do not read /etc/hosts; only use addn-hosts and DHCP/hosts.",
|
||||
[DnsmasqConfKeys.AddnHosts] = "Additional hosts files (one per line).",
|
||||
[DnsmasqConfKeys.Hostsdir] = "Directory of hosts files; new/changed files are read automatically.",
|
||||
[DnsmasqConfKeys.ReadEthers] = "Read /etc/ethers for MAC→IP mappings (like dhcp-host).",
|
||||
|
||||
// --- Resolver / DNS ---
|
||||
[DnsmasqConfKeys.ExpandHosts] = "Expand simple names in /etc/hosts with the local domain.",
|
||||
@@ -56,11 +57,16 @@ public static class DnsmasqOptionTooltips
|
||||
[DnsmasqConfKeys.NoDhcpInterface] = "No DHCP/TFTP/RA on these interfaces; DNS only. Can repeat.",
|
||||
[DnsmasqConfKeys.NoDhcpv4Interface] = "No DHCPv4 on these interfaces. Can repeat.",
|
||||
[DnsmasqConfKeys.NoDhcpv6Interface] = "No DHCPv6/RA on these interfaces. Can repeat.",
|
||||
[DnsmasqConfKeys.Ipset] = "Add resolved IPs to ipset (domain, set names). Can repeat.",
|
||||
[DnsmasqConfKeys.Nftset] = "Add resolved IPs to nftables sets. Can repeat.",
|
||||
|
||||
// --- DNS records ---
|
||||
[DnsmasqConfKeys.Domain] = "Local domain(s); optional IP. Can repeat (e.g. domain=home,192.168.1.1).",
|
||||
[DnsmasqConfKeys.Cname] = "CNAME records (alias, target). Can repeat.",
|
||||
[DnsmasqConfKeys.MxHost] = "MX records (domain, host, priority). Can repeat.",
|
||||
[DnsmasqConfKeys.MxTarget] = "Default target for MX records (used with localmx).",
|
||||
[DnsmasqConfKeys.Localmx] = "Serve MX for local machines using mx-target.",
|
||||
[DnsmasqConfKeys.Selfmx] = "Serve MX pointing to self for local machines.",
|
||||
[DnsmasqConfKeys.Srv] = "SRV records. Can repeat.",
|
||||
[DnsmasqConfKeys.PtrRecord] = "PTR records for reverse DNS. Can repeat.",
|
||||
[DnsmasqConfKeys.TxtRecord] = "TXT records. Can repeat.",
|
||||
@@ -71,6 +77,8 @@ public static class DnsmasqOptionTooltips
|
||||
|
||||
// --- DHCP ---
|
||||
[DnsmasqConfKeys.DhcpAuthoritative] = "DHCP server is authoritative; required for DHCP to work.",
|
||||
[DnsmasqConfKeys.DhcpRapidCommit] = "DHCPv4 Rapid Commit (RFC 4039); use only if single server or all commit.",
|
||||
[DnsmasqConfKeys.DhcpScript] = "Script run on lease add/delete (add|del, MAC, IP, hostname).",
|
||||
[DnsmasqConfKeys.LeasefileRo] = "Do not create or truncate the DHCP lease file.",
|
||||
[DnsmasqConfKeys.DhcpLeasefile] = "Path to the DHCP lease file.",
|
||||
[DnsmasqConfKeys.DhcpLeaseMax] = "Maximum number of DHCP leases to hold.",
|
||||
@@ -78,7 +86,11 @@ public static class DnsmasqOptionTooltips
|
||||
[DnsmasqConfKeys.DhcpRange] = "DHCP address range(s) and lease time. Can repeat.",
|
||||
[DnsmasqConfKeys.DhcpHost] = "DHCP host entries (reservations by MAC or client-id). Can repeat.",
|
||||
[DnsmasqConfKeys.DhcpOption] = "DHCP option lines sent to clients. Can repeat.",
|
||||
[DnsmasqConfKeys.DhcpOptionForce] = "Like dhcp-option but force send even if not in parameter request list. Can repeat.",
|
||||
[DnsmasqConfKeys.DhcpMatch] = "Match DHCP clients (e.g. set tag from option). Can repeat.",
|
||||
[DnsmasqConfKeys.DhcpMac] = "Set tag when client MAC matches pattern. Can repeat.",
|
||||
[DnsmasqConfKeys.DhcpNameMatch] = "Set tag when client name matches. Can repeat.",
|
||||
[DnsmasqConfKeys.DhcpIgnoreNames] = "Ignore client names when tag set. Can repeat.",
|
||||
[DnsmasqConfKeys.DhcpBoot] = "Boot file and server for PXE. Can repeat.",
|
||||
[DnsmasqConfKeys.DhcpIgnore] = "Ignore DHCP clients (e.g. by tag). Can repeat.",
|
||||
[DnsmasqConfKeys.DhcpVendorclass] = "Match by DHCP vendor class. Can repeat.",
|
||||
@@ -89,6 +101,8 @@ public static class DnsmasqOptionTooltips
|
||||
// --- TFTP / PXE ---
|
||||
[DnsmasqConfKeys.EnableTftp] = "Enable the built-in TFTP server.",
|
||||
[DnsmasqConfKeys.TftpSecure] = "Only allow TFTP access from DHCP-assigned clients.",
|
||||
[DnsmasqConfKeys.TftpNoFail] = "Do not abort if tftp-root is missing.",
|
||||
[DnsmasqConfKeys.TftpNoBlocksize] = "Do not negotiate TFTP blocksize (for broken clients).",
|
||||
[DnsmasqConfKeys.TftpRoot] = "Root directory for TFTP files.",
|
||||
[DnsmasqConfKeys.PxePrompt] = "PXE boot prompt (e.g. timeout,0 to disable).",
|
||||
[DnsmasqConfKeys.PxeService] = "PXE service definitions. Can repeat.",
|
||||
@@ -123,6 +137,8 @@ public static class DnsmasqOptionTooltips
|
||||
[DnsmasqConfKeys.LocalService] = "Restrict to local network or localhost (net|host).",
|
||||
[DnsmasqConfKeys.EnableDbus] = "Enable DBus interface (optional service name).",
|
||||
[DnsmasqConfKeys.EnableUbus] = "Enable UBus interface (optional service name).",
|
||||
[DnsmasqConfKeys.EnableRa] = "Enable router advertisements for DHCPv6 subnets.",
|
||||
[DnsmasqConfKeys.LogDhcp] = "Log DHCP transactions (leases, options).",
|
||||
}.ToFrozenDictionary();
|
||||
|
||||
/// <summary>Returns a short tooltip for the option, or null if none is defined.</summary>
|
||||
|
||||
@@ -48,6 +48,7 @@ public static class EffectiveConfigFieldBuilder
|
||||
list.Add(Multi(SectionHosts, DnsmasqConfKeys.AddnHosts, status,
|
||||
s => ToValueWithSourceList(s?.AddnHostsPaths, Sources(s)?.AddnHostsPaths)));
|
||||
list.Add(Single(SectionHosts, DnsmasqConfKeys.Hostsdir, status, s => Config(s)?.HostsdirPath, s => Sources(s)?.HostsdirPath, null));
|
||||
list.Add(Single(SectionHosts, DnsmasqConfKeys.ReadEthers, status, s => Config(s)?.ReadEthers, s => Sources(s)?.ReadEthers, null));
|
||||
|
||||
// --- Resolver / DNS (most-used first: server/local, rev-server, address, resolv-file) ---
|
||||
list.Add(Multi(SectionResolver, "server / local", status, Items(ec => ec?.ServerLocalValues, src => src?.ServerLocalValues)));
|
||||
@@ -82,6 +83,8 @@ public static class EffectiveConfigFieldBuilder
|
||||
list.Add(Single(SectionResolver, DnsmasqConfKeys.FilterAaaa, status, s => Config(s)?.FilterAaaa, s => Sources(s)?.FilterAaaa, null));
|
||||
list.Add(Single(SectionResolver, DnsmasqConfKeys.LocaliseQueries, status, s => Config(s)?.LocaliseQueries, s => Sources(s)?.LocaliseQueries, null));
|
||||
list.Add(Single(SectionResolver, DnsmasqConfKeys.FastDnsRetry, status, s => Config(s)?.FastDnsRetry, s => Sources(s)?.FastDnsRetry, null));
|
||||
list.Add(Multi(SectionResolver, DnsmasqConfKeys.Ipset, status, Items(ec => ec?.IpsetValues, src => src?.IpsetValues)));
|
||||
list.Add(Multi(SectionResolver, DnsmasqConfKeys.Nftset, status, Items(ec => ec?.NftsetValues, src => src?.NftsetValues)));
|
||||
|
||||
// --- DNS records (authoritative / local) ---
|
||||
list.Add(Multi(SectionDnsRecords, DnsmasqConfKeys.Domain, status, Items(ec => ec?.DomainValues, src => src?.DomainValues)));
|
||||
@@ -94,17 +97,26 @@ public static class EffectiveConfigFieldBuilder
|
||||
list.Add(Multi(SectionDnsRecords, DnsmasqConfKeys.HostRecord, status, Items(ec => ec?.HostRecordValues, src => src?.HostRecordValues)));
|
||||
list.Add(Multi(SectionDnsRecords, DnsmasqConfKeys.DynamicHost, status, Items(ec => ec?.DynamicHostValues, src => src?.DynamicHostValues)));
|
||||
list.Add(Multi(SectionDnsRecords, DnsmasqConfKeys.InterfaceName, status, Items(ec => ec?.InterfaceNameValues, src => src?.InterfaceNameValues)));
|
||||
list.Add(Single(SectionDnsRecords, DnsmasqConfKeys.MxTarget, status, s => Config(s)?.MxTarget, s => Sources(s)?.MxTarget, null));
|
||||
list.Add(Single(SectionDnsRecords, DnsmasqConfKeys.Localmx, status, s => Config(s)?.Localmx, s => Sources(s)?.Localmx, null));
|
||||
list.Add(Single(SectionDnsRecords, DnsmasqConfKeys.Selfmx, status, s => Config(s)?.Selfmx, s => Sources(s)?.Selfmx, null));
|
||||
|
||||
// --- DHCP ---
|
||||
list.Add(Single(SectionDhcp, DnsmasqConfKeys.DhcpAuthoritative, status, s => Config(s)?.DhcpAuthoritative, s => Sources(s)?.DhcpAuthoritative, null));
|
||||
list.Add(Single(SectionDhcp, DnsmasqConfKeys.DhcpRapidCommit, status, s => Config(s)?.DhcpRapidCommit, s => Sources(s)?.DhcpRapidCommit, null));
|
||||
list.Add(Single(SectionDhcp, DnsmasqConfKeys.LeasefileRo, status, s => Config(s)?.LeasefileRo, s => Sources(s)?.LeasefileRo, null));
|
||||
list.Add(Single(SectionDhcp, DnsmasqConfKeys.DhcpScript, status, s => Config(s)?.DhcpScriptPath, s => Sources(s)?.DhcpScriptPath, null));
|
||||
list.Add(Single(SectionDhcp, DnsmasqConfKeys.DhcpLeasefile, status, s => Config(s)?.DhcpLeaseFilePath, s => Sources(s)?.DhcpLeaseFilePath, null));
|
||||
list.Add(Single(SectionDhcp, DnsmasqConfKeys.DhcpLeaseMax, status, s => Config(s)?.DhcpLeaseMax, s => Sources(s)?.DhcpLeaseMax, null));
|
||||
list.Add(Single(SectionDhcp, DnsmasqConfKeys.DhcpTtl, status, s => Config(s)?.DhcpTtl, s => Sources(s)?.DhcpTtl, null));
|
||||
list.Add(Multi(SectionDhcp, DnsmasqConfKeys.DhcpRange, status, Items(ec => ec?.DhcpRanges, src => src?.DhcpRanges)));
|
||||
list.Add(Multi(SectionDhcp, DnsmasqConfKeys.DhcpHost, status, Items(ec => ec?.DhcpHostLines, src => src?.DhcpHostLines)));
|
||||
list.Add(Multi(SectionDhcp, DnsmasqConfKeys.DhcpOption, status, Items(ec => ec?.DhcpOptionLines, src => src?.DhcpOptionLines)));
|
||||
list.Add(Multi(SectionDhcp, DnsmasqConfKeys.DhcpOptionForce, status, Items(ec => ec?.DhcpOptionForceLines, src => src?.DhcpOptionForceLines)));
|
||||
list.Add(Multi(SectionDhcp, DnsmasqConfKeys.DhcpMatch, status, Items(ec => ec?.DhcpMatchValues, src => src?.DhcpMatchValues)));
|
||||
list.Add(Multi(SectionDhcp, DnsmasqConfKeys.DhcpMac, status, Items(ec => ec?.DhcpMacValues, src => src?.DhcpMacValues)));
|
||||
list.Add(Multi(SectionDhcp, DnsmasqConfKeys.DhcpNameMatch, status, Items(ec => ec?.DhcpNameMatchValues, src => src?.DhcpNameMatchValues)));
|
||||
list.Add(Multi(SectionDhcp, DnsmasqConfKeys.DhcpIgnoreNames, status, Items(ec => ec?.DhcpIgnoreNamesValues, src => src?.DhcpIgnoreNamesValues)));
|
||||
list.Add(Multi(SectionDhcp, DnsmasqConfKeys.DhcpBoot, status, Items(ec => ec?.DhcpBootValues, src => src?.DhcpBootValues)));
|
||||
list.Add(Multi(SectionDhcp, DnsmasqConfKeys.DhcpIgnore, status, Items(ec => ec?.DhcpIgnoreValues, src => src?.DhcpIgnoreValues)));
|
||||
list.Add(Multi(SectionDhcp, DnsmasqConfKeys.DhcpVendorclass, status, Items(ec => ec?.DhcpVendorclassValues, src => src?.DhcpVendorclassValues)));
|
||||
@@ -115,6 +127,8 @@ public static class EffectiveConfigFieldBuilder
|
||||
// --- TFTP / PXE ---
|
||||
list.Add(Single(SectionTftpPxe, DnsmasqConfKeys.EnableTftp, status, s => Config(s)?.EnableTftp, s => Sources(s)?.EnableTftp, null));
|
||||
list.Add(Single(SectionTftpPxe, DnsmasqConfKeys.TftpSecure, status, s => Config(s)?.TftpSecure, s => Sources(s)?.TftpSecure, null));
|
||||
list.Add(Single(SectionTftpPxe, DnsmasqConfKeys.TftpNoFail, status, s => Config(s)?.TftpNoFail, s => Sources(s)?.TftpNoFail, null));
|
||||
list.Add(Single(SectionTftpPxe, DnsmasqConfKeys.TftpNoBlocksize, status, s => Config(s)?.TftpNoBlocksize, s => Sources(s)?.TftpNoBlocksize, null));
|
||||
list.Add(Single(SectionTftpPxe, DnsmasqConfKeys.TftpRoot, status, s => Config(s)?.TftpRootPath, s => Sources(s)?.TftpRootPath, null));
|
||||
list.Add(Single(SectionTftpPxe, DnsmasqConfKeys.PxePrompt, status, s => Config(s)?.PxePrompt, s => Sources(s)?.PxePrompt, null));
|
||||
list.Add(Multi(SectionTftpPxe, DnsmasqConfKeys.PxeService, status, Items(ec => ec?.PxeServiceValues, src => src?.PxeServiceValues)));
|
||||
@@ -154,6 +168,8 @@ public static class EffectiveConfigFieldBuilder
|
||||
list.Add(Single(SectionProcess, DnsmasqConfKeys.LogFacility, status, s => Config(s)?.LogFacility, s => Sources(s)?.LogFacility, null));
|
||||
list.Add(Single(SectionProcess, DnsmasqConfKeys.EnableDbus, status, s => Config(s)?.EnableDbus, s => Sources(s)?.EnableDbus, null));
|
||||
list.Add(Single(SectionProcess, DnsmasqConfKeys.EnableUbus, status, s => Config(s)?.EnableUbus, s => Sources(s)?.EnableUbus, null));
|
||||
list.Add(Single(SectionProcess, DnsmasqConfKeys.EnableRa, status, s => Config(s)?.EnableRa, s => Sources(s)?.EnableRa, null));
|
||||
list.Add(Single(SectionProcess, DnsmasqConfKeys.LogDhcp, status, s => Config(s)?.LogDhcp, s => Sources(s)?.LogDhcp, null));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -259,6 +259,12 @@ public sealed class ConfigSetCache : IConfigSetCache, IDisposable
|
||||
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 expandHosts = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.ExpandHosts);
|
||||
var bogusPriv = DnsmasqConfIncludeParser.GetFlagFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.BogusPriv);
|
||||
@@ -285,6 +291,14 @@ public sealed class ConfigSetCache : IConfigSetCache, IDisposable
|
||||
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 dhcpLeaseFilePath = DnsmasqConfIncludeParser.GetDhcpLeaseFilePathFromConfigFiles(paths, pathToLines);
|
||||
|
||||
@@ -342,6 +356,10 @@ public sealed class ConfigSetCache : IConfigSetCache, IDisposable
|
||||
var enableUbus = string.IsNullOrWhiteSpace(enableUbusVal) ? null : enableUbusVal.Trim();
|
||||
var (fastDnsRetryVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.FastDnsRetry);
|
||||
var fastDnsRetry = string.IsNullOrWhiteSpace(fastDnsRetryVal) ? null : fastDnsRetryVal.Trim();
|
||||
var (dhcpScriptVal, dhcpScriptDir) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.DhcpScript);
|
||||
var dhcpScriptPath = string.IsNullOrWhiteSpace(dhcpScriptVal) ? null : DnsmasqConfIncludeParser.ResolvePath(dhcpScriptVal?.Trim(), dhcpScriptDir);
|
||||
var (mxTargetVal, _) = DnsmasqConfIncludeParser.GetLastValueFromConfigFiles(paths, pathToLines, DnsmasqConfKeys.MxTarget);
|
||||
var mxTarget = string.IsNullOrWhiteSpace(mxTargetVal) ? null : mxTargetVal.Trim();
|
||||
|
||||
return new EffectiveDnsmasqConfig(
|
||||
noHosts, addnHosts, hostsdirPath,
|
||||
@@ -349,12 +367,14 @@ public sealed class ConfigSetCache : IConfigSetCache, IDisposable
|
||||
dhcpMatchValues, dhcpBootValues, dhcpIgnoreValues, dhcpVendorclassValues, dhcpUserclassValues, raParamValues, slaacValues, pxeServiceValues, trustAnchorValues, resolvFiles,
|
||||
rebindDomainOk, bogusNxdomain, ignoreAddress, alias, filterRr, cacheRr, authServer, noDhcpInterface, noDhcpv4Interface, noDhcpv6Interface,
|
||||
domainValues, cnameValues, mxHostValues, srvValues, ptrRecordValues, txtRecordValues, naptrRecordValues, hostRecordValues, dynamicHostValues, interfaceNameValues,
|
||||
dhcpOptionForceLines, ipsetValues, nftsetValues, dhcpMacValues, dhcpNameMatchValues, dhcpIgnoreNamesValues,
|
||||
expandHosts, bogusPriv, strictOrder, allServers, noResolv, domainNeeded, noPoll, bindInterfaces, bindDynamic, noNegcache,
|
||||
dnsLoopDetect, stopDnsRebind, rebindLocalhostOk, clearOnReload, filterwin2k, filterA, filterAaaa, localiseQueries, logDebug, dhcpAuthoritative, leasefileRo,
|
||||
enableTftp, tftpSecure, dnssec, dnssecCheckUnsigned,
|
||||
enableTftp, tftpSecure, tftpNoFail, tftpNoBlocksize, dnssec, dnssecCheckUnsigned, readEthers, dhcpRapidCommit, localmx, selfmx, enableRa, logDhcp,
|
||||
dhcpLeaseFilePath, cacheSize, port, localTtl, pidFilePath, user, group, logFacility, logQueries,
|
||||
authTtl, ednsPacketMax, queryPort, portLimit, minPort, maxPort, logAsync, localService, dhcpLeaseMax,
|
||||
negTtl, maxTtl, maxCacheTtl, minCacheTtl, dhcpTtl, tftpRootPath, pxePrompt, enableDbus, enableUbus, fastDnsRetry
|
||||
negTtl, maxTtl, maxCacheTtl, minCacheTtl, dhcpTtl, tftpRootPath, pxePrompt, enableDbus, enableUbus, fastDnsRetry,
|
||||
dhcpScriptPath, mxTarget
|
||||
);
|
||||
}
|
||||
|
||||
@@ -402,6 +422,12 @@ public sealed class ConfigSetCache : IConfigSetCache, IDisposable
|
||||
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 (_, expandHostsSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.ExpandHosts, managedFilePath);
|
||||
var (_, bogusPrivSource) = DnsmasqConfIncludeParser.GetFlagFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.BogusPriv, managedFilePath);
|
||||
@@ -428,6 +454,14 @@ public sealed class ConfigSetCache : IConfigSetCache, IDisposable
|
||||
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 (_, dhcpLeaseFilePathSource) = DnsmasqConfIncludeParser.GetDhcpLeaseFilePathFromConfigFilesWithSource(paths, pathToLines, managedFilePath);
|
||||
var (_, cacheSizeSource) = DnsmasqConfIncludeParser.GetLastValueFromConfigFilesWithSource(paths, pathToLines, DnsmasqConfKeys.CacheSize, managedFilePath);
|
||||
@@ -457,6 +491,8 @@ public sealed class ConfigSetCache : IConfigSetCache, IDisposable
|
||||
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);
|
||||
|
||||
return new EffectiveConfigSources(
|
||||
noHostsSource, addnHostsWithSource.Select(t => new PathWithSource(t.Path, t.Source)).ToList(), hostsdirPathSource,
|
||||
@@ -499,6 +535,12 @@ public sealed class ConfigSetCache : IConfigSetCache, IDisposable
|
||||
hostRecordWithSource.Select(t => new ValueWithSource(t.Value, t.Source)).ToList(),
|
||||
dynamicHostWithSource.Select(t => new ValueWithSource(t.Value, t.Source)).ToList(),
|
||||
interfaceNameWithSource.Select(t => new ValueWithSource(t.Value, t.Source)).ToList(),
|
||||
dhcpOptionForceWithSource.Select(t => new ValueWithSource(t.Value, t.Source)).ToList(),
|
||||
ipsetWithSource.Select(t => new ValueWithSource(t.Value, t.Source)).ToList(),
|
||||
nftsetWithSource.Select(t => new ValueWithSource(t.Value, t.Source)).ToList(),
|
||||
dhcpMacWithSource.Select(t => new ValueWithSource(t.Value, t.Source)).ToList(),
|
||||
dhcpNameMatchWithSource.Select(t => new ValueWithSource(t.Value, t.Source)).ToList(),
|
||||
dhcpIgnoreNamesWithSource.Select(t => new ValueWithSource(t.Value, t.Source)).ToList(),
|
||||
expandHostsSource,
|
||||
bogusPrivSource,
|
||||
strictOrderSource,
|
||||
@@ -522,8 +564,16 @@ public sealed class ConfigSetCache : IConfigSetCache, IDisposable
|
||||
leasefileRoSource,
|
||||
enableTftpSource,
|
||||
tftpSecureSource,
|
||||
tftpNoFailSource,
|
||||
tftpNoBlocksizeSource,
|
||||
dnssecSource,
|
||||
dnssecCheckUnsignedSource,
|
||||
readEthersSource,
|
||||
dhcpRapidCommitSource,
|
||||
localmxSource,
|
||||
selfmxSource,
|
||||
enableRaSource,
|
||||
logDhcpSource,
|
||||
dhcpLeaseFilePathSource,
|
||||
cacheSizeSource,
|
||||
portSource,
|
||||
@@ -551,7 +601,9 @@ public sealed class ConfigSetCache : IConfigSetCache, IDisposable
|
||||
pxePromptSource,
|
||||
enableDbusSource,
|
||||
enableUbusSource,
|
||||
fastDnsRetrySource
|
||||
fastDnsRetrySource,
|
||||
dhcpScriptPathSource,
|
||||
mxTargetSource
|
||||
);
|
||||
}
|
||||
|
||||
@@ -602,14 +654,18 @@ public sealed class ConfigSetCache : IConfigSetCache, IDisposable
|
||||
DomainValues: Array.Empty<string>(), CnameValues: Array.Empty<string>(), MxHostValues: Array.Empty<string>(), SrvValues: Array.Empty<string>(),
|
||||
PtrRecordValues: Array.Empty<string>(), TxtRecordValues: Array.Empty<string>(), NaptrRecordValues: Array.Empty<string>(),
|
||||
HostRecordValues: Array.Empty<string>(), DynamicHostValues: Array.Empty<string>(), InterfaceNameValues: Array.Empty<string>(),
|
||||
DhcpOptionForceLines: Array.Empty<string>(), IpsetValues: Array.Empty<string>(), NftsetValues: Array.Empty<string>(),
|
||||
DhcpMacValues: Array.Empty<string>(), DhcpNameMatchValues: Array.Empty<string>(), DhcpIgnoreNamesValues: Array.Empty<string>(),
|
||||
ExpandHosts: false, BogusPriv: false, StrictOrder: false, AllServers: false, NoResolv: false, DomainNeeded: false, NoPoll: false,
|
||||
BindInterfaces: false, BindDynamic: false, NoNegcache: false, DnsLoopDetect: false, StopDnsRebind: false, RebindLocalhostOk: false, ClearOnReload: false,
|
||||
Filterwin2k: false, FilterA: false, FilterAaaa: false, LocaliseQueries: false, LogDebug: false, DhcpAuthoritative: false, LeasefileRo: false,
|
||||
EnableTftp: false, TftpSecure: false, Dnssec: false, DnssecCheckUnsigned: false,
|
||||
EnableTftp: false, TftpSecure: false, TftpNoFail: false, TftpNoBlocksize: false, Dnssec: false, DnssecCheckUnsigned: false,
|
||||
ReadEthers: false, DhcpRapidCommit: false, Localmx: false, Selfmx: false, EnableRa: false, LogDhcp: false,
|
||||
DhcpLeaseFilePath: null, CacheSize: null, Port: null, LocalTtl: null, PidFilePath: null, User: null, Group: null,
|
||||
LogFacility: null, LogQueries: null, AuthTtl: null, EdnsPacketMax: null, QueryPort: null, PortLimit: null, MinPort: null, MaxPort: null, LogAsync: null, LocalService: null,
|
||||
DhcpLeaseMax: null, NegTtl: null, MaxTtl: null, MaxCacheTtl: null, MinCacheTtl: null, DhcpTtl: null,
|
||||
TftpRootPath: null, PxePrompt: null, EnableDbus: null, EnableUbus: null, FastDnsRetry: null
|
||||
TftpRootPath: null, PxePrompt: null, EnableDbus: null, EnableUbus: null, FastDnsRetry: null,
|
||||
DhcpScriptPath: null, MxTarget: null
|
||||
);
|
||||
|
||||
private static EffectiveConfigSources CreateDefaultEffectiveConfigSources() =>
|
||||
@@ -631,14 +687,18 @@ public sealed class ConfigSetCache : IConfigSetCache, IDisposable
|
||||
DomainValues: Array.Empty<ValueWithSource>(), CnameValues: Array.Empty<ValueWithSource>(), MxHostValues: Array.Empty<ValueWithSource>(), SrvValues: Array.Empty<ValueWithSource>(),
|
||||
PtrRecordValues: Array.Empty<ValueWithSource>(), TxtRecordValues: Array.Empty<ValueWithSource>(), NaptrRecordValues: Array.Empty<ValueWithSource>(),
|
||||
HostRecordValues: Array.Empty<ValueWithSource>(), DynamicHostValues: Array.Empty<ValueWithSource>(), InterfaceNameValues: Array.Empty<ValueWithSource>(),
|
||||
DhcpOptionForceLines: Array.Empty<ValueWithSource>(), IpsetValues: Array.Empty<ValueWithSource>(), NftsetValues: Array.Empty<ValueWithSource>(),
|
||||
DhcpMacValues: Array.Empty<ValueWithSource>(), DhcpNameMatchValues: Array.Empty<ValueWithSource>(), DhcpIgnoreNamesValues: Array.Empty<ValueWithSource>(),
|
||||
ExpandHosts: null, BogusPriv: null, StrictOrder: null, AllServers: null, NoResolv: null, DomainNeeded: null, NoPoll: null,
|
||||
BindInterfaces: null, BindDynamic: null, NoNegcache: null, DnsLoopDetect: null, StopDnsRebind: null, RebindLocalhostOk: null, ClearOnReload: null,
|
||||
Filterwin2k: null, FilterA: null, FilterAaaa: null, LocaliseQueries: null, LogDebug: null, DhcpAuthoritative: null, LeasefileRo: null,
|
||||
EnableTftp: null, TftpSecure: null, Dnssec: null, DnssecCheckUnsigned: null,
|
||||
EnableTftp: null, TftpSecure: null, TftpNoFail: null, TftpNoBlocksize: null, Dnssec: null, DnssecCheckUnsigned: null,
|
||||
ReadEthers: null, DhcpRapidCommit: null, Localmx: null, Selfmx: null, EnableRa: null, LogDhcp: null,
|
||||
DhcpLeaseFilePath: null, CacheSize: null, Port: null, LocalTtl: null, PidFilePath: null, User: null, Group: null,
|
||||
LogFacility: null, LogQueries: null, AuthTtl: null, EdnsPacketMax: null, QueryPort: null, PortLimit: null, MinPort: null, MaxPort: null, LogAsync: null, LocalService: null,
|
||||
DhcpLeaseMax: null, NegTtl: null, MaxTtl: null, MaxCacheTtl: null, MinCacheTtl: null, DhcpTtl: null,
|
||||
TftpRootPath: null, PxePrompt: null, EnableDbus: null, EnableUbus: null, FastDnsRetry: null
|
||||
TftpRootPath: null, PxePrompt: null, EnableDbus: null, EnableUbus: null, FastDnsRetry: null,
|
||||
DhcpScriptPath: null, MxTarget: null
|
||||
);
|
||||
|
||||
private static int? TryParseInt(string? value)
|
||||
|
||||
@@ -42,11 +42,19 @@ public class EffectiveConfigRenderFragmentRegistry : IEffectiveConfigRenderFragm
|
||||
RegisterFlag(EffectiveConfigFieldBuilder.SectionResolver, DnsmasqConfKeys.FilterAaaa);
|
||||
RegisterFlag(EffectiveConfigFieldBuilder.SectionResolver, DnsmasqConfKeys.LocaliseQueries);
|
||||
RegisterFlag(EffectiveConfigFieldBuilder.SectionDhcp, DnsmasqConfKeys.DhcpAuthoritative);
|
||||
RegisterFlag(EffectiveConfigFieldBuilder.SectionHosts, DnsmasqConfKeys.ReadEthers);
|
||||
RegisterFlag(EffectiveConfigFieldBuilder.SectionDhcp, DnsmasqConfKeys.DhcpRapidCommit);
|
||||
RegisterFlag(EffectiveConfigFieldBuilder.SectionDhcp, DnsmasqConfKeys.LeasefileRo);
|
||||
RegisterFlag(EffectiveConfigFieldBuilder.SectionTftpPxe, DnsmasqConfKeys.EnableTftp);
|
||||
RegisterFlag(EffectiveConfigFieldBuilder.SectionTftpPxe, DnsmasqConfKeys.TftpSecure);
|
||||
RegisterFlag(EffectiveConfigFieldBuilder.SectionTftpPxe, DnsmasqConfKeys.TftpNoFail);
|
||||
RegisterFlag(EffectiveConfigFieldBuilder.SectionTftpPxe, DnsmasqConfKeys.TftpNoBlocksize);
|
||||
RegisterFlag(EffectiveConfigFieldBuilder.SectionDnsRecords, DnsmasqConfKeys.Localmx);
|
||||
RegisterFlag(EffectiveConfigFieldBuilder.SectionDnsRecords, DnsmasqConfKeys.Selfmx);
|
||||
RegisterFlag(EffectiveConfigFieldBuilder.SectionDnssec, DnsmasqConfKeys.Dnssec);
|
||||
RegisterFlag(EffectiveConfigFieldBuilder.SectionDnssec, DnsmasqConfKeys.DnssecCheckUnsigned);
|
||||
RegisterFlag(EffectiveConfigFieldBuilder.SectionProcess, DnsmasqConfKeys.EnableRa);
|
||||
RegisterFlag(EffectiveConfigFieldBuilder.SectionProcess, DnsmasqConfKeys.LogDhcp);
|
||||
}
|
||||
|
||||
private void RegisterFlag(string sectionId, string optionName)
|
||||
|
||||
@@ -55,6 +55,12 @@ public record EffectiveConfigSources(
|
||||
IReadOnlyList<ValueWithSource> HostRecordValues,
|
||||
IReadOnlyList<ValueWithSource> DynamicHostValues,
|
||||
IReadOnlyList<ValueWithSource> InterfaceNameValues,
|
||||
IReadOnlyList<ValueWithSource> DhcpOptionForceLines,
|
||||
IReadOnlyList<ValueWithSource> IpsetValues,
|
||||
IReadOnlyList<ValueWithSource> NftsetValues,
|
||||
IReadOnlyList<ValueWithSource> DhcpMacValues,
|
||||
IReadOnlyList<ValueWithSource> DhcpNameMatchValues,
|
||||
IReadOnlyList<ValueWithSource> DhcpIgnoreNamesValues,
|
||||
|
||||
// --- Flags (set if any occurrence; source = first file that set it, so we know if readonly) ---
|
||||
ConfigValueSource? ExpandHosts,
|
||||
@@ -80,8 +86,16 @@ public record EffectiveConfigSources(
|
||||
ConfigValueSource? LeasefileRo,
|
||||
ConfigValueSource? EnableTftp,
|
||||
ConfigValueSource? TftpSecure,
|
||||
ConfigValueSource? TftpNoFail,
|
||||
ConfigValueSource? TftpNoBlocksize,
|
||||
ConfigValueSource? Dnssec,
|
||||
ConfigValueSource? DnssecCheckUnsigned,
|
||||
ConfigValueSource? ReadEthers,
|
||||
ConfigValueSource? DhcpRapidCommit,
|
||||
ConfigValueSource? Localmx,
|
||||
ConfigValueSource? Selfmx,
|
||||
ConfigValueSource? EnableRa,
|
||||
ConfigValueSource? LogDhcp,
|
||||
|
||||
// --- Single-value (last occurrence wins; source = file that set the last value) ---
|
||||
ConfigValueSource? DhcpLeaseFilePath,
|
||||
@@ -111,5 +125,7 @@ public record EffectiveConfigSources(
|
||||
ConfigValueSource? PxePrompt,
|
||||
ConfigValueSource? EnableDbus,
|
||||
ConfigValueSource? EnableUbus,
|
||||
ConfigValueSource? FastDnsRetry
|
||||
ConfigValueSource? FastDnsRetry,
|
||||
ConfigValueSource? DhcpScriptPath,
|
||||
ConfigValueSource? MxTarget
|
||||
);
|
||||
|
||||
@@ -59,6 +59,12 @@ public record EffectiveDnsmasqConfig(
|
||||
IReadOnlyList<string> HostRecordValues,
|
||||
IReadOnlyList<string> DynamicHostValues,
|
||||
IReadOnlyList<string> InterfaceNameValues,
|
||||
IReadOnlyList<string> DhcpOptionForceLines,
|
||||
IReadOnlyList<string> IpsetValues,
|
||||
IReadOnlyList<string> NftsetValues,
|
||||
IReadOnlyList<string> DhcpMacValues,
|
||||
IReadOnlyList<string> DhcpNameMatchValues,
|
||||
IReadOnlyList<string> DhcpIgnoreNamesValues,
|
||||
|
||||
// --- Boolean flags (set if any file contains the option) ---
|
||||
bool ExpandHosts,
|
||||
@@ -84,8 +90,16 @@ public record EffectiveDnsmasqConfig(
|
||||
bool LeasefileRo,
|
||||
bool EnableTftp,
|
||||
bool TftpSecure,
|
||||
bool TftpNoFail,
|
||||
bool TftpNoBlocksize,
|
||||
bool Dnssec,
|
||||
bool DnssecCheckUnsigned,
|
||||
bool ReadEthers,
|
||||
bool DhcpRapidCommit,
|
||||
bool Localmx,
|
||||
bool Selfmx,
|
||||
bool EnableRa,
|
||||
bool LogDhcp,
|
||||
|
||||
// --- Single-value options (last occurrence wins; null = not set, dnsmasq default) ---
|
||||
string? DhcpLeaseFilePath,
|
||||
@@ -115,7 +129,9 @@ public record EffectiveDnsmasqConfig(
|
||||
string? PxePrompt,
|
||||
string? EnableDbus,
|
||||
string? EnableUbus,
|
||||
string? FastDnsRetry
|
||||
string? FastDnsRetry,
|
||||
string? DhcpScriptPath,
|
||||
string? MxTarget
|
||||
)
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
Vendored
+2
-1
@@ -8,7 +8,8 @@ Source for the Docker test harness: `scripts/prepare-test-mount.sh` syncs this d
|
||||
|------------|--------|
|
||||
| **dnsmasq-test.conf** | Harness main config (`/data/dnsmasq-test.conf`). DNS + DHCP; `conf-dir=/data/dnsmasq.d`, multiple server/addn-hosts/address/dhcp-range. |
|
||||
| **dnsmasq.conf** | Minimal main (conf-dir only). Used by unit tests when conf-dir is absent. |
|
||||
| **dnsmasq.conf.example** | Commented example; not used by harness or tests. |
|
||||
| **dnsmasq.conf.example** | Short commented reference (option categories). Not used by harness. |
|
||||
| **dnsmasq.official.conf.example** | Official example from [imp/dnsmasq](https://github.com/imp/dnsmasq); all options commented. Used by unit tests to assert parser handles full example. |
|
||||
| **dnsmasq.d/** | Included configs (conf-dir; alphabetical order). In the harness, "Config files (load order)" should list main, then these, then zz-dnsmasq-webui.conf. |
|
||||
| **dnsmasq.d/01-other.conf** | `domain=local`. Not managed. |
|
||||
| **dnsmasq.d/02-servers.conf** | Extra `server=` / `local=` (readonly in UI). |
|
||||
|
||||
+689
@@ -0,0 +1,689 @@
|
||||
# Configuration file for dnsmasq.
|
||||
#
|
||||
# Format is one option per line, legal options are the same
|
||||
# as the long options legal on the command line. See
|
||||
# "/usr/sbin/dnsmasq --help" or "man 8 dnsmasq" for details.
|
||||
|
||||
# Listen on this specific port instead of the standard DNS port
|
||||
# (53). Setting this to zero completely disables DNS function,
|
||||
# leaving only DHCP and/or TFTP.
|
||||
#port=5353
|
||||
|
||||
# The following two options make you a better netizen, since they
|
||||
# tell dnsmasq to filter out queries which the public DNS cannot
|
||||
# answer, and which load the servers (especially the root servers)
|
||||
# unnecessarily. If you have a dial-on-demand link they also stop
|
||||
# these requests from bringing up the link unnecessarily.
|
||||
|
||||
# Never forward plain names (without a dot or domain part)
|
||||
#domain-needed
|
||||
# Never forward addresses in the non-routed address spaces.
|
||||
#bogus-priv
|
||||
|
||||
# Uncomment these to enable DNSSEC validation and caching:
|
||||
# (Requires dnsmasq to be built with DNSSEC option.)
|
||||
#conf-file=%%PREFIX%%/share/dnsmasq/trust-anchors.conf
|
||||
#dnssec
|
||||
|
||||
# Replies which are not DNSSEC signed may be legitimate, because the domain
|
||||
# is unsigned, or may be forgeries. Setting this option tells dnsmasq to
|
||||
# check that an unsigned reply is OK, by finding a secure proof that a DS
|
||||
# record somewhere between the root and the domain does not exist.
|
||||
# The cost of setting this is that even queries in unsigned domains will need
|
||||
# one or more extra DNS queries to verify.
|
||||
#dnssec-check-unsigned
|
||||
|
||||
# Uncomment this to filter useless windows-originated DNS requests
|
||||
# which can trigger dial-on-demand links needlessly.
|
||||
# Note that (amongst other things) this blocks all SRV requests,
|
||||
# so don't use it if you use eg Kerberos, SIP, XMMP or Google-talk.
|
||||
# This option only affects forwarding, SRV records originating for
|
||||
# dnsmasq (via srv-host= lines) are not suppressed by it.
|
||||
#filterwin2k
|
||||
|
||||
# Change this line if you want dns to get its upstream servers from
|
||||
# somewhere other that /etc/resolv.conf
|
||||
#resolv-file=
|
||||
|
||||
# By default, dnsmasq will send queries to any of the upstream
|
||||
# servers it knows about and tries to favour servers to are known
|
||||
# to be up. Uncommenting this forces dnsmasq to try each query
|
||||
# with each server strictly in the order they appear in
|
||||
# /etc/resolv.conf
|
||||
#strict-order
|
||||
|
||||
# If you don't want dnsmasq to read /etc/resolv.conf or any other
|
||||
# file, getting its servers from this file instead (see below), then
|
||||
# uncomment this.
|
||||
#no-resolv
|
||||
|
||||
# If you don't want dnsmasq to poll /etc/resolv.conf or other resolv
|
||||
# files for changes and re-read them then uncomment this.
|
||||
#no-poll
|
||||
|
||||
# Add other name servers here, with domain specs if they are for
|
||||
# non-public domains.
|
||||
#server=/localnet/192.168.0.1
|
||||
|
||||
# Example of routing PTR queries to nameservers: this will send all
|
||||
# address->name queries for 192.168.3/24 to nameserver 10.1.2.3
|
||||
#server=/3.168.192.in-addr.arpa/10.1.2.3
|
||||
|
||||
# Add local-only domains here, queries in these domains are answered
|
||||
# from /etc/hosts or DHCP only.
|
||||
#local=/localnet/
|
||||
|
||||
# Add domains which you want to force to an IP address here.
|
||||
# The example below send any host in double-click.net to a local
|
||||
# web-server.
|
||||
#address=/double-click.net/127.0.0.1
|
||||
|
||||
# --address (and --server) work with IPv6 addresses too.
|
||||
#address=/www.thekelleys.org.uk/fe80::20d:60ff:fe36:f83
|
||||
|
||||
# Add the IPs of all queries to yahoo.com, google.com, and their
|
||||
# subdomains to the vpn and search ipsets:
|
||||
#ipset=/yahoo.com/google.com/vpn,search
|
||||
|
||||
# Add the IPs of all queries to yahoo.com, google.com, and their
|
||||
# subdomains to netfilters sets, which is equivalent to
|
||||
# 'nft add element ip test vpn { ... }; nft add element ip test search { ... }'
|
||||
#nftset=/yahoo.com/google.com/ip#test#vpn,ip#test#search
|
||||
|
||||
# Use netfilters sets for both IPv4 and IPv6:
|
||||
# This adds all addresses in *.yahoo.com to vpn4 and vpn6 for IPv4 and IPv6 addresses.
|
||||
#nftset=/yahoo.com/4#ip#test#vpn4
|
||||
#nftset=/yahoo.com/6#ip#test#vpn6
|
||||
|
||||
# You can control how dnsmasq talks to a server: this forces
|
||||
# queries to 10.1.2.3 to be routed via eth1
|
||||
# server=10.1.2.3@eth1
|
||||
|
||||
# and this sets the source (ie local) address used to talk to
|
||||
# 10.1.2.3 to 192.168.1.1 port 55 (there must be an interface with that
|
||||
# IP on the machine, obviously).
|
||||
# server=10.1.2.3@192.168.1.1#55
|
||||
|
||||
# If you want dnsmasq to change uid and gid to something other
|
||||
# than the default, edit the following lines.
|
||||
#user=
|
||||
#group=
|
||||
|
||||
# If you want dnsmasq to listen for DHCP and DNS requests only on
|
||||
# specified interfaces (and the loopback) give the name of the
|
||||
# interface (eg eth0) here.
|
||||
# Repeat the line for more than one interface.
|
||||
#interface=
|
||||
# Or you can specify which interface _not_ to listen on
|
||||
#except-interface=
|
||||
# Or which to listen on by address (remember to include 127.0.0.1 if
|
||||
# you use this.)
|
||||
#listen-address=
|
||||
# If you want dnsmasq to provide only DNS service on an interface,
|
||||
# configure it as shown above, and then use the following line to
|
||||
# disable DHCP and TFTP on it.
|
||||
#no-dhcp-interface=
|
||||
|
||||
# On systems which support it, dnsmasq binds the wildcard address,
|
||||
# even when it is listening on only some interfaces. It then discards
|
||||
# requests that it shouldn't reply to. This has the advantage of
|
||||
# working even when interfaces come and go and change address. If you
|
||||
# want dnsmasq to really bind only the interfaces it is listening on,
|
||||
# uncomment this option. About the only time you may need this is when
|
||||
# running another nameserver on the same machine.
|
||||
#bind-interfaces
|
||||
|
||||
# If you don't want dnsmasq to read /etc/hosts, uncomment the
|
||||
# following line.
|
||||
#no-hosts
|
||||
# or if you want it to read another file, as well as /etc/hosts, use
|
||||
# this.
|
||||
#addn-hosts=/etc/banner_add_hosts
|
||||
|
||||
# Set this (and domain: see below) if you want to have a domain
|
||||
# automatically added to simple names in a hosts-file.
|
||||
#expand-hosts
|
||||
|
||||
# Set the domain for dnsmasq. this is optional, but if it is set, it
|
||||
# does the following things.
|
||||
# 1) Allows DHCP hosts to have fully qualified domain names, as long
|
||||
# as the domain part matches this setting.
|
||||
# 2) Sets the "domain" DHCP option thereby potentially setting the
|
||||
# domain of all systems configured by DHCP
|
||||
# 3) Provides the domain part for "expand-hosts"
|
||||
#domain=thekelleys.org.uk
|
||||
|
||||
# Set a different domain for a particular subnet
|
||||
#domain=wireless.thekelleys.org.uk,192.168.2.0/24
|
||||
|
||||
# Same idea, but range rather then subnet
|
||||
#domain=reserved.thekelleys.org.uk,192.68.3.100,192.168.3.200
|
||||
|
||||
# Uncomment this to enable the integrated DHCP server, you need
|
||||
# to supply the range of addresses available for lease and optionally
|
||||
# a lease time. If you have more than one network, you will need to
|
||||
# repeat this for each network on which you want to supply DHCP
|
||||
# service.
|
||||
#dhcp-range=192.168.0.50,192.168.0.150,12h
|
||||
|
||||
# This is an example of a DHCP range where the netmask is given. This
|
||||
# is needed for networks we reach the dnsmasq DHCP server via a relay
|
||||
# agent. If you don't know what a DHCP relay agent is, you probably
|
||||
# don't need to worry about this.
|
||||
#dhcp-range=192.168.0.50,192.168.0.150,255.255.255.0,12h
|
||||
|
||||
# This is an example of a DHCP range which sets a tag, so that
|
||||
# some DHCP options may be set only for this network.
|
||||
#dhcp-range=set:red,192.168.0.50,192.168.0.150
|
||||
|
||||
# Use this DHCP range only when the tag "green" is set.
|
||||
#dhcp-range=tag:green,192.168.0.50,192.168.0.150,12h
|
||||
|
||||
# Specify a subnet which can't be used for dynamic address allocation,
|
||||
# is available for hosts with matching --dhcp-host lines. Note that
|
||||
# dhcp-host declarations will be ignored unless there is a dhcp-range
|
||||
# of some type for the subnet in question.
|
||||
# In this case the netmask is implied (it comes from the network
|
||||
# configuration on the machine running dnsmasq) it is possible to give
|
||||
# an explicit netmask instead.
|
||||
#dhcp-range=192.168.0.0,static
|
||||
|
||||
# Enable DHCPv6. Note that the prefix-length does not need to be specified
|
||||
# and defaults to 64 if missing/
|
||||
#dhcp-range=1234::2, 1234::500, 64, 12h
|
||||
|
||||
# Do Router Advertisements, BUT NOT DHCP for this subnet.
|
||||
#dhcp-range=1234::, ra-only
|
||||
|
||||
# Do Router Advertisements, BUT NOT DHCP for this subnet, also try and
|
||||
# add names to the DNS for the IPv6 address of SLAAC-configured dual-stack
|
||||
# hosts. Use the DHCPv4 lease to derive the name, network segment and
|
||||
# MAC address and assume that the host will also have an
|
||||
# IPv6 address calculated using the SLAAC algorithm.
|
||||
#dhcp-range=1234::, ra-names
|
||||
|
||||
# Do Router Advertisements, BUT NOT DHCP for this subnet.
|
||||
# Set the lifetime to 46 hours. (Note: minimum lifetime is 2 hours.)
|
||||
#dhcp-range=1234::, ra-only, 48h
|
||||
|
||||
# Do DHCP and Router Advertisements for this subnet. Set the A bit in the RA
|
||||
# so that clients can use SLAAC addresses as well as DHCP ones.
|
||||
#dhcp-range=1234::2, 1234::500, slaac
|
||||
|
||||
# Do Router Advertisements and stateless DHCP for this subnet. Clients will
|
||||
# not get addresses from DHCP, but they will get other configuration information.
|
||||
# They will use SLAAC for addresses.
|
||||
#dhcp-range=1234::, ra-stateless
|
||||
|
||||
# Do stateless DHCP, SLAAC, and generate DNS names for SLAAC addresses
|
||||
# from DHCPv4 leases.
|
||||
#dhcp-range=1234::, ra-stateless, ra-names
|
||||
|
||||
# Do router advertisements for all subnets where we're doing DHCPv6
|
||||
# Unless overridden by ra-stateless, ra-names, et al, the router
|
||||
# advertisements will have the M and O bits set, so that the clients
|
||||
# get addresses and configuration from DHCPv6, and the A bit reset, so the
|
||||
# clients don't use SLAAC addresses.
|
||||
#enable-ra
|
||||
|
||||
# Supply parameters for specified hosts using DHCP. There are lots
|
||||
# of valid alternatives, so we will give examples of each. Note that
|
||||
# IP addresses DO NOT have to be in the range given above, they just
|
||||
# need to be on the same network. The order of the parameters in these
|
||||
# do not matter, it's permissible to give name, address and MAC in any
|
||||
# order.
|
||||
|
||||
# Always allocate the host with Ethernet address 11:22:33:44:55:66
|
||||
# The IP address 192.168.0.60
|
||||
#dhcp-host=11:22:33:44:55:66,192.168.0.60
|
||||
|
||||
# Always set the name of the host with hardware address
|
||||
# 11:22:33:44:55:66 to be "fred"
|
||||
#dhcp-host=11:22:33:44:55:66,fred
|
||||
|
||||
# Always give the host with Ethernet address 11:22:33:44:55:66
|
||||
# the name fred and IP address 192.168.0.60 and lease time 45 minutes
|
||||
#dhcp-host=11:22:33:44:55:66,fred,192.168.0.60,45m
|
||||
|
||||
# Give a host with Ethernet address 11:22:33:44:55:66 or
|
||||
# 12:34:56:78:90:12 the IP address 192.168.0.60. Dnsmasq will assume
|
||||
# that these two Ethernet interfaces will never be in use at the same
|
||||
# time, and give the IP address to the second, even if it is already
|
||||
# in use by the first. Useful for laptops with wired and wireless
|
||||
# addresses.
|
||||
#dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.60
|
||||
|
||||
# Give the machine which says its name is "bert" IP address
|
||||
# 192.168.0.70 and an infinite lease
|
||||
#dhcp-host=bert,192.168.0.70,infinite
|
||||
|
||||
# Always give the host with client identifier 01:02:02:04
|
||||
# the IP address 192.168.0.60
|
||||
#dhcp-host=id:01:02:02:04,192.168.0.60
|
||||
|
||||
# Always give the InfiniBand interface with hardware address
|
||||
# 80:00:00:48:fe:80:00:00:00:00:00:00:f4:52:14:03:00:28:05:81 the
|
||||
# ip address 192.168.0.61. The client id is derived from the prefix
|
||||
# ff:00:00:00:00:00:02:00:00:02:c9:00 and the last 8 pairs of
|
||||
# hex digits of the hardware address.
|
||||
#dhcp-host=id:ff:00:00:00:00:00:02:00:00:02:c9:00:f4:52:14:03:00:28:05:81,192.168.0.61
|
||||
|
||||
# Always give the host with client identifier "marjorie"
|
||||
# the IP address 192.168.0.60
|
||||
#dhcp-host=id:marjorie,192.168.0.60
|
||||
|
||||
# Enable the address given for "judge" in /etc/hosts
|
||||
# to be given to a machine presenting the name "judge" when
|
||||
# it asks for a DHCP lease.
|
||||
#dhcp-host=judge
|
||||
|
||||
# Never offer DHCP service to a machine whose Ethernet
|
||||
# address is 11:22:33:44:55:66
|
||||
#dhcp-host=11:22:33:44:55:66,ignore
|
||||
|
||||
# Ignore any client-id presented by the machine with Ethernet
|
||||
# address 11:22:33:44:55:66. This is useful to prevent a machine
|
||||
# being treated differently when running under different OS's or
|
||||
# between PXE boot and OS boot.
|
||||
#dhcp-host=11:22:33:44:55:66,id:*
|
||||
|
||||
# Send extra options which are tagged as "red" to
|
||||
# the machine with Ethernet address 11:22:33:44:55:66
|
||||
#dhcp-host=11:22:33:44:55:66,set:red
|
||||
|
||||
# Send extra options which are tagged as "red" to
|
||||
# any machine with Ethernet address starting 11:22:33:
|
||||
#dhcp-host=11:22:33:*:*:*,set:red
|
||||
|
||||
# Give a fixed IPv6 address and name to client with
|
||||
# DUID 00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2
|
||||
# Note the MAC addresses CANNOT be used to identify DHCPv6 clients.
|
||||
# Note also that the [] around the IPv6 address are obligatory.
|
||||
#dhcp-host=id:00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2, fred, [1234::5]
|
||||
|
||||
# Ignore any clients which are not specified in dhcp-host lines
|
||||
# or /etc/ethers. Equivalent to ISC "deny unknown-clients".
|
||||
# This relies on the special "known" tag which is set when
|
||||
# a host is matched.
|
||||
#dhcp-ignore=tag:!known
|
||||
|
||||
# Send extra options which are tagged as "red" to any machine whose
|
||||
# DHCP vendorclass string includes the substring "Linux"
|
||||
#dhcp-vendorclass=set:red,Linux
|
||||
|
||||
# Send extra options which are tagged as "red" to any machine one
|
||||
# of whose DHCP userclass strings includes the substring "accounts"
|
||||
#dhcp-userclass=set:red,accounts
|
||||
|
||||
# Send extra options which are tagged as "red" to any machine whose
|
||||
# MAC address matches the pattern.
|
||||
#dhcp-mac=set:red,00:60:8C:*:*:*
|
||||
|
||||
# If this line is uncommented, dnsmasq will read /etc/ethers and act
|
||||
# on the ethernet-address/IP pairs found there just as if they had
|
||||
# been given as --dhcp-host options. Useful if you keep
|
||||
# MAC-address/host mappings there for other purposes.
|
||||
#read-ethers
|
||||
|
||||
# Send options to hosts which ask for a DHCP lease.
|
||||
# See RFC 2132 for details of available options.
|
||||
# Common options can be given to dnsmasq by name:
|
||||
# run "dnsmasq --help dhcp" to get a list.
|
||||
# Note that all the common settings, such as netmask and
|
||||
# broadcast address, DNS server and default route, are given
|
||||
# sane defaults by dnsmasq. You very likely will not need
|
||||
# any dhcp-options. If you use Windows clients and Samba, there
|
||||
# are some options which are recommended, they are detailed at the
|
||||
# end of this section.
|
||||
|
||||
# Override the default route supplied by dnsmasq, which assumes the
|
||||
# router is the same machine as the one running dnsmasq.
|
||||
#dhcp-option=3,1.2.3.4
|
||||
|
||||
# Do the same thing, but using the option name
|
||||
#dhcp-option=option:router,1.2.3.4
|
||||
|
||||
# Override the default route supplied by dnsmasq and send no default
|
||||
# route at all. Note that this only works for the options sent by
|
||||
# default (1, 3, 6, 12, 28) the same line will send a zero-length option
|
||||
# for all other option numbers.
|
||||
#dhcp-option=3
|
||||
|
||||
# Set the NTP time server addresses to 192.168.0.4 and 10.10.0.5
|
||||
#dhcp-option=option:ntp-server,192.168.0.4,10.10.0.5
|
||||
|
||||
# Send DHCPv6 option. Note [] around IPv6 addresses.
|
||||
#dhcp-option=option6:dns-server,[1234::77],[1234::88]
|
||||
|
||||
# Send DHCPv6 option for namservers as the machine running
|
||||
# dnsmasq and another.
|
||||
#dhcp-option=option6:dns-server,[::],[1234::88]
|
||||
|
||||
# Ask client to poll for option changes every six hours. (RFC4242)
|
||||
#dhcp-option=option6:information-refresh-time,6h
|
||||
|
||||
# Set option 58 client renewal time (T1). Defaults to half of the
|
||||
# lease time if not specified. (RFC2132)
|
||||
#dhcp-option=option:T1,1m
|
||||
|
||||
# Set option 59 rebinding time (T2). Defaults to 7/8 of the
|
||||
# lease time if not specified. (RFC2132)
|
||||
#dhcp-option=option:T2,2m
|
||||
|
||||
# Set the NTP time server address to be the same machine as
|
||||
# is running dnsmasq
|
||||
#dhcp-option=42,0.0.0.0
|
||||
|
||||
# Set the NIS domain name to "welly"
|
||||
#dhcp-option=40,welly
|
||||
|
||||
# Set the default time-to-live to 50
|
||||
#dhcp-option=23,50
|
||||
|
||||
# Set the "all subnets are local" flag
|
||||
#dhcp-option=27,1
|
||||
|
||||
# Send the etherboot magic flag and then etherboot options (a string).
|
||||
#dhcp-option=128,e4:45:74:68:00:00
|
||||
#dhcp-option=129,NIC=eepro100
|
||||
|
||||
# Specify an option which will only be sent to the "red" network
|
||||
# (see dhcp-range for the declaration of the "red" network)
|
||||
# Note that the tag: part must precede the option: part.
|
||||
#dhcp-option = tag:red, option:ntp-server, 192.168.1.1
|
||||
|
||||
# The following DHCP options set up dnsmasq in the same way as is specified
|
||||
# for the ISC dhcpcd in
|
||||
# https://web.archive.org/web/20040313070105/http://us1.samba.org/samba/ftp/docs/textdocs/DHCP-Server-Configuration.txt
|
||||
# adapted for a typical dnsmasq installation where the host running
|
||||
# dnsmasq is also the host running samba.
|
||||
# you may want to uncomment some or all of them if you use
|
||||
# Windows clients and Samba.
|
||||
#dhcp-option=19,0 # option ip-forwarding off
|
||||
#dhcp-option=44,0.0.0.0 # set netbios-over-TCP/IP nameserver(s) aka WINS server(s)
|
||||
#dhcp-option=45,0.0.0.0 # netbios datagram distribution server
|
||||
#dhcp-option=46,8 # netbios node type
|
||||
|
||||
# Send an empty WPAD option. This may be REQUIRED to get windows 7 to behave.
|
||||
#dhcp-option=252,"\n"
|
||||
|
||||
# Send RFC-3397 DNS domain search DHCP option. WARNING: Your DHCP client
|
||||
# probably doesn't support this......
|
||||
#dhcp-option=option:domain-search,eng.apple.com,marketing.apple.com
|
||||
|
||||
# Send RFC-3442 classless static routes (note the netmask encoding)
|
||||
#dhcp-option=121,192.168.1.0/24,1.2.3.4,10.0.0.0/8,5.6.7.8
|
||||
|
||||
# Send vendor-class specific options encapsulated in DHCP option 43.
|
||||
# The meaning of the options is defined by the vendor-class so
|
||||
# options are sent only when the client supplied vendor class
|
||||
# matches the class given here. (A substring match is OK, so "MSFT"
|
||||
# matches "MSFT" and "MSFT 5.0"). This example sets the
|
||||
# mtftp address to 0.0.0.0 for PXEClients.
|
||||
#dhcp-option=vendor:PXEClient,1,0.0.0.0
|
||||
|
||||
# Send microsoft-specific option to tell windows to release the DHCP lease
|
||||
# when it shuts down. Note the "i" flag, to tell dnsmasq to send the
|
||||
# value as a four-byte integer - that's what microsoft wants. See
|
||||
# http://technet2.microsoft.com/WindowsServer/en/library/a70f1bb7-d2d4-49f0-96d6-4b7414ecfaae1033.mspx?mfr=true
|
||||
#dhcp-option=vendor:MSFT,2,1i
|
||||
|
||||
# Send the Encapsulated-vendor-class ID needed by some configurations of
|
||||
# Etherboot to allow is to recognise the DHCP server.
|
||||
#dhcp-option=vendor:Etherboot,60,"Etherboot"
|
||||
|
||||
# Send options to PXELinux. Note that we need to send the options even
|
||||
# though they don't appear in the parameter request list, so we need
|
||||
# to use dhcp-option-force here.
|
||||
# See http://syslinux.zytor.com/pxe.php#special for details.
|
||||
# Magic number - needed before anything else is recognised
|
||||
#dhcp-option-force=208,f1:00:74:7e
|
||||
# Configuration file name
|
||||
#dhcp-option-force=209,configs/common
|
||||
# Path prefix
|
||||
#dhcp-option-force=210,/tftpboot/pxelinux/files/
|
||||
# Reboot time. (Note 'i' to send 32-bit value)
|
||||
#dhcp-option-force=211,30i
|
||||
|
||||
# Set the boot filename for netboot/PXE. You will only need
|
||||
# this if you want to boot machines over the network and you will need
|
||||
# a TFTP server; either dnsmasq's built-in TFTP server or an
|
||||
# external one. (See below for how to enable the TFTP server.)
|
||||
#dhcp-boot=pxelinux.0
|
||||
|
||||
# The same as above, but use custom tftp-server instead machine running dnsmasq
|
||||
#dhcp-boot=pxelinux,server.name,192.168.1.100
|
||||
|
||||
# Boot for iPXE. The idea is to send two different
|
||||
# filenames, the first loads iPXE, and the second tells iPXE what to
|
||||
# load. The dhcp-match sets the ipxe tag for requests from iPXE.
|
||||
#dhcp-boot=undionly.kpxe
|
||||
#dhcp-match=set:ipxe,175 # iPXE sends a 175 option.
|
||||
#dhcp-boot=tag:ipxe,http://boot.ipxe.org/demo/boot.php
|
||||
|
||||
# Encapsulated options for iPXE. All the options are
|
||||
# encapsulated within option 175
|
||||
#dhcp-option=encap:175, 1, 5b # priority code
|
||||
#dhcp-option=encap:175, 176, 1b # no-proxydhcp
|
||||
#dhcp-option=encap:175, 177, string # bus-id
|
||||
#dhcp-option=encap:175, 189, 1b # BIOS drive code
|
||||
#dhcp-option=encap:175, 190, user # iSCSI username
|
||||
#dhcp-option=encap:175, 191, pass # iSCSI password
|
||||
|
||||
# Test for the architecture of a netboot client. PXE clients are
|
||||
# supposed to send their architecture as option 93. (See RFC 4578)
|
||||
#dhcp-match=peecees, option:client-arch, 0 #x86-32
|
||||
#dhcp-match=itanics, option:client-arch, 2 #IA64
|
||||
#dhcp-match=hammers, option:client-arch, 6 #x86-64
|
||||
#dhcp-match=mactels, option:client-arch, 7 #EFI x86-64
|
||||
|
||||
# Do real PXE, rather than just booting a single file, this is an
|
||||
# alternative to dhcp-boot.
|
||||
#pxe-prompt="What system shall I netboot?"
|
||||
# or with timeout before first available action is taken:
|
||||
#pxe-prompt="Press F8 for menu.", 60
|
||||
|
||||
# Available boot services. for PXE.
|
||||
#pxe-service=x86PC, "Boot from local disk"
|
||||
|
||||
# Loads <tftp-root>/pxelinux.0 from dnsmasq TFTP server.
|
||||
#pxe-service=x86PC, "Install Linux", pxelinux
|
||||
|
||||
# Loads <tftp-root>/pxelinux.0 from TFTP server at 1.2.3.4.
|
||||
# Beware this fails on old PXE ROMS.
|
||||
#pxe-service=x86PC, "Install Linux", pxelinux, 1.2.3.4
|
||||
|
||||
# Use bootserver on network, found my multicast or broadcast.
|
||||
#pxe-service=x86PC, "Install windows from RIS server", 1
|
||||
|
||||
# Use bootserver at a known IP address.
|
||||
#pxe-service=x86PC, "Install windows from RIS server", 1, 1.2.3.4
|
||||
|
||||
# If you have multicast-FTP available,
|
||||
# information for that can be passed in a similar way using options 1
|
||||
# to 5. See page 19 of
|
||||
# http://download.intel.com/design/archives/wfm/downloads/pxespec.pdf
|
||||
|
||||
|
||||
# Enable dnsmasq's built-in TFTP server
|
||||
#enable-tftp
|
||||
|
||||
# Set the root directory for files available via FTP.
|
||||
#tftp-root=/var/ftpd
|
||||
|
||||
# Do not abort if the tftp-root is unavailable
|
||||
#tftp-no-fail
|
||||
|
||||
# Make the TFTP server more secure: with this set, only files owned by
|
||||
# the user dnsmasq is running as will be send over the net.
|
||||
#tftp-secure
|
||||
|
||||
# This option stops dnsmasq from negotiating a larger blocksize for TFTP
|
||||
# transfers. It will slow things down, but may rescue some broken TFTP
|
||||
# clients.
|
||||
#tftp-no-blocksize
|
||||
|
||||
# Set the boot file name only when the "red" tag is set.
|
||||
#dhcp-boot=tag:red,pxelinux.red-net
|
||||
|
||||
# An example of dhcp-boot with an external TFTP server: the name and IP
|
||||
# address of the server are given after the filename.
|
||||
# Can fail with old PXE ROMS. Overridden by --pxe-service.
|
||||
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,192.168.0.3
|
||||
|
||||
# If there are multiple external tftp servers having a same name
|
||||
# (using /etc/hosts) then that name can be specified as the
|
||||
# tftp_servername (the third option to dhcp-boot) and in that
|
||||
# case dnsmasq resolves this name and returns the resultant IP
|
||||
# addresses in round robin fashion. This facility can be used to
|
||||
# load balance the tftp load among a set of servers.
|
||||
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,tftp_server_name
|
||||
|
||||
# Set the limit on DHCP leases, the default is 150
|
||||
#dhcp-lease-max=150
|
||||
|
||||
# The DHCP server needs somewhere on disk to keep its lease database.
|
||||
# This defaults to a sane location, but if you want to change it, use
|
||||
# the line below.
|
||||
#dhcp-leasefile=/var/lib/misc/dnsmasq.leases
|
||||
|
||||
# Set the DHCP server to authoritative mode. In this mode it will barge in
|
||||
# and take over the lease for any client which broadcasts on the network,
|
||||
# whether it has a record of the lease or not. This avoids long timeouts
|
||||
# when a machine wakes up on a new network. DO NOT enable this if there's
|
||||
# the slightest chance that you might end up accidentally configuring a DHCP
|
||||
# server for your campus/company accidentally. The ISC server uses
|
||||
# the same option, and this URL provides more information:
|
||||
# http://www.isc.org/files/auth.html
|
||||
#dhcp-authoritative
|
||||
|
||||
# Set the DHCP server to enable DHCPv4 Rapid Commit Option per RFC 4039.
|
||||
# In this mode it will respond to a DHCPDISCOVER message including a Rapid Commit
|
||||
# option with a DHCPACK including a Rapid Commit option and fully committed address
|
||||
# and configuration information. This must only be enabled if either the server is
|
||||
# the only server for the subnet, or multiple servers are present and they each
|
||||
# commit a binding for all clients.
|
||||
#dhcp-rapid-commit
|
||||
|
||||
# Run an executable when a DHCP lease is created or destroyed.
|
||||
# The arguments sent to the script are "add" or "del",
|
||||
# then the MAC address, the IP address and finally the hostname
|
||||
# if there is one.
|
||||
#dhcp-script=/bin/echo
|
||||
|
||||
# Set the cachesize here.
|
||||
#cache-size=150
|
||||
|
||||
# If you want to disable negative caching, uncomment this.
|
||||
#no-negcache
|
||||
|
||||
# Normally responses which come from /etc/hosts and the DHCP lease
|
||||
# file have Time-To-Live set as zero, which conventionally means
|
||||
# do not cache further. If you are happy to trade lower load on the
|
||||
# server for potentially stale date, you can set a time-to-live (in
|
||||
# seconds) here.
|
||||
#local-ttl=
|
||||
|
||||
# If you want dnsmasq to detect attempts by Verisign to send queries
|
||||
# to unregistered .com and .net hosts to its sitefinder service and
|
||||
# have dnsmasq instead return the correct NXDOMAIN response, uncomment
|
||||
# this line. You can add similar lines to do the same for other
|
||||
# registries which have implemented wildcard A records.
|
||||
#bogus-nxdomain=64.94.110.11
|
||||
|
||||
# If you want to fix up DNS results from upstream servers, use the
|
||||
# alias option. This only works for IPv4.
|
||||
# This alias makes a result of 1.2.3.4 appear as 5.6.7.8
|
||||
#alias=1.2.3.4,5.6.7.8
|
||||
# and this maps 1.2.3.x to 5.6.7.x
|
||||
#alias=1.2.3.0,5.6.7.0,255.255.255.0
|
||||
# and this maps 192.168.0.10->192.168.0.40 to 10.0.0.10->10.0.0.40
|
||||
#alias=192.168.0.10-192.168.0.40,10.0.0.0,255.255.255.0
|
||||
|
||||
# Change these lines if you want dnsmasq to serve MX records.
|
||||
|
||||
# Return an MX record named "maildomain.com" with target
|
||||
# servermachine.com and preference 50
|
||||
#mx-host=maildomain.com,servermachine.com,50
|
||||
|
||||
# Set the default target for MX records created using the localmx option.
|
||||
#mx-target=servermachine.com
|
||||
|
||||
# Return an MX record pointing to the mx-target for all local
|
||||
# machines.
|
||||
#localmx
|
||||
|
||||
# Return an MX record pointing to itself for all local machines.
|
||||
#selfmx
|
||||
|
||||
# Change the following lines if you want dnsmasq to serve SRV
|
||||
# records. These are useful if you want to serve ldap requests for
|
||||
# Active Directory and other windows-originated DNS requests.
|
||||
# See RFC 2782.
|
||||
# You may add multiple srv-host lines.
|
||||
# The fields are <name>,<target>,<port>,<priority>,<weight>
|
||||
# If the domain part if missing from the name (so that is just has the
|
||||
# service and protocol sections) then the domain given by the domain=
|
||||
# config option is used. (Note that expand-hosts does not need to be
|
||||
# set for this to work.)
|
||||
|
||||
# A SRV record sending LDAP for the example.com domain to
|
||||
# ldapserver.example.com port 389
|
||||
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389
|
||||
|
||||
# A SRV record sending LDAP for the example.com domain to
|
||||
# ldapserver.example.com port 389 (using domain=)
|
||||
#domain=example.com
|
||||
#srv-host=_ldap._tcp,ldapserver.example.com,389
|
||||
|
||||
# Two SRV records for LDAP, each with different priorities
|
||||
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389,1
|
||||
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389,2
|
||||
|
||||
# A SRV record indicating that there is no LDAP server for the domain
|
||||
# example.com
|
||||
#srv-host=_ldap._tcp.example.com
|
||||
|
||||
# The following line shows how to make dnsmasq serve an arbitrary PTR
|
||||
# record. This is useful for DNS-SD. (Note that the
|
||||
# domain-name expansion done for SRV records _does_not
|
||||
# occur for PTR records.)
|
||||
#ptr-record=_http._tcp.dns-sd-services,"New Employee Page._http._tcp.dns-sd-services"
|
||||
|
||||
# Change the following lines to enable dnsmasq to serve TXT records.
|
||||
# These are used for things like SPF and zeroconf. (Note that the
|
||||
# domain-name expansion done for SRV records _does_not
|
||||
# occur for TXT records.)
|
||||
|
||||
#Example SPF.
|
||||
#txt-record=example.com,"v=spf1 a -all"
|
||||
|
||||
#Example zeroconf
|
||||
#txt-record=_http._tcp.example.com,name=value,paper=A4
|
||||
|
||||
# Provide an alias for a "local" DNS name. Note that this _only_ works
|
||||
# for targets which are names from DHCP or /etc/hosts. Give host
|
||||
# "bert" another name, bertrand
|
||||
#cname=bertrand,bert
|
||||
|
||||
# For debugging purposes, log each DNS query as it passes through
|
||||
# dnsmasq.
|
||||
#log-queries
|
||||
|
||||
# Log lots of extra information about DHCP transactions.
|
||||
#log-dhcp
|
||||
|
||||
# Include another lot of configuration options.
|
||||
#conf-file=/etc/dnsmasq.more.conf
|
||||
#conf-dir=/etc/dnsmasq.d
|
||||
|
||||
# Include all the files in a directory except those ending in .bak
|
||||
#conf-dir=/etc/dnsmasq.d,.bak
|
||||
|
||||
# Include all files in a directory which end in .conf
|
||||
#conf-dir=/etc/dnsmasq.d/,*.conf
|
||||
|
||||
# If a DHCP client claims that its name is "wpad", ignore that.
|
||||
# This fixes a security hole. see CERT Vulnerability VU#598349
|
||||
#dhcp-name-match=set:wpad-ignore,wpad
|
||||
#dhcp-ignore-names=tag:wpad-ignore
|
||||
Reference in New Issue
Block a user