From 471555e2ea2ad804741aa7b7fe1f17fa7a26769e Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Sat, 13 Jan 2024 17:50:13 +0100 Subject: [PATCH 01/10] Fix systemd socket unit --- ext/systemd/pdns-dhcp.socket | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ext/systemd/pdns-dhcp.socket b/ext/systemd/pdns-dhcp.socket index b514f4b..f13126c 100644 --- a/ext/systemd/pdns-dhcp.socket +++ b/ext/systemd/pdns-dhcp.socket @@ -1,11 +1,8 @@ -# WARNING -# This currently not supported. - [Unit] Description=pdns-dhcp PowerDNS Remote Socket [Socket] -ListenStream=/run/pdns-dhcp/pdns-dhcp.sock +ListenStream=/run/pdns-dhcp/pdns.sock Accept=no [Install] From 1c390f2756c78d9274dcee0dc10b3fc5f91c5829 Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Sat, 13 Jan 2024 17:52:19 +0100 Subject: [PATCH 02/10] Add powerdns remote backend config file --- ext/powerdns/pdns-dhcp.conf | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 ext/powerdns/pdns-dhcp.conf diff --git a/ext/powerdns/pdns-dhcp.conf b/ext/powerdns/pdns-dhcp.conf new file mode 100644 index 0000000..6cf4ed2 --- /dev/null +++ b/ext/powerdns/pdns-dhcp.conf @@ -0,0 +1,2 @@ +launch+=remote +remote-connection-string+=unix:path=/run/pdns-dhcp/pdns.sock From 58020c81c9e6067bf34f23cd7da98b53912e60de Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Sat, 13 Jan 2024 21:14:14 +0100 Subject: [PATCH 03/10] Review --- ext/kea/{dhcp4.leases => kea-leases4.csv} | 0 ext/kea/{dhcp6.leases => kea-leases6.csv} | 0 src/pdns-dhcp/Kea/KeaDhcpLeaseWatcher.cs | 6 +++++- src/pdns-dhcp/Program.cs | 2 +- src/pdns-dhcp/appsettings.Development.json | 4 ++-- src/pdns-dhcp/appsettings.json | 4 ++-- src/pdns-dhcp/pdns-dhcp.csproj | 1 - 7 files changed, 10 insertions(+), 7 deletions(-) rename ext/kea/{dhcp4.leases => kea-leases4.csv} (100%) rename ext/kea/{dhcp6.leases => kea-leases6.csv} (100%) diff --git a/ext/kea/dhcp4.leases b/ext/kea/kea-leases4.csv similarity index 100% rename from ext/kea/dhcp4.leases rename to ext/kea/kea-leases4.csv diff --git a/ext/kea/dhcp6.leases b/ext/kea/kea-leases6.csv similarity index 100% rename from ext/kea/dhcp6.leases rename to ext/kea/kea-leases6.csv diff --git a/src/pdns-dhcp/Kea/KeaDhcpLeaseWatcher.cs b/src/pdns-dhcp/Kea/KeaDhcpLeaseWatcher.cs index c3487fd..e6c619f 100644 --- a/src/pdns-dhcp/Kea/KeaDhcpLeaseWatcher.cs +++ b/src/pdns-dhcp/Kea/KeaDhcpLeaseWatcher.cs @@ -170,11 +170,15 @@ public sealed class KeaDhcpLeaseWatcher : IHostedService { if (reader is null) { + // LongRunning, force spawning a thread + // As this may block for a long time. reader = await Task.Factory.StartNew( s => MemfileReader.From((Stream)s!), _pipe.Reader.AsStream(), stoppingToken, - TaskCreationOptions.AttachedToParent, TaskScheduler.Default); + TaskCreationOptions.DenyChildAttach | TaskCreationOptions.LongRunning, + TaskScheduler.Default) + .ConfigureAwait(false); continue; } diff --git a/src/pdns-dhcp/Program.cs b/src/pdns-dhcp/Program.cs index 71dfeac..1d47dd3 100644 --- a/src/pdns-dhcp/Program.cs +++ b/src/pdns-dhcp/Program.cs @@ -60,7 +60,7 @@ builder.Services.Configure(options => builder.WebHost.ConfigureKestrel((context, options) => { - if (context.Configuration.GetRequiredSection("PowerDns:Listener").Get() is { } pdnsOptions) + if (context.Configuration.GetSection("PowerDns:Listener").Get() is { } pdnsOptions) { var path = PathEx.ExpandPath(pdnsOptions.Socket); FileInfo file = new(path); diff --git a/src/pdns-dhcp/appsettings.Development.json b/src/pdns-dhcp/appsettings.Development.json index dd2f5bf..a2fbe6c 100644 --- a/src/pdns-dhcp/appsettings.Development.json +++ b/src/pdns-dhcp/appsettings.Development.json @@ -2,10 +2,10 @@ "Dhcp": { "Kea": { "Dhcp4": { - "Leases": "../../ext/kea/dhcp4.leases" + "Leases": "../../ext/kea/kea-leases4.csv" }, "Dhcp6": { - "Leases": "../../ext/kea/dhcp6.leases" + "Leases": "../../ext/kea/kea-leases6.csv" } } }, diff --git a/src/pdns-dhcp/appsettings.json b/src/pdns-dhcp/appsettings.json index e345227..bda961c 100644 --- a/src/pdns-dhcp/appsettings.json +++ b/src/pdns-dhcp/appsettings.json @@ -2,10 +2,10 @@ "Dhcp": { "Kea": { "Dhcp4": { - "Leases": "/var/lib/kea/dhcp4.leases" + "Leases": "/var/lib/kea/kea-leases4.csv" }, "Dhcp6": { - "Leases": "/var/lib/kea/dhcp6.leases" + "Leases": "/var/lib/kea/kea-leases6.csv" } } }, diff --git a/src/pdns-dhcp/pdns-dhcp.csproj b/src/pdns-dhcp/pdns-dhcp.csproj index 965bf09..f0414a1 100644 --- a/src/pdns-dhcp/pdns-dhcp.csproj +++ b/src/pdns-dhcp/pdns-dhcp.csproj @@ -17,7 +17,6 @@ - From f61eba0fdd105af70cff538be6922cbdc7ec2f7b Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Sat, 13 Jan 2024 21:15:14 +0100 Subject: [PATCH 04/10] Review --- src/pdns-dhcp/Program.cs | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/pdns-dhcp/Program.cs b/src/pdns-dhcp/Program.cs index 1d47dd3..c7b4a15 100644 --- a/src/pdns-dhcp/Program.cs +++ b/src/pdns-dhcp/Program.cs @@ -60,26 +60,23 @@ builder.Services.Configure(options => builder.WebHost.ConfigureKestrel((context, options) => { - if (context.Configuration.GetSection("PowerDns:Listener").Get() is { } pdnsOptions) + bool isSystemd = false; + options.UseSystemd(options => + { + isSystemd = true; + options.UseConnectionHandler(); + }); + + if (!isSystemd && context.Configuration.GetRequiredSection("PowerDns:Listener").Get() is { } pdnsOptions) { var path = PathEx.ExpandPath(pdnsOptions.Socket); FileInfo file = new(path); file.Directory!.Create(); - bool isSystemd = false; - options.UseSystemd(options => + file.Delete(); + options.ListenUnixSocket(path, options => { - isSystemd = true; options.UseConnectionHandler(); }); - - if (!isSystemd) - { - file.Delete(); - options.ListenUnixSocket(path, options => - { - options.UseConnectionHandler(); - }); - } } }); From af6a02b6dc7234b4546dde7b332831262c94859d Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Sat, 13 Jan 2024 21:16:11 +0100 Subject: [PATCH 05/10] Add README --- README.md | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..ff17817 --- /dev/null +++ b/README.md @@ -0,0 +1,82 @@ +# pdns-dhcp + +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 +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. +Make sure to enable the memfile lease store. + +Install and configure PowerDNS, including the [remote backend](https://doc.powerdns.com/authoritative/backends/remote.html). +A sample configuration file is provided. + +Deploy pdns-dhcp to /opt/pdns-dhcp +Setup systemd using the provided socket and service units, configure as necessary. + +Start Kea, pdns-dhcp and PowerDNS. + +**To be done**: Packaging for common Linux distributions. +Deb-packages (Debian) +RPM-packages (EL) + +### Configuration + +pdns-dhcp 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: +``` +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/pdns-dhcp/pdns.sock +``` + +`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). + +pdns-dhcp 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.Threading](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 From 854b51b46b4df43470f1ee77adb361b459fc8dc5 Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Sun, 14 Jan 2024 00:14:32 +0100 Subject: [PATCH 06/10] System.Text.Json deserialization is incompatible with this usage --- src/pdns-dhcp/PowerDns/Methods.cs | 19 ++-- src/pdns-dhcp/PowerDns/PowerDnsHandler.cs | 86 ++++++++++++++++--- .../PowerDns/PowerDnsSerializerContext.cs | 1 - 3 files changed, 77 insertions(+), 29 deletions(-) diff --git a/src/pdns-dhcp/PowerDns/Methods.cs b/src/pdns-dhcp/PowerDns/Methods.cs index bc823e6..37f5928 100644 --- a/src/pdns-dhcp/PowerDns/Methods.cs +++ b/src/pdns-dhcp/PowerDns/Methods.cs @@ -1,21 +1,12 @@ -using System.Text.Json.Serialization; - namespace pdns_dhcp.PowerDns; public interface IMethod; -[JsonPolymorphic(TypeDiscriminatorPropertyName = "method")] -[JsonDerivedType(typeof(InitializeMethod), "initialize")] -[JsonDerivedType(typeof(LookupMethod), "lookup")] -public class Method; +public record MethodBase(string Method); -public abstract class Method(TParam parameters) : Method - where TParam : MethodParameters -{ - [JsonPropertyName("parameters")] - public TParam Parameters => parameters; -} +public abstract record Method(string Method, TParam Parameters) : MethodBase(Method) + where TParam : MethodParameters; -public class InitializeMethod(InitializeParameters parameters) : Method(parameters), IMethod; +public record InitializeMethod(InitializeParameters Parameters) : Method("initialize", Parameters), IMethod; -public class LookupMethod(LookupParameters parameters) : Method(parameters), IMethod; +public record LookupMethod(LookupParameters Parameters) : Method("lookup", Parameters), IMethod; diff --git a/src/pdns-dhcp/PowerDns/PowerDnsHandler.cs b/src/pdns-dhcp/PowerDns/PowerDnsHandler.cs index e2ee4c6..795b9a9 100644 --- a/src/pdns-dhcp/PowerDns/PowerDnsHandler.cs +++ b/src/pdns-dhcp/PowerDns/PowerDnsHandler.cs @@ -1,4 +1,5 @@ using System.Buffers; +using System.Collections.ObjectModel; using System.IO.Pipelines; using System.Net.Sockets; using System.Text.Json; @@ -15,9 +16,34 @@ namespace pdns_dhcp.PowerDns; public class PowerDnsHandler : ConnectionHandler { + delegate MethodBase? HandlerConverter(in JsonElement element); + + private static readonly ReadOnlyDictionary Converters; + private readonly ILogger _logger; private readonly DnsRepository _repository; + static PowerDnsHandler() + { + Dictionary converters = new(StringComparer.OrdinalIgnoreCase) + { + ["initialize"] = ToInitialize, + ["lookup"] = ToLookup + }; + + Converters = converters.AsReadOnly(); + + static InitializeMethod ToInitialize(in JsonElement element) + { + return new(element.Deserialize(PowerDnsSerializerContext.Default.InitializeParameters)!); + } + + static LookupMethod ToLookup(in JsonElement element) + { + return new(element.Deserialize(PowerDnsSerializerContext.Default.LookupParameters)!); + } + } + public PowerDnsHandler(DnsRepository repository, ILogger logger) { _logger = logger; @@ -41,22 +67,43 @@ public class PowerDnsHandler : ConnectionHandler foreach (var memory in read.Buffer) { buffer.Write(memory.Span); - if (ConsumeJson(buffer, json, ref state)) + if (!ConsumeJson(buffer, json, ref state)) + { + continue; + } + + MethodBase method; + try + { + using var jsonDocument = JsonDocument.Parse(json.WrittenMemory); + var root = jsonDocument.RootElement; + if (!root.TryGetProperty("method", out var methodElement)) + { + continue; + } + + if (Parse(methodElement, root.GetProperty("parameters")) is not { } methodLocal) + { + continue; + } + + method = methodLocal; + } + finally { - var method = JsonSerializer.Deserialize(json.WrittenSpan, PowerDnsSerializerContext.Default.Method)!; json.Clear(); state = default; - - Reply reply = BoolReply.False; - try - { - reply = await Handle(method, connection.ConnectionClosed).ConfigureAwait(false); - } - catch (Exception e) { } - - await JsonSerializer.SerializeAsync(writer, reply, PowerDnsSerializerContext.Default.Reply, connection.ConnectionClosed) - .ConfigureAwait(continueOnCapturedContext: false); } + + Reply reply = BoolReply.False; + try + { + reply = await Handle(method, connection.ConnectionClosed).ConfigureAwait(false); + } + catch (Exception e) { } + + await JsonSerializer.SerializeAsync(writer, reply, PowerDnsSerializerContext.Default.Reply, connection.ConnectionClosed) + .ConfigureAwait(continueOnCapturedContext: false); } input.AdvanceTo(read.Buffer.End); @@ -111,9 +158,20 @@ public class PowerDnsHandler : ConnectionHandler return final; } + + static MethodBase? Parse(in JsonElement element, in JsonElement parameters) + { + HandlerConverter? converter = default; + return element.GetString() switch + { + null => null, + { } methodName when !Converters.TryGetValue(methodName, out converter) => new MethodBase(methodName), + _ => converter(parameters) + }; + } } - private ValueTask Handle(Method method, CancellationToken cancellationToken = default) + private ValueTask Handle(MethodBase method, CancellationToken cancellationToken = default) { return method switch { @@ -123,7 +181,7 @@ public class PowerDnsHandler : ConnectionHandler _ => LogUnhandled(_logger, method) }; - static ValueTask LogUnhandled(ILogger logger, Method method) + static ValueTask LogUnhandled(ILogger logger, MethodBase method) { logger.LogWarning("Unhandled Method {Method}", method); return ValueTask.FromResult(BoolReply.False); diff --git a/src/pdns-dhcp/PowerDns/PowerDnsSerializerContext.cs b/src/pdns-dhcp/PowerDns/PowerDnsSerializerContext.cs index 20fddce..84c3085 100644 --- a/src/pdns-dhcp/PowerDns/PowerDnsSerializerContext.cs +++ b/src/pdns-dhcp/PowerDns/PowerDnsSerializerContext.cs @@ -3,7 +3,6 @@ using System.Text.Json.Serialization; namespace pdns_dhcp.PowerDns; [JsonSerializable(typeof(Reply))] -[JsonSerializable(typeof(Method))] [JsonSerializable(typeof(Parameters))] [JsonSourceGenerationOptions( DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, From 6a334352bef1f13095bff9aa8102ca07f647fe8b Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Sun, 14 Jan 2024 00:39:16 +0100 Subject: [PATCH 07/10] Include logging --- src/pdns-dhcp/PowerDns/PowerDnsHandler.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/pdns-dhcp/PowerDns/PowerDnsHandler.cs b/src/pdns-dhcp/PowerDns/PowerDnsHandler.cs index 795b9a9..cacee28 100644 --- a/src/pdns-dhcp/PowerDns/PowerDnsHandler.cs +++ b/src/pdns-dhcp/PowerDns/PowerDnsHandler.cs @@ -79,6 +79,7 @@ public class PowerDnsHandler : ConnectionHandler var root = jsonDocument.RootElement; if (!root.TryGetProperty("method", out var methodElement)) { + _logger.LogWarning("Json Document missing required property method: {document}", jsonDocument); continue; } @@ -190,6 +191,11 @@ public class PowerDnsHandler : ConnectionHandler private ValueTask HandleInitialize(InitializeParameters parameters) { + if (_logger.IsEnabled(LogLevel.Information)) + { + _logger.LogInformation("Handling Initialize {parameters}", parameters); + } + return ValueTask.FromResult(BoolReply.True); } @@ -209,6 +215,11 @@ public class PowerDnsHandler : ConnectionHandler return ValueTask.FromResult(BoolReply.False); } + if (_logger.IsEnabled(LogLevel.Information)) + { + _logger.LogInformation("Searching for {key} in {family}", parameters.Qname, parameters.Qtype); + } + return FindByName(((AddressFamily)qtype, parameters.Qname.AsMemory()), _repository, _logger); static async ValueTask FindByName((AddressFamily Family, ReadOnlyMemory Qname) query, DnsRepository repository, ILogger logger) From 76ebb55ab733af3c89d609dbad03416dc326018e Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Sun, 14 Jan 2024 01:11:41 +0100 Subject: [PATCH 08/10] Review logging --- src/pdns-dhcp/Kea/KeaDhcpLeaseWatcher.cs | 2 +- src/pdns-dhcp/Kea/KeaService.cs | 2 +- src/pdns-dhcp/PowerDns/Methods.cs | 2 +- src/pdns-dhcp/PowerDns/Parameters.cs | 31 ++++++++- src/pdns-dhcp/PowerDns/PowerDnsHandler.cs | 69 ++++++++++--------- .../PowerDns/PowerDnsSerializerContext.cs | 2 +- src/pdns-dhcp/Services/DhcpWatcher.cs | 2 +- 7 files changed, 71 insertions(+), 39 deletions(-) diff --git a/src/pdns-dhcp/Kea/KeaDhcpLeaseWatcher.cs b/src/pdns-dhcp/Kea/KeaDhcpLeaseWatcher.cs index e6c619f..13ff3b0 100644 --- a/src/pdns-dhcp/Kea/KeaDhcpLeaseWatcher.cs +++ b/src/pdns-dhcp/Kea/KeaDhcpLeaseWatcher.cs @@ -206,7 +206,7 @@ public sealed class KeaDhcpLeaseWatcher : IHostedService } else { - await waitHandle.WaitOneAsync(stoppingToken).ConfigureAwait(continueOnCapturedContext: false); + await waitHandle.WaitOneAsync(stoppingToken).ConfigureAwait(false); } } } diff --git a/src/pdns-dhcp/Kea/KeaService.cs b/src/pdns-dhcp/Kea/KeaService.cs index 863be32..c166227 100644 --- a/src/pdns-dhcp/Kea/KeaService.cs +++ b/src/pdns-dhcp/Kea/KeaService.cs @@ -49,6 +49,6 @@ public class KeaService : IHostedService var waitTask = Task.WhenAll(tasks); TaskCompletionSource taskCompletionSource = new(); using var registration = cancellationToken.Register(s => ((TaskCompletionSource)s!).SetCanceled(), taskCompletionSource); - await Task.WhenAny(waitTask, taskCompletionSource.Task).ConfigureAwait(continueOnCapturedContext: false); + await Task.WhenAny(waitTask, taskCompletionSource.Task).ConfigureAwait(false); } } diff --git a/src/pdns-dhcp/PowerDns/Methods.cs b/src/pdns-dhcp/PowerDns/Methods.cs index 37f5928..1a6a64a 100644 --- a/src/pdns-dhcp/PowerDns/Methods.cs +++ b/src/pdns-dhcp/PowerDns/Methods.cs @@ -4,7 +4,7 @@ public interface IMethod; public record MethodBase(string Method); -public abstract record Method(string Method, TParam Parameters) : MethodBase(Method) +public record Method(string Method, TParam Parameters) : MethodBase(Method) where TParam : MethodParameters; public record InitializeMethod(InitializeParameters Parameters) : Method("initialize", Parameters), IMethod; diff --git a/src/pdns-dhcp/PowerDns/Parameters.cs b/src/pdns-dhcp/PowerDns/Parameters.cs index 93238c1..4d11a5d 100644 --- a/src/pdns-dhcp/PowerDns/Parameters.cs +++ b/src/pdns-dhcp/PowerDns/Parameters.cs @@ -1,16 +1,43 @@ +using System.Text; using System.Text.Json; using System.Text.Json.Serialization; namespace pdns_dhcp.PowerDns; -[JsonDerivedType(typeof(InitializeParameters))] -[JsonDerivedType(typeof(LookupParameters))] public record class Parameters; +[JsonDerivedType(typeof(InitializeParameters))] +[JsonDerivedType(typeof(LookupParameters))] public record class MethodParameters : Parameters { [JsonExtensionData] public Dictionary AdditionalProperties { get; set; } = []; + + protected override bool PrintMembers(StringBuilder builder) + { + if (base.PrintMembers(builder)) + { + builder.Append(", "); + } + + builder.Append("AdditionalProperties = ["); + bool append = false; + foreach (var kv in AdditionalProperties) + { + if (append) + { + builder.Append(", "); + } + + append = true; + builder.Append(kv.Key); + builder.Append(" = "); + builder.Append(kv.Value); + } + + builder.Append(']'); + return true; + } } public record class InitializeParameters( diff --git a/src/pdns-dhcp/PowerDns/PowerDnsHandler.cs b/src/pdns-dhcp/PowerDns/PowerDnsHandler.cs index cacee28..fa8b598 100644 --- a/src/pdns-dhcp/PowerDns/PowerDnsHandler.cs +++ b/src/pdns-dhcp/PowerDns/PowerDnsHandler.cs @@ -72,39 +72,44 @@ public class PowerDnsHandler : ConnectionHandler continue; } - MethodBase method; - try - { - using var jsonDocument = JsonDocument.Parse(json.WrittenMemory); - var root = jsonDocument.RootElement; - if (!root.TryGetProperty("method", out var methodElement)) - { - _logger.LogWarning("Json Document missing required property method: {document}", jsonDocument); - continue; - } - - if (Parse(methodElement, root.GetProperty("parameters")) is not { } methodLocal) - { - continue; - } - - method = methodLocal; - } - finally - { - json.Clear(); - state = default; - } - Reply reply = BoolReply.False; try { + MethodBase method; + try + { + using var jsonDocument = JsonDocument.Parse(json.WrittenMemory); + var root = jsonDocument.RootElement; + if (!root.TryGetProperty("method", out var methodElement)) + { + _logger.LogWarning("Json Document missing required property method: {document}", jsonDocument); + continue; + } + + if (Parse(methodElement, root.GetProperty("parameters")) is not { } methodLocal) + { + continue; + } + + method = methodLocal; + } + finally + { + json.Clear(); + state = default; + } + reply = await Handle(method, connection.ConnectionClosed).ConfigureAwait(false); } - catch (Exception e) { } - - await JsonSerializer.SerializeAsync(writer, reply, PowerDnsSerializerContext.Default.Reply, connection.ConnectionClosed) - .ConfigureAwait(continueOnCapturedContext: false); + catch (Exception e) + { + _logger.LogError(e, "Error"); + } + finally + { + await JsonSerializer.SerializeAsync(writer, reply, PowerDnsSerializerContext.Default.Reply, connection.ConnectionClosed) + .ConfigureAwait(false); + } } input.AdvanceTo(read.Buffer.End); @@ -166,7 +171,7 @@ public class PowerDnsHandler : ConnectionHandler return element.GetString() switch { null => null, - { } methodName when !Converters.TryGetValue(methodName, out converter) => new MethodBase(methodName), + { } methodName when !Converters.TryGetValue(methodName, out converter) => new Method(methodName, parameters.Deserialize(PowerDnsSerializerContext.Default.MethodParameters)!), _ => converter(parameters) }; } @@ -184,7 +189,7 @@ public class PowerDnsHandler : ConnectionHandler static ValueTask LogUnhandled(ILogger logger, MethodBase method) { - logger.LogWarning("Unhandled Method {Method}", method); + logger.LogWarning("Unhandled {Method}", method); return ValueTask.FromResult(BoolReply.False); } } @@ -193,7 +198,7 @@ public class PowerDnsHandler : ConnectionHandler { if (_logger.IsEnabled(LogLevel.Information)) { - _logger.LogInformation("Handling Initialize {parameters}", parameters); + _logger.LogInformation("Handling {parameters}", parameters); } return ValueTask.FromResult(BoolReply.True); @@ -217,7 +222,7 @@ public class PowerDnsHandler : ConnectionHandler if (_logger.IsEnabled(LogLevel.Information)) { - _logger.LogInformation("Searching for {key} in {family}", parameters.Qname, parameters.Qtype); + _logger.LogInformation("Lookup {key} in {family}", parameters.Qname, parameters.Qtype); } return FindByName(((AddressFamily)qtype, parameters.Qname.AsMemory()), _repository, _logger); diff --git a/src/pdns-dhcp/PowerDns/PowerDnsSerializerContext.cs b/src/pdns-dhcp/PowerDns/PowerDnsSerializerContext.cs index 84c3085..942bc8c 100644 --- a/src/pdns-dhcp/PowerDns/PowerDnsSerializerContext.cs +++ b/src/pdns-dhcp/PowerDns/PowerDnsSerializerContext.cs @@ -3,7 +3,7 @@ using System.Text.Json.Serialization; namespace pdns_dhcp.PowerDns; [JsonSerializable(typeof(Reply))] -[JsonSerializable(typeof(Parameters))] +[JsonSerializable(typeof(MethodParameters))] [JsonSourceGenerationOptions( DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, NumberHandling = JsonNumberHandling.AllowReadingFromString, diff --git a/src/pdns-dhcp/Services/DhcpWatcher.cs b/src/pdns-dhcp/Services/DhcpWatcher.cs index 0ce62ed..da6c4c1 100644 --- a/src/pdns-dhcp/Services/DhcpWatcher.cs +++ b/src/pdns-dhcp/Services/DhcpWatcher.cs @@ -45,6 +45,6 @@ public class DhcpWatcher : IHostedService var waitTask = Task.WhenAll(tasks); TaskCompletionSource taskCompletionSource = new(); using var registration = cancellationToken.Register(s => ((TaskCompletionSource)s!).SetCanceled(), taskCompletionSource); - await Task.WhenAny(waitTask, taskCompletionSource.Task).ConfigureAwait(continueOnCapturedContext: false); + await Task.WhenAny(waitTask, taskCompletionSource.Task).ConfigureAwait(false); } } From 554a36c5764941f49d324df70f53ec786de04710 Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Sun, 14 Jan 2024 01:29:21 +0100 Subject: [PATCH 09/10] Review dependency --- README.md | 2 +- src/pdns-dhcp/pdns-dhcp.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ff17817..eb95879 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ Incorporates following libraries directly: **.NET Foundation and Contributors** - [CommunityToolkit.HighPerformance](https://github.com/CommunityToolkit/dotnet) - MIT -- [dotNext.Threading](https://github.com/dotnet/dotNext) - 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 diff --git a/src/pdns-dhcp/pdns-dhcp.csproj b/src/pdns-dhcp/pdns-dhcp.csproj index f0414a1..96c0157 100644 --- a/src/pdns-dhcp/pdns-dhcp.csproj +++ b/src/pdns-dhcp/pdns-dhcp.csproj @@ -15,7 +15,7 @@ - + From f596342275ece336360a427505558062de1d08d8 Mon Sep 17 00:00:00 2001 From: AliveDevil Date: Sun, 14 Jan 2024 01:42:29 +0100 Subject: [PATCH 10/10] Review --- src/pdns-dhcp/Kea/KeaDhcpLease.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pdns-dhcp/Kea/KeaDhcpLease.cs b/src/pdns-dhcp/Kea/KeaDhcpLease.cs index 4254440..ae1f965 100644 --- a/src/pdns-dhcp/Kea/KeaDhcpLease.cs +++ b/src/pdns-dhcp/Kea/KeaDhcpLease.cs @@ -43,7 +43,7 @@ public static class KeaDhcpLease if (converted) { - writer.Write(escapedChar); + writer.Write([escapedChar]); } else {