Dhcp4 parser
This commit is contained in:
parent
5e69ae245e
commit
4c7671b396
5 changed files with 124 additions and 11 deletions
|
|
@ -1,17 +1,71 @@
|
|||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
|
||||
using nietras.SeparatedValues;
|
||||
|
||||
namespace pdns_dhcp.Kea;
|
||||
|
||||
// ref: https://github.com/isc-projects/kea/blob/Kea-2.5.3/src/lib/dhcpsrv/csv_lease_file4.h
|
||||
public record struct KeaDhcp4Lease(
|
||||
string Address,
|
||||
string HWAddr,
|
||||
IPAddress Address,
|
||||
PhysicalAddress HWAddr,
|
||||
string? ClientId,
|
||||
uint ValidLifetime,
|
||||
ulong Expire,
|
||||
string SubnetId,
|
||||
byte FqdnFwd,
|
||||
byte FqdnRev,
|
||||
DateTimeOffset Expire,
|
||||
uint SubnetId,
|
||||
bool FqdnFwd,
|
||||
bool FqdnRev,
|
||||
string Hostname,
|
||||
uint State,
|
||||
string UserContext,
|
||||
uint PoolId
|
||||
);
|
||||
string? UserContext,
|
||||
uint PoolId)
|
||||
{
|
||||
public static KeaDhcp4Lease Parse(in SepReader.Row row)
|
||||
{
|
||||
var address = IPAddress.Parse(row[0].Span);
|
||||
PhysicalAddress hwaddr = PhysicalAddress.None;
|
||||
if (row[1].Span is { IsEmpty: false } physical)
|
||||
{
|
||||
hwaddr = PhysicalAddress.Parse(physical);
|
||||
}
|
||||
string? clientId = row[2].ToString();
|
||||
uint validLifetime = uint.Parse(row[3].Span);
|
||||
DateTimeOffset expire = DateTimeOffset.FromUnixTimeSeconds(unchecked((long)ulong.Parse(row[4].Span)));
|
||||
uint subnetId = uint.Parse(row[5].Span);
|
||||
bool fqdnFwd = sbyte.Parse(row[6].Span) != 0;
|
||||
bool fqdnRev = sbyte.Parse(row[7].Span) != 0;
|
||||
string hostname = KeaDhcpLease.Unescape(row[8].Span);
|
||||
|
||||
uint state = 0;
|
||||
if (row.ColCount > 9)
|
||||
{
|
||||
state = uint.Parse(row[9].Span);
|
||||
}
|
||||
|
||||
string? userContext = default;
|
||||
if (row.ColCount > 10)
|
||||
{
|
||||
userContext = KeaDhcpLease.Unescape(row[10].Span);
|
||||
}
|
||||
|
||||
uint poolId = 0;
|
||||
if (row.ColCount > 11)
|
||||
{
|
||||
poolId = uint.Parse(row[11].Span);
|
||||
}
|
||||
|
||||
return new(
|
||||
address,
|
||||
hwaddr,
|
||||
clientId,
|
||||
validLifetime,
|
||||
expire,
|
||||
subnetId,
|
||||
fqdnFwd,
|
||||
fqdnRev,
|
||||
hostname,
|
||||
state,
|
||||
userContext,
|
||||
poolId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,5 +4,8 @@ namespace pdns_dhcp.Kea;
|
|||
|
||||
public class KeaDhcp4LeaseHandler : IKeaDhcpLeaseHandler
|
||||
{
|
||||
public void Handle(in SepReader.Row row) { }
|
||||
public void Handle(in SepReader.Row row)
|
||||
{
|
||||
KeaDhcp4Lease lease = KeaDhcp4Lease.Parse(row);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
49
src/pdns-dhcp/Kea/KeaDhcpLease.cs
Normal file
49
src/pdns-dhcp/Kea/KeaDhcpLease.cs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
using System.Buffers;
|
||||
using System.Globalization;
|
||||
|
||||
using DotNext.Buffers;
|
||||
|
||||
namespace pdns_dhcp.Kea;
|
||||
|
||||
public static class KeaDhcpLease
|
||||
{
|
||||
private static ReadOnlySpan<char> EscapeTag => ['&', '#', 'x'];
|
||||
|
||||
public static string Unescape(in ReadOnlySpan<char> text)
|
||||
{
|
||||
int esc_pos = text.IndexOf(EscapeTag);
|
||||
return esc_pos == -1 ? text.ToString() : SlowPath(esc_pos, text);
|
||||
|
||||
static string SlowPath(int esc_pos, in ReadOnlySpan<char> text)
|
||||
{
|
||||
SpanReader<char> reader = new(text);
|
||||
ArrayBufferWriter<char> writer = new(text.Length);
|
||||
while (reader.RemainingCount > 0)
|
||||
{
|
||||
writer.Write(reader.Read(esc_pos));
|
||||
reader.Advance(EscapeTag.Length);
|
||||
if (EscapeTag.Length <= reader.RemainingCount - 2)
|
||||
{
|
||||
var digits = reader.Read(2);
|
||||
if (byte.TryParse(digits, NumberStyles.AllowHexSpecifier, null, out var escaped_char))
|
||||
{
|
||||
writer.Write((char)escaped_char);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(EscapeTag);
|
||||
writer.Write(digits);
|
||||
}
|
||||
}
|
||||
|
||||
esc_pos = reader.RemainingSpan.IndexOf(EscapeTag);
|
||||
if (esc_pos == -1)
|
||||
{
|
||||
writer.Write(reader.ReadToEnd());
|
||||
}
|
||||
}
|
||||
|
||||
return writer.WrittenSpan.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -163,7 +163,11 @@ public sealed class KeaDhcpLeaseWatcher<T> : IHostedService
|
|||
{
|
||||
if (reader is null)
|
||||
{
|
||||
reader = Sep.Reader().From(_pipe.Reader.AsStream());
|
||||
reader = Sep.New(',').Reader(o => o with
|
||||
{
|
||||
DisableColCountCheck = true,
|
||||
Unescape = false
|
||||
}).From(_pipe.Reader.AsStream());
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -172,6 +176,8 @@ public sealed class KeaDhcpLeaseWatcher<T> : IHostedService
|
|||
// TODO Error state.
|
||||
return;
|
||||
}
|
||||
|
||||
_handler.Handle(reader.Current);
|
||||
}
|
||||
|
||||
var memory = writer.GetMemory();
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DotNext" Version="4.15.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Sep" Version="0.3.0" />
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue