Cleanup Namespaces
This commit is contained in:
parent
9b49f880a2
commit
6c901ea46b
21 changed files with 230 additions and 31 deletions
|
|
@ -1,7 +1,7 @@
|
|||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace netddi.Data;
|
||||
namespace DotNetDDI.Data;
|
||||
|
||||
public class ApplicationDbContext : IdentityDbContext
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
// <auto-generated />
|
||||
using System;
|
||||
using netddi.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
namespace netddi.Data.Migrations
|
||||
namespace DotNetDDI.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("00000000000000_CreateIdentitySchema")]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace netddi.Data.Migrations
|
||||
namespace DotNetDDI.Data.Migrations
|
||||
{
|
||||
public partial class CreateIdentitySchema : Migration
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
// <auto-generated />
|
||||
using System;
|
||||
using netddi.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
namespace netddi.Data.Migrations
|
||||
namespace DotNetDDI.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
partial class ApplicationDbContextModelSnapshot : ModelSnapshot
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<Project>
|
||||
<!-- See https://aka.ms/dotnet/msbuild/customize for more details on customizing your build -->
|
||||
<PropertyGroup>
|
||||
|
||||
<ArtifactsPath>$(MSBuildThisFileDirectory)artifacts</ArtifactsPath>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,2 @@
|
|||
<Project>
|
||||
<!-- See https://aka.ms/dotnet/msbuild/customize for more details on customizing your build -->
|
||||
<Target Name="CustomAfterBuildTarget" AfterTargets="Build">
|
||||
<Message Text="Hello from CustomAfterBuildTarget" Importance="high" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ using System.Diagnostics;
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace netddi.Pages;
|
||||
namespace DotNetDDI.Pages;
|
||||
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
[IgnoreAntiforgeryToken]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace netddi.Pages;
|
||||
namespace DotNetDDI.Pages;
|
||||
|
||||
public class IndexModel : PageModel
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace netddi.Pages;
|
||||
namespace DotNetDDI.Pages;
|
||||
|
||||
public class PrivacyModel : PageModel
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@ViewData["Title"] - netddi</title>
|
||||
<title>@ViewData["Title"] - .NET DDI</title>
|
||||
<script type="importmap"></script>
|
||||
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
<header>
|
||||
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" asp-area="" asp-page="/Index">netddi</a>
|
||||
<a class="navbar-brand" asp-area="" asp-page="/Index">.NET DDI</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
|
||||
aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
|
|
@ -40,7 +40,7 @@
|
|||
|
||||
<footer class="border-top footer text-muted">
|
||||
<div class="container">
|
||||
© 2025 - netddi - <a asp-area="" asp-page="/Privacy">Privacy</a>
|
||||
© 2025 - .NET DDI - <a asp-area="" asp-page="/Privacy">Privacy</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
@using Microsoft.AspNetCore.Identity
|
||||
@using netddi
|
||||
@using netddi.Data
|
||||
@namespace netddi.Pages
|
||||
@using DotNetDDI
|
||||
@using DotNetDDI.Data
|
||||
@namespace DotNetDDI.Pages
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
|
|
|
|||
51
Program.cs
51
Program.cs
|
|
@ -1,34 +1,73 @@
|
|||
using DotNetDDI.Data;
|
||||
using DotNetDDI.Integrations.Kea;
|
||||
using DotNetDDI.Integrations.PowerDns;
|
||||
using DotNetDDI.Options;
|
||||
using DotNetDDI.Services.Dhcp;
|
||||
using DotNetDDI.Services.Dns;
|
||||
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using netddi.Data;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
builder.Services.AddSystemd();
|
||||
|
||||
// Add services to the container.
|
||||
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
|
||||
builder.Services.AddDbContext<ApplicationDbContext>(options =>
|
||||
options.UseSqlite(connectionString));
|
||||
options.UseSqlite(connectionString));
|
||||
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
|
||||
|
||||
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
|
||||
.AddEntityFrameworkStores<ApplicationDbContext>();
|
||||
.AddEntityFrameworkStores<ApplicationDbContext>();
|
||||
builder.Services.AddRazorPages();
|
||||
|
||||
builder.Services.Configure<DhcpOptions>(builder.Configuration.GetRequiredSection("Dhcp"));
|
||||
builder.Services.Configure<PowerDnsOptions>(builder.Configuration.GetRequiredSection("PowerDns"));
|
||||
|
||||
builder.Services.AddHostedService<DhcpWatcher>();
|
||||
builder.Services.AddHostedService<DhcpQueueWorker>();
|
||||
|
||||
builder.Services.AddSingleton<DhcpLeaseQueue>();
|
||||
builder.Services.AddSingleton<DnsRepository>();
|
||||
|
||||
builder.Services.AddDhcpWatcherFactory();
|
||||
builder.Services.AddKeaFactory();
|
||||
|
||||
builder.WebHost.ConfigureKestrel((context, options) =>
|
||||
{
|
||||
options.UseSystemd(_ => throw new InvalidOperationException("SystemD Socket Activation is not supported by Kestrel."));
|
||||
|
||||
var pdnsOptions = context.Configuration.GetRequiredSection("PowerDns:Listener").Get<PowerDnsListenerOptions>();
|
||||
ArgumentNullException.ThrowIfNull(pdnsOptions);
|
||||
var path = PathEx.ExpandPath(pdnsOptions.Socket);
|
||||
FileInfo file = new(path);
|
||||
file.Directory!.Create();
|
||||
file.Delete();
|
||||
options.ListenUnixSocket(path, options =>
|
||||
{
|
||||
options.UseConnectionHandler<PowerDnsHandler>();
|
||||
});
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseMigrationsEndPoint();
|
||||
app.UseMigrationsEndPoint();
|
||||
}
|
||||
else
|
||||
{
|
||||
app.UseExceptionHandler("/Error");
|
||||
app.UseExceptionHandler("/Error");
|
||||
}
|
||||
|
||||
app.UseRouting();
|
||||
|
||||
app.UseAuthorization();
|
||||
if (app.Configuration.GetValue("Admin:Authentication", true))
|
||||
{
|
||||
app.UseAuthorization();
|
||||
}
|
||||
|
||||
app.UseStaticFiles();
|
||||
app.MapRazorPages();
|
||||
|
|
|
|||
84
README.md
84
README.md
|
|
@ -1 +1,85 @@
|
|||
# .NET Dhcp Dns Ipam
|
||||
|
||||
Enabling PowerDNS to query popular supported Dhcp-servers.
|
||||
|
||||
This project was born out of the necessity for my home-lab network to be able to resolve both IPv4 and IPv6 addresses from one Dhcp-service.
|
||||
|
||||
Theoretically Kea can update DNS servers using RFC2136 nsupdate-mechanisms using kea-ddns, but this interoperation can cause issues in networks with devices sharing a hostname (i.e. DHCID records), missing update requests due to service restarts or temporary connectivity issues.
|
||||
|
||||
## Scope
|
||||
|
||||
At the moment there is no need to implement more than is minimally required to get Dhcp4 and Dhcp6 leases queryable by PowerDNS using the memfile "database" of Kea using the remote backend with unix domain sockets.
|
||||
|
||||
Following parts may be implemented later as I see fit:
|
||||
- Different PowerDNS remote backends
|
||||
- mainly HTTP REST
|
||||
- Support different Kea lease databases
|
||||
- MySQL
|
||||
- PostgreSQL
|
||||
|
||||
## Building
|
||||
|
||||
Requires .NET 8 SDK<br>
|
||||
Create binary using
|
||||
> dotnet publish -c Release -p:PublishTrimmed=true -p:PublishSingleFile=true --self-contained
|
||||
|
||||
## Usage
|
||||
|
||||
Install, and configure Kea (optionally with Stork) Dhcp4, Dhcp6 or both.<br>
|
||||
Make sure to enable the memfile lease store.
|
||||
|
||||
Install and configure PowerDNS, including the [remote backend](https://doc.powerdns.com/authoritative/backends/remote.html).<br>
|
||||
A sample configuration file is provided.
|
||||
|
||||
Deploy netddi to /opt/netddi<br>
|
||||
Setup systemd using the provided socket and service units, configure as necessary.
|
||||
|
||||
Start Kea, netddi and PowerDNS.
|
||||
|
||||
**To be done**: Packaging for common Linux distributions.<br>
|
||||
Deb-packages (Debian)<br>
|
||||
RPM-packages (EL)
|
||||
|
||||
### Configuration
|
||||
|
||||
netddi can be configured using environment variables or the appsettings.json file - [Configuration#Binding hierarchies](https://learn.microsoft.com/dotnet/core/extensions/configuration#binding-hierarchies) describes the naming scheme in this section.
|
||||
|
||||
Default configuration:
|
||||
```
|
||||
Admin:Authentication=true
|
||||
Dhcp:Kea:Dhcp4:Leases=/var/lib/kea/kea-leases4.csv
|
||||
Dhcp:Kea:Dhcp6:Leases=/var/lib/kea/kea-leases6.csv
|
||||
PowerDns:UniqueHostnames=true
|
||||
PowerDns:Listener:Socket=/run/netddi/pdns.sock
|
||||
```
|
||||
|
||||
`Admin:Authentication` enables configuring whether the Admin interface is guarded by admin login.
|
||||
|
||||
`Dhcp:Kea` allows configuring `Dhcp4` and `Dhcp6` lease file watchers, respective for each of both services.
|
||||
|
||||
In `PowerDns:Listener:Socket` you can optionally configure the unix domain socket to be used in case Systemd isn't providing them (e.g. when starting the service manually).
|
||||
|
||||
netddi continuously monitors the Dhcp service leases and upon seeing a new lease all previous records that match in hostname and lease type (IPv4, IPv6) are replaced. If you want to change this behavior you can opt-out of this behavior by setting `PowerDns:UniqueHostnames=false`.
|
||||
|
||||
See [Logging in C#](https://learn.microsoft.com/dotnet/core/extensions/logging?tabs=command-line#configure-logging-without-code) for options related to logging.
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
Incorporates following libraries directly:
|
||||
|
||||
**.NET Foundation and Contributors**
|
||||
- [CommunityToolkit.HighPerformance](https://github.com/CommunityToolkit/dotnet) - MIT
|
||||
- [dotNext](https://github.com/dotnet/dotNext) - MIT
|
||||
- Several runtime libraries, as part of [.NET](https://github.com/dotnet/runtime)
|
||||
- Microsoft.AspNetCore.App
|
||||
- Microsoft.Extensions.Configuration.Binder
|
||||
- Microsoft.Extensions.Hosting.Systemd
|
||||
- System.IO.Pipelines
|
||||
|
||||
**[Nietras](https://github.com/nietras)**
|
||||
- [Sep](https://github.com/nietras/Sep) - MIT
|
||||
|
||||
Incorporates data structures and protocol implementations as required for interop scenarios:
|
||||
|
||||
- [kea](https://gitlab.isc.org/isc-projects/kea) by [ISC](https://isc.org/) - MPL 2.0
|
||||
- [PowerDNS](https://github.com/PowerDNS/pdns) by [PowerDNS.COM BV](https://www.powerdns.com/) and contributors - GPL 2.0
|
||||
|
|
|
|||
|
|
@ -1,9 +1,34 @@
|
|||
{
|
||||
"Admin": {
|
||||
"Authentication": false
|
||||
},
|
||||
"DetailedErrors": true,
|
||||
"Dhcp": {
|
||||
"Kea": {
|
||||
"Dhcp4": {
|
||||
"Leases": "../../ext/kea/kea-leases4.csv"
|
||||
},
|
||||
"Dhcp6": {
|
||||
"Leases": "../../ext/kea/kea-leases6.csv"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Kestrel": {
|
||||
"Endpoints": {
|
||||
"Http": {
|
||||
"Url": "http://[::1]:5000"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"PowerDns": {
|
||||
"Listener": {
|
||||
"Socket": "${XDG_RUNTIME_DIR}/netddi/pdns.sock"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,38 @@
|
|||
{
|
||||
"Admin": {
|
||||
"Authentication": true
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": "DataSource=app.db;Cache=Shared"
|
||||
},
|
||||
"Dhcp": {
|
||||
"Kea": {
|
||||
"Dhcp4": {
|
||||
"Leases": "/var/lib/kea/kea-leases4.csv"
|
||||
},
|
||||
"Dhcp6": {
|
||||
"Leases": "/var/lib/kea/kea-leases6.csv"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Kestrel": {
|
||||
"Endpoints": {
|
||||
"Http": {
|
||||
"Url": "http://[::]:80"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
"PowerDns": {
|
||||
"Listener": {
|
||||
"Socket": "/run/netddi/pdns.sock"
|
||||
},
|
||||
"UniqueHostnames": true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
6
ext/kea/kea-leases4.csv
Normal file
6
ext/kea/kea-leases4.csv
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
address,hwaddr,client_id,valid_lifetime,expire,subnet_id,fqdn_fwd,fqdn_rev,hostname,state,user_context
|
||||
192.0.2.1,06:07:08:09:0a:bc,,200,200,8,1,1,host.example.com,0,
|
||||
192.0.2.2,,,200,200,8,1,1,host.example.com,0,
|
||||
192.0.2.3,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04,100,100,7,0,0,,1,{ "foobar": true }
|
||||
192.0.2.4,,11:22:33:44:55:66,200,200,8,1,1,host.example.com,0,
|
||||
192.0.2.5,,,200,200,8,1,1,,1,
|
||||
|
Can't render this file because it contains an unexpected character in line 4 and column 66.
|
7
ext/kea/kea-leases6.csv
Normal file
7
ext/kea/kea-leases6.csv
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
address,duid,valid_lifetime,expire,subnet_id,pref_lifetime,lease_type,iaid,prefix_len,fqdn_fwd,fqdn_rev,hostname,hwaddr,state,user_context,hwtype,hwaddr_source,pool_id
|
||||
2001:db8:1::1,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,200,200,8,100,0,7,0,1,1,host.example.com,,1,,1,0,0
|
||||
2001:db8:1::1,,200,200,8,100,0,7,0,1,1,host.example.com,,1,,1,0,0
|
||||
2001:db8:2::10,01:01:01:01:0a:01:02:03:04:05,300,300,6,150,0,8,0,0,0,,,1,,1,0,0
|
||||
3000:1::,00:01:02:03:04:05:06:0a:0b:0c:0d:0e:0f,0,200,8,0,2,16,64,0,0,,,1,{ "foobar": true },,1,0,0
|
||||
2001:db8:1::2,00:00:00,200,200,8,100,0,7,0,1,1,host.example.com,,0,,1,0,0
|
||||
2001:db8:1::3,00:00:00,200,200,8,100,0,7,0,1,1,host.example.com,,1,,1,0,0
|
||||
|
Can't render this file because it contains an unexpected character in line 5 and column 77.
|
2
ext/powerdns/netddi.conf
Normal file
2
ext/powerdns/netddi.conf
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
launch+=remote
|
||||
remote-connection-string+=unix:path=/run/netddi/pdns.sock
|
||||
11
ext/systemd/netddi.service
Normal file
11
ext/systemd/netddi.service
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
[Unit]
|
||||
Description=PowerDNS/DHCP Companion Remote
|
||||
Before=pdns.service
|
||||
|
||||
[Service]
|
||||
Type=notify
|
||||
ExecStart=/opt/netddi/netddi
|
||||
WorkingDirectory=/etc/netddi
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
9
ext/systemd/netddi.socket
Normal file
9
ext/systemd/netddi.socket
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
[Unit]
|
||||
Description=netddi PowerDNS Remote Socket
|
||||
|
||||
[Socket]
|
||||
ListenStream=/run/netddi/pdns.sock
|
||||
Accept=no
|
||||
|
||||
[Install]
|
||||
WantedBy=sockets.target
|
||||
|
|
@ -1,5 +1,2 @@
|
|||
{
|
||||
"sdk": {
|
||||
"version": "9.0.102"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue