Initial commit: dnsmasq web UI

- ASP.NET Core 9 Blazor Web App + Web API
- Hosts file management (read/write, hosts(5) format)
- DHCP static hosts (dhcp-host=, dnsmasq config)
- DHCP leases (read-only, dnsmasq lease file format)
- Reload and status commands (configurable)
- Docker: standalone app image + Dockerfile.dnsmasq (app + dnsmasq)
- docker-compose.test.yml: app + dhcp-client, testdata mount
- Unit tests (Hosts, DhcpHost, Leases, DnsmasqConfig parsers) using testdata
This commit is contained in:
2026-01-31 03:06:46 +10:00
commit e99b2d0453
105 changed files with 62565 additions and 0 deletions
@@ -0,0 +1,50 @@
using DnsmasqWebUI.Models;
using DnsmasqWebUI.Services.Abstractions;
using Microsoft.AspNetCore.Mvc;
namespace DnsmasqWebUI.Controllers;
[ApiController]
[Route("api/[controller]")]
public class DhcpController : ControllerBase
{
private readonly IDnsmasqConfigService _configService;
private readonly IReloadService _reloadService;
public DhcpController(IDnsmasqConfigService configService, IReloadService reloadService)
{
_configService = configService;
_reloadService = reloadService;
}
[HttpGet("hosts")]
public async Task<ActionResult<IReadOnlyList<DhcpHostEntry>>> GetHosts(CancellationToken ct)
{
try
{
var entries = await _configService.ReadDhcpHostsAsync(ct);
return Ok(entries);
}
catch (Exception ex)
{
return StatusCode(500, new { error = ex.Message });
}
}
[HttpPut("hosts")]
public async Task<ActionResult<object>> PutHosts([FromBody] List<DhcpHostEntry>? entries, CancellationToken ct)
{
if (entries == null)
return BadRequest(new { error = "Body required" });
try
{
await _configService.WriteDhcpHostsAsync(entries, ct);
var reload = await _reloadService.ReloadAsync(ct);
return Ok(new { saved = true, reload = new { reload.Success, reload.ExitCode, reload.StdErr } });
}
catch (Exception ex)
{
return StatusCode(500, new { error = ex.Message });
}
}
}