diff --git a/src/IPMeow.Dhcp/IPMeow.Dhcp.csproj b/src/IPMeow.Dhcp/IPMeow.Dhcp.csproj
index 499b6e0..835ae55 100644
--- a/src/IPMeow.Dhcp/IPMeow.Dhcp.csproj
+++ b/src/IPMeow.Dhcp/IPMeow.Dhcp.csproj
@@ -4,8 +4,8 @@
-
-
+
+
diff --git a/src/IPMeow.Dhcp/Program.cs b/src/IPMeow.Dhcp/Program.cs
index 50d605c..cde91b0 100644
--- a/src/IPMeow.Dhcp/Program.cs
+++ b/src/IPMeow.Dhcp/Program.cs
@@ -1,5 +1,8 @@
using IPMeow.Dhcp.Server.Dhcp4;
-using IPMeow.Lib.Host;
+using IPMeow.Dhcp.Server.Dhcp6;
+using IPMeow.Dhcp.Standalone;
+using IPMeow.Lib.Request;
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace IPMeow.Dhcp
@@ -8,7 +11,13 @@ namespace IPMeow.Dhcp
{
public static async Task Main(string[] args)
{
- var app = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args).Build();
+ var app = Host.CreateDefaultBuilder(args).ConfigureServices(s =>
+ {
+ s.AddScoped();
+ s.AddSingleton, DecoupledIPAddressProvider>();
+ s.AddHostedService();
+ s.AddHostedService();
+ }).Build();
Console.WriteLine("Listening on DHCP...");
diff --git a/src/IPMeow.Dhcp/Server/Dhcp4/DhcpPacket.cs b/src/IPMeow.Dhcp/Server/Dhcp4/DhcpPacket.cs
index 539cfb6..b4c7a5f 100644
--- a/src/IPMeow.Dhcp/Server/Dhcp4/DhcpPacket.cs
+++ b/src/IPMeow.Dhcp/Server/Dhcp4/DhcpPacket.cs
@@ -1,6 +1,7 @@
using System.Net;
using System.Text;
using IPMeow.Lib;
+using IPMeow.Lib.Address;
namespace IPMeow.Dhcp.Server.Dhcp4;
@@ -20,7 +21,12 @@ public class DhcpPacket
public required byte[] ClientHWAddress { get; init; }
public required string ServerHostName { get; init; }
public required string BootFileName { get; init; }
- public bool? IsValidated { get; set; }
+ public bool IsValidated { get; set; }
+
+ public override string ToString()
+ {
+ return $"{OpType}, htype: {HType}, hlen: {HLen}, hops: {Hops}\nXid: {Xid}, Seconds: {Seconds}, Flags: {Flags:x}\nci: {ClientAddress}\nyi: {YourAddress}, ns: {NextServerAddress}, ra: {RelayAgentAddress}\nhw: {MacAddress.Parse(GetMacAddress())}\nhost: {ServerHostName}\nboot: {BootFileName}";
+ }
public byte[] GetClientHwAddress()
{
@@ -36,6 +42,8 @@ public class DhcpPacket
return buf;
}
+ public byte[] GetMacAddress() => ClientHWAddress[0..6];
+
public byte[] GetSnameBytes()
{
var buf = new byte[64];
diff --git a/src/IPMeow.Dhcp/Server/Dhcp4/DhcpServer.cs b/src/IPMeow.Dhcp/Server/Dhcp4/DhcpServer.cs
index fb9e642..6a381cc 100644
--- a/src/IPMeow.Dhcp/Server/Dhcp4/DhcpServer.cs
+++ b/src/IPMeow.Dhcp/Server/Dhcp4/DhcpServer.cs
@@ -1,6 +1,6 @@
using System.Net;
using System.Net.Sockets;
-using IPMeow.Lib.Address;
+using IPMeow.Lib.Request;
namespace IPMeow.Dhcp.Server.Dhcp4;
@@ -8,27 +8,20 @@ public class Dhcp4Server : IDhcpServer, IDisposable
{
public const int clientPort = 68, serverPort = 67;
- public Dhcp4Server(IAddressProvider addressProvider)
+ public Dhcp4Server(IAddressProvider addressProvider)
{
_addrProvider = addressProvider;
_udp = new UdpClient(serverPort, AddressFamily.InterNetwork);
}
- private readonly IAddressProvider _addrProvider;
+ private readonly IAddressProvider _addrProvider;
- public event EventHandler DhcpRequestedEvent;
+ public event EventHandler DhcpRequestedEvent = delegate { };
- public async Task Run()
+ protected async Task Receive(CancellationToken token)
{
- while (true)
- {
- await Receive();
- }
- }
-
- protected async Task Receive()
- {
- var datagram = await _udp.ReceiveAsync();
+ var datagram = await _udp.ReceiveAsync(token);
+ Console.WriteLine($"New v4 request: {datagram.Buffer.Length}");
if (datagram.Buffer.Length < 236 || datagram.Buffer.Length > 576)
{
@@ -36,19 +29,23 @@ public class Dhcp4Server : IDhcpServer, IDisposable
}
var packet = DhcpPacket.Deserialize(datagram.Buffer);
- packet.IsValidated = ValidateIncoming(packet);
- if (!packet.IsValidated.Value)
+ if (!ValidateIncoming(packet))
{
return;
}
+ packet.IsValidated = true;
+
Console.WriteLine("Solicitation: ");
Console.WriteLine(packet.ToString());
+
+ //TODO
}
public bool ValidateIncoming(DhcpPacket packet)
{
+ Console.WriteLine(packet.ToString());
if (packet.OpType != DhcpOpType.BOOTREQUEST)
{
return false;
@@ -72,7 +69,31 @@ public class Dhcp4Server : IDhcpServer, IDisposable
public void Dispose()
{
- throw new NotImplementedException();
+ GC.SuppressFinalize(this);
+ _udp.Dispose();
+ }
+
+ async Task Run(CancellationToken token)
+ {
+ while (true)
+ {
+ if (token.IsCancellationRequested)
+ {
+ return;
+ }
+ await Receive(token);
+ }
+ }
+
+ public async Task StartAsync(CancellationToken cancellationToken)
+ {
+ new Thread(async () => await Run(cancellationToken)).Start();
+ Console.WriteLine("V4 started.");
+ }
+
+ public Task StopAsync(CancellationToken cancellationToken)
+ {
+ return Task.CompletedTask;
}
private readonly UdpClient _udp;
diff --git a/src/IPMeow.Dhcp/Server/Dhcp6/DhcpOption.cs b/src/IPMeow.Dhcp/Server/Dhcp6/DhcpOption.cs
index 01cc8bb..a8a826e 100644
--- a/src/IPMeow.Dhcp/Server/Dhcp6/DhcpOption.cs
+++ b/src/IPMeow.Dhcp/Server/Dhcp6/DhcpOption.cs
@@ -15,8 +15,18 @@ public enum DhcpOptionCode : short
ElapsedTime = 8,
ServerUnicast = 12,
StatusCode = 13,
-
-
+ VendorClass = 16,
+ VendorOptions = 17,
+ IfaceId = 18,
+ DnsServers = 23,
+ DomainList = 24,
+ SntpServers = 31,
+ SubscriberId = 38,
+ ClientFqdn = 39,
+ V6Lost = 51,
+ NtpServer = 56,
+ Addrsel = 84,
+ AddrselTable = 85,
}
public interface IDhcpOption
@@ -37,7 +47,7 @@ public class ClientIdentifierOption : IDhcpOption
public object GetData()
{
- return new Duid(Data);
+ return Duid.Parse(Data);
}
}
@@ -51,7 +61,7 @@ public class ServerIdentifierOption : IDhcpOption
public object GetData()
{
- return new Duid(Data);
+ return Duid.Parse(Data);
}
}
@@ -155,3 +165,101 @@ public class StatusCodeOption : IDhcpOption
return new DhcpStatus(code, message);
}
}
+
+public class VendorClassOption : IDhcpOption
+{
+ public DhcpOptionCode Code => DhcpOptionCode.VendorClass;
+
+ public required byte[] Data { get; set; }
+
+ public Type DataType => typeof(byte[]);
+
+ public object GetData()
+ {
+ return Data;
+ }
+}
+
+public class InterfaceIdOption : IDhcpOption
+{
+ public DhcpOptionCode Code => DhcpOptionCode.VendorClass;
+
+ public required byte[] Data { get; set; }
+
+ public Type DataType => typeof(byte[]);
+
+ public object GetData()
+ {
+ return Data;
+ }
+}
+
+public class SubscriberIdOption : IDhcpOption
+{
+ public DhcpOptionCode Code => DhcpOptionCode.VendorClass;
+
+ public required byte[] Data { get; set; }
+
+ public Type DataType => typeof(byte[]);
+
+ public object GetData()
+ {
+ return Data;
+ }
+}
+
+public class V6LostOption : IDhcpOption
+{
+ public DhcpOptionCode Code => DhcpOptionCode.VendorClass;
+
+ public required byte[] Data { get; set; }
+
+ public Type DataType => typeof(byte[]);
+
+ public object GetData()
+ {
+ return Data;
+ }
+}
+
+public class ClientFqdnOption : IDhcpOption
+{
+ public DhcpOptionCode Code => DhcpOptionCode.VendorClass;
+
+ public required byte[] Data { get; set; }
+
+ public Type DataType => typeof(byte[]);
+
+ public object GetData()
+ {
+ return Data;
+ }
+}
+
+public class DnsServersOption : IDhcpOption
+{
+ public DhcpOptionCode Code => DhcpOptionCode.VendorClass;
+
+ public required byte[] Data { get; set; }
+
+ public Type DataType => typeof(byte[]);
+
+ public object GetData()
+ {
+ return Data;
+ }
+}
+
+public class NtpServerOption : IDhcpOption
+{
+ public DhcpOptionCode Code => DhcpOptionCode.VendorClass;
+
+ public required byte[] Data { get; set; }
+
+ public Type DataType => typeof(byte[]);
+
+ public object GetData()
+ {
+ return Data;
+ }
+}
diff --git a/src/IPMeow.Dhcp/Server/Dhcp6/DhcpPacket.cs b/src/IPMeow.Dhcp/Server/Dhcp6/DhcpPacket.cs
index f15a17c..065d40a 100644
--- a/src/IPMeow.Dhcp/Server/Dhcp6/DhcpPacket.cs
+++ b/src/IPMeow.Dhcp/Server/Dhcp6/DhcpPacket.cs
@@ -16,14 +16,69 @@ public class DhcpPacket
{
Data = data
},
- DhcpOptionCode.ServerId => throw new NotImplementedException(),
- DhcpOptionCode.IANonTempAssoc => throw new NotImplementedException(),
- DhcpOptionCode.IATempAssoc => throw new NotImplementedException(),
- DhcpOptionCode.IAAddr => throw new NotImplementedException(),
- DhcpOptionCode.OptionRequest => throw new NotImplementedException(),
+ DhcpOptionCode.ServerId => new ServerIdentifierOption()
+ {
+ Data = data
+ },
+ DhcpOptionCode.IANonTempAssoc => new NonTempIdentityAssociationOption()
+ {
+ Data = data
+ },
+ DhcpOptionCode.IATempAssoc => new TempIdentityAssociationOption()
+ {
+ Data = data
+ },
+ DhcpOptionCode.IAAddr => new IAAddressOption()
+ {
+ Data = data
+ },
+ DhcpOptionCode.OptionRequest => new OptionRequestOption()
+ {
+ Data = data
+ },
DhcpOptionCode.Preference => throw new NotImplementedException(),
- DhcpOptionCode.ElapsedTime => throw new NotImplementedException(),
- DhcpOptionCode.StatusCode => throw new NotImplementedException(),
+ DhcpOptionCode.ElapsedTime => new ElapsedTimeOption()
+ {
+ Data = data
+ },
+ DhcpOptionCode.StatusCode => new StatusCodeOption()
+ {
+ Data = data
+ },
+ DhcpOptionCode.ServerUnicast => new ServerUnicastOption()
+ {
+ Data = data
+ },
+ DhcpOptionCode.VendorClass => new VendorClassOption()
+ {
+ Data = data
+ },
+ DhcpOptionCode.IfaceId => new InterfaceIdOption()
+ {
+ Data = data
+ },
+ DhcpOptionCode.DnsServers => new DnsServersOption()
+ {
+ Data = data
+ },
+ DhcpOptionCode.SubscriberId => new SubscriberIdOption()
+ {
+ Data = data
+ },
+ DhcpOptionCode.ClientFqdn => new ClientFqdnOption()
+ {
+ Data = data
+ },
+ DhcpOptionCode.V6Lost => new V6LostOption()
+ {
+ Data = data
+ },
+ DhcpOptionCode.NtpServer => new NtpServerOption()
+ {
+ Data = data
+ },
+ DhcpOptionCode.Addrsel => throw new NotImplementedException(),
+ DhcpOptionCode.AddrselTable => throw new NotImplementedException(),
_ => throw new InvalidOperationException($"Invalid option type {type}")
};
}
@@ -36,13 +91,22 @@ public class DhcpPacket
DhcpMessageType MessageType = (DhcpMessageType)header[0];
- uint Xid = BitConverter.ToUInt32(header, 1);
+ header[0] = 0;
+ uint Xid = BitConverter.ToUInt32(header);
+
+ Console.WriteLine("Preview:\n{0}", string.Join(' ', data.Select(b => b.ToString("x2"))));
+
+ Console.WriteLine($"v6: {Xid}, {enu.Position}, {MessageType}, {data.Length}");
+
+ List options = new();
while (enu.Position < data.Length)
{
- short optionCode = enu.TakeInt16();
+ DhcpOptionCode optionCode = (DhcpOptionCode)enu.TakeInt16();
short optionLen = enu.TakeInt16();
+ Console.WriteLine($"D: {data.Length}, {enu.Position}, {optionCode}, {optionLen}");
+
if (enu.Position + optionLen > data.Length)
{
throw new DataMisalignedException("Invalid option length.");
@@ -50,13 +114,17 @@ public class DhcpPacket
byte[] optionData = enu.TakeBytes(optionLen);
+ Console.WriteLine(string.Join(' ', optionData.Select(b => b.ToString("x2"))));
+ IDhcpOption option = GetOption(optionCode, optionData);
+ options.Add(option);
}
return new()
{
MessageType = MessageType,
- Xid = Xid
+ Xid = Xid,
+ Options = options
};
}
}
diff --git a/src/IPMeow.Dhcp/Server/Dhcp6/DhcpServer.cs b/src/IPMeow.Dhcp/Server/Dhcp6/DhcpServer.cs
index 7ee2bcb..16dd7b1 100644
--- a/src/IPMeow.Dhcp/Server/Dhcp6/DhcpServer.cs
+++ b/src/IPMeow.Dhcp/Server/Dhcp6/DhcpServer.cs
@@ -1,6 +1,6 @@
using System.Net;
using System.Net.Sockets;
-using IPMeow.Lib.Address;
+using IPMeow.Lib.Request;
namespace IPMeow.Dhcp.Server.Dhcp6;
@@ -8,17 +8,18 @@ public class Dhcp6Server : IDhcpServer, IDisposable
{
public const int clientPort = 546, serverPort = 547;
- public Dhcp6Server(IAddressProvider addressProvider)
+ public Dhcp6Server(IAddressProvider addressProvider)
{
_addrProvider = addressProvider;
- _listener = new(new IPEndPoint(IPAddress.Parse("ff02::1:2"), serverPort));
+ _listener = new(serverPort, AddressFamily.InterNetworkV6);
+ _listener.JoinMulticastGroup(IPAddress.Parse("ff02::1:2"));
_sender = new(clientPort, AddressFamily.InterNetworkV6);
}
- private readonly IAddressProvider _addrProvider;
+ private readonly IAddressProvider _addrProvider;
private readonly UdpClient _listener, _sender;
- public event EventHandler DhcpRequestedEvent;
+ public event EventHandler DhcpRequestedEvent = delegate { };
public void Dispose()
{
@@ -27,24 +28,44 @@ public class Dhcp6Server : IDhcpServer, IDisposable
_sender.Dispose();
}
- public async Task Run()
+ protected async Task Receive(CancellationToken token)
{
- while (true)
- {
- await Receive();
- }
- }
+ var datagram = await _listener.ReceiveAsync(token);
- protected async Task Receive()
- {
- var datagram = await _listener.ReceiveAsync();
+ Console.WriteLine($"From v6: {datagram.RemoteEndPoint}, len: {datagram.Buffer.Length}");
var packet = DhcpPacket.Deserialize(datagram.Buffer);
+ Console.WriteLine($"New v6 packet: {packet.Xid}, len: {datagram.Buffer.Length}");
+
if (packet.MessageType is DhcpMessageType.Invalid or DhcpMessageType.Solicit or DhcpMessageType.Confirm or DhcpMessageType.Rebind)
{
return;
}
+ //TODO
+ }
+
+ public async Task Run(CancellationToken token)
+ {
+ while (true)
+ {
+ if (token.IsCancellationRequested)
+ {
+ return;
+ }
+ await Receive(token);
+ }
+ }
+
+ public async Task StartAsync(CancellationToken cancellationToken)
+ {
+ new Thread(async () => await Run(cancellationToken)).Start();
+ Console.WriteLine("V6 started.");
+ }
+
+ public Task StopAsync(CancellationToken cancellationToken)
+ {
+ return Task.CompletedTask;
}
}
diff --git a/src/IPMeow.Dhcp/Server/Dhcp6/DhcpStatus.cs b/src/IPMeow.Dhcp/Server/Dhcp6/DhcpStatus.cs
index 7f86dea..5ce8c3c 100644
--- a/src/IPMeow.Dhcp/Server/Dhcp6/DhcpStatus.cs
+++ b/src/IPMeow.Dhcp/Server/Dhcp6/DhcpStatus.cs
@@ -2,6 +2,33 @@ using System.Text;
namespace IPMeow.Dhcp.Server.Dhcp6;
+public enum DhcpStatusCode : short
+{
+ Success = 0,
+ UnspecifiedFail = 1,
+ NoAddrAvailable = 2,
+ NoBinding = 3,
+ NotOnLink = 4,
+ UseMulticast = 5,
+ NoPrefixAvailable = 6,
+ UnknownQueryType = 7,
+ MalformedQuery = 8,
+ NotConfigured = 9,
+ NotAllowed = 10,
+ QueryTerminated = 11,
+ DataMissing = 12,
+ CatchUpComplete = 13,
+ NotSupported = 14,
+ TlsConnRefused = 15,
+ AddrInUse = 16,
+ ConfigConflict = 17,
+ MissingBindingInfo = 18,
+ OutdatedBindingInfo = 19,
+ ServerShuttingDown = 20,
+ DnsUpdateNotSupported = 21,
+ ExcessiveTimeSkew = 22
+}
+
public struct DhcpStatus
{
public DhcpStatus(ushort code, string? message)
diff --git a/src/IPMeow.Dhcp/Server/Dhcp6/Duid.cs b/src/IPMeow.Dhcp/Server/Dhcp6/Duid.cs
index 29ffb0d..0b34700 100644
--- a/src/IPMeow.Dhcp/Server/Dhcp6/Duid.cs
+++ b/src/IPMeow.Dhcp/Server/Dhcp6/Duid.cs
@@ -1,3 +1,5 @@
+using IPMeow.Lib.Request;
+
namespace IPMeow.Dhcp.Server.Dhcp6;
public enum DuidType : short
@@ -8,12 +10,36 @@ public enum DuidType : short
Uuid = 4
}
-public readonly struct Duid
+public readonly struct Duid : IRequestClientIdentifier
{
- public Duid(byte[] data)
+ private Duid(DuidType type, byte[] data)
{
- Type = (DuidType)BitConverter.ToInt16(data.AsSpan()[0..2]);
- Data = data[2..];
+ Type = type;
+ Data = data;
+ }
+
+ private static readonly Duid Invalid = new(0, Array.Empty());
+
+ public static bool TryParse(byte[] data, out Duid duid)
+ {
+ short dType = BitConverter.ToInt16(data.AsSpan()[0..2]);
+
+ if (!Enum.IsDefined(typeof(DuidType), dType))
+ {
+ duid = Invalid;
+ return false;
+ }
+
+ byte[] duidData = data[2..];
+
+ duid = new((DuidType)dType, duidData);
+
+ return true;
+ }
+
+ public static Duid Parse(byte[] data)
+ {
+ return TryParse(data, out Duid duid) ? duid : throw new InvalidDataException("Invalid data supplied.");
}
public DuidType Type { get; }
diff --git a/src/IPMeow.Dhcp/Server/DhcpEvent.cs b/src/IPMeow.Dhcp/Server/DhcpEvent.cs
index 1dc3548..402eaa8 100644
--- a/src/IPMeow.Dhcp/Server/DhcpEvent.cs
+++ b/src/IPMeow.Dhcp/Server/DhcpEvent.cs
@@ -1,13 +1,9 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
using System.Net;
-using System.Threading.Tasks;
using IPMeow.Lib.Address;
namespace IPMeow.Dhcp.Server;
-public class DhcpRequestEvent
+public class DhcpRequestEventArgs : EventArgs
{
public bool IsV6 { get; init; }
public IPAddress? RequestOrigin { get; init; }
diff --git a/src/IPMeow.Dhcp/Server/IDhcpServer.cs b/src/IPMeow.Dhcp/Server/IDhcpServer.cs
index 9d5977f..ce49f35 100644
--- a/src/IPMeow.Dhcp/Server/IDhcpServer.cs
+++ b/src/IPMeow.Dhcp/Server/IDhcpServer.cs
@@ -1,8 +1,8 @@
+using Microsoft.Extensions.Hosting;
+
namespace IPMeow.Dhcp.Server;
-public interface IDhcpServer
+public interface IDhcpServer : IHostedService
{
- Task Run();
-
- event EventHandler DhcpRequestedEvent;
+ event EventHandler DhcpRequestedEvent;
}
diff --git a/src/IPMeow.Dhcp/Standalone/DecoupledAddressProvider.cs b/src/IPMeow.Dhcp/Standalone/DecoupledAddressProvider.cs
index 37aa955..bf375b3 100644
--- a/src/IPMeow.Dhcp/Standalone/DecoupledAddressProvider.cs
+++ b/src/IPMeow.Dhcp/Standalone/DecoupledAddressProvider.cs
@@ -1,50 +1,20 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
using System.Net;
-using System.Threading.Tasks;
-using IPMeow.Lib.Address;
+using IPMeow.Lib.Request;
namespace IPMeow.Dhcp.Standalone;
-public class DecoupledIPv6AddressProvider : IPv6AddressProvider
+
+public class DecoupledIPAddressProvider : IAddressProvider
{
- public DecoupledIPv6AddressProvider(HttpClient http)
+ public DecoupledIPAddressProvider(HttpClient http)
{
_http = http;
}
private readonly HttpClient _http;
- public IPv6Address GetAddress()
- {
- _http.GetAsync("/api/request/6/free");
- throw new NotImplementedException();
- }
-
- public IPv6Address GetAddress(MacAddress mac)
+ public IPAddress GetAddress(AddressRequestContext ctx)
{
- throw new NotImplementedException();
- }
-}
-
-public class DecoupledIPv4AddressProvider : IPv4AddressProvider
-{
- public DecoupledIPv4AddressProvider(HttpClient http)
- {
- _http = http;
- }
-
- private readonly HttpClient _http;
-
- public IPv4Address GetAddress()
- {
- _http.GetAsync("/api/request/4/free");
- throw new NotImplementedException();
- }
-
- public IPv4Address GetAddress(MacAddress mac)
- {
- _http.GetAsync($"/api/request/4/mac/{mac}");
+ _http.GetAsync($"/api/request/{(ctx.IsV6 ? "6" : "4")}/free");
throw new NotImplementedException();
}
}
diff --git a/src/IPMeow.Lib/Address/IAddressProvider.cs b/src/IPMeow.Lib/Address/IAddressProvider.cs
deleted file mode 100644
index b2f4e3a..0000000
--- a/src/IPMeow.Lib/Address/IAddressProvider.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Net;
-using System.Threading.Tasks;
-
-namespace IPMeow.Lib.Address;
-
-public interface IAddressProvider
-{
- public IPAddress GetAddress();
- public IPAddress GetAddress(MacAddress mac);
-}
-
-public interface IPv4AddressProvider
-{
- public IPv4Address GetAddress();
- public IPv4Address GetAddress(MacAddress mac);
-}
-
-public interface IPv6AddressProvider
-{
- public IPv6Address GetAddress();
- public IPv6Address GetAddress(MacAddress mac);
-}
diff --git a/src/IPMeow.Lib/Address/MacAddress.cs b/src/IPMeow.Lib/Address/MacAddress.cs
index d01e2f4..befe296 100644
--- a/src/IPMeow.Lib/Address/MacAddress.cs
+++ b/src/IPMeow.Lib/Address/MacAddress.cs
@@ -22,7 +22,7 @@ public readonly struct MacAddress
return mac.Value;
}
- throw new ArgumentException("Invalid address byte length. Expected 6 octets.");
+ throw new ArgumentException($"Invalid address byte length. Expected 6 octets. Got {addr.Length} octets.");
}
public static MacAddress Parse(string addr)
@@ -32,7 +32,7 @@ public readonly struct MacAddress
return mac.Value;
}
- throw new FormatException("Invalid address format.");
+ throw new FormatException($"Invalid address format: {addr}.");
}
public static bool TryParse(byte[] addr, [NotNullWhen(true)] out MacAddress? mac)
diff --git a/src/IPMeow.Lib/BitEnumerator.cs b/src/IPMeow.Lib/BitEnumerator.cs
index 0fe95d4..81e2dd0 100644
--- a/src/IPMeow.Lib/BitEnumerator.cs
+++ b/src/IPMeow.Lib/BitEnumerator.cs
@@ -1,3 +1,5 @@
+using System.Buffers.Binary;
+
namespace IPMeow.Lib;
public class BitEnumerator
@@ -26,7 +28,7 @@ public class BitEnumerator
public short TakeInt16()
{
- short num = BitConverter.ToInt16(_data.AsSpan()[_position..(_position + 2)]);
+ short num = BinaryPrimitives.ReadInt16BigEndian(_data.AsSpan()[_position..(_position + 2)]);
_position += 2;
@@ -35,7 +37,7 @@ public class BitEnumerator
public int TakeInt32()
{
- int num = BitConverter.ToInt32(_data.AsSpan()[_position..(_position + 4)]);
+ int num = BinaryPrimitives.ReadInt32BigEndian(_data.AsSpan()[_position..(_position + 4)]);
_position += 4;
@@ -44,7 +46,7 @@ public class BitEnumerator
public long TakeInt64()
{
- long num = BitConverter.ToInt64(_data.AsSpan()[_position..(_position + 8)]);
+ long num = BinaryPrimitives.ReadInt64BigEndian(_data.AsSpan()[_position..(_position + 8)]);
_position += 8;
@@ -53,7 +55,7 @@ public class BitEnumerator
public ushort TakeUInt16()
{
- ushort num = BitConverter.ToUInt16(_data.AsSpan()[_position..(_position + 2)]);
+ ushort num = BinaryPrimitives.ReadUInt16BigEndian(_data.AsSpan()[_position..(_position + 2)]);
_position += 2;
@@ -62,7 +64,7 @@ public class BitEnumerator
public uint TakeUInt32()
{
- uint num = BitConverter.ToUInt32(_data.AsSpan()[_position..(_position + 4)]);
+ uint num = BinaryPrimitives.ReadUInt32BigEndian(_data.AsSpan()[_position..(_position + 4)]);
_position += 4;
@@ -71,7 +73,7 @@ public class BitEnumerator
public ulong TakeUInt64()
{
- ulong num = BitConverter.ToUInt64(_data.AsSpan()[_position..(_position + 8)]);
+ ulong num = BinaryPrimitives.ReadUInt64BigEndian(_data.AsSpan()[_position..(_position + 8)]);
_position += 8;
diff --git a/src/IPMeow.Lib/Host/Host.cs b/src/IPMeow.Lib/Host/Host.cs
index f450c47..2d55843 100644
--- a/src/IPMeow.Lib/Host/Host.cs
+++ b/src/IPMeow.Lib/Host/Host.cs
@@ -8,7 +8,17 @@ public class Host : IBindable
{
[Key]
public required string Id { get; set; }
- public DateTime? LastPing { get; set; }
+ [MaxLength(16)]
+ public byte[] Duid { get; set; } = default!;
+ public HostType HostType { get; set; }
public required IPAddressCollection Addresses { get; set; }
public required MacAddress Mac { get; set; }
}
+
+public enum HostType : byte
+{
+ Physical = 0b1,
+ Virtual = 0b10,
+ Container = 0b100,
+ Other = 0b1000000,
+}
diff --git a/src/IPMeow.Lib/Host/HostInterface.cs b/src/IPMeow.Lib/Host/HostInterface.cs
new file mode 100644
index 0000000..5b98788
--- /dev/null
+++ b/src/IPMeow.Lib/Host/HostInterface.cs
@@ -0,0 +1,15 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace IPMeow.Lib.Host;
+
+public class HostInterface
+{
+ [Key]
+ public required string Id { get; set; }
+ public byte[] IAID { get; set; } = default!;
+ public DateTime LastPinged { get; set; }
+ public DateTime LastAssignment { get; set; }
+
+ public string HostId { get; set; } = default!;
+ public virtual Host Host { get; set; } = default!;
+}
diff --git a/src/IPMeow.Lib/Request/AddressRequestContext.cs b/src/IPMeow.Lib/Request/AddressRequestContext.cs
new file mode 100644
index 0000000..9a16c57
--- /dev/null
+++ b/src/IPMeow.Lib/Request/AddressRequestContext.cs
@@ -0,0 +1,9 @@
+using IPMeow.Lib.Address;
+
+namespace IPMeow.Lib.Request;
+
+public class AddressRequestContext
+{
+ public bool IsV6 { get; set; }
+ public MacAddress? MacAddress { get; set; }
+}
diff --git a/src/IPMeow.Lib/Request/IAddressProvider.cs b/src/IPMeow.Lib/Request/IAddressProvider.cs
new file mode 100644
index 0000000..0f36726
--- /dev/null
+++ b/src/IPMeow.Lib/Request/IAddressProvider.cs
@@ -0,0 +1,8 @@
+using System.Net;
+
+namespace IPMeow.Lib.Request;
+
+public interface IAddressProvider where T : AddressRequestContext
+{
+ public IPAddress GetAddress(T ctx);
+}
diff --git a/src/IPMeow.Lib/Request/IRequestClientIdentifier.cs b/src/IPMeow.Lib/Request/IRequestClientIdentifier.cs
new file mode 100644
index 0000000..497ee7e
--- /dev/null
+++ b/src/IPMeow.Lib/Request/IRequestClientIdentifier.cs
@@ -0,0 +1,6 @@
+namespace IPMeow.Lib.Request;
+
+public interface IRequestClientIdentifier
+{
+
+}
diff --git a/src/IPMeow.Server/Controllers/AddressController.cs b/src/IPMeow.Server/Controllers/AddressController.cs
new file mode 100644
index 0000000..85cd294
--- /dev/null
+++ b/src/IPMeow.Server/Controllers/AddressController.cs
@@ -0,0 +1,21 @@
+using IPMeow.Lib.Request;
+using Microsoft.AspNetCore.Mvc;
+
+namespace IPMeow.Server.Controllers;
+
+[ApiController]
+[Route("api/[controller]")]
+public class AddressController : ControllerBase
+{
+ [HttpPost("request")]
+ public async Task RequestAddress(AddressRequestContext ctx)
+ {
+ throw new NotImplementedException();
+ }
+
+ [HttpGet]
+ public async Task ConfirmRequest()
+ {
+ throw new NotImplementedException();
+ }
+}
diff --git a/src/IPMeow.Server/Data/IpamContext.cs b/src/IPMeow.Server/Data/IpamContext.cs
new file mode 100644
index 0000000..dbd6b6c
--- /dev/null
+++ b/src/IPMeow.Server/Data/IpamContext.cs
@@ -0,0 +1,26 @@
+using IPMeow.Lib.Host;
+using IPMeow.Server.Data.Model;
+using Microsoft.EntityFrameworkCore;
+
+namespace IPMeow.Server.Data;
+
+public class IpamContext : DbContext
+{
+ public DbSet Hosts => Set();
+ public DbSet HostInterfaces => Set();
+ public DbSet Assignments => Set();
+
+ protected override void OnConfiguring(DbContextOptionsBuilder opt)
+ {
+ opt.LogTo(t => Console.WriteLine(t));
+ opt.EnableDetailedErrors();
+ opt.EnableSensitiveDataLogging();
+ base.OnConfiguring(opt);
+ }
+
+ protected override void OnModelCreating(ModelBuilder mb)
+ {
+ mb.Entity().HasKey(ass => new { Address = ass.Address.GetAddressBytes(), HostId = ass.HostInterfaceId });
+ base.OnModelCreating(mb);
+ }
+}
diff --git a/src/IPMeow.Server/Data/Model/AddressAssignment.cs b/src/IPMeow.Server/Data/Model/AddressAssignment.cs
new file mode 100644
index 0000000..b2a348f
--- /dev/null
+++ b/src/IPMeow.Server/Data/Model/AddressAssignment.cs
@@ -0,0 +1,13 @@
+using System.Net;
+using IPMeow.Lib.Host;
+
+namespace IPMeow.Server.Data.Model;
+
+public class AddressAssignment
+{
+ public required string HostInterfaceId { get; set; }
+ public required IPAddress Address { get; set; }
+ public DateTime LastAssigned { get; set; }
+
+ public virtual HostInterface HostInterface { get; set; } = default!;
+}
diff --git a/src/IPMeow.Server/Data/Model/AddressBlock.cs b/src/IPMeow.Server/Data/Model/AddressBlock.cs
new file mode 100644
index 0000000..f8af6c5
--- /dev/null
+++ b/src/IPMeow.Server/Data/Model/AddressBlock.cs
@@ -0,0 +1,9 @@
+using System.Net;
+
+namespace IPMeow.Server.Data.Model;
+
+public class AddressBlock
+{
+ public required IPAddress Address { get; set; }
+ public required int Prefix { get; set; }
+}
diff --git a/src/IPMeow.Server/Data/Model/AddressPolicy.cs b/src/IPMeow.Server/Data/Model/AddressPolicy.cs
new file mode 100644
index 0000000..e15f8c2
--- /dev/null
+++ b/src/IPMeow.Server/Data/Model/AddressPolicy.cs
@@ -0,0 +1,6 @@
+namespace IPMeow.Server.Data.Model;
+
+public class AddressPolicy
+{
+ public bool IsTemporary { get; set; }
+}
diff --git a/src/IPMeow.Server/IPMeow.Server.csproj b/src/IPMeow.Server/IPMeow.Server.csproj
index 72a1294..752d874 100644
--- a/src/IPMeow.Server/IPMeow.Server.csproj
+++ b/src/IPMeow.Server/IPMeow.Server.csproj
@@ -1,5 +1,14 @@
+
+
+
+
+
+
+
+
+
net7.0
enable
diff --git a/src/IPMeow.Server/Program.cs b/src/IPMeow.Server/Program.cs
index 0244463..0c96491 100644
--- a/src/IPMeow.Server/Program.cs
+++ b/src/IPMeow.Server/Program.cs
@@ -1,4 +1,9 @@
+using IPMeow.Server.Data;
+
var builder = WebApplication.CreateBuilder(args);
+
+builder.Services.AddDbContext();
+
var app = builder.Build();
app.Run();
diff --git a/test/IPMeow.Test/StructTests.cs b/test/IPMeow.Test/StructTests.cs
index b4579ed..ea26132 100644
--- a/test/IPMeow.Test/StructTests.cs
+++ b/test/IPMeow.Test/StructTests.cs
@@ -1,4 +1,3 @@
-using IPMeow.Lib;
using IPMeow.Lib.Address;
namespace IPMeow.Test;