diff --git a/README.md b/README.md
index ccd5c58..6cb78ce 100644
--- a/README.md
+++ b/README.md
@@ -477,9 +477,9 @@ sudo ./scripts/install.sh --uninstall --purge --system
**Codebase overview:**
-- **Entry and config:** `Program.cs` wires the host; configuration (e.g. `Dnsmasq__*`) is in `Configuration/` (`DnsmasqOptions`, `ApplicationOptions`). Options are validated at startup.
-- **Config and hosts:** Services in `Services/` and `Services/Abstractions/` read and write dnsmasq config and hosts. A **managed** config file and optional managed hosts file are written by the app; the main config must include the managed file (e.g. via a final `conf-file=` line). Caches (`ConfigSetCache`, `HostsCache`) keep in-memory snapshots and refresh on file changes or staleness.
-- **Parsers and models:** `Parsers/` parses dnsmasq config lines and files (`DnsmasqConfIncludeParser`, `DnsmasqConfDirectiveParser`, etc.). Models in `Models/` represent config sets, config, sources, DHCP entries, hosts, leases.
+- **Entry and config:** `Program.cs` wires the host; configuration (e.g. `Dnsmasq__*`) lives in `Models/Config/` (`DnsmasqOptions`, `ApplicationOptions`, `DnsmasqOptionsValidator`). Options are validated at startup.
+- **Infrastructure:** Under `Infrastructure/`: **Client/** (HTTP API clients and `Abstractions/`), **Services/** and **Services/Abstractions/** (caches, config/hosts/leases services, reload, hosted services), **Parsers/** (dnsmasq config and hosts line parsers), **Helpers/Config/** and **Helpers/Http/** (option keys, encoding, tooltips, JSON options). A **managed** config file and optional managed hosts file are written by the app; the main config must include the managed file (e.g. via a final `conf-file=` line). Caches (`ConfigSetCache`, `HostsCache`) keep in-memory snapshots and refresh on file changes or staleness.
+- **Models:** `Models/Config/` (options, validators, `DnsmasqConfLine`); `Models/Contracts/` (snapshots and DTOs such as `ConfigSetSnapshot`, `HostsSnapshot`, `ManagedConfigContent`, `ProcessRunResult`, `ReloadResult`); `Models/Dnsmasq/` (status, `SaveWithReloadResult`, and `EffectiveConfig/` for effective config and sources); `Models/Client/`, `Models/Dhcp/`, `Models/Hosts/` (UI and API DTOs).
- **API and UI:** `Controllers/` expose API endpoints; `Components/` contains Blazor Server components for config editor, hosts, DHCP, Dnsmasq status, and app settings. Static assets in `wwwroot/`.
- **Tests:** `DnsmasqWebUI.Tests` contains unit tests for parsers, config set service, config, and related logic. Run with `dotnet test`.
diff --git a/src/DnsmasqWebUI/Infrastructure/Client/Abstractions/IConfigSetClient.cs b/src/DnsmasqWebUI/Infrastructure/Client/Abstractions/IConfigSetClient.cs
index 38154d2..dacc900 100644
--- a/src/DnsmasqWebUI/Infrastructure/Client/Abstractions/IConfigSetClient.cs
+++ b/src/DnsmasqWebUI/Infrastructure/Client/Abstractions/IConfigSetClient.cs
@@ -5,5 +5,6 @@ namespace DnsmasqWebUI.Infrastructure.Client.Abstractions;
/// Typed client for GET api/config/set.
public interface IConfigSetClient
{
+ /// Gets the config set (main + conf-file/conf-dir) and managed file path from GET api/config/set.
Task GetConfigSetAsync(CancellationToken ct = default);
}
diff --git a/src/DnsmasqWebUI/Infrastructure/Client/Abstractions/IDhcpHostsClient.cs b/src/DnsmasqWebUI/Infrastructure/Client/Abstractions/IDhcpHostsClient.cs
index 9012d78..6248efa 100644
--- a/src/DnsmasqWebUI/Infrastructure/Client/Abstractions/IDhcpHostsClient.cs
+++ b/src/DnsmasqWebUI/Infrastructure/Client/Abstractions/IDhcpHostsClient.cs
@@ -7,6 +7,9 @@ namespace DnsmasqWebUI.Infrastructure.Client.Abstractions;
/// Typed client for GET/PUT api/dhcp/hosts.
public interface IDhcpHostsClient
{
+ /// Gets DHCP host entries from GET api/dhcp/hosts.
Task> GetDhcpHostsAsync(CancellationToken ct = default);
+
+ /// Writes DHCP host entries and triggers reload via PUT api/dhcp/hosts.
Task SaveDhcpHostsAsync(IReadOnlyList entries, CancellationToken ct = default);
}
diff --git a/src/DnsmasqWebUI/Infrastructure/Client/Abstractions/IHostsClient.cs b/src/DnsmasqWebUI/Infrastructure/Client/Abstractions/IHostsClient.cs
index 847c405..4495b74 100644
--- a/src/DnsmasqWebUI/Infrastructure/Client/Abstractions/IHostsClient.cs
+++ b/src/DnsmasqWebUI/Infrastructure/Client/Abstractions/IHostsClient.cs
@@ -7,7 +7,12 @@ namespace DnsmasqWebUI.Infrastructure.Client.Abstractions;
/// Typed client for GET/PUT api/hosts.
public interface IHostsClient
{
+ /// Gets managed hosts file entries from GET api/hosts.
Task> GetHostsAsync(CancellationToken ct = default);
+
+ /// Gets read-only hosts files (system + addn-hosts) from GET api/hosts/readonly.
Task> GetReadOnlyHostsAsync(CancellationToken ct = default);
+
+ /// Writes managed hosts file and triggers reload via PUT api/hosts.
Task SaveHostsAsync(IReadOnlyList entries, CancellationToken ct = default);
}
diff --git a/src/DnsmasqWebUI/Infrastructure/Client/Abstractions/ILeasesClient.cs b/src/DnsmasqWebUI/Infrastructure/Client/Abstractions/ILeasesClient.cs
index 989f0f3..241a7bb 100644
--- a/src/DnsmasqWebUI/Infrastructure/Client/Abstractions/ILeasesClient.cs
+++ b/src/DnsmasqWebUI/Infrastructure/Client/Abstractions/ILeasesClient.cs
@@ -5,6 +5,7 @@ namespace DnsmasqWebUI.Infrastructure.Client.Abstractions;
/// Typed client for GET api/leases.
public interface ILeasesClient
{
+ /// Gets DHCP lease entries from GET api/leases. Optionally forces a cache refresh on the server.
/// When true, invalidates the server cache so the next read is from disk (e.g. after manual Refresh).
Task GetLeasesAsync(bool forceRefresh = false, CancellationToken ct = default);
}
diff --git a/src/DnsmasqWebUI/Infrastructure/Client/Abstractions/IReloadClient.cs b/src/DnsmasqWebUI/Infrastructure/Client/Abstractions/IReloadClient.cs
index 502786f..f2c9905 100644
--- a/src/DnsmasqWebUI/Infrastructure/Client/Abstractions/IReloadClient.cs
+++ b/src/DnsmasqWebUI/Infrastructure/Client/Abstractions/IReloadClient.cs
@@ -5,5 +5,6 @@ namespace DnsmasqWebUI.Infrastructure.Client.Abstractions;
/// Typed client for POST api/reload.
public interface IReloadClient
{
+ /// Triggers dnsmasq reload via POST api/reload.
Task ReloadAsync(CancellationToken ct = default);
}
diff --git a/src/DnsmasqWebUI/Infrastructure/Client/Abstractions/IStatusClient.cs b/src/DnsmasqWebUI/Infrastructure/Client/Abstractions/IStatusClient.cs
index 2c527b2..842e274 100644
--- a/src/DnsmasqWebUI/Infrastructure/Client/Abstractions/IStatusClient.cs
+++ b/src/DnsmasqWebUI/Infrastructure/Client/Abstractions/IStatusClient.cs
@@ -5,5 +5,6 @@ namespace DnsmasqWebUI.Infrastructure.Client.Abstractions;
/// Typed client for GET api/status.
public interface IStatusClient
{
+ /// Gets dnsmasq and config status from GET api/status.
Task GetStatusAsync(CancellationToken ct = default);
}
diff --git a/src/DnsmasqWebUI/Infrastructure/Services/Abstractions/IDnsmasqConfigService.cs b/src/DnsmasqWebUI/Infrastructure/Services/Abstractions/IDnsmasqConfigService.cs
index 6205c02..9a3d9ff 100644
--- a/src/DnsmasqWebUI/Infrastructure/Services/Abstractions/IDnsmasqConfigService.cs
+++ b/src/DnsmasqWebUI/Infrastructure/Services/Abstractions/IDnsmasqConfigService.cs
@@ -6,10 +6,18 @@ using DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig;
namespace DnsmasqWebUI.Infrastructure.Services.Abstractions;
+/// Reads and writes the managed dnsmasq config file and DHCP hosts entries (the app-managed config and dhcp-host= lines).
public interface IDnsmasqConfigService : IApplicationScopedService
{
+ /// Reads DHCP host entries from the managed config (dhcp-host= lines).
Task> ReadDhcpHostsAsync(CancellationToken ct = default);
+
+ /// Writes DHCP host entries to the managed config file (replaces dhcp-host= lines).
Task WriteDhcpHostsAsync(IReadOnlyList entries, CancellationToken ct = default);
+
+ /// Reads the full managed config file as structured lines plus the effective addn-hosts path in file (for display).
Task ReadManagedConfigAsync(CancellationToken ct = default);
+
+ /// Writes the full managed config file from the given lines (round-trip from ReadManagedConfigAsync).
Task WriteManagedConfigAsync(IReadOnlyList lines, CancellationToken ct = default);
}
diff --git a/src/DnsmasqWebUI/Infrastructure/Services/Abstractions/IHostsFileService.cs b/src/DnsmasqWebUI/Infrastructure/Services/Abstractions/IHostsFileService.cs
index de8ce7e..031c27d 100644
--- a/src/DnsmasqWebUI/Infrastructure/Services/Abstractions/IHostsFileService.cs
+++ b/src/DnsmasqWebUI/Infrastructure/Services/Abstractions/IHostsFileService.cs
@@ -2,8 +2,12 @@ using DnsmasqWebUI.Models.Hosts;
namespace DnsmasqWebUI.Infrastructure.Services.Abstractions;
+/// Reads and writes the app-managed hosts file (the single hosts file the app edits).
public interface IHostsFileService : IApplicationScopedService
{
+ /// Reads all entries from the managed hosts file (including comments and passthrough lines).
Task> ReadAsync(CancellationToken ct = default);
+
+ /// Writes the given entries to the managed hosts file (replaces file content).
Task WriteAsync(IReadOnlyList entries, CancellationToken ct = default);
}
diff --git a/src/DnsmasqWebUI/Infrastructure/Services/Abstractions/ILeasesCache.cs b/src/DnsmasqWebUI/Infrastructure/Services/Abstractions/ILeasesCache.cs
index d70da22..f0b2436 100644
--- a/src/DnsmasqWebUI/Infrastructure/Services/Abstractions/ILeasesCache.cs
+++ b/src/DnsmasqWebUI/Infrastructure/Services/Abstractions/ILeasesCache.cs
@@ -10,5 +10,6 @@ public interface ILeasesCache : IApplicationSingleton
/// Forces the next to re-read the file. Use for manual Refresh; no need to recreate the file watcher.
void Invalidate();
+ /// Returns cached lease entries, or re-reads from disk if invalidated or file changed.
Task<(bool Available, IReadOnlyList? Entries)> GetOrRefreshAsync(CancellationToken ct = default);
}
diff --git a/src/DnsmasqWebUI/Infrastructure/Services/Abstractions/ILeasesFileService.cs b/src/DnsmasqWebUI/Infrastructure/Services/Abstractions/ILeasesFileService.cs
index 9b6f45d..9540b6b 100644
--- a/src/DnsmasqWebUI/Infrastructure/Services/Abstractions/ILeasesFileService.cs
+++ b/src/DnsmasqWebUI/Infrastructure/Services/Abstractions/ILeasesFileService.cs
@@ -2,8 +2,12 @@ using DnsmasqWebUI.Models.Dhcp;
namespace DnsmasqWebUI.Infrastructure.Services.Abstractions;
+/// Reads the dnsmasq DHCP leases file (path from effective config).
public interface ILeasesFileService : IApplicationScopedService
{
+ /// Reads lease entries from the leases file. Throws if file is not configured or not readable.
Task> ReadAsync(CancellationToken ct = default);
+
+ /// Attempts to read the leases file. Returns (false, null) when not configured or not readable; (true, entries) otherwise.
Task<(bool Available, IReadOnlyList? Entries)> TryReadAsync(CancellationToken ct = default);
}
diff --git a/src/DnsmasqWebUI/Infrastructure/Services/Abstractions/IReloadService.cs b/src/DnsmasqWebUI/Infrastructure/Services/Abstractions/IReloadService.cs
index b1d8bbd..f7dbde9 100644
--- a/src/DnsmasqWebUI/Infrastructure/Services/Abstractions/IReloadService.cs
+++ b/src/DnsmasqWebUI/Infrastructure/Services/Abstractions/IReloadService.cs
@@ -1,8 +1,15 @@
namespace DnsmasqWebUI.Infrastructure.Services.Abstractions;
+/// Runs the configured dnsmasq reload command (e.g. systemctl reload dnsmasq).
public interface IReloadService : IApplicationScopedService
{
+ /// Executes the reload command and returns exit code and output. Serialised so only one reload runs at a time.
Task ReloadAsync(CancellationToken ct = default);
}
+/// Result of running the reload command.
+/// True when the command exited with code 0.
+/// Process exit code; -1 when failed to start or timed out.
+/// Standard output from the command.
+/// Standard error from the command.
public record ReloadResult(bool Success, int ExitCode, string? StdOut, string? StdErr);
diff --git a/src/DnsmasqWebUI/Models/Contracts/ConfigSetSnapshot.cs b/src/DnsmasqWebUI/Models/Contracts/ConfigSetSnapshot.cs
index 18fbc4a..23567de 100644
--- a/src/DnsmasqWebUI/Models/Contracts/ConfigSetSnapshot.cs
+++ b/src/DnsmasqWebUI/Models/Contracts/ConfigSetSnapshot.cs
@@ -5,6 +5,11 @@ using DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig;
namespace DnsmasqWebUI.Models.Contracts;
/// Immutable snapshot from the config set cache: config set, effective config, sources, managed file content, and DHCP host entries (one read per refresh).
+/// Ordered config set (main + conf-file/conf-dir) and managed file paths.
+/// Effective dnsmasq config built from all files.
+/// Source per field (file path, readonly) for UI tooltips.
+/// Parsed lines and effective addn-hosts path of the managed config file.
+/// DHCP host entries read from the managed file.
public record ConfigSetSnapshot(
DnsmasqConfigSet Set,
EffectiveDnsmasqConfig Config,
diff --git a/src/DnsmasqWebUI/Models/Contracts/HostsSnapshot.cs b/src/DnsmasqWebUI/Models/Contracts/HostsSnapshot.cs
index 7a6a4c6..57276c0 100644
--- a/src/DnsmasqWebUI/Models/Contracts/HostsSnapshot.cs
+++ b/src/DnsmasqWebUI/Models/Contracts/HostsSnapshot.cs
@@ -3,6 +3,8 @@ using DnsmasqWebUI.Models.Hosts;
namespace DnsmasqWebUI.Models.Contracts;
/// Immutable snapshot from the hosts cache: managed hosts file entries and read-only hosts files (system + addn-hosts).
+/// Entries from the app-managed hosts file.
+/// Read-only hosts files (system hosts when configured, then addn-hosts that are not the managed file).
public record HostsSnapshot(
IReadOnlyList ManagedEntries,
IReadOnlyList ReadOnlyFiles
diff --git a/src/DnsmasqWebUI/Models/Contracts/ManagedConfigContent.cs b/src/DnsmasqWebUI/Models/Contracts/ManagedConfigContent.cs
index 8961628..3f7f9de 100644
--- a/src/DnsmasqWebUI/Models/Contracts/ManagedConfigContent.cs
+++ b/src/DnsmasqWebUI/Models/Contracts/ManagedConfigContent.cs
@@ -3,4 +3,6 @@ using DnsmasqWebUI.Models.Config;
namespace DnsmasqWebUI.Models.Contracts;
/// Full managed file content. EffectiveHostsPathInFile is parsed from AddnHosts line if present (for display only).
+/// Parsed config lines (blank, comment, addn-hosts, dhcp-host, other).
+/// Path from addn-hosts= in the managed file, for display; empty when not set.
public record ManagedConfigContent(IReadOnlyList Lines, string EffectiveHostsPathInFile);
diff --git a/src/DnsmasqWebUI/Models/Dhcp/DhcpHostEntry.cs b/src/DnsmasqWebUI/Models/Dhcp/DhcpHostEntry.cs
index cec86db..02d036d 100644
--- a/src/DnsmasqWebUI/Models/Dhcp/DhcpHostEntry.cs
+++ b/src/DnsmasqWebUI/Models/Dhcp/DhcpHostEntry.cs
@@ -1,21 +1,42 @@
namespace DnsmasqWebUI.Models.Dhcp;
+/// One dhcp-host= line (MAC(s), optional address, name, lease, options). Used for GET/PUT api/dhcp/hosts.
public class DhcpHostEntry
{
+ /// 1-based line number in the config file. Used for display and matching.
public int LineNumber { get; set; }
/// Stable identifier (content-based: MACs|Address|Name, with ":LineNumber" for uniqueness). Set by server on GET; used to match entries on PUT so reordering is safe.
public string Id { get; set; } = "";
+ /// Original line text as read from the config (for passthrough and round-trip).
public string RawLine { get; set; } = "";
+
+ /// True when the line is a comment (starts with #).
public bool IsComment { get; set; }
+
+ /// True when the entry was marked for deletion in the UI (removed on save).
public bool IsDeleted { get; set; }
+
+ /// True when the line could not be parsed (preserved as RawLine on write).
public bool Ignore { get; set; }
+
+ /// MAC address(es) from the dhcp-host line. One or more; order preserved.
public List MacAddresses { get; set; } = new();
+
+ /// Hostname or DHCP hostname from the line; null when not set.
public string? Name { get; set; }
+
+ /// Reserved IP address from the line; null when not set.
public string? Address { get; set; }
+
+ /// Lease identifier (e.g. "01:02:03:04:05:06"); null when not set.
public string? Lease { get; set; }
+
+ /// Extra tokens after the main dhcp-host fields (e.g. set:name); preserved on write.
public List Extra { get; set; } = new();
+
+ /// Inline comment text from the line; null when none.
public string? Comment { get; set; }
/// True when this entry is from the managed file (editable). False when from main config or another file (read-only). Set by server on GET; new entries created in the UI should set this to true.
diff --git a/src/DnsmasqWebUI/Models/Dhcp/LeaseEntry.cs b/src/DnsmasqWebUI/Models/Dhcp/LeaseEntry.cs
index bb06479..ec841ef 100644
--- a/src/DnsmasqWebUI/Models/Dhcp/LeaseEntry.cs
+++ b/src/DnsmasqWebUI/Models/Dhcp/LeaseEntry.cs
@@ -1,11 +1,23 @@
namespace DnsmasqWebUI.Models.Dhcp;
+/// One DHCP lease entry from the dnsmasq leases file (timestamp, MAC, IP, hostname, client-id).
public class LeaseEntry
{
+ /// Lease expiry time as Unix timestamp (seconds since epoch).
public long Epoch { get; set; }
+
+ /// Client MAC address.
public string Mac { get; set; } = "";
+
+ /// Assigned IP address.
public string Address { get; set; } = "";
+
+ /// Hostname from DHCP or DNS; empty when unknown.
public string Name { get; set; } = "";
+
+ /// DHCP client identifier; empty when not set.
public string ClientId { get; set; } = "";
+
+ /// Lease expiry as DateTime (derived from Epoch).
public DateTime Timestamp => DateTimeOffset.FromUnixTimeSeconds(Epoch).DateTime;
}
diff --git a/src/DnsmasqWebUI/Models/Dhcp/LeasesResult.cs b/src/DnsmasqWebUI/Models/Dhcp/LeasesResult.cs
index 39c6c99..8d936c6 100644
--- a/src/DnsmasqWebUI/Models/Dhcp/LeasesResult.cs
+++ b/src/DnsmasqWebUI/Models/Dhcp/LeasesResult.cs
@@ -1,4 +1,7 @@
namespace DnsmasqWebUI.Models.Dhcp;
/// Result of GET api/leases: whether leases are available and the list of entries.
+/// True when the leases file is configured and readable; false when not configured or path invalid.
+/// Lease entries; null when not available or file unreadable (Message explains).
+/// Error or status message (e.g. "Leases not configured."); null when successful.
public record LeasesResult(bool Available, IReadOnlyList? Entries, string? Message);
diff --git a/src/DnsmasqWebUI/Models/Dnsmasq/EffectiveConfig/DnsmasqConfigSet.cs b/src/DnsmasqWebUI/Models/Dnsmasq/EffectiveConfig/DnsmasqConfigSet.cs
index fbb6834..d2ae52e 100644
--- a/src/DnsmasqWebUI/Models/Dnsmasq/EffectiveConfig/DnsmasqConfigSet.cs
+++ b/src/DnsmasqWebUI/Models/Dnsmasq/EffectiveConfig/DnsmasqConfigSet.cs
@@ -1,6 +1,10 @@
namespace DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig;
/// Ordered set of dnsmasq config files (main + conf-file + conf-dir). ManagedFilePath is the single config file we read/write; ManagedHostsFilePath is the single hosts file we read/write.
+/// Path to the main dnsmasq config file (e.g. /etc/dnsmasq.conf).
+/// Path to the app-managed config file (e.g. zz-dnsmasq-webui.conf).
+/// Path to the app-managed hosts file; null when not configured.
+/// Ordered list of config files (main + included) for display.
public record DnsmasqConfigSet(
string MainConfigPath,
string ManagedFilePath,
diff --git a/src/DnsmasqWebUI/Models/Dnsmasq/EffectiveConfig/DnsmasqConfigSetEntry.cs b/src/DnsmasqWebUI/Models/Dnsmasq/EffectiveConfig/DnsmasqConfigSetEntry.cs
index 3fb7113..14cd250 100644
--- a/src/DnsmasqWebUI/Models/Dnsmasq/EffectiveConfig/DnsmasqConfigSetEntry.cs
+++ b/src/DnsmasqWebUI/Models/Dnsmasq/EffectiveConfig/DnsmasqConfigSetEntry.cs
@@ -1,4 +1,8 @@
namespace DnsmasqWebUI.Models.Dnsmasq.EffectiveConfig;
/// One file in the dnsmasq config set (main or included). IsManaged is true only for the app-managed file.
+/// Absolute path of the config file.
+/// Filename only (e.g. dnsmasq.conf, 01-default.conf).
+/// Whether the file is main, conf-file, or conf-dir.
+/// True when this file is the app-managed config file (editable from UI).
public record DnsmasqConfigSetEntry(string Path, string FileName, DnsmasqConfFileSource Source, bool IsManaged);
diff --git a/src/DnsmasqWebUI/Models/Dnsmasq/SaveWithReloadResult.cs b/src/DnsmasqWebUI/Models/Dnsmasq/SaveWithReloadResult.cs
index 4caadda..1a3d83a 100644
--- a/src/DnsmasqWebUI/Models/Dnsmasq/SaveWithReloadResult.cs
+++ b/src/DnsmasqWebUI/Models/Dnsmasq/SaveWithReloadResult.cs
@@ -3,4 +3,6 @@ using DnsmasqWebUI.Infrastructure.Services.Abstractions;
namespace DnsmasqWebUI.Models.Dnsmasq;
/// Result of a save operation that triggers a dnsmasq reload (e.g. PUT api/hosts, PUT api/dhcp/hosts).
+/// True when the write succeeded (reload result may still indicate failure).
+/// Result of the reload command run after save.
public record SaveWithReloadResult(bool Saved, ReloadResult Reload);
diff --git a/src/DnsmasqWebUI/Models/Hosts/HostEntry.cs b/src/DnsmasqWebUI/Models/Hosts/HostEntry.cs
index faeea3e..4cec9f3 100644
--- a/src/DnsmasqWebUI/Models/Hosts/HostEntry.cs
+++ b/src/DnsmasqWebUI/Models/Hosts/HostEntry.cs
@@ -1,5 +1,6 @@
namespace DnsmasqWebUI.Models.Hosts;
+/// One line or entry in an /etc/hosts-style file (IP, names, comment, or passthrough).
public class HostEntry
{
/// 1-based line number in the file. Used for display and as fallback when Id is not set.
@@ -8,9 +9,18 @@ public class HostEntry
/// Stable identifier: host entries use "Address|name1,name2" (content-based, stable across reorder); passthrough use "line:LineNumber". Set by server on GET; optional on PUT (order is preserved).
public string Id { get; set; } = "";
+ /// IP address (e.g. 192.168.1.1). Empty for comment or passthrough lines.
public string Address { get; set; } = "";
+
+ /// Canonical hostname and aliases. Order preserved.
public List Names { get; set; } = new();
+
+ /// Original line text as read from the file (for passthrough and round-trip).
public string RawLine { get; set; } = "";
+
+ /// True when the line is a comment (starts with #).
public bool IsComment { get; set; }
+
+ /// True when the line could not be parsed as address/names (e.g. malformed or comment); preserved as RawLine on write.
public bool IsPassthrough { get; set; }
}
diff --git a/src/DnsmasqWebUI/Models/Hosts/ReadOnlyHostsFile.cs b/src/DnsmasqWebUI/Models/Hosts/ReadOnlyHostsFile.cs
index a1bfc00..ae3fd96 100644
--- a/src/DnsmasqWebUI/Models/Hosts/ReadOnlyHostsFile.cs
+++ b/src/DnsmasqWebUI/Models/Hosts/ReadOnlyHostsFile.cs
@@ -1,4 +1,6 @@
namespace DnsmasqWebUI.Models.Hosts;
/// Path and parsed entries for a read-only addn-hosts file (not the managed hosts file).
+/// Absolute path of the hosts file (e.g. /etc/hosts or an addn-hosts path).
+/// Parsed entries from the file (IP, names, comments, passthrough).
public record ReadOnlyHostsFile(string Path, IReadOnlyList Entries);