This commit is contained in:
Connection Refused
2019-12-02 19:51:12 +08:00
commit b2ea730984
229 changed files with 86605 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
using DNS.Protocol;
using System.Threading;
using System.Threading.Tasks;
namespace DNS.Client.RequestResolver
{
public interface IRequestResolver
{
Task<IResponse> Resolve(IRequest request, CancellationToken cancellationToken = default(CancellationToken));
}
}

View File

@@ -0,0 +1,14 @@
using DNS.Protocol;
using System.Threading;
using System.Threading.Tasks;
namespace DNS.Client.RequestResolver
{
public class NullRequestResolver : IRequestResolver
{
public Task<IResponse> Resolve(IRequest request, CancellationToken cancellationToken = default(CancellationToken))
{
throw new ResponseException("Request failed");
}
}
}

View File

@@ -0,0 +1,72 @@
using DNS.Protocol;
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
namespace DNS.Client.RequestResolver
{
public class TcpRequestResolver : IRequestResolver
{
private IPEndPoint dns;
public TcpRequestResolver(IPEndPoint dns)
{
this.dns = dns;
}
public async Task<IResponse> Resolve(IRequest request, CancellationToken cancellationToken = default(CancellationToken))
{
using (TcpClient tcp = new TcpClient())
{
await tcp.ConnectAsync(dns.Address, dns.Port);
Stream stream = tcp.GetStream();
byte[] buffer = request.ToArray();
byte[] length = BitConverter.GetBytes((ushort)buffer.Length);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(length);
}
await stream.WriteAsync(length, 0, length.Length, cancellationToken);
await stream.WriteAsync(buffer, 0, buffer.Length, cancellationToken);
buffer = new byte[2];
await Read(stream, buffer, cancellationToken);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(buffer);
}
buffer = new byte[BitConverter.ToUInt16(buffer, 0)];
await Read(stream, buffer, cancellationToken);
IResponse response = Response.FromArray(buffer);
return new ClientResponse(request, response, buffer);
}
}
private static async Task Read(Stream stream, byte[] buffer, CancellationToken cancellationToken)
{
int length = buffer.Length;
int offset = 0;
int size = 0;
while (length > 0 && (size = await stream.ReadAsync(buffer, offset, length, cancellationToken)) > 0)
{
offset += size;
length -= size;
}
if (length > 0)
{
throw new IOException("Unexpected end of stream");
}
}
}
}

View File

@@ -0,0 +1,57 @@
using DNS.Protocol;
using DNS.Protocol.Utils;
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
namespace DNS.Client.RequestResolver
{
public class UdpRequestResolver : IRequestResolver
{
private int timeout;
private IRequestResolver fallback;
private IPEndPoint dns;
public UdpRequestResolver(IPEndPoint dns, IRequestResolver fallback, int timeout = 5000)
{
this.dns = dns;
this.fallback = fallback;
this.timeout = timeout;
}
public UdpRequestResolver(IPEndPoint dns, int timeout = 5000)
{
this.dns = dns;
this.fallback = new NullRequestResolver();
this.timeout = timeout;
}
public async Task<IResponse> Resolve(IRequest request, CancellationToken cancellationToken = default(CancellationToken))
{
using (UdpClient udp = new UdpClient())
{
await udp
.SendAsync(request.ToArray(), request.Size, dns)
.WithCancellationTimeout(TimeSpan.FromMilliseconds(timeout), cancellationToken);
UdpReceiveResult result = await udp
.ReceiveAsync()
.WithCancellationTimeout(TimeSpan.FromMilliseconds(timeout), cancellationToken);
if (!result.RemoteEndPoint.Equals(dns)) throw new IOException("Remote endpoint mismatch");
byte[] buffer = result.Buffer;
Response response = Response.FromArray(buffer);
if (response.Truncated)
{
return await fallback.Resolve(request, cancellationToken);
}
return new ClientResponse(request, response, buffer);
}
}
}
}