Change byte[] to ReadOnlyMemory<byte>. Implement DNS system.
This commit is contained in:
parent
8ab872589c
commit
efdf871b4e
25 changed files with 623 additions and 30 deletions
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -2,5 +2,6 @@
|
|||
"sonarlint.connectedMode.project": {
|
||||
"connectionId": "",
|
||||
"projectKey": ""
|
||||
}
|
||||
},
|
||||
"dotnet.defaultSolution": "IPMeow.sln"
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IPMeow.Test", "test\IPMeow.
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IPMeow.Dhcp", "src\IPMeow.Dhcp\IPMeow.Dhcp.csproj", "{E43DAE0D-7B29-443A-875B-3F5B5D8D2985}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IPMeow.Dns", "src\IPMeow.Dns\IPMeow.Dns.csproj", "{8FC668A7-613D-453A-B8C5-9560AC0CD3C7}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -52,6 +54,10 @@ Global
|
|||
{E43DAE0D-7B29-443A-875B-3F5B5D8D2985}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E43DAE0D-7B29-443A-875B-3F5B5D8D2985}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E43DAE0D-7B29-443A-875B-3F5B5D8D2985}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8FC668A7-613D-453A-B8C5-9560AC0CD3C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8FC668A7-613D-453A-B8C5-9560AC0CD3C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8FC668A7-613D-453A-B8C5-9560AC0CD3C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8FC668A7-613D-453A-B8C5-9560AC0CD3C7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{7B05EB40-4EDE-4ECA-A877-76B5A121ED52} = {8C8C298E-21E9-4519-AAC0-205AF974F4E2}
|
||||
|
@ -60,5 +66,6 @@ Global
|
|||
{81E9956C-89B1-4724-A006-1D1E398DBE81} = {8C8C298E-21E9-4519-AAC0-205AF974F4E2}
|
||||
{7B861E40-93E1-4A53-A0F2-A744E94BD517} = {74533C64-0AB7-493E-8824-94B0CFC563B2}
|
||||
{E43DAE0D-7B29-443A-875B-3F5B5D8D2985} = {8C8C298E-21E9-4519-AAC0-205AF974F4E2}
|
||||
{8FC668A7-613D-453A-B8C5-9560AC0CD3C7} = {8C8C298E-21E9-4519-AAC0-205AF974F4E2}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
@ -32,7 +32,7 @@ public class BootpHeader
|
|||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Hops}\nXid: {Xid}, Seconds: {Seconds}, Flags: {Flags:x}\nci: {ClientAddress}\nyi: {YourAddress}, ns: {NextServerAddress}, ra: {RelayAgentAddress}\nhw: {MacAddress.Parse(GetMacAddress())}";
|
||||
return $"{Hops}\nXid: {Xid}, Seconds: {Seconds}, Flags: {Flags:x}\nci: {ClientAddress}\nyi: {YourAddress}, ns: {NextServerAddress}, ra: {RelayAgentAddress}\nhw: {GetMacAddress()}";
|
||||
}
|
||||
|
||||
public byte[] GetClientHwAddress()
|
||||
|
@ -49,7 +49,7 @@ public class BootpHeader
|
|||
return buf;
|
||||
}
|
||||
|
||||
public byte[] GetMacAddress() => ClientHWAddress[0..6];
|
||||
public MacAddress GetMacAddress() => MacAddress.Parse(ClientHWAddress[0..6]);
|
||||
|
||||
public static BootpHeader? Deserialize(byte[] data)
|
||||
{
|
||||
|
|
|
@ -14,8 +14,13 @@ public class Dhcp4Server : IDhcpServer, IDisposable
|
|||
{
|
||||
_addrProvider = addressProvider;
|
||||
_udp = new UdpClient(serverPort, AddressFamily.InterNetwork);
|
||||
_token = new();
|
||||
_serverThread = new Thread(async () => await Run(_token.Token));
|
||||
}
|
||||
|
||||
private readonly CancellationTokenSource _token;
|
||||
private readonly Thread _serverThread;
|
||||
|
||||
private readonly IAddressProvider<AddressRequestContext> _addrProvider;
|
||||
|
||||
public event EventHandler<DhcpRequestEventArgs> DhcpRequestedEvent = delegate { };
|
||||
|
@ -46,10 +51,18 @@ public class Dhcp4Server : IDhcpServer, IDisposable
|
|||
|
||||
packet.IsValidated = true;
|
||||
|
||||
AddressRequestContext ctx = new()
|
||||
{
|
||||
IsV6 = false,
|
||||
MacAddress = packet.Header.GetMacAddress()
|
||||
};
|
||||
|
||||
_addrProvider.GetAddress(ctx);
|
||||
|
||||
DhcpRequestedEvent.Invoke(this, new()
|
||||
{
|
||||
IsV6 = false,
|
||||
MacAddress = MacAddress.Parse(packet.Header.GetMacAddress()),
|
||||
MacAddress = packet.Header.GetMacAddress(),
|
||||
RequestOrigin = packet.Header.ClientAddress
|
||||
});
|
||||
//TODO
|
||||
|
@ -97,15 +110,20 @@ public class Dhcp4Server : IDhcpServer, IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
new Thread(async () => await Run(cancellationToken)).Start();
|
||||
_serverThread.Start();
|
||||
Console.WriteLine("V4 started.");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
public async Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
await Task.Run(() =>
|
||||
{
|
||||
_token.Cancel();
|
||||
_serverThread.Join();
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
private readonly UdpClient _udp;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using IPMeow.Lib.Address;
|
||||
using IPMeow.Lib.Request;
|
||||
|
||||
namespace IPMeow.Dhcp.Server.Dhcp6;
|
||||
|
@ -15,11 +16,17 @@ public class Dhcp6Server : IDhcpServer, IDisposable
|
|||
_listener = new(serverPort, AddressFamily.InterNetworkV6);
|
||||
_listener.JoinMulticastGroup(IPAddress.Parse("ff02::1:2"));
|
||||
_sender = new(clientPort, AddressFamily.InterNetworkV6);
|
||||
|
||||
_token = new();
|
||||
_thread = new(async () => await Run(_token.Token));
|
||||
}
|
||||
|
||||
private readonly IAddressProvider<AddressRequestContext> _addrProvider;
|
||||
private readonly UdpClient _listener, _sender;
|
||||
|
||||
private readonly Thread _thread;
|
||||
private readonly CancellationTokenSource _token;
|
||||
|
||||
public event EventHandler<DhcpRequestEventArgs> DhcpRequestedEvent = delegate { };
|
||||
|
||||
public void Dispose()
|
||||
|
@ -49,6 +56,15 @@ public class Dhcp6Server : IDhcpServer, IDisposable
|
|||
return;
|
||||
}
|
||||
|
||||
AddressRequestContext ctx = new()
|
||||
{
|
||||
IsV6 = true,
|
||||
MacAddress = null
|
||||
};
|
||||
|
||||
|
||||
_addrProvider.GetAddress(ctx);
|
||||
|
||||
//TODO
|
||||
}
|
||||
|
||||
|
@ -64,14 +80,19 @@ public class Dhcp6Server : IDhcpServer, IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
new Thread(async () => await Run(cancellationToken)).Start();
|
||||
_thread.Start();
|
||||
Console.WriteLine("V6 started.");
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
_token.Cancel();
|
||||
_thread.Join();
|
||||
}, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
119
src/IPMeow.Dns/DnsMessage.cs
Normal file
119
src/IPMeow.Dns/DnsMessage.cs
Normal file
|
@ -0,0 +1,119 @@
|
|||
using System;
|
||||
using System.Buffers;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using IPMeow.Lib;
|
||||
|
||||
namespace IPMeow.Dns;
|
||||
|
||||
public struct DnsMessage : IBinarySerializable<DnsMessage>
|
||||
{
|
||||
public UInt128 Header { get; set; }
|
||||
public ushort MessageId { get; set; }
|
||||
public bool IsAuthoritative { get; set; }
|
||||
public bool IsTruncated { get; set; }
|
||||
public bool IsRecursionDesired { get; set; }
|
||||
public bool IsRecursionAvailable { get; set; }
|
||||
public DnsMessageType MessageType { get; set; }
|
||||
public DnsMessageOpcode Opcode { get; set; }
|
||||
public DnsResponseCode ResponseCode { get; set; }
|
||||
public ICollection<ResourceRecord> Questions { get; set; }
|
||||
|
||||
public static DnsMessage Deserialize(ReadOnlyMemory<byte> data)
|
||||
{
|
||||
BitEnumerator b = new(data);
|
||||
|
||||
ushort messageId = b.TakeUInt16();
|
||||
|
||||
short flags = b.TakeInt16();
|
||||
|
||||
DnsMessageType type = BitUtils.GetBit(flags, 0) ? DnsMessageType.Reply : DnsMessageType.Query;
|
||||
DnsMessageOpcode opcode = (DnsMessageOpcode)(flags & (0xf << 11) >> 11);
|
||||
bool isAuth = BitUtils.GetBit(flags, 5);
|
||||
bool isTruncated = BitUtils.GetBit(flags, 6);
|
||||
bool isRecursionDesired = BitUtils.GetBit(flags, 7);
|
||||
bool isRecursionAvailable = BitUtils.GetBit(flags, 8);
|
||||
DnsResponseCode code = (DnsResponseCode)(flags & 0xf);
|
||||
|
||||
short question = b.TakeInt16(), answer = b.TakeInt16(), authority = b.TakeInt16(), additional = b.TakeInt16();
|
||||
|
||||
return new DnsMessage()
|
||||
{
|
||||
MessageId = messageId,
|
||||
MessageType = type,
|
||||
Opcode = opcode,
|
||||
IsAuthoritative = isAuth,
|
||||
IsTruncated = isTruncated,
|
||||
IsRecursionDesired = isRecursionDesired,
|
||||
IsRecursionAvailable = isRecursionAvailable,
|
||||
ResponseCode = code,
|
||||
};
|
||||
}
|
||||
|
||||
public readonly ReadOnlyMemory<byte> Serialize()
|
||||
{
|
||||
ArrayBufferWriter<byte> buffer = new(12); //(this.AnswerCount + this.AuthorityCount + this.QuestionCount + this.AdditionalDataCount));
|
||||
|
||||
int flags = (ushort)ResponseCode | ((ushort)Opcode << 11);
|
||||
|
||||
if (MessageType == DnsMessageType.Reply)
|
||||
{
|
||||
flags |= 0x8000;
|
||||
}
|
||||
|
||||
flags |= IsAuthoritative ? 0b10000000000 : 0;
|
||||
flags |= IsTruncated ? 0b1000000000 : 0;
|
||||
flags |= IsRecursionDesired ? 0b100000000 : 0;
|
||||
flags |= IsRecursionAvailable ? 0b10000000 : 0;
|
||||
|
||||
BinaryPrimitives.WriteUInt16BigEndian(buffer.GetSpan(), MessageId);
|
||||
buffer.Advance(2);
|
||||
BinaryPrimitives.WriteUInt16BigEndian(buffer.GetSpan(), (ushort)flags);
|
||||
buffer.Advance(2);
|
||||
BinaryPrimitives.WriteInt16BigEndian(buffer.GetSpan(), (short)Questions.Count);
|
||||
buffer.Advance(2);
|
||||
BinaryPrimitives.WriteInt16BigEndian(buffer.GetSpan(), 0);
|
||||
buffer.Advance(2);
|
||||
BinaryPrimitives.WriteInt16BigEndian(buffer.GetSpan(), 0);
|
||||
buffer.Advance(2);
|
||||
BinaryPrimitives.WriteInt16BigEndian(buffer.GetSpan(), 0);
|
||||
buffer.Advance(2);
|
||||
|
||||
if (Questions.Any())
|
||||
{
|
||||
foreach (var question in Questions)
|
||||
{
|
||||
buffer.Write(question.Serialize().Span);
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.WrittenMemory;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public enum DnsMessageType : byte
|
||||
{
|
||||
Query = 0,
|
||||
Reply = 1
|
||||
}
|
||||
|
||||
public enum DnsMessageOpcode : byte
|
||||
{
|
||||
Query = 0,
|
||||
InverseQuery = 1,
|
||||
Status = 2
|
||||
}
|
||||
|
||||
public enum DnsResponseCode : byte
|
||||
{
|
||||
Ok = 0,
|
||||
FormatError = 1,
|
||||
ServerFail = 2,
|
||||
NxDomain = 3
|
||||
}
|
13
src/IPMeow.Dns/IPMeow.Dns.csproj
Normal file
13
src/IPMeow.Dns/IPMeow.Dns.csproj
Normal file
|
@ -0,0 +1,13 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\IPMeow.Lib\IPMeow.Lib.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
109
src/IPMeow.Dns/ResourceRecord.cs
Normal file
109
src/IPMeow.Dns/ResourceRecord.cs
Normal file
|
@ -0,0 +1,109 @@
|
|||
using System;
|
||||
using System.Buffers;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using IPMeow.Lib;
|
||||
|
||||
namespace IPMeow.Dns;
|
||||
|
||||
public enum ResourceRecordType : short
|
||||
{
|
||||
Invalid = 0,
|
||||
A = 1,
|
||||
NS = 2,
|
||||
CNAME = 5,
|
||||
SOA = 6,
|
||||
PTR = 12,
|
||||
MX = 15,
|
||||
TXT = 16,
|
||||
RP = 17,
|
||||
AAAA = 28,
|
||||
LOC = 29,
|
||||
SRV = 33,
|
||||
NAPTR = 35,
|
||||
CERT = 37,
|
||||
DNAME = 39,
|
||||
OPT = 41,
|
||||
DS = 43,
|
||||
SSHFP = 44,
|
||||
RRSIG = 46,
|
||||
NSEC = 47,
|
||||
DNSKEY = 48,
|
||||
DHCID = 49,
|
||||
NSEC3 = 50,
|
||||
NSEC3PARAM = 51,
|
||||
TLSA = 52,
|
||||
HIP = 55,
|
||||
OPENPGPKEY = 61,
|
||||
CSYNC = 62,
|
||||
CAA = 257,
|
||||
}
|
||||
|
||||
public enum ResourceRecordClass : short
|
||||
{
|
||||
Invalid = 0,
|
||||
IN = 1,
|
||||
CH = 3,
|
||||
HS = 4,
|
||||
}
|
||||
|
||||
public struct ResourceRecord : IBinarySerializable<ResourceRecord>
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public ResourceRecordType Type { get; set; }
|
||||
public ResourceRecordClass Class { get; set; }
|
||||
public TimeSpan Ttl { get; set; }
|
||||
|
||||
|
||||
public static ResourceRecord Deserialize(ReadOnlyMemory<byte> data)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ReadOnlySpan<byte> SerializeName()
|
||||
{
|
||||
string name = Name.Normalize().Trim('.');
|
||||
|
||||
if (name.Length > 255)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("Name must be less than 255");
|
||||
}
|
||||
|
||||
ArrayBufferWriter<byte> buffer = new(name.Length + 1 + 4);
|
||||
|
||||
foreach (string s in name.Split('.'))
|
||||
{
|
||||
byte[] b = Encoding.UTF8.GetBytes(s);
|
||||
var lenBuf = buffer.GetSpan(1);
|
||||
lenBuf[0] = (byte)b.Length;
|
||||
buffer.Advance(1);
|
||||
buffer.Write(b);
|
||||
}
|
||||
var zero = buffer.GetSpan(1);
|
||||
zero[0] = 0;
|
||||
buffer.Advance(1);
|
||||
|
||||
return buffer.WrittenSpan;
|
||||
}
|
||||
|
||||
public ReadOnlyMemory<byte> Serialize()
|
||||
{
|
||||
var buffer = new ArrayBufferWriter<byte>();
|
||||
|
||||
buffer.Write(SerializeName());
|
||||
BinaryPrimitives.WriteInt16BigEndian(buffer.GetSpan(), (short)Type);
|
||||
buffer.Advance(2);
|
||||
BinaryPrimitives.WriteInt16BigEndian(buffer.GetSpan(), (short)Class);
|
||||
buffer.Advance(2);
|
||||
BinaryPrimitives.WriteInt32BigEndian(buffer.GetSpan(), (int)Ttl.TotalSeconds);
|
||||
buffer.Advance(4);
|
||||
//TODO: Implement RDATA
|
||||
BinaryPrimitives.WriteInt16BigEndian(buffer.GetSpan(), 0);
|
||||
buffer.Advance(2);
|
||||
return buffer.WrittenMemory;
|
||||
}
|
||||
}
|
|
@ -1,9 +1,10 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using IPMeow.Lib.Identity;
|
||||
|
||||
namespace IPMeow.Lib.Address;
|
||||
|
||||
public readonly struct MacAddress
|
||||
public readonly struct MacAddress : IIdentity
|
||||
{
|
||||
public MacAddress(byte[] addr)
|
||||
{
|
||||
|
|
|
@ -4,17 +4,17 @@ namespace IPMeow.Lib;
|
|||
|
||||
public class BitEnumerator
|
||||
{
|
||||
public BitEnumerator(byte[] data)
|
||||
public BitEnumerator(ReadOnlyMemory<byte> data)
|
||||
{
|
||||
_data = data;
|
||||
}
|
||||
|
||||
private readonly byte[] _data;
|
||||
private readonly ReadOnlyMemory<byte> _data;
|
||||
private int _position = 0;
|
||||
|
||||
public byte TakeByte()
|
||||
{
|
||||
return _data[_position++];
|
||||
return _data.Span[_position++];
|
||||
}
|
||||
|
||||
public byte[] TakeBytes(int len)
|
||||
|
@ -23,12 +23,12 @@ public class BitEnumerator
|
|||
|
||||
_position += len;
|
||||
|
||||
return data;
|
||||
return data.ToArray();
|
||||
}
|
||||
|
||||
public short TakeInt16()
|
||||
{
|
||||
short num = BinaryPrimitives.ReadInt16BigEndian(_data.AsSpan()[_position..(_position + 2)]);
|
||||
short num = BinaryPrimitives.ReadInt16BigEndian(_data.Span[_position..(_position + 2)]);
|
||||
|
||||
_position += 2;
|
||||
|
||||
|
@ -37,7 +37,7 @@ public class BitEnumerator
|
|||
|
||||
public int TakeInt32()
|
||||
{
|
||||
int num = BinaryPrimitives.ReadInt32BigEndian(_data.AsSpan()[_position..(_position + 4)]);
|
||||
int num = BinaryPrimitives.ReadInt32BigEndian(_data.Span[_position..(_position + 4)]);
|
||||
|
||||
_position += 4;
|
||||
|
||||
|
@ -46,7 +46,7 @@ public class BitEnumerator
|
|||
|
||||
public long TakeInt64()
|
||||
{
|
||||
long num = BinaryPrimitives.ReadInt64BigEndian(_data.AsSpan()[_position..(_position + 8)]);
|
||||
long num = BinaryPrimitives.ReadInt64BigEndian(_data.Span[_position..(_position + 8)]);
|
||||
|
||||
_position += 8;
|
||||
|
||||
|
@ -55,7 +55,7 @@ public class BitEnumerator
|
|||
|
||||
public ushort TakeUInt16()
|
||||
{
|
||||
ushort num = BinaryPrimitives.ReadUInt16BigEndian(_data.AsSpan()[_position..(_position + 2)]);
|
||||
ushort num = BinaryPrimitives.ReadUInt16BigEndian(_data.Span[_position..(_position + 2)]);
|
||||
|
||||
_position += 2;
|
||||
|
||||
|
@ -64,7 +64,7 @@ public class BitEnumerator
|
|||
|
||||
public uint TakeUInt32()
|
||||
{
|
||||
uint num = BinaryPrimitives.ReadUInt32BigEndian(_data.AsSpan()[_position..(_position + 4)]);
|
||||
uint num = BinaryPrimitives.ReadUInt32BigEndian(_data.Span[_position..(_position + 4)]);
|
||||
|
||||
_position += 4;
|
||||
|
||||
|
@ -73,7 +73,7 @@ public class BitEnumerator
|
|||
|
||||
public ulong TakeUInt64()
|
||||
{
|
||||
ulong num = BinaryPrimitives.ReadUInt64BigEndian(_data.AsSpan()[_position..(_position + 8)]);
|
||||
ulong num = BinaryPrimitives.ReadUInt64BigEndian(_data.Span[_position..(_position + 8)]);
|
||||
|
||||
_position += 8;
|
||||
|
||||
|
|
24
src/IPMeow.Lib/BitUtils.cs
Normal file
24
src/IPMeow.Lib/BitUtils.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IPMeow.Lib;
|
||||
|
||||
public static class BitUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the nth most significant bit
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="bit"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool GetBit(short data, int bit)
|
||||
{
|
||||
return (data & (0x1 << (15 - bit))) == (0x1 << (15 - bit));
|
||||
}
|
||||
}
|
13
src/IPMeow.Lib/IBinarySerializable.cs
Normal file
13
src/IPMeow.Lib/IBinarySerializable.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IPMeow.Lib;
|
||||
|
||||
public interface IBinarySerializable<T>
|
||||
{
|
||||
public ReadOnlyMemory<byte> Serialize();
|
||||
|
||||
public static abstract T Deserialize(ReadOnlyMemory<byte> data);
|
||||
}
|
11
src/IPMeow.Lib/Identity/DhcpClientId.cs
Normal file
11
src/IPMeow.Lib/Identity/DhcpClientId.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IPMeow.Lib.Identity;
|
||||
|
||||
public class DhcpClientId : IIdentity
|
||||
{
|
||||
|
||||
}
|
19
src/IPMeow.Lib/Identity/Duid.cs
Normal file
19
src/IPMeow.Lib/Identity/Duid.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IPMeow.Lib.Identity;
|
||||
|
||||
public class Duid : IIdentity
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public enum DuidType : short
|
||||
{
|
||||
LinkLayerTime = 1,
|
||||
EnterpriseNumber = 2,
|
||||
LinkLayerAddress = 3,
|
||||
Uuid = 4
|
||||
}
|
11
src/IPMeow.Lib/Identity/IIdentity.cs
Normal file
11
src/IPMeow.Lib/Identity/IIdentity.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IPMeow.Lib.Identity;
|
||||
|
||||
public interface IIdentity
|
||||
{
|
||||
|
||||
}
|
11
src/IPMeow.Lib/Identity/Identity.cs
Normal file
11
src/IPMeow.Lib/Identity/Identity.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IPMeow.Lib.Identity;
|
||||
|
||||
public class Identity<T> where T : IIdentity
|
||||
{
|
||||
|
||||
}
|
14
src/IPMeow.Lib/Server/DnsServer.cs
Normal file
14
src/IPMeow.Lib/Server/DnsServer.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IPMeow.Lib.Server;
|
||||
|
||||
public class DnsServer : IRoutedServer
|
||||
{
|
||||
public required IPAddress Address { get; set; }
|
||||
public required ICollection<Protocol> Protocols { get; set; }
|
||||
public bool SupportsTls { get; set; }
|
||||
}
|
13
src/IPMeow.Lib/Server/IRoutedServer.cs
Normal file
13
src/IPMeow.Lib/Server/IRoutedServer.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IPMeow.Lib.Server;
|
||||
|
||||
public interface IRoutedServer
|
||||
{
|
||||
public IPAddress Address { get; set; }
|
||||
public ICollection<Protocol> Protocols { get; set; }
|
||||
}
|
12
src/IPMeow.Lib/Server/Protocol.cs
Normal file
12
src/IPMeow.Lib/Server/Protocol.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IPMeow.Lib.Server;
|
||||
|
||||
public struct Protocol
|
||||
{
|
||||
public short Port { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
51
src/IPMeow.Lib/Server/Protocols.cs
Normal file
51
src/IPMeow.Lib/Server/Protocols.cs
Normal file
|
@ -0,0 +1,51 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IPMeow.Lib.Server;
|
||||
|
||||
public static class Protocols
|
||||
{
|
||||
private static readonly HashSet<Protocol> _protos = new()
|
||||
{
|
||||
Http,
|
||||
Dns,
|
||||
DnsOverTls,
|
||||
DnsOverHttps,
|
||||
Ntp,
|
||||
Ssh,
|
||||
Snmp,
|
||||
Ldap,
|
||||
Kerberos,
|
||||
Radius,
|
||||
Smtp,
|
||||
Pop3,
|
||||
Imap
|
||||
};
|
||||
|
||||
public static readonly Protocol Http = new() { Name = "HTTP", Port = 80 };
|
||||
public static readonly Protocol Dns = new() { Name = "DNS", Port = 53 };
|
||||
public static readonly Protocol DnsOverTls = new() { Name = "DNS-over-TLS", Port = 853 };
|
||||
public static readonly Protocol DnsOverHttps = new() { Name = "DNS-over-HTTPS", Port = 443 };
|
||||
public static readonly Protocol Ntp = new() { Name = "NTP", Port = 123 };
|
||||
public static readonly Protocol Ssh = new() { Name = "SSH", Port = 22 };
|
||||
public static readonly Protocol Snmp = new() { Name = "SNMP", Port = 161 };
|
||||
public static readonly Protocol Ldap = new() { Name = "LDAP", Port = 389 };
|
||||
public static readonly Protocol Kerberos = new() { Name = "Kerberos", Port = 88 };
|
||||
public static readonly Protocol Radius = new() { Name = "RADIUS", Port = 1812 };
|
||||
public static readonly Protocol Smtp = new() { Name = "SMTP", Port = 25 };
|
||||
public static readonly Protocol Pop3 = new() { Name = "POP3", Port = 110 };
|
||||
public static readonly Protocol Imap = new() { Name = "IMAP", Port = 143 };
|
||||
|
||||
public static Protocol? GetByPort(short port)
|
||||
{
|
||||
return _protos.SingleOrDefault(s => s.Port == port);
|
||||
}
|
||||
|
||||
public static Protocol? GetByName(string name)
|
||||
{
|
||||
return _protos.SingleOrDefault(s => s.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
|
13
src/IPMeow.Lib/Site/Network.cs
Normal file
13
src/IPMeow.Lib/Site/Network.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using IPMeow.Lib.Address;
|
||||
using IPMeow.Lib.Server;
|
||||
|
||||
namespace IPMeow.Lib.Site;
|
||||
|
||||
public class Network
|
||||
{
|
||||
[Key]
|
||||
public required string Name { get; set; }
|
||||
public virtual ICollection<DnsServer> DnsServers { get; set; }
|
||||
public virtual ICollection<Address.Network> Networks { get; set; }
|
||||
}
|
|
@ -4,12 +4,31 @@ using Microsoft.AspNetCore.Mvc;
|
|||
namespace IPMeow.Server.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class AddressController : ControllerBase
|
||||
[Route("api/address/v6")]
|
||||
public class V6AddressController : ControllerBase
|
||||
{
|
||||
[HttpPost("request")]
|
||||
public async Task<IActionResult> RequestAddress(AddressRequestContext ctx)
|
||||
{
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> ConfirmRequest()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
[ApiController]
|
||||
[Route("api/address/v4")]
|
||||
public class V4AddressController : ControllerBase
|
||||
{
|
||||
[HttpPost("request")]
|
||||
public async Task<IActionResult> RequestAddress(AddressRequestContext ctx)
|
||||
{
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
|
36
src/IPMeow.Server/Controllers/InfoController.cs
Normal file
36
src/IPMeow.Server/Controllers/InfoController.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace IPMeow.Server.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("/api/info")]
|
||||
public class InfoController
|
||||
{
|
||||
[HttpGet("all")]
|
||||
public async Task<IActionResult> GetAllData()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[HttpGet("dns")]
|
||||
public async Task<IActionResult> GetDnsServers()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[HttpGet("ntp")]
|
||||
public async Task<IActionResult> GetNtpServers()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[HttpGet("snmp")]
|
||||
public async Task<IActionResult> GetSnmpServers()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
56
test/IPMeow.Test/DnsTest.cs
Normal file
56
test/IPMeow.Test/DnsTest.cs
Normal file
|
@ -0,0 +1,56 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading.Tasks;
|
||||
using IPMeow.Dns;
|
||||
|
||||
namespace IPMeow.Test;
|
||||
|
||||
public class DnsTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task TestDns()
|
||||
{
|
||||
DnsMessage msg = new()
|
||||
{
|
||||
IsRecursionDesired = true,
|
||||
IsRecursionAvailable = true,
|
||||
MessageId = 0xbabe,
|
||||
MessageType = DnsMessageType.Query,
|
||||
Opcode = DnsMessageOpcode.Query,
|
||||
Questions = new List<ResourceRecord>()
|
||||
{
|
||||
new ResourceRecord()
|
||||
{
|
||||
Class = ResourceRecordClass.IN,
|
||||
Ttl = TimeSpan.Zero,
|
||||
Name = "meow.lgbt",
|
||||
Type = ResourceRecordType.A
|
||||
},
|
||||
},
|
||||
ResponseCode = 0,
|
||||
};
|
||||
|
||||
await Send(msg);
|
||||
Console.WriteLine("sendt");
|
||||
|
||||
msg.IsRecursionDesired = false;
|
||||
msg.IsAuthoritative = true;
|
||||
msg.MessageType = DnsMessageType.Reply;
|
||||
msg.Opcode = DnsMessageOpcode.Status;
|
||||
msg.ResponseCode = DnsResponseCode.NxDomain;
|
||||
|
||||
await Send(msg);
|
||||
}
|
||||
|
||||
private async Task Send(DnsMessage msg)
|
||||
{
|
||||
var data = msg.Serialize();
|
||||
|
||||
using UdpClient udp = new UdpClient(AddressFamily.InterNetwork);
|
||||
udp.Connect(IPAddress.Parse("1.1.1.1"), 53);
|
||||
await udp.SendAsync(data);
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@
|
|||
<ProjectReference Include="..\..\src\IPMeow.Cli\IPMeow.Cli.csproj" />
|
||||
<ProjectReference Include="..\..\src\IPMeow.Server\IPMeow.Server.csproj" />
|
||||
<ProjectReference Include="..\..\src\IPMeow.Viewer\IPMeow.Viewer.csproj" />
|
||||
<ProjectReference Include="..\..\src\IPMeow.Dns\IPMeow.Dns.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
Loading…
Reference in a new issue