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);