Neukonstruktion
This commit is contained in:
24
MailServer/MailServer.sln
Normal file
24
MailServer/MailServer.sln
Normal file
@ -0,0 +1,24 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.25920.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MailServer", "MailServer\MailServer.csproj", "{ABB6A3E6-38B6-4D02-AC9C-91FA69CF03BE}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D43013F8-933F-4ADC-8943-08E91662A070}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{ABB6A3E6-38B6-4D02-AC9C-91FA69CF03BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ABB6A3E6-38B6-4D02-AC9C-91FA69CF03BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ABB6A3E6-38B6-4D02-AC9C-91FA69CF03BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ABB6A3E6-38B6-4D02-AC9C-91FA69CF03BE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
199
MailServer/MailServer/DNS/DnsErrorCode.cs
Normal file
199
MailServer/MailServer/DNS/DnsErrorCode.cs
Normal file
@ -0,0 +1,199 @@
|
||||
////using System;
|
||||
////using System.Collections.Generic;
|
||||
|
||||
////namespace DnsClient
|
||||
////{
|
||||
//// /*
|
||||
//// * Reference RFC6895#section-2.3
|
||||
//// *
|
||||
//// RCODE Name Description Reference
|
||||
//// Decimal
|
||||
//// Hexadecimal
|
||||
|
||||
//// 0 NoError No Error [RFC1035]
|
||||
//// 1 FormErr Format Error [RFC1035]
|
||||
//// 2 ServFail Server Failure [RFC1035]
|
||||
//// 3 NXDomain Non-Existent Domain [RFC1035]
|
||||
//// 4 NotImp Not Implemented [RFC1035]
|
||||
//// 5 Refused Query Refused [RFC1035]
|
||||
//// 6 YXDomain Name Exists when it should not [RFC2136]
|
||||
//// 7 YXRRSet RR Set Exists when it should not [RFC2136]
|
||||
//// 8 NXRRSet RR Set that should exist does not [RFC2136]
|
||||
//// 9 NotAuth Server Not Authoritative for zone [RFC2136]
|
||||
//// 9 NotAuth Not Authorized [RFC2845]
|
||||
//// 10 NotZone Name not contained in zone [RFC2136]
|
||||
|
||||
//// 11 - 15
|
||||
//// 0xB - 0xF Unassigned
|
||||
|
||||
//// 16 BADVERS Bad OPT Version [RFC6891]
|
||||
//// 16 BADSIG TSIG Signature Failure [RFC2845]
|
||||
//// 17 BADKEY Key not recognized [RFC2845]
|
||||
//// 18 BADTIME Signature out of time window [RFC2845]
|
||||
//// 19 BADMODE Bad TKEY Mode [RFC2930]
|
||||
//// 20 BADNAME Duplicate key name [RFC2930]
|
||||
//// 21 BADALG Algorithm not supported [RFC2930]
|
||||
//// 22 BADTRUNC Bad Truncation [RFC4635]
|
||||
|
||||
//// 23 - 3,840
|
||||
//// 0x0017 - 0x0F00 Unassigned
|
||||
|
||||
//// 3,841 - 4,095
|
||||
//// 0x0F01 - 0x0FFF Reserved for Private Use
|
||||
|
||||
//// 4,096 - 65,534
|
||||
//// 0x1000 - 0xFFFE Unassigned
|
||||
|
||||
//// 65,535
|
||||
//// 0xFFFF Reserved; can only be allocated by Standards
|
||||
//// Action.
|
||||
//// */
|
||||
|
||||
//// public enum DnsErrorCode : ushort
|
||||
//// {
|
||||
//// NoError = 0,
|
||||
//// FormErr = 1,
|
||||
//// ServFail = 2,
|
||||
//// NXDomain = 3,
|
||||
//// NotImp = 4,
|
||||
//// Refused = 5,
|
||||
//// YXDomain = 6,
|
||||
//// YXRRSet = 7,
|
||||
//// NXRRSet = 8,
|
||||
//// NotAuth = 9,
|
||||
//// NotZone = 10,
|
||||
//// BADVERS = 16, // or BADSIG
|
||||
//// BADKEY = 17,
|
||||
//// BADTIME = 18,
|
||||
//// BADMODE = 19,
|
||||
//// BADNAME = 20,
|
||||
//// BADALG = 21,
|
||||
//// BADTRUNC = 22,
|
||||
//// BADCOOKIE = 23,
|
||||
//// Unassigned = 666
|
||||
//// }
|
||||
|
||||
//// public static class DnsErrorCodeText
|
||||
//// {
|
||||
//// public const string BADALG = "Algorithm not supported";
|
||||
//// public const string BADCOOKIE = "Bad/missing Server Cookie";
|
||||
//// public const string BADKEY = "Key not recognized";
|
||||
//// public const string BADMODE = "Bad TKEY Mode";
|
||||
//// public const string BADNAME = "Duplicate key name";
|
||||
//// public const string BADSIG = "TSIG Signature Failure";
|
||||
//// public const string BADTIME = "Signature out of time window";
|
||||
//// public const string BADTRUNC = "Bad Truncation";
|
||||
//// public const string BADVERS = "Bad OPT Version";
|
||||
//// public const string FormErr = "Format Error";
|
||||
//// public const string NoError = "No Error";
|
||||
//// public const string NotAuth = "Server Not Authoritative for zone or Not Authorized";
|
||||
//// public const string NotImp = "Not Implemented";
|
||||
//// public const string NotZone = "Name not contained in zone";
|
||||
//// public const string NXDomain = "Non-Existent Domain";
|
||||
//// public const string NXRRSet = "RR Set that should exist does not";
|
||||
//// public const string Refused = "Query Refused";
|
||||
//// public const string ServFail = "Server Failure";
|
||||
//// public const string Unassigned = "Unknown Error";
|
||||
//// public const string YXDomain = "Name Exists when it should not";
|
||||
//// public const string YXRRSet = "RR Set Exists when it should not";
|
||||
|
||||
//// private static readonly Dictionary<DnsErrorCode, string> errors = new Dictionary<DnsErrorCode, string>()
|
||||
//// {
|
||||
//// { DnsErrorCode.NoError, DnsErrorCodeText.NoError },
|
||||
//// { DnsErrorCode.FormErr, DnsErrorCodeText.FormErr },
|
||||
//// { DnsErrorCode.ServFail, DnsErrorCodeText.ServFail },
|
||||
//// { DnsErrorCode.NXDomain, DnsErrorCodeText.NXDomain },
|
||||
//// { DnsErrorCode.NotImp, DnsErrorCodeText.NotImp },
|
||||
//// { DnsErrorCode.Refused, DnsErrorCodeText.Refused },
|
||||
//// { DnsErrorCode.YXDomain, DnsErrorCodeText.YXDomain },
|
||||
//// { DnsErrorCode.YXRRSet, DnsErrorCodeText.YXRRSet },
|
||||
//// { DnsErrorCode.NXRRSet, DnsErrorCodeText.NXRRSet },
|
||||
//// { DnsErrorCode.NotAuth, DnsErrorCodeText.NotAuth },
|
||||
//// { DnsErrorCode.NotZone, DnsErrorCodeText.NotZone },
|
||||
//// { DnsErrorCode.BADVERS, DnsErrorCodeText.BADVERS },
|
||||
//// { DnsErrorCode.BADKEY, DnsErrorCodeText.BADKEY },
|
||||
//// { DnsErrorCode.BADTIME, DnsErrorCodeText.BADTIME },
|
||||
//// { DnsErrorCode.BADMODE, DnsErrorCodeText.BADMODE },
|
||||
//// { DnsErrorCode.BADNAME, DnsErrorCodeText.BADNAME },
|
||||
//// { DnsErrorCode.BADALG, DnsErrorCodeText.BADALG },
|
||||
//// { DnsErrorCode.BADTRUNC, DnsErrorCodeText.BADTRUNC },
|
||||
//// { DnsErrorCode.BADCOOKIE, DnsErrorCodeText.BADCOOKIE },
|
||||
//// };
|
||||
|
||||
//// public static string GetErrorText(DnsErrorCode code)
|
||||
//// {
|
||||
//// if (!errors.ContainsKey(code))
|
||||
//// {
|
||||
//// return Unassigned;
|
||||
//// }
|
||||
|
||||
//// return errors[code];
|
||||
//// }
|
||||
//// }
|
||||
|
||||
//// public class DnsErrorException : Exception
|
||||
//// {
|
||||
//// public DnsErrorCode Code { get; }
|
||||
|
||||
//// public string DnsError { get; }
|
||||
|
||||
//// /// <summary>
|
||||
//// /// Creates an instance of <see cref="DnsErrorException"/> with <see cref="DnsErrorCode.Unassigned"/>.
|
||||
//// /// </summary>
|
||||
//// public DnsErrorException() : base(DnsErrorCodeText.Unassigned)
|
||||
//// {
|
||||
//// Code = DnsErrorCode.Unassigned;
|
||||
//// DnsError = DnsErrorCodeText.GetErrorText(Code);
|
||||
//// }
|
||||
|
||||
//// /// <summary>
|
||||
//// /// Creates an instance of <see cref="DnsErrorException"/> with <see cref="DnsErrorCode.Unassigned"/>
|
||||
//// /// and a custom message.
|
||||
//// /// </summary>
|
||||
//// public DnsErrorException(string message) : base(message)
|
||||
//// {
|
||||
//// Code = DnsErrorCode.Unassigned;
|
||||
//// DnsError = DnsErrorCodeText.GetErrorText(Code);
|
||||
//// }
|
||||
|
||||
//// /// <summary>
|
||||
//// /// Creates an instance of <see cref="DnsErrorException"/> with
|
||||
//// /// the standard error text for this <paramref name="code"/>.
|
||||
//// /// </summary>
|
||||
//// public DnsErrorException(DnsErrorCode code) : base(DnsErrorCodeText.GetErrorText(code))
|
||||
//// {
|
||||
//// Code = code;
|
||||
//// DnsError = DnsErrorCodeText.GetErrorText(Code);
|
||||
//// }
|
||||
|
||||
//// /// <summary>
|
||||
//// /// Creates an instance of <see cref="DnsErrorException"/> with <see cref="DnsErrorCode.Unassigned"/>
|
||||
//// /// and a custom message.
|
||||
//// /// </summary>
|
||||
//// public DnsErrorException(string message, Exception innerException) : base(message, innerException)
|
||||
//// {
|
||||
//// Code = DnsErrorCode.Unassigned;
|
||||
//// DnsError = DnsErrorCodeText.GetErrorText(Code);
|
||||
//// }
|
||||
|
||||
//// /// <summary>
|
||||
//// /// Creates an instance of <see cref="DnsErrorException"/> with a custom message
|
||||
//// /// and the given <paramref name="code"/>.
|
||||
//// /// </summary>
|
||||
//// public DnsErrorException(DnsErrorCode code, string message) : base(message)
|
||||
//// {
|
||||
//// Code = code;
|
||||
//// DnsError = DnsErrorCodeText.GetErrorText(Code);
|
||||
//// }
|
||||
|
||||
//// /// <summary>
|
||||
//// /// Creates an instance of <see cref="DnsErrorException"/> with a custom message
|
||||
//// /// and the given <paramref name="code"/>.
|
||||
//// /// </summary>
|
||||
//// public DnsErrorException(DnsErrorCode code, string message, Exception innerException) : base(message, innerException)
|
||||
//// {
|
||||
//// Code = code;
|
||||
//// DnsError = DnsErrorCodeText.GetErrorText(Code);
|
||||
//// }
|
||||
//// }
|
||||
////}
|
47
MailServer/MailServer/DNS/DnsHeaderFlag.cs
Normal file
47
MailServer/MailServer/DNS/DnsHeaderFlag.cs
Normal file
@ -0,0 +1,47 @@
|
||||
using System;
|
||||
|
||||
namespace DnsClient
|
||||
{
|
||||
/* Reference: https://tools.ietf.org/html/rfc6895#section-2
|
||||
* Response header fields
|
||||
*
|
||||
1 1 1 1 1 1
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| ID |
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
==> |QR| OpCode |AA|TC|RD|RA| Z|AD|CD| RCODE | <==
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| QDCOUNT/ZOCOUNT |
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| ANCOUNT/PRCOUNT |
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| NSCOUNT/UPCOUNT |
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| ARCOUNT |
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
|
||||
* */
|
||||
|
||||
/// <summary>
|
||||
/// The flags of the header's second 16bit value
|
||||
/// </summary>
|
||||
public enum DnsHeaderFlag : ushort
|
||||
{
|
||||
IsCheckingDisabled = 0x0010,
|
||||
IsAuthenticData = 0x0020,
|
||||
FutureUse = 0x0040, // Z bit seems to be ignored now, see https://tools.ietf.org/html/rfc6895#section-2.1
|
||||
RecursionAvailable = 0x0080,
|
||||
RecursionDesired = 0x0100,
|
||||
ResultTruncated = 0x0200,
|
||||
HasAuthorityAnswer = 0x0400,
|
||||
HasQuery = 0x8000,
|
||||
}
|
||||
|
||||
public static class DnsHeader
|
||||
{
|
||||
public static readonly ushort OPCODE_MASK = 0x7800;
|
||||
public static readonly ushort OPCODE_SHIFT = 11;
|
||||
public static readonly ushort RCODE_MASK = 0x000F;
|
||||
}
|
||||
}
|
101
MailServer/MailServer/DNS/DnsMessageHandler.cs
Normal file
101
MailServer/MailServer/DNS/DnsMessageHandler.cs
Normal file
@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using DnsClient.Protocol;
|
||||
|
||||
namespace DnsClient
|
||||
{
|
||||
public abstract class DnsMessageHandler : IDisposable
|
||||
{
|
||||
private bool _disposedValue = false;
|
||||
|
||||
public abstract Task<DnsResponseMessage> QueryAsync(IPEndPoint server, DnsRequestMessage request, CancellationToken cancellationToken);
|
||||
|
||||
public abstract bool IsTransientException<T>(T exception) where T : Exception;
|
||||
|
||||
public virtual byte[] GetRequestData(DnsRequestMessage request)
|
||||
{
|
||||
var question = request.Question;
|
||||
var questionData = question.QueryName.AsBytes();
|
||||
|
||||
// 4 more bytes for the type and class
|
||||
var writer = new DnsDatagramWriter(DnsRequestHeader.HeaderLength + questionData.Length + 4);
|
||||
|
||||
writer.SetInt16Network((short)request.Header.Id);
|
||||
writer.SetUInt16Network(request.Header.RawFlags);
|
||||
writer.SetInt16Network((short)request.Header.QuestionCount);
|
||||
|
||||
// jump to end of header, we didn't write all fields
|
||||
writer.Index = DnsRequestHeader.HeaderLength;
|
||||
|
||||
writer.SetBytes(questionData, questionData.Length);
|
||||
writer.SetUInt16Network((ushort)question.QuestionType);
|
||||
writer.SetUInt16Network((ushort)question.QuestionClass);
|
||||
|
||||
return writer.Data;
|
||||
}
|
||||
|
||||
public virtual DnsResponseMessage GetResponseMessage(byte[] responseData)
|
||||
{
|
||||
var reader = new DnsDatagramReader(responseData);
|
||||
var factory = new DnsRecordFactory(reader);
|
||||
|
||||
var id = reader.ReadUInt16Reverse();
|
||||
var flags = reader.ReadUInt16Reverse();
|
||||
var questionCount = reader.ReadUInt16Reverse();
|
||||
var answerCount = reader.ReadUInt16Reverse();
|
||||
var nameServerCount = reader.ReadUInt16Reverse();
|
||||
var additionalCount = reader.ReadUInt16Reverse();
|
||||
|
||||
var header = new DnsResponseHeader(id, flags, questionCount, answerCount, additionalCount, nameServerCount);
|
||||
var response = new DnsResponseMessage(header);
|
||||
|
||||
for (int questionIndex = 0; questionIndex < questionCount; questionIndex++)
|
||||
{
|
||||
var question = new DnsQuestion(reader.ReadName(), (QueryType)reader.ReadUInt16Reverse(), (QueryClass)reader.ReadUInt16Reverse());
|
||||
response.AddQuestion(question);
|
||||
}
|
||||
|
||||
for (int answerIndex = 0; answerIndex < answerCount; answerIndex++)
|
||||
{
|
||||
var info = factory.ReadRecordInfo();
|
||||
var record = factory.GetRecord(info);
|
||||
response.AddAnswer(record);
|
||||
}
|
||||
|
||||
for (int serverIndex = 0; serverIndex < nameServerCount; serverIndex++)
|
||||
{
|
||||
var info = factory.ReadRecordInfo();
|
||||
var record = factory.GetRecord(info);
|
||||
response.AddAuthority(record);
|
||||
}
|
||||
|
||||
for (int additionalIndex = 0; additionalIndex < additionalCount; additionalIndex++)
|
||||
{
|
||||
var info = factory.ReadRecordInfo();
|
||||
var record = factory.GetRecord(info);
|
||||
response.AddAdditional(record);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
}
|
||||
|
||||
_disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
}
|
||||
}
|
350
MailServer/MailServer/DNS/DnsName.cs
Normal file
350
MailServer/MailServer/DNS/DnsName.cs
Normal file
@ -0,0 +1,350 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace DnsClient
|
||||
{
|
||||
public class DnsName : IComparable
|
||||
{
|
||||
private const byte ReferenceByte = 0xc0;
|
||||
private List<string> _labels = new List<string>();
|
||||
private short _octets = 1;
|
||||
|
||||
public bool HasRootLabel => (_labels.Count > 0 && Get(0).Equals(""));
|
||||
|
||||
public bool IsEmpty => Size == 0;
|
||||
|
||||
public bool IsHostName => !_labels.Any(p => !IsHostNameLabel(p));
|
||||
|
||||
public int Octets => _octets;
|
||||
|
||||
public int Size => _labels.Where(p => p != "").Count();
|
||||
|
||||
/// <summary>
|
||||
/// Creates an empty <see cref="DnsName"/> instance.
|
||||
/// </summary>
|
||||
public DnsName()
|
||||
{
|
||||
Add(0, "");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="DnsName"/> by parsing the <paramref name="name"/>.
|
||||
/// </summary>
|
||||
/// <param name="name">The input name.</param>
|
||||
public DnsName(string name)
|
||||
{
|
||||
if (name == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(name));
|
||||
}
|
||||
|
||||
if (name.Length > 0)
|
||||
{
|
||||
Parse(name);
|
||||
}
|
||||
|
||||
if (!HasRootLabel) Add(0, "");
|
||||
}
|
||||
|
||||
public static DnsName FromBytes(byte[] data, ref int offset)
|
||||
{
|
||||
if (data == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(data));
|
||||
}
|
||||
if (offset > data.Length - 1)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(offset));
|
||||
}
|
||||
|
||||
var result = new DnsName();
|
||||
|
||||
// read the length byte for the label, then get the content from offset+1 to length
|
||||
// proceed till we reach zero length byte.
|
||||
byte length;
|
||||
while ((length = data[offset++]) != 0)
|
||||
{
|
||||
// respect the reference bit and lookup the name at the given position
|
||||
// the reader will advance only for the 2 bytes read.
|
||||
if ((length & ReferenceByte) != 0)
|
||||
{
|
||||
var subset = (length & 0x3f) << 8 | data[offset++];
|
||||
var subName = FromBytes(data, ref subset);
|
||||
result.Concat(subName);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (offset + length > data.Length - 1)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(data),
|
||||
$"Found invalid label position {offset - 1} or length {length} in the source data.");
|
||||
}
|
||||
|
||||
var label = Encoding.ASCII.GetString(data, offset, length);
|
||||
result.Add(1, label);
|
||||
offset += length;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void Add(int pos, string label)
|
||||
{
|
||||
if (label == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(label));
|
||||
}
|
||||
if (pos < 0 || pos > _labels.Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(pos));
|
||||
}
|
||||
// Check for empty labels: may have only one, and only at end.
|
||||
int len = label.Length;
|
||||
if ((pos > 0 && len == 0) ||
|
||||
(pos == 0 && HasRootLabel))
|
||||
{
|
||||
throw new InvalidOperationException("Empty label must be the last label in a domain name");
|
||||
}
|
||||
|
||||
// Total length must not be larger than 255 characters (including the ending zero).
|
||||
if (len > 0)
|
||||
{
|
||||
if (_octets + len + 1 >= 256)
|
||||
{
|
||||
throw new InvalidOperationException("Name too long");
|
||||
}
|
||||
_octets += (short)(len + 1);
|
||||
}
|
||||
|
||||
int i = _labels.Count - pos;
|
||||
VerifyLabel(label);
|
||||
_labels.Insert(i, label);
|
||||
}
|
||||
|
||||
public byte[] AsBytes()
|
||||
{
|
||||
var bytes = new byte[_octets];
|
||||
var offset = 0;
|
||||
for (int i = _labels.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var label = Get(i);
|
||||
|
||||
// should never cause issues as each label's length is limited to 64 chars.
|
||||
var len = checked((byte)label.Length);
|
||||
|
||||
// set the label length byte
|
||||
bytes[offset++] = len;
|
||||
|
||||
// set the label's content
|
||||
var labelBytes = Encoding.ASCII.GetBytes(label);
|
||||
Array.ConstrainedCopy(labelBytes, 0, bytes, offset, len);
|
||||
|
||||
offset += len;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return ToString().CompareTo(obj.ToString());
|
||||
}
|
||||
|
||||
public void Concat(DnsName other)
|
||||
{
|
||||
if (other == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(other));
|
||||
}
|
||||
|
||||
foreach (var label in other._labels.Where(p => !string.IsNullOrWhiteSpace(p)))
|
||||
{
|
||||
Add(1, label);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var otherName = obj as DnsName;
|
||||
if (otherName == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return CompareTo(otherName) == 0;
|
||||
}
|
||||
|
||||
public string Get(int pos)
|
||||
{
|
||||
if (pos < 0 || pos > _labels.Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(pos));
|
||||
}
|
||||
|
||||
return _labels[_labels.Count - pos - 1];
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return ToString().GetHashCode();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var buf = new StringBuilder();
|
||||
foreach (var label in _labels)
|
||||
{
|
||||
if (buf.Length > 0 || label.Length == 0)
|
||||
{
|
||||
buf.Append('.');
|
||||
}
|
||||
|
||||
Escaped(buf, label);
|
||||
}
|
||||
|
||||
var name = buf.ToString();
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
private static bool IsHostNameChar(char c)
|
||||
{
|
||||
return (c == '-' ||
|
||||
c >= 'a' && c <= 'z' ||
|
||||
c >= 'A' && c <= 'Z' ||
|
||||
c >= '0' && c <= '9');
|
||||
}
|
||||
|
||||
private static bool IsHostNameLabel(string label)
|
||||
{
|
||||
for (int i = 0; i < label.Length; i++)
|
||||
{
|
||||
char c = label.ElementAt(i);
|
||||
if (!IsHostNameChar(c))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return !(label.StartsWith("-") || label.EndsWith("-"));
|
||||
}
|
||||
|
||||
private static void VerifyLabel(string label)
|
||||
{
|
||||
// http://www.freesoft.org/CIE/RFC/1035/9.htm
|
||||
// dns name limits are 63octets per label
|
||||
// (63 letters).(63 letters).(63 letters).(62 letters)
|
||||
if (label.Length > 63)
|
||||
{
|
||||
throw new InvalidOperationException("Label exceeds 63 octets: " + label);
|
||||
}
|
||||
|
||||
// Check for two-byte characters.
|
||||
for (int i = 0; i < label.Length; i++)
|
||||
{
|
||||
char c = label.ElementAt(i);
|
||||
if ((c & 0xFF00) != 0)
|
||||
{
|
||||
throw new InvalidOperationException("Label has two-byte char: " + label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Escaped(StringBuilder buf, string label)
|
||||
{
|
||||
for (int i = 0; i < label.Length; i++)
|
||||
{
|
||||
char c = label.ElementAt(i);
|
||||
if (c == '.' || c == '\\')
|
||||
{
|
||||
buf.Append('\\');
|
||||
}
|
||||
|
||||
buf.Append(c);
|
||||
}
|
||||
}
|
||||
|
||||
private char GetEscaped(string domainName, int pos)
|
||||
{
|
||||
try
|
||||
{
|
||||
// assert (name.charAt(pos) == '\\');
|
||||
char c1 = domainName.ElementAt(++pos);
|
||||
if (IsDigit(c1))
|
||||
{
|
||||
// sequence is `\DDD'
|
||||
char c2 = domainName.ElementAt(++pos);
|
||||
char c3 = domainName.ElementAt(++pos);
|
||||
if (IsDigit(c2) && IsDigit(c3))
|
||||
{
|
||||
return (char)((c1 - '0') * 100 + (c2 - '0') * 10 + (c3 - '0'));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("Invalid escape sequence.", nameof(domainName));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return c1;
|
||||
}
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
{
|
||||
throw new ArgumentException("Invalid escape sequence.", nameof(domainName));
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsDigit(char c)
|
||||
{
|
||||
return (c >= '0' && c <= '9');
|
||||
}
|
||||
|
||||
private void Parse(string domainName)
|
||||
{
|
||||
var label = new StringBuilder();
|
||||
|
||||
for (int index = 0; index < domainName.Length; index++)
|
||||
{
|
||||
var c = domainName[index];
|
||||
|
||||
if (c == '\\')
|
||||
{
|
||||
c = GetEscaped(domainName, index++);
|
||||
if (IsDigit(domainName[index]))
|
||||
{
|
||||
index += 2;
|
||||
}
|
||||
|
||||
label.Append(c);
|
||||
}
|
||||
else if (c != '.')
|
||||
{
|
||||
label.Append(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
Add(0, label.ToString());
|
||||
label.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (label.Length > 0)
|
||||
{
|
||||
Add(0, label.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
66
MailServer/MailServer/DNS/DnsOpCode.cs
Normal file
66
MailServer/MailServer/DNS/DnsOpCode.cs
Normal file
@ -0,0 +1,66 @@
|
||||
using System;
|
||||
|
||||
namespace DnsClient
|
||||
{
|
||||
/*
|
||||
*
|
||||
* Reference: [RFC6895][RFC1035]
|
||||
0 Query [RFC1035]
|
||||
1 IQuery (Inverse Query, OBSOLETE) [RFC3425]
|
||||
2 Status [RFC1035]
|
||||
3 Unassigned
|
||||
4 Notify [RFC1996]
|
||||
5 Update [RFC2136]
|
||||
6-15 Unassigned
|
||||
* */
|
||||
|
||||
/// <summary>
|
||||
/// RFCs 1035, 1996, 2136, 3425.
|
||||
/// Specifies kind of query in this message.
|
||||
/// This value is set by the originator of a query and copied into the response.
|
||||
/// </summary>
|
||||
public enum DnsOpCode : short
|
||||
{
|
||||
/// <summary>
|
||||
/// RFC 1035.
|
||||
/// A standard query.
|
||||
/// </summary>
|
||||
Query,
|
||||
|
||||
/// <summary>
|
||||
/// RFC 3425.
|
||||
/// An inverse query.
|
||||
/// </summary>
|
||||
[Obsolete]
|
||||
IQuery,
|
||||
|
||||
/// <summary>
|
||||
/// RFC 1035.
|
||||
/// A server status request.
|
||||
/// </summary>
|
||||
Status,
|
||||
|
||||
Unassinged3,
|
||||
|
||||
/// <summary>
|
||||
/// RFC 1996.
|
||||
/// </summary>
|
||||
Notify,
|
||||
|
||||
/// <summary>
|
||||
/// RFC 2136.
|
||||
/// </summary>
|
||||
Update,
|
||||
|
||||
Unassinged6,
|
||||
Unassinged7,
|
||||
Unassinged8,
|
||||
Unassinged9,
|
||||
Unassinged10,
|
||||
Unassinged11,
|
||||
Unassinged12,
|
||||
Unassinged13,
|
||||
Unassinged14,
|
||||
Unassinged15,
|
||||
}
|
||||
}
|
117
MailServer/MailServer/DNS/DnsQueryResponse.cs
Normal file
117
MailServer/MailServer/DNS/DnsQueryResponse.cs
Normal file
@ -0,0 +1,117 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using DnsClient.Protocol;
|
||||
using DnsClient.Protocol.Record;
|
||||
|
||||
namespace DnsClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Immutable version of the <see cref="DnsResponseMessage"/>.
|
||||
/// </summary>
|
||||
public class DnsQueryResponse
|
||||
{
|
||||
private int? _hashCode;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of additional records.
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<DnsResourceRecord> Additionals { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all answers, addtional and authority records.
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<DnsResourceRecord> AllRecords
|
||||
{
|
||||
get
|
||||
{
|
||||
return Answers.Concat(Additionals).Concat(Authorities).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of answer records.
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<DnsResourceRecord> Answers { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of authority records.
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<DnsResourceRecord> Authorities { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string value representing the error response code in case an error occured, otherwise empty.
|
||||
/// </summary>
|
||||
public string ErrorMessage => HasError ? DnsResponseCodeText.GetErrorText(Header.ResponseCode) : string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// A flag indicating if the header contains a response codde other than <see cref="DnsResponseCode.NoError"/>.
|
||||
/// </summary>
|
||||
public bool HasError => Header?.ResponseCode != DnsResponseCode.NoError;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the header of the response.
|
||||
/// </summary>
|
||||
public DnsResponseHeader Header { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of questions.
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<DnsQuestion> Questions { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instace of <see cref="DnsQueryResponse"/>.
|
||||
/// </summary>
|
||||
/// <see cref="DnsResponseMessage"/>
|
||||
public DnsQueryResponse(
|
||||
DnsResponseHeader header,
|
||||
IReadOnlyCollection<DnsQuestion> questions,
|
||||
IReadOnlyCollection<DnsResourceRecord> answers,
|
||||
IReadOnlyCollection<DnsResourceRecord> additionals,
|
||||
IReadOnlyCollection<DnsResourceRecord> authorities)
|
||||
{
|
||||
if (header == null) throw new ArgumentNullException(nameof(header));
|
||||
if (questions == null) throw new ArgumentNullException(nameof(questions));
|
||||
if (answers == null) throw new ArgumentNullException(nameof(answers));
|
||||
if (additionals == null) throw new ArgumentNullException(nameof(additionals));
|
||||
if (authorities == null) throw new ArgumentNullException(nameof(authorities));
|
||||
|
||||
Header = header;
|
||||
Questions = questions;
|
||||
Answers = answers;
|
||||
Additionals = additionals;
|
||||
Authorities = authorities;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var response = obj as DnsQueryResponse;
|
||||
if (response == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return
|
||||
Header.ToString().Equals(response.Header.ToString())
|
||||
&& string.Join("", Questions).Equals(string.Join("", response.Questions))
|
||||
&& string.Join("", AllRecords).Equals(string.Join("", response.AllRecords));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int GetHashCode()
|
||||
{
|
||||
if (!_hashCode.HasValue)
|
||||
{
|
||||
_hashCode = (Header.ToString() + string.Join("", Questions) + string.Join("", AllRecords)).GetHashCode();
|
||||
}
|
||||
|
||||
return _hashCode.Value;
|
||||
}
|
||||
}
|
||||
}
|
40
MailServer/MailServer/DNS/DnsQuestion.cs
Normal file
40
MailServer/MailServer/DNS/DnsQuestion.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using System;
|
||||
|
||||
namespace DnsClient
|
||||
{
|
||||
public class DnsQuestion
|
||||
{
|
||||
public DnsName QueryName { get; }
|
||||
|
||||
public QueryClass QuestionClass { get; }
|
||||
|
||||
public QueryType QuestionType { get; }
|
||||
|
||||
public DnsQuestion(string queryName, QueryType questionType, QueryClass questionClass)
|
||||
: this(new DnsName(queryName), questionType, questionClass)
|
||||
{
|
||||
}
|
||||
|
||||
public DnsQuestion(DnsName queryName, QueryType questionType, QueryClass questionClass)
|
||||
{
|
||||
if (queryName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(queryName));
|
||||
}
|
||||
|
||||
QueryName = queryName;
|
||||
QuestionType = questionType;
|
||||
QuestionClass = questionClass;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return ToString(0);
|
||||
}
|
||||
|
||||
public string ToString(int offset = -32)
|
||||
{
|
||||
return string.Format("{0,"+offset+"} \t{1} \t{2}", QueryName, QuestionClass, QuestionType);
|
||||
}
|
||||
}
|
||||
}
|
75
MailServer/MailServer/DNS/DnsRequestHeader.cs
Normal file
75
MailServer/MailServer/DNS/DnsRequestHeader.cs
Normal file
@ -0,0 +1,75 @@
|
||||
namespace DnsClient
|
||||
{
|
||||
public class DnsRequestHeader
|
||||
{
|
||||
public const int HeaderLength = 12;
|
||||
|
||||
private ushort _flags = 0;
|
||||
|
||||
public ushort RawFlags => _flags;
|
||||
|
||||
public DnsHeaderFlag HeaderFlags
|
||||
{
|
||||
get
|
||||
{
|
||||
return (DnsHeaderFlag)_flags;
|
||||
}
|
||||
set
|
||||
{
|
||||
_flags &= (ushort)~(DnsHeaderFlag.IsCheckingDisabled);
|
||||
_flags &= (ushort)~(DnsHeaderFlag.IsAuthenticData);
|
||||
_flags &= (ushort)~(DnsHeaderFlag.FutureUse);
|
||||
_flags &= (ushort)~(DnsHeaderFlag.HasQuery);
|
||||
_flags &= (ushort)~(DnsHeaderFlag.HasAuthorityAnswer);
|
||||
_flags &= (ushort)~(DnsHeaderFlag.ResultTruncated);
|
||||
_flags &= (ushort)~(DnsHeaderFlag.RecursionDesired);
|
||||
_flags &= (ushort)~(DnsHeaderFlag.RecursionAvailable);
|
||||
_flags |= (ushort)value;
|
||||
}
|
||||
}
|
||||
|
||||
public int Id { get; set; }
|
||||
|
||||
public DnsOpCode OpCode
|
||||
{
|
||||
get
|
||||
{
|
||||
return (DnsOpCode)((DnsHeader.OPCODE_MASK & _flags) >> DnsHeader.OPCODE_SHIFT);
|
||||
}
|
||||
set
|
||||
{
|
||||
_flags &= (ushort)~(DnsHeader.OPCODE_MASK);
|
||||
_flags |= (ushort)(((ushort)value << DnsHeader.OPCODE_SHIFT) & DnsHeader.OPCODE_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
public int QuestionCount { get; set; }
|
||||
|
||||
public bool UseRecursion
|
||||
{
|
||||
get { return (HeaderFlags | DnsHeaderFlag.RecursionDesired) != 0; }
|
||||
set
|
||||
{
|
||||
HeaderFlags |= DnsHeaderFlag.RecursionDesired;
|
||||
}
|
||||
}
|
||||
|
||||
public DnsRequestHeader(int id, int questionCount, DnsOpCode queryKind)
|
||||
: this(id, questionCount, true, queryKind)
|
||||
{
|
||||
}
|
||||
|
||||
public DnsRequestHeader(int id, int questionCount, bool useRecursion, DnsOpCode queryKind)
|
||||
{
|
||||
Id = id;
|
||||
QuestionCount = questionCount;
|
||||
OpCode = queryKind;
|
||||
UseRecursion = useRecursion;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Id} - Qs: {QuestionCount} Recursion: {UseRecursion} OpCode: {OpCode}";
|
||||
}
|
||||
}
|
||||
}
|
261
MailServer/MailServer/DNS/DnsResponseCode.cs
Normal file
261
MailServer/MailServer/DNS/DnsResponseCode.cs
Normal file
@ -0,0 +1,261 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DnsClient
|
||||
{
|
||||
/*
|
||||
* Reference RFC6895#section-2.3
|
||||
*/
|
||||
// <summary>
|
||||
/// RFCs 1035, 2136, 2671, 2845, 2930, 4635.
|
||||
/// </summary>
|
||||
public enum DnsResponseCode : ushort
|
||||
{
|
||||
/// <summary>
|
||||
/// RFC 1035.
|
||||
/// No error condition
|
||||
/// </summary>
|
||||
NoError = 0,
|
||||
|
||||
/// <summary>
|
||||
/// RFC 1035.
|
||||
/// Format error. The name server was unable to interpret the query.
|
||||
/// </summary>
|
||||
FormatError = 1,
|
||||
|
||||
/// <summary>
|
||||
/// RFC 1035.
|
||||
/// Server failure. The name server was unable to process this query due to a problem with the name server.
|
||||
/// </summary>
|
||||
ServerFailure = 2,
|
||||
|
||||
/// <summary>
|
||||
/// RFC 1035.
|
||||
/// Name Error. Meaningful only for responses from an authoritative name server,
|
||||
/// this code signifies that the domain name referenced in the query does not exist.
|
||||
/// </summary>
|
||||
NotExistentDomain = 3,
|
||||
|
||||
/// <summary>
|
||||
/// RFC 1035.
|
||||
/// Not Implemented. The name server does not support the requested kind of query.
|
||||
/// </summary>
|
||||
NotImplemented = 4,
|
||||
|
||||
/// <summary>
|
||||
/// RFC 1035.
|
||||
/// Refused. The name server refuses to perform the specified operation for policy reasons.
|
||||
/// For example, a name server may not wish to provide the information to the particular requester,
|
||||
/// or a name server may not wish to perform a particular operation (e.g., zone transfer) for particular data.
|
||||
/// </summary>
|
||||
Refused = 5,
|
||||
|
||||
/// <summary>
|
||||
/// RFC 2136.
|
||||
/// Name Exists when it should not.
|
||||
/// </summary>
|
||||
ExistingDomain = 6,
|
||||
|
||||
/// <summary>
|
||||
/// RFC 2136.
|
||||
/// Resource record set exists when it should not.
|
||||
/// </summary>
|
||||
ExistingResourceRecordSet = 7,
|
||||
|
||||
/// <summary>
|
||||
/// RFC 2136.
|
||||
/// Resource record set that should exist but does not.
|
||||
/// </summary>
|
||||
MissingResourceRecordSet = 8,
|
||||
|
||||
/// <summary>
|
||||
/// RFC 2136 / RFC2845
|
||||
/// Server Not Authoritative for zone / Not Authorized.
|
||||
/// </summary>
|
||||
NotAuthorized = 9,
|
||||
|
||||
/// <summary>
|
||||
/// RFC 2136.
|
||||
/// Name not contained in zone.
|
||||
/// </summary>
|
||||
NotZone = 10,
|
||||
|
||||
/// <summary>
|
||||
/// RFCs 2671 / 2845.
|
||||
/// Bad OPT Version or TSIG Signature Failure.
|
||||
/// </summary>
|
||||
BadVersionOrBadSignature = 16,
|
||||
|
||||
/// <summary>
|
||||
/// RFC 2845.
|
||||
/// Key not recognized.
|
||||
/// </summary>
|
||||
BadKey = 17,
|
||||
|
||||
/// <summary>
|
||||
/// RFC 2845.
|
||||
/// Signature out of time window.
|
||||
/// </summary>
|
||||
BadTime = 18,
|
||||
|
||||
/// <summary>
|
||||
/// RFC 2930.
|
||||
/// Bad TKEY Mode.
|
||||
/// </summary>
|
||||
BadMode = 19,
|
||||
|
||||
/// <summary>
|
||||
/// RFC 2930.
|
||||
/// Duplicate key name.
|
||||
/// </summary>
|
||||
BadName = 20,
|
||||
|
||||
/// <summary>
|
||||
/// RFC 2930.
|
||||
/// Algorithm not supported.
|
||||
/// </summary>
|
||||
BadAlgorithm = 21,
|
||||
|
||||
/// <summary>
|
||||
/// RFC 4635.
|
||||
/// BADTRUNC - Bad Truncation.
|
||||
/// </summary>
|
||||
BadTruncation = 22,
|
||||
|
||||
/// <summary>
|
||||
/// RFC 7873
|
||||
/// Bad/missing Server Cookie
|
||||
/// </summary>
|
||||
BadCookie = 23,
|
||||
|
||||
/// <summary>
|
||||
/// Unknown error.
|
||||
/// </summary>
|
||||
Unassigned = 666
|
||||
}
|
||||
|
||||
|
||||
public static class DnsResponseCodeText
|
||||
{
|
||||
internal const string BADALG = "Algorithm not supported";
|
||||
internal const string BADCOOKIE = "Bad/missing Server Cookie";
|
||||
internal const string BADKEY = "Key not recognized";
|
||||
internal const string BADMODE = "Bad TKEY Mode";
|
||||
internal const string BADNAME = "Duplicate key name";
|
||||
internal const string BADSIG = "TSIG Signature Failure";
|
||||
internal const string BADTIME = "Signature out of time window";
|
||||
internal const string BADTRUNC = "Bad Truncation";
|
||||
internal const string BADVERS = "Bad OPT Version";
|
||||
internal const string FormErr = "Format Error";
|
||||
internal const string NoError = "No Error";
|
||||
internal const string NotAuth = "Server Not Authoritative for zone or Not Authorized";
|
||||
internal const string NotImp = "Not Implemented";
|
||||
internal const string NotZone = "Name not contained in zone";
|
||||
internal const string NXDomain = "Non-Existent Domain";
|
||||
internal const string NXRRSet = "RR Set that should exist does not";
|
||||
internal const string Refused = "Query Refused";
|
||||
internal const string ServFail = "Server Failure";
|
||||
internal const string Unassigned = "Unknown Error";
|
||||
internal const string YXDomain = "Name Exists when it should not";
|
||||
internal const string YXRRSet = "RR Set Exists when it should not";
|
||||
|
||||
private static readonly Dictionary<DnsResponseCode, string> errors = new Dictionary<DnsResponseCode, string>()
|
||||
{
|
||||
{ DnsResponseCode.NoError, DnsResponseCodeText.NoError },
|
||||
{ DnsResponseCode.FormatError, DnsResponseCodeText.FormErr },
|
||||
{ DnsResponseCode.ServerFailure, DnsResponseCodeText.ServFail },
|
||||
{ DnsResponseCode.NotExistentDomain, DnsResponseCodeText.NXDomain },
|
||||
{ DnsResponseCode.NotImplemented, DnsResponseCodeText.NotImp },
|
||||
{ DnsResponseCode.Refused, DnsResponseCodeText.Refused },
|
||||
{ DnsResponseCode.ExistingDomain, DnsResponseCodeText.YXDomain },
|
||||
{ DnsResponseCode.ExistingResourceRecordSet, DnsResponseCodeText.YXRRSet },
|
||||
{ DnsResponseCode.MissingResourceRecordSet, DnsResponseCodeText.NXRRSet },
|
||||
{ DnsResponseCode.NotAuthorized, DnsResponseCodeText.NotAuth },
|
||||
{ DnsResponseCode.NotZone, DnsResponseCodeText.NotZone },
|
||||
{ DnsResponseCode.BadVersionOrBadSignature, DnsResponseCodeText.BADVERS },
|
||||
{ DnsResponseCode.BadKey, DnsResponseCodeText.BADKEY },
|
||||
{ DnsResponseCode.BadTime, DnsResponseCodeText.BADTIME },
|
||||
{ DnsResponseCode.BadMode, DnsResponseCodeText.BADMODE },
|
||||
{ DnsResponseCode.BadName, DnsResponseCodeText.BADNAME },
|
||||
{ DnsResponseCode.BadAlgorithm, DnsResponseCodeText.BADALG },
|
||||
{ DnsResponseCode.BadTruncation, DnsResponseCodeText.BADTRUNC },
|
||||
{ DnsResponseCode.BadCookie, DnsResponseCodeText.BADCOOKIE },
|
||||
};
|
||||
|
||||
public static string GetErrorText(DnsResponseCode code)
|
||||
{
|
||||
if (!errors.ContainsKey(code))
|
||||
{
|
||||
return Unassigned;
|
||||
}
|
||||
|
||||
return errors[code];
|
||||
}
|
||||
}
|
||||
|
||||
public class DnsResponseException : Exception
|
||||
{
|
||||
public DnsResponseCode Code { get; }
|
||||
|
||||
public string DnsError { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of <see cref="DnsResponseException"/> with <see cref="DnsResponseCode.Unassigned"/>.
|
||||
/// </summary>
|
||||
public DnsResponseException() : base(DnsResponseCodeText.Unassigned)
|
||||
{
|
||||
Code = DnsResponseCode.Unassigned;
|
||||
DnsError = DnsResponseCodeText.GetErrorText(Code);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of <see cref="DnsResponseException"/> with <see cref="DnsResponseCode.Unassigned"/>
|
||||
/// and a custom message.
|
||||
/// </summary>
|
||||
public DnsResponseException(string message) : base(message)
|
||||
{
|
||||
Code = DnsResponseCode.Unassigned;
|
||||
DnsError = DnsResponseCodeText.GetErrorText(Code);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of <see cref="DnsResponseException"/> with
|
||||
/// the standard error text for this <paramref name="code"/>.
|
||||
/// </summary>
|
||||
public DnsResponseException(DnsResponseCode code) : base(DnsResponseCodeText.GetErrorText(code))
|
||||
{
|
||||
Code = code;
|
||||
DnsError = DnsResponseCodeText.GetErrorText(Code);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of <see cref="DnsResponseException"/> with <see cref="DnsResponseCode.Unassigned"/>
|
||||
/// and a custom message.
|
||||
/// </summary>
|
||||
public DnsResponseException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
Code = DnsResponseCode.Unassigned;
|
||||
DnsError = DnsResponseCodeText.GetErrorText(Code);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of <see cref="DnsResponseException"/> with a custom message
|
||||
/// and the given <paramref name="code"/>.
|
||||
/// </summary>
|
||||
public DnsResponseException(DnsResponseCode code, string message) : base(message)
|
||||
{
|
||||
Code = code;
|
||||
DnsError = DnsResponseCodeText.GetErrorText(Code);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of <see cref="DnsResponseException"/> with a custom message
|
||||
/// and the given <paramref name="code"/>.
|
||||
/// </summary>
|
||||
public DnsResponseException(DnsResponseCode code, string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
Code = code;
|
||||
DnsError = DnsResponseCodeText.GetErrorText(Code);
|
||||
}
|
||||
}
|
||||
}
|
57
MailServer/MailServer/DNS/DnsResponseHeader.cs
Normal file
57
MailServer/MailServer/DNS/DnsResponseHeader.cs
Normal file
@ -0,0 +1,57 @@
|
||||
namespace DnsClient
|
||||
{
|
||||
public class DnsResponseHeader
|
||||
{
|
||||
private readonly ushort _flags = 0;
|
||||
|
||||
public int AdditionalCount { get; }
|
||||
|
||||
public int AnswerCount { get; }
|
||||
|
||||
public bool FutureUse => HasFlag(DnsHeaderFlag.FutureUse);
|
||||
|
||||
public bool HasAuthorityAnswer => HasFlag(DnsHeaderFlag.HasAuthorityAnswer);
|
||||
|
||||
public DnsHeaderFlag HeaderFlags => (DnsHeaderFlag)_flags;
|
||||
|
||||
public int Id { get; }
|
||||
|
||||
public bool IsAuthenticData => HasFlag(DnsHeaderFlag.IsAuthenticData);
|
||||
|
||||
public bool IsCheckingDisabled => HasFlag(DnsHeaderFlag.IsCheckingDisabled);
|
||||
|
||||
public bool HasQuery => HasFlag(DnsHeaderFlag.HasQuery);
|
||||
|
||||
public int NameServerCount { get; }
|
||||
|
||||
public DnsOpCode OPCode => (DnsOpCode)((DnsHeader.OPCODE_MASK & _flags) >> DnsHeader.OPCODE_SHIFT);
|
||||
|
||||
public int QuestionCount { get; }
|
||||
|
||||
public bool RecursionAvailable => HasFlag(DnsHeaderFlag.RecursionAvailable);
|
||||
|
||||
public DnsResponseCode ResponseCode => (DnsResponseCode)(_flags & DnsHeader.RCODE_MASK);
|
||||
|
||||
////ResponseCode {set
|
||||
////{
|
||||
//// _flags &= (ushort)~(DnsHeader.RCODE_MASK);
|
||||
//// _flags |= (ushort)((ushort)value & DnsHeader.RCODE_MASK);
|
||||
////}}
|
||||
|
||||
public bool ResultTruncated => HasFlag(DnsHeaderFlag.ResultTruncated);
|
||||
|
||||
public bool RecursionDesired => HasFlag(DnsHeaderFlag.RecursionDesired);
|
||||
|
||||
public DnsResponseHeader(int id, ushort flags, int questionCount, int answerCount, int additionalCount, int serverCount)
|
||||
{
|
||||
Id = id;
|
||||
_flags = flags;
|
||||
QuestionCount = questionCount;
|
||||
AnswerCount = answerCount;
|
||||
AdditionalCount = additionalCount;
|
||||
NameServerCount = serverCount;
|
||||
}
|
||||
|
||||
private bool HasFlag(DnsHeaderFlag flag) => (HeaderFlags & flag) != 0;
|
||||
}
|
||||
}
|
64
MailServer/MailServer/DNS/DnsUdpMessageHandler.cs
Normal file
64
MailServer/MailServer/DNS/DnsUdpMessageHandler.cs
Normal file
@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using DnsClient.Protocol;
|
||||
|
||||
namespace DnsClient
|
||||
{
|
||||
public class DnsUdpMessageHandler : DnsMessageHandler, IDisposable
|
||||
{
|
||||
private readonly UdpClient _client = new UdpClient();
|
||||
private bool _disposedValue = false;
|
||||
|
||||
public override bool IsTransientException<T>(T exception)
|
||||
{
|
||||
Debug.WriteLine("Check transient {0}.", exception);
|
||||
if (exception is SocketException) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override async Task<DnsResponseMessage> QueryAsync(
|
||||
IPEndPoint server,
|
||||
DnsRequestMessage request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
//using (var udpClient = new UdpClient())
|
||||
//{
|
||||
var data = GetRequestData(request);
|
||||
await _client.SendAsync(data, data.Length, server);
|
||||
|
||||
var result = await _client.ReceiveAsync();
|
||||
|
||||
var response = GetResponseMessage(result.Buffer);
|
||||
|
||||
if (request.Header.Id != response.Header.Id)
|
||||
{
|
||||
throw new DnsResponseException("Header id missmatch.");
|
||||
}
|
||||
|
||||
return response;
|
||||
//}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_client.Dispose();
|
||||
}
|
||||
|
||||
_disposedValue = true;
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
368
MailServer/MailServer/DNS/LookupClient.cs
Normal file
368
MailServer/MailServer/DNS/LookupClient.cs
Normal file
@ -0,0 +1,368 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using DnsClient.Protocol;
|
||||
|
||||
namespace DnsClient
|
||||
{
|
||||
public class LookupClient : IDisposable
|
||||
{
|
||||
private static readonly TimeSpan s_defaultTimeout = TimeSpan.FromSeconds(5);
|
||||
private static readonly TimeSpan s_infiniteTimeout = System.Threading.Timeout.InfiniteTimeSpan;
|
||||
private static readonly TimeSpan s_maxTimeout = TimeSpan.FromMilliseconds(int.MaxValue);
|
||||
private static ushort _uniqueId = 0;
|
||||
private readonly ResponseCache _cache = new ResponseCache(true);
|
||||
private readonly object _endpointLock = new object();
|
||||
private readonly DnsMessageHandler _messageHandler;
|
||||
private Queue<EndPointInfo> _endpoints;
|
||||
private TimeSpan _timeout = s_defaultTimeout;
|
||||
private bool _disposedValue = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of configured name servers.
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<IPEndPoint> NameServers { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or set a flag indicating if recursion should be enabled for DNS queries.
|
||||
/// </summary>
|
||||
public bool Recursion { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets number of tries to connect to one name server before trying the next one or throwing an exception.
|
||||
/// </summary>
|
||||
public int Retries { get; set; } = 5;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a flag indicating if the <see cref="LookupClient"/> should throw an <see cref="DnsResponseException"/>
|
||||
/// if the returned result contains an error flag other than <see cref="DnsResponseCode.NoError"/>.
|
||||
/// (The default behavior is <c>False</c>).
|
||||
/// </summary>
|
||||
public bool ThrowDnsErrors { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets timeout in milliseconds.
|
||||
/// Timeout must be greater than zero and less than <see cref="int.MaxValue"/>.
|
||||
/// </summary>
|
||||
public TimeSpan Timeout
|
||||
{
|
||||
get { return _timeout; }
|
||||
set
|
||||
{
|
||||
if ((value <= TimeSpan.Zero || value > s_maxTimeout) && value != s_infiniteTimeout)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(value));
|
||||
}
|
||||
|
||||
_timeout = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a flag indicating if the <see cref="LookupClient"/> should use caching or not.
|
||||
/// The TTL of cached results is defined by each resource record individually.
|
||||
/// </summary>
|
||||
public bool UseCache
|
||||
{
|
||||
get
|
||||
{
|
||||
return _cache.Enabled;
|
||||
}
|
||||
set
|
||||
{
|
||||
_cache.Enabled = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a <see cref="TimeSpan"/> which can override the TTL of a resource record in case the
|
||||
/// TTL of the record is lower than this minimum value.
|
||||
/// This is useful in cases where the server retruns a zero TTL and the record should be cached for a
|
||||
/// very short duration anyways.
|
||||
///
|
||||
/// This setting gets igonred in case <see cref="UseCache"/> is set to <c>False</c>.
|
||||
/// </summary>
|
||||
public TimeSpan? MimimumCacheTimeout
|
||||
{
|
||||
get
|
||||
{
|
||||
return _cache.MinimumTimout;
|
||||
}
|
||||
set
|
||||
{
|
||||
_cache.MinimumTimout = value;
|
||||
}
|
||||
}
|
||||
|
||||
public LookupClient()
|
||||
: this(NameServer.ResolveNameServers().ToArray())
|
||||
{
|
||||
}
|
||||
|
||||
public LookupClient(params IPEndPoint[] nameServers)
|
||||
: this(new DnsUdpMessageHandler(), nameServers)
|
||||
{
|
||||
}
|
||||
|
||||
public LookupClient(params IPAddress[] nameServers)
|
||||
: this(
|
||||
new DnsUdpMessageHandler(),
|
||||
nameServers.Select(p => new IPEndPoint(p, NameServer.DefaultPort)).ToArray())
|
||||
{
|
||||
}
|
||||
|
||||
public LookupClient(DnsMessageHandler messageHandler, ICollection<IPEndPoint> nameServers)
|
||||
{
|
||||
if (messageHandler == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(messageHandler));
|
||||
}
|
||||
if (nameServers == null || nameServers.Count == 0)
|
||||
{
|
||||
throw new ArgumentException("At least one name server must be configured.", nameof(nameServers));
|
||||
}
|
||||
|
||||
NameServers = nameServers.ToArray();
|
||||
_endpoints = new Queue<EndPointInfo>();
|
||||
foreach (var server in NameServers)
|
||||
{
|
||||
_endpoints.Enqueue(new EndPointInfo(server));
|
||||
}
|
||||
_messageHandler = messageHandler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Translates the IPV4 or IPV6 address into an arpa address.
|
||||
/// </summary>
|
||||
/// <param name="ip">IP address to get the arpa address form</param>
|
||||
/// <returns>The mirrored IPV4 or IPV6 arpa address</returns>
|
||||
public static string GetArpaName(IPAddress ip)
|
||||
{
|
||||
var bytes = ip.GetAddressBytes();
|
||||
Array.Reverse(bytes);
|
||||
|
||||
// check IP6
|
||||
if (ip.AddressFamily == AddressFamily.InterNetworkV6)
|
||||
{
|
||||
// reveresed bytes need to be split into 4 bit parts and separated by '.'
|
||||
var newBytes = bytes
|
||||
.SelectMany(b => new[] { (b >> 0) & 0xf, (b >> 4) & 0xf })
|
||||
.Aggregate(new StringBuilder(), (s, b) => s.Append(b.ToString("x")).Append(".")) + "ip6.arpa.";
|
||||
|
||||
return newBytes;
|
||||
}
|
||||
else if (ip.AddressFamily == AddressFamily.InterNetwork)
|
||||
{
|
||||
// else IP4
|
||||
return string.Join(".", bytes) + ".in-addr.arpa.";
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Not a valid IP4 or IP6 address.");
|
||||
}
|
||||
|
||||
public Task<DnsQueryResponse> QueryAsync(string query, QueryType queryType)
|
||||
=> QueryAsync(query, queryType, CancellationToken.None);
|
||||
|
||||
public Task<DnsQueryResponse> QueryAsync(string query, QueryType queryType, CancellationToken cancellationToken)
|
||||
=> QueryAsync(query, queryType, QueryClass.IN, cancellationToken);
|
||||
|
||||
public Task<DnsQueryResponse> QueryAsync(string query, QueryType queryType, QueryClass queryClass)
|
||||
=> QueryAsync(query, queryType, queryClass, CancellationToken.None);
|
||||
|
||||
public Task<DnsQueryResponse> QueryAsync(string query, QueryType queryType, QueryClass queryClass, CancellationToken cancellationToken)
|
||||
=> QueryAsync(new DnsQuestion(query, queryType, queryClass), cancellationToken);
|
||||
|
||||
////public Task<DnsQueryResponse> QueryAsync(params DnsQuestion[] questions)
|
||||
//// => QueryAsync(CancellationToken.None, questions);
|
||||
|
||||
private async Task<DnsQueryResponse> QueryAsync(DnsQuestion question, CancellationToken cancellationToken)
|
||||
{
|
||||
if (question == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(question));
|
||||
}
|
||||
|
||||
var head = new DnsRequestHeader(GetNextUniqueId(), 1, Recursion, DnsOpCode.Query);
|
||||
var request = new DnsRequestMessage(head, question);
|
||||
var cacheKey = ResponseCache.GetCacheKey(question);
|
||||
var result = await _cache.GetOrAdd(cacheKey, async () => await ResolveQueryAsync(request, cancellationToken));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Task<DnsQueryResponse> QueryReverseAsync(IPAddress ipAddress)
|
||||
=> QueryReverseAsync(ipAddress, CancellationToken.None);
|
||||
|
||||
public Task<DnsQueryResponse> QueryReverseAsync(IPAddress ipAddress, CancellationToken cancellationToken)
|
||||
{
|
||||
if (ipAddress == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(ipAddress));
|
||||
}
|
||||
|
||||
var arpa = GetArpaName(ipAddress);
|
||||
return QueryAsync(arpa, QueryType.PTR, QueryClass.IN, cancellationToken);
|
||||
}
|
||||
|
||||
private static ushort GetNextUniqueId()
|
||||
{
|
||||
if (_uniqueId == ushort.MaxValue || _uniqueId == 0)
|
||||
{
|
||||
_uniqueId = (ushort)(new Random()).Next(ushort.MaxValue / 2);
|
||||
}
|
||||
|
||||
return _uniqueId++;
|
||||
}
|
||||
|
||||
// TODO: TCP fallback on truncates
|
||||
// TODO: most popular DNS servers do not support mulitple queries in one packet, therefore, split it into multiple requests?
|
||||
//private async Task<DnsQueryResponse> QueryAsync(DnsRequestMessage request, CancellationToken cancellationToken)
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
private async Task<DnsQueryResponse> ResolveQueryAsync(DnsRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
if (request == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(request));
|
||||
}
|
||||
|
||||
for (int index = 0; index < NameServers.Count; index++)
|
||||
{
|
||||
EndPointInfo serverInfo = null;
|
||||
lock (_endpointLock)
|
||||
{
|
||||
while (_endpoints.Count > 0 && serverInfo == null)
|
||||
{
|
||||
serverInfo = _endpoints.Dequeue();
|
||||
|
||||
if (serverInfo.IsDisabled)
|
||||
{
|
||||
serverInfo = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// put it back and then use it..
|
||||
_endpoints.Enqueue(serverInfo);
|
||||
}
|
||||
}
|
||||
|
||||
if (serverInfo == null)
|
||||
{
|
||||
// let's be optimistic and eable them again, maybe they wher offline one for a while
|
||||
_endpoints.ToList().ForEach(p => p.IsDisabled = false);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
var tries = 0;
|
||||
do
|
||||
{
|
||||
tries++;
|
||||
try
|
||||
{
|
||||
DnsResponseMessage response;
|
||||
var resultTask = _messageHandler.QueryAsync(serverInfo.Endpoint, request, cancellationToken);
|
||||
if (Timeout != s_infiniteTimeout)
|
||||
{
|
||||
response = await resultTask.TimeoutAfter(Timeout);
|
||||
}
|
||||
|
||||
response = await resultTask;
|
||||
|
||||
var result = response.AsReadonly;
|
||||
|
||||
if (ThrowDnsErrors && result.Header.ResponseCode != DnsResponseCode.NoError)
|
||||
{
|
||||
throw new DnsResponseException(result.Header.ResponseCode);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (DnsResponseException)
|
||||
{
|
||||
// occurs only if the option to throw dns exceptions is enabled on the lookup client. (see above).
|
||||
// lets not mess with the stack
|
||||
throw;
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
// do nothing... transient if timeoutAfter timed out
|
||||
}
|
||||
catch (SocketException ex) when (ex.SocketErrorCode == SocketError.AddressFamilyNotSupported)
|
||||
{
|
||||
// this socket error might indicate the server endpoint is actually bad and should be ignored in future queries.
|
||||
serverInfo.IsDisabled = true;
|
||||
Debug.WriteLine($"Disabling name server {serverInfo.Endpoint}.");
|
||||
break;
|
||||
}
|
||||
catch (Exception ex) when (_messageHandler.IsTransientException(ex))
|
||||
{
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var agg = ex as AggregateException;
|
||||
if (agg != null)
|
||||
{
|
||||
agg.Handle(e =>
|
||||
{
|
||||
if (e is TimeoutException) return true;
|
||||
if (_messageHandler.IsTransientException(e)) return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
throw new DnsResponseException("Unhandled exception", agg.InnerException);
|
||||
}
|
||||
|
||||
throw new DnsResponseException("Unhandled exception", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// do cleanup stuff or logging?
|
||||
}
|
||||
} while (tries <= Retries && !cancellationToken.IsCancellationRequested);
|
||||
}
|
||||
|
||||
throw new DnsResponseException($"No connection could be established to any of the following name servers: {string.Join(", ", NameServers)}.");
|
||||
}
|
||||
|
||||
private class EndPointInfo
|
||||
{
|
||||
public IPEndPoint Endpoint { get; }
|
||||
|
||||
public bool IsDisabled { get; set; }
|
||||
|
||||
public EndPointInfo(IPEndPoint endpoint)
|
||||
{
|
||||
Endpoint = endpoint;
|
||||
IsDisabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_messageHandler.Dispose();
|
||||
}
|
||||
|
||||
_disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
}
|
||||
}
|
44
MailServer/MailServer/DNS/NameServer.cs
Normal file
44
MailServer/MailServer/DNS/NameServer.cs
Normal file
@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
|
||||
namespace DnsClient
|
||||
{
|
||||
public class NameServer
|
||||
{
|
||||
/// <summary>
|
||||
/// The default DNS server port.
|
||||
/// </summary>
|
||||
public const int DefaultPort = 53;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of name servers by iterating over the available network interfaces.
|
||||
/// </summary>
|
||||
/// <returns>The list of name servers.</returns>
|
||||
public static ICollection<IPEndPoint> ResolveNameServers()
|
||||
{
|
||||
var result = new HashSet<IPEndPoint>();
|
||||
|
||||
var adapters = NetworkInterface.GetAllNetworkInterfaces();
|
||||
foreach (NetworkInterface networkInterface in
|
||||
adapters
|
||||
.Where(p => p.OperationalStatus == OperationalStatus.Up
|
||||
&& p.NetworkInterfaceType != NetworkInterfaceType.Loopback))
|
||||
{
|
||||
foreach (IPAddress dnsAddress in networkInterface
|
||||
.GetIPProperties()
|
||||
.DnsAddresses
|
||||
.Where(i =>
|
||||
i.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork
|
||||
|| i.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6))
|
||||
{
|
||||
result.Add(new IPEndPoint(dnsAddress, DefaultPort));
|
||||
}
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
135
MailServer/MailServer/DNS/Protocol/DnsDatagramReader.cs
Normal file
135
MailServer/MailServer/DNS/Protocol/DnsDatagramReader.cs
Normal file
@ -0,0 +1,135 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
namespace DnsClient.Protocol
|
||||
{
|
||||
public class DnsDatagramReader
|
||||
{
|
||||
private readonly byte[] _data;
|
||||
private int _index;
|
||||
|
||||
public int Index
|
||||
{
|
||||
get
|
||||
{
|
||||
return _index;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value < 0 || value > _data.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(value));
|
||||
}
|
||||
|
||||
_index = value;
|
||||
}
|
||||
}
|
||||
|
||||
public DnsDatagramReader(byte[] data, int startIndex = 0)
|
||||
{
|
||||
_data = data;
|
||||
Index = startIndex;
|
||||
}
|
||||
|
||||
/*
|
||||
https://tools.ietf.org/html/rfc1035#section-3.3:
|
||||
<character-string> is a single
|
||||
length octet followed by that number of characters. <character-string>
|
||||
is treated as binary information, and can be up to 256 characters in
|
||||
length (including the length octet).
|
||||
* */
|
||||
/// <summary>
|
||||
/// Reads the single length octet and the following characters as ASCII text.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string ReadString()
|
||||
{
|
||||
var length = ReadByte();
|
||||
|
||||
var result = Encoding.ASCII.GetString(_data, _index, length);
|
||||
_index += length;
|
||||
return result;
|
||||
}
|
||||
|
||||
public byte ReadByte()
|
||||
{
|
||||
if (_index >= _data.Length)
|
||||
{
|
||||
throw new IndexOutOfRangeException("Cannot read byte.");
|
||||
}
|
||||
else
|
||||
{
|
||||
return _data[_index++];
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] ReadBytes(int length)
|
||||
{
|
||||
if (_data.Length < _index + length)
|
||||
{
|
||||
throw new IndexOutOfRangeException($"Cannot read that many bytes: '{length}'.");
|
||||
}
|
||||
|
||||
var result = new byte[length];
|
||||
Array.Copy(_data, _index, result, 0, length);
|
||||
_index += length;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an IP address from the next 4 bytes.
|
||||
/// </summary>
|
||||
/// <returns>The <see cref="IPAddress"/>.</returns>
|
||||
/// <exception cref="IndexOutOfRangeException">If there are no 4 bytes to read.</exception>
|
||||
public IPAddress ReadIPAddress()
|
||||
{
|
||||
if (_data.Length < _index + 4)
|
||||
{
|
||||
throw new IndexOutOfRangeException("IPAddress expected exactly 4 bytes.");
|
||||
}
|
||||
|
||||
return new IPAddress(ReadBytes(4));
|
||||
}
|
||||
|
||||
public IPAddress ReadIPv6Address()
|
||||
{
|
||||
var address = new IPAddress(ReadBytes(8 * 2));
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
public DnsName ReadName()
|
||||
{
|
||||
return DnsName.FromBytes(_data, ref _index);
|
||||
}
|
||||
|
||||
public ushort ReadUInt16()
|
||||
{
|
||||
if (_data.Length < Index + 2)
|
||||
{
|
||||
throw new IndexOutOfRangeException("Cannot read more data.");
|
||||
}
|
||||
|
||||
var result = BitConverter.ToUInt16(_data, _index);
|
||||
_index += 2;
|
||||
return result;
|
||||
}
|
||||
|
||||
public ushort ReadUInt16Reverse()
|
||||
{
|
||||
if (_data.Length < Index + 2)
|
||||
{
|
||||
throw new IndexOutOfRangeException("Cannot read more data.");
|
||||
}
|
||||
|
||||
byte a = _data[_index++], b = _data[_index++];
|
||||
return (ushort)(a << 8 | b);
|
||||
}
|
||||
|
||||
public uint ReadUInt32Reverse()
|
||||
{
|
||||
return (uint)(ReadUInt16Reverse() << 16 | ReadUInt16Reverse());
|
||||
}
|
||||
}
|
||||
}
|
113
MailServer/MailServer/DNS/Protocol/DnsDatagramWriter.cs
Normal file
113
MailServer/MailServer/DNS/Protocol/DnsDatagramWriter.cs
Normal file
@ -0,0 +1,113 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace DnsClient.Protocol
|
||||
{
|
||||
public class DnsDatagramWriter
|
||||
{
|
||||
private byte[] _buffer;
|
||||
|
||||
public byte[] Data => _buffer;
|
||||
|
||||
public int Index { get; set; }
|
||||
|
||||
public DnsDatagramWriter(int length)
|
||||
{
|
||||
_buffer = new byte[length];
|
||||
}
|
||||
|
||||
private DnsDatagramWriter(byte[] data, int newLength)
|
||||
{
|
||||
if (data.Length > newLength)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(newLength));
|
||||
}
|
||||
|
||||
_buffer = new byte[newLength];
|
||||
Array.Copy(data, _buffer, data.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new writer instance with a new length.
|
||||
/// </summary>
|
||||
/// <param name="byLength">The amount of bytes the current buffer should be extended by.</param>
|
||||
/// <returns>A new writer.</returns>
|
||||
public void Extend(int byLength)
|
||||
{
|
||||
if (byLength <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(byLength));
|
||||
}
|
||||
|
||||
var fullLength = byLength + _buffer.Length;
|
||||
var newBuffer = new byte[fullLength];
|
||||
Array.Copy(_buffer, 0, newBuffer, 0, _buffer.Length);
|
||||
//return new DnsDatagramWriter(newBuffer, fullLength) { Offset = Offset };
|
||||
_buffer = newBuffer;
|
||||
}
|
||||
|
||||
public void SetBytes(byte[] data, int length) => SetBytes(data, 0, Index, length);
|
||||
|
||||
public void SetInt(int value) => SetInt(value, Index);
|
||||
|
||||
public void SetInt16(short value) => SetInt16(value, Index);
|
||||
|
||||
public void SetInt16Network(short value) => SetInt16Network(value, Index);
|
||||
|
||||
public void SetUInt32Network(uint value)
|
||||
{
|
||||
var bytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((int)value));
|
||||
SetBytes(bytes, Index, bytes.Length);
|
||||
}
|
||||
|
||||
public void SetIntNetwork(int value) => SetIntNetwork(value, Index);
|
||||
|
||||
public void SetUInt16(ushort value) => SetInt16((short)value, Index);
|
||||
|
||||
public void SetUInt16Network(ushort value) => SetInt16Network((short)value, Index);
|
||||
|
||||
private void SetBytes(byte[] data, int destOffset, int length)
|
||||
{
|
||||
SetBytes(data, 0, destOffset, length);
|
||||
}
|
||||
|
||||
private void SetBytes(byte[] data, int dataOffset, int destOffset, int length)
|
||||
{
|
||||
if (length + dataOffset > data.Length || length + dataOffset > _buffer.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(length));
|
||||
}
|
||||
if (destOffset + dataOffset + length > _buffer.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(destOffset));
|
||||
}
|
||||
|
||||
Array.ConstrainedCopy(data, dataOffset, _buffer, destOffset, length);
|
||||
Index = destOffset + length;
|
||||
}
|
||||
|
||||
private void SetInt(int value, int offset)
|
||||
{
|
||||
var bytes = BitConverter.GetBytes(value);
|
||||
SetBytes(bytes, offset, bytes.Length);
|
||||
}
|
||||
|
||||
private void SetInt16(short value, int offset)
|
||||
{
|
||||
var bytes = BitConverter.GetBytes(value);
|
||||
SetBytes(bytes, offset, bytes.Length);
|
||||
}
|
||||
|
||||
private void SetInt16Network(short value, int offset)
|
||||
{
|
||||
var bytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(value));
|
||||
SetBytes(bytes, offset, bytes.Length);
|
||||
}
|
||||
|
||||
private void SetIntNetwork(int value, int offset)
|
||||
{
|
||||
var bytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(value));
|
||||
SetBytes(bytes, offset, bytes.Length);
|
||||
}
|
||||
}
|
||||
}
|
195
MailServer/MailServer/DNS/Protocol/DnsRecordFactory.cs
Normal file
195
MailServer/MailServer/DNS/Protocol/DnsRecordFactory.cs
Normal file
@ -0,0 +1,195 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using DnsClient.Protocol.Record;
|
||||
|
||||
namespace DnsClient.Protocol
|
||||
{
|
||||
public class DnsRecordFactory
|
||||
{
|
||||
public static IDictionary<ResourceRecordType, Func<DnsDatagramReader, ResourceRecordInfo, DnsResourceRecord>> s_recordFactory =
|
||||
new Dictionary<ResourceRecordType, Func<DnsDatagramReader, ResourceRecordInfo, DnsResourceRecord>>();
|
||||
|
||||
private readonly DnsDatagramReader _reader;
|
||||
|
||||
public DnsRecordFactory(DnsDatagramReader reader)
|
||||
{
|
||||
if (reader == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(reader));
|
||||
}
|
||||
|
||||
_reader = reader;
|
||||
}
|
||||
|
||||
/*
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| |
|
||||
/ /
|
||||
/ NAME /
|
||||
| |
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| TYPE |
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| CLASS |
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| TTL |
|
||||
| |
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| RDLENGTH |
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
|
||||
/ RDATA /
|
||||
/ /
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
* */
|
||||
public ResourceRecordInfo ReadRecordInfo()
|
||||
{
|
||||
return new ResourceRecordInfo(
|
||||
_reader.ReadName().ToString(), // name
|
||||
(ResourceRecordType)_reader.ReadUInt16Reverse(),// type
|
||||
(QueryClass)_reader.ReadUInt16Reverse(), // class
|
||||
_reader.ReadUInt32Reverse(), // ttl - 32bit!!
|
||||
_reader.ReadUInt16Reverse()); // RDLength
|
||||
//reader.ReadBytes(reader.ReadUInt16Reverse())); // rdata
|
||||
}
|
||||
|
||||
public DnsResourceRecord GetRecord(ResourceRecordInfo info)
|
||||
{
|
||||
if (info == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(info));
|
||||
}
|
||||
|
||||
var oldIndex = _reader.Index;
|
||||
DnsResourceRecord result;
|
||||
|
||||
if (s_recordFactory.ContainsKey(info.RecordType))
|
||||
{
|
||||
result = s_recordFactory[info.RecordType](_reader, info);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (info.RecordType)
|
||||
{
|
||||
case ResourceRecordType.A:
|
||||
result = ResolveARecord(info);
|
||||
break;
|
||||
|
||||
case ResourceRecordType.NS:
|
||||
result = ResolveNsRecord(info);
|
||||
break;
|
||||
|
||||
case ResourceRecordType.SOA:
|
||||
result = ResolveSoaRecord(info);
|
||||
break;
|
||||
|
||||
case ResourceRecordType.PTR:
|
||||
result = ResolvePtrRecord(info);
|
||||
break;
|
||||
|
||||
case ResourceRecordType.MX:
|
||||
result = ResolveMXRecord(info);
|
||||
break;
|
||||
|
||||
case ResourceRecordType.TXT:
|
||||
result = ResolveTXTRecord(info);
|
||||
break;
|
||||
|
||||
case ResourceRecordType.AAAA:
|
||||
result = ResolveAAAARecord(info);
|
||||
break;
|
||||
|
||||
case ResourceRecordType.SRV:
|
||||
result = ResolveSrvRecord(info);
|
||||
break;
|
||||
|
||||
default:
|
||||
// update reader index because we don't read full data for the empty record
|
||||
_reader.Index += info.RawDataLength;
|
||||
result = new EmptyRecord(info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// sanity check
|
||||
if (_reader.Index != oldIndex + info.RawDataLength)
|
||||
{
|
||||
throw new InvalidOperationException("Record reader index out of sync.");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private PtrRecord ResolvePtrRecord(ResourceRecordInfo info)
|
||||
{
|
||||
return new PtrRecord(info, _reader.ReadName().ToString());
|
||||
}
|
||||
|
||||
private AAAARecord ResolveAAAARecord(ResourceRecordInfo info)
|
||||
{
|
||||
var address = _reader.ReadIPv6Address();
|
||||
return new AAAARecord(info, address);
|
||||
}
|
||||
|
||||
// default resolver implementation for an A Record
|
||||
private ARecord ResolveARecord(ResourceRecordInfo info)
|
||||
{
|
||||
if (info.RawDataLength != 4)
|
||||
{
|
||||
throw new IndexOutOfRangeException($"Reading wrong length for an IP address. Expected 4 found {info.RawDataLength}.");
|
||||
}
|
||||
|
||||
return new ARecord(info, _reader.ReadIPAddress());
|
||||
}
|
||||
|
||||
private MxRecord ResolveMXRecord(ResourceRecordInfo info)
|
||||
{
|
||||
var preference = _reader.ReadUInt16Reverse();
|
||||
var domain = _reader.ReadName();
|
||||
|
||||
return new MxRecord(info, preference, domain.ToString());
|
||||
}
|
||||
|
||||
private NsRecord ResolveNsRecord(ResourceRecordInfo info)
|
||||
{
|
||||
var name = _reader.ReadName();
|
||||
return new NsRecord(info, name.ToString());
|
||||
}
|
||||
|
||||
private SoaRecord ResolveSoaRecord(ResourceRecordInfo info)
|
||||
{
|
||||
var mName = _reader.ReadName();
|
||||
var rName = _reader.ReadName();
|
||||
var serial = _reader.ReadUInt32Reverse();
|
||||
var refresh = _reader.ReadUInt32Reverse();
|
||||
var retry = _reader.ReadUInt32Reverse();
|
||||
var expire = _reader.ReadUInt32Reverse();
|
||||
var minimum = _reader.ReadUInt32Reverse();
|
||||
|
||||
return new SoaRecord(info, mName.ToString(), rName.ToString(), serial, refresh, retry, expire, minimum);
|
||||
}
|
||||
|
||||
private SrvRecord ResolveSrvRecord(ResourceRecordInfo info)
|
||||
{
|
||||
var priority = _reader.ReadUInt16Reverse();
|
||||
var weight = _reader.ReadUInt16Reverse();
|
||||
var port = _reader.ReadUInt16Reverse();
|
||||
var target = _reader.ReadName();
|
||||
|
||||
return new SrvRecord(info, priority, weight, port, target.ToString());
|
||||
}
|
||||
|
||||
private TxtRecord ResolveTXTRecord(ResourceRecordInfo info)
|
||||
{
|
||||
int pos = _reader.Index;
|
||||
|
||||
var values = new List<string>();
|
||||
while ((_reader.Index - pos) < info.RawDataLength)
|
||||
{
|
||||
values.Add(_reader.ReadString());
|
||||
}
|
||||
|
||||
return new TxtRecord(info, values.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
34
MailServer/MailServer/DNS/Protocol/DnsRequestMessage.cs
Normal file
34
MailServer/MailServer/DNS/Protocol/DnsRequestMessage.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace DnsClient.Protocol
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a simple request message which can be send through <see cref="DnsMessageHandler"/>.
|
||||
/// </summary>
|
||||
public class DnsRequestMessage
|
||||
{
|
||||
public DnsRequestHeader Header { get; }
|
||||
|
||||
public DnsQuestion Question { get; }
|
||||
|
||||
public DnsRequestMessage(DnsRequestHeader header, DnsQuestion question)
|
||||
{
|
||||
if (header == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(header));
|
||||
}
|
||||
if (question == null )
|
||||
{
|
||||
throw new ArgumentNullException(nameof(question));
|
||||
}
|
||||
if (header.QuestionCount != 1)
|
||||
{
|
||||
throw new InvalidOperationException("Header question count and number of questions do not match.");
|
||||
}
|
||||
|
||||
Header = header;
|
||||
Question = question;
|
||||
}
|
||||
}
|
||||
}
|
84
MailServer/MailServer/DNS/Protocol/DnsResourceRecord.cs
Normal file
84
MailServer/MailServer/DNS/Protocol/DnsResourceRecord.cs
Normal file
@ -0,0 +1,84 @@
|
||||
using System;
|
||||
|
||||
namespace DnsClient.Protocol
|
||||
{
|
||||
public abstract class DnsResourceRecord : ResourceRecordInfo
|
||||
{
|
||||
public DnsResourceRecord(ResourceRecordInfo info)
|
||||
: base(info.QueryName, info.RecordType, info.RecordClass, info.TimeToLive, info.RawDataLength)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return ToString(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Same as <c>ToString</c> but offsets the <see cref="ResourceRecordInfo.QueryName"/>
|
||||
/// by <paramref name="offset"/>.
|
||||
/// Set the offset to -32 for example to make it print nicely in consols.
|
||||
/// </summary>
|
||||
/// <param name="offset">The offset.</param>
|
||||
/// <returns>A string representing this instance.</returns>
|
||||
public virtual string ToString(int offset = 0)
|
||||
{
|
||||
return string.Format("{0," + offset + "}{1} \t{2} \t{3} \t{4}",
|
||||
QueryName,
|
||||
TimeToLive,
|
||||
RecordClass,
|
||||
RecordType,
|
||||
RecordToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the actual record's value only and not the full object representation.
|
||||
/// <see cref="ToString(int)"/> uses this to compose the full string value of this instance.
|
||||
/// </summary>
|
||||
/// <returns>A string representing this record.</returns>
|
||||
public abstract string RecordToString();
|
||||
}
|
||||
|
||||
public class ResourceRecordInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The query name.
|
||||
/// </summary>
|
||||
public string QueryName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies type of resource record.
|
||||
/// </summary>
|
||||
public ResourceRecordType RecordType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Specifies type class of resource record, mostly IN but can be CS, CH or HS .
|
||||
/// </summary>
|
||||
public QueryClass RecordClass { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The TTL value for the record set by the server.
|
||||
/// </summary>
|
||||
public uint TimeToLive { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of bytes for this resource record stored in RDATA
|
||||
/// </summary>
|
||||
public int RawDataLength { get; }
|
||||
|
||||
public ResourceRecordInfo(string queryName, ResourceRecordType recordType, QueryClass recordClass, uint ttl, int length)
|
||||
{
|
||||
if (queryName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(queryName));
|
||||
}
|
||||
|
||||
QueryName = queryName;
|
||||
RecordType = recordType;
|
||||
RecordClass = recordClass;
|
||||
TimeToLive = ttl;
|
||||
RawDataLength = length;
|
||||
}
|
||||
}
|
||||
}
|
76
MailServer/MailServer/DNS/Protocol/DnsResponseMessage.cs
Normal file
76
MailServer/MailServer/DNS/Protocol/DnsResponseMessage.cs
Normal file
@ -0,0 +1,76 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace DnsClient.Protocol
|
||||
{
|
||||
/// <summary>
|
||||
/// A simple response message which gets returned by the <see cref="LookupClient"/>.
|
||||
/// </summary>
|
||||
public class DnsResponseMessage
|
||||
{
|
||||
private readonly IList<DnsResourceRecord> _additionals = new List<DnsResourceRecord>();
|
||||
private readonly IList<DnsResourceRecord> _answers = new List<DnsResourceRecord>();
|
||||
private readonly IList<DnsResourceRecord> _authorities = new List<DnsResourceRecord>();
|
||||
private readonly DnsResponseHeader _header;
|
||||
private readonly IList<DnsQuestion> _questions = new List<DnsQuestion>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the readonly representation of this message which can be returned.
|
||||
/// </summary>
|
||||
public DnsQueryResponse AsReadonly
|
||||
=> new DnsQueryResponse(_header, _questions.ToArray(), _answers.ToArray(), _additionals.ToArray(), _authorities.ToArray());
|
||||
|
||||
public DnsResponseHeader Header => _header;
|
||||
|
||||
public DnsResponseMessage(DnsResponseHeader header)
|
||||
{
|
||||
if (header == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(header));
|
||||
}
|
||||
|
||||
_header = header;
|
||||
}
|
||||
|
||||
public void AddAdditional(DnsResourceRecord record)
|
||||
{
|
||||
if (record == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(record));
|
||||
}
|
||||
|
||||
_additionals.Add(record);
|
||||
}
|
||||
|
||||
public void AddAnswer(DnsResourceRecord record)
|
||||
{
|
||||
if (record == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(record));
|
||||
}
|
||||
|
||||
_answers.Add(record);
|
||||
}
|
||||
|
||||
public void AddAuthority(DnsResourceRecord record)
|
||||
{
|
||||
if (record == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(record));
|
||||
}
|
||||
|
||||
_authorities.Add(record);
|
||||
}
|
||||
|
||||
public void AddQuestion(DnsQuestion question)
|
||||
{
|
||||
if (question == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(question));
|
||||
}
|
||||
|
||||
_questions.Add(question);
|
||||
}
|
||||
}
|
||||
}
|
45
MailServer/MailServer/DNS/Protocol/Record/ARecord.cs
Normal file
45
MailServer/MailServer/DNS/Protocol/Record/ARecord.cs
Normal file
@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace DnsClient.Protocol.Record
|
||||
{
|
||||
/*
|
||||
3.4.1. A RDATA format
|
||||
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| ADDRESS |
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
|
||||
where:
|
||||
|
||||
ADDRESS A 32 bit Internet address.
|
||||
|
||||
Hosts that have multiple Internet addresses will have multiple A
|
||||
records.
|
||||
*
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// A DNS resource record represending an IP address.
|
||||
/// Hosts that have multiple Internet addresses will have multiple A records.
|
||||
/// </summary>
|
||||
public class ARecord : DnsResourceRecord
|
||||
{
|
||||
public IPAddress Address { get; }
|
||||
|
||||
public ARecord(ResourceRecordInfo info, IPAddress address) : base(info)
|
||||
{
|
||||
if (address == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(address));
|
||||
}
|
||||
|
||||
Address = address;
|
||||
}
|
||||
|
||||
public override string RecordToString()
|
||||
{
|
||||
return Address.ToString();
|
||||
}
|
||||
}
|
||||
}
|
35
MailServer/MailServer/DNS/Protocol/Record/AaaaRecord.cs
Normal file
35
MailServer/MailServer/DNS/Protocol/Record/AaaaRecord.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace DnsClient.Protocol.Record
|
||||
{
|
||||
/* https://tools.ietf.org/html/rfc3596#section-2.2
|
||||
2.2 AAAA data format
|
||||
|
||||
A 128 bit IPv6 address is encoded in the data portion of an AAAA
|
||||
resource record in network byte order (high-order byte first).
|
||||
*/
|
||||
/// <summary>
|
||||
/// A 128 bit IPv6 address is encoded in the data portion of an AAAA
|
||||
/// resource record in network byte order(high-order byte first).
|
||||
/// </summary>
|
||||
public class AAAARecord : DnsResourceRecord
|
||||
{
|
||||
public IPAddress Address { get; }
|
||||
|
||||
public AAAARecord(ResourceRecordInfo info, IPAddress address) : base(info)
|
||||
{
|
||||
if (address == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(address));
|
||||
}
|
||||
|
||||
Address = address;
|
||||
}
|
||||
|
||||
public override string RecordToString()
|
||||
{
|
||||
return Address.ToString();
|
||||
}
|
||||
}
|
||||
}
|
93
MailServer/MailServer/DNS/Protocol/Record/CaaRecord.cs
Normal file
93
MailServer/MailServer/DNS/Protocol/Record/CaaRecord.cs
Normal file
@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DnsClient.Protocol.Record
|
||||
{
|
||||
/* RFC 6844 (https://tools.ietf.org/html/rfc6844#section-5.1)
|
||||
A CAA RR contains a single property entry consisting of a tag-value
|
||||
pair. Each tag represents a property of the CAA record. The value
|
||||
of a CAA property is that specified in the corresponding value field.
|
||||
|
||||
A domain name MAY have multiple CAA RRs associated with it and a
|
||||
given property MAY be specified more than once.
|
||||
|
||||
The CAA data field contains one property entry. A property entry
|
||||
consists of the following data fields:
|
||||
|
||||
+0-1-2-3-4-5-6-7-|0-1-2-3-4-5-6-7-|
|
||||
| Flags | Tag Length = n |
|
||||
+----------------+----------------+...+---------------+
|
||||
| Tag char 0 | Tag char 1 |...| Tag char n-1 |
|
||||
+----------------+----------------+...+---------------+
|
||||
+----------------+----------------+.....+----------------+
|
||||
| Value byte 0 | Value byte 1 |.....| Value byte m-1 |
|
||||
+----------------+----------------+.....+----------------+
|
||||
|
||||
Where n is the length specified in the Tag length field and m is the
|
||||
remaining octets in the Value field (m = d - n - 2) where d is the
|
||||
length of the RDATA section.
|
||||
|
||||
The data fields are defined as follows:
|
||||
|
||||
Flags: One octet containing the following fields:
|
||||
|
||||
Bit 0, Issuer Critical Flag: If the value is set to '1', the
|
||||
critical flag is asserted and the property MUST be understood
|
||||
if the CAA record is to be correctly processed by a certificate
|
||||
issuer.
|
||||
|
||||
A Certification Authority MUST NOT issue certificates for any
|
||||
Domain that contains a CAA critical property for an unknown or
|
||||
unsupported property tag that for which the issuer critical
|
||||
flag is set.
|
||||
|
||||
Note that according to the conventions set out in [RFC1035], bit 0
|
||||
is the Most Significant Bit and bit 7 is the Least Significant
|
||||
Bit. Thus, the Flags value 1 means that bit 7 is set while a value
|
||||
of 128 means that bit 0 is set according to this convention.
|
||||
|
||||
All other bit positions are reserved for future use.
|
||||
|
||||
To ensure compatibility with future extensions to CAA, DNS records
|
||||
compliant with this version of the CAA specification MUST clear
|
||||
(set to "0") all reserved flags bits. Applications that interpret
|
||||
CAA records MUST ignore the value of all reserved flag bits.
|
||||
|
||||
Tag Length: A single octet containing an unsigned integer specifying
|
||||
the tag length in octets. The tag length MUST be at least 1 and
|
||||
SHOULD be no more than 15.
|
||||
|
||||
Tag: The property identifier, a sequence of US-ASCII characters.
|
||||
|
||||
Tag values MAY contain US-ASCII characters 'a' through 'z', 'A'
|
||||
through 'Z', and the numbers 0 through 9. Tag values SHOULD NOT
|
||||
contain any other characters. Matching of tag values is case
|
||||
insensitive.
|
||||
|
||||
Tag values submitted for registration by IANA MUST NOT contain any
|
||||
characters other than the (lowercase) US-ASCII characters 'a'
|
||||
through 'z' and the numbers 0 through 9.
|
||||
|
||||
Value: A sequence of octets representing the property value.
|
||||
Property values are encoded as binary values and MAY employ sub-
|
||||
formats.
|
||||
|
||||
The length of the value field is specified implicitly as the
|
||||
remaining length of the enclosing Resource Record data field.
|
||||
* */
|
||||
/// <summary>
|
||||
/// Record type 257
|
||||
/// The Certification Authority Authorization (CAA) DNS Resource Record
|
||||
/// allows a DNS domain name holder to specify one or more Certification
|
||||
/// Authorities(CAs) authorized to issue certificates for that domain.
|
||||
/// CAA Resource Records allow a public Certification Authority to
|
||||
/// implement additional controls to reduce the risk of unintended
|
||||
/// certificate mis-issue.This document defines the syntax of the CAA
|
||||
/// record and rules for processing CAA records by certificate issuers.
|
||||
/// </summary>
|
||||
public class CaaRecord
|
||||
{
|
||||
}
|
||||
}
|
14
MailServer/MailServer/DNS/Protocol/Record/EmptyRecord.cs
Normal file
14
MailServer/MailServer/DNS/Protocol/Record/EmptyRecord.cs
Normal file
@ -0,0 +1,14 @@
|
||||
namespace DnsClient.Protocol.Record
|
||||
{
|
||||
public class EmptyRecord : DnsResourceRecord
|
||||
{
|
||||
public EmptyRecord(ResourceRecordInfo info) : base(info)
|
||||
{
|
||||
}
|
||||
|
||||
public override string RecordToString()
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
65
MailServer/MailServer/DNS/Protocol/Record/MXRecord.cs
Normal file
65
MailServer/MailServer/DNS/Protocol/Record/MXRecord.cs
Normal file
@ -0,0 +1,65 @@
|
||||
using System;
|
||||
|
||||
namespace DnsClient.Protocol.Record
|
||||
{
|
||||
/*
|
||||
3.3.9. MX RDATA format
|
||||
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| PREFERENCE |
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
/ EXCHANGE /
|
||||
/ /
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
|
||||
where:
|
||||
|
||||
PREFERENCE A 16 bit integer which specifies the preference given to
|
||||
this RR among others at the same owner. Lower values
|
||||
are preferred.
|
||||
|
||||
EXCHANGE A <domain-name> which specifies a host willing to act as
|
||||
a mail exchange for the owner name.
|
||||
|
||||
MX records cause type A additional section processing for the host
|
||||
specified by EXCHANGE. The use of MX RRs is explained in detail in
|
||||
[RFC-974].
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// MX records cause type A additional section processing for the host
|
||||
/// specified by EXCHANGE.The use of MX RRs is explained in detail in
|
||||
/// [RFC-974].
|
||||
/// </summary>
|
||||
public class MxRecord : DnsResourceRecord
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a 16 bit integer which specifies the preference given to
|
||||
/// this RR among others at the same owner.
|
||||
/// Lower values are preferred.
|
||||
/// </summary>
|
||||
public ushort Preference { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A <domain-name> which specifies a host willing to act as a mail exchange.
|
||||
/// </summary>
|
||||
public string Exchange { get; }
|
||||
|
||||
public MxRecord(ResourceRecordInfo info, ushort preference, string domainName)
|
||||
: base(info)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(domainName))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(domainName));
|
||||
}
|
||||
|
||||
Preference = preference;
|
||||
Exchange = domainName;
|
||||
}
|
||||
|
||||
public override string RecordToString()
|
||||
{
|
||||
return string.Format("{0} {1}", Preference, Exchange);
|
||||
}
|
||||
}
|
||||
}
|
51
MailServer/MailServer/DNS/Protocol/Record/NsRecord.cs
Normal file
51
MailServer/MailServer/DNS/Protocol/Record/NsRecord.cs
Normal file
@ -0,0 +1,51 @@
|
||||
using System;
|
||||
|
||||
namespace DnsClient.Protocol.Record
|
||||
{
|
||||
/*
|
||||
https://tools.ietf.org/html/rfc1035#section-3.3.11:
|
||||
NS RDATA format
|
||||
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
/ NSDNAME /
|
||||
/ /
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
|
||||
where:
|
||||
|
||||
NSDNAME A <domain-name> which specifies a host which should be
|
||||
authoritative for the specified class and domain.
|
||||
|
||||
NS records cause both the usual additional section processing to locate
|
||||
a type A record, and, when used in a referral, a special search of the
|
||||
zone in which they reside for glue information.
|
||||
|
||||
The NS RR states that the named host should be expected to have a zone
|
||||
starting at owner name of the specified class. Note that the class may
|
||||
not indicate the protocol family which should be used to communicate
|
||||
with the host, although it is typically a strong hint. For example,
|
||||
hosts which are name servers for either Internet (IN) or Hesiod (HS)
|
||||
class information are normally queried using IN class protocols.
|
||||
*/
|
||||
|
||||
public class NsRecord : DnsResourceRecord
|
||||
{
|
||||
public string NSDName { get; }
|
||||
|
||||
internal NsRecord(ResourceRecordInfo info, string name)
|
||||
: base(info)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(name));
|
||||
}
|
||||
|
||||
NSDName = name;
|
||||
}
|
||||
|
||||
public override string RecordToString()
|
||||
{
|
||||
return NSDName;
|
||||
}
|
||||
}
|
||||
}
|
44
MailServer/MailServer/DNS/Protocol/Record/PtrRecord.cs
Normal file
44
MailServer/MailServer/DNS/Protocol/Record/PtrRecord.cs
Normal file
@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace DnsClient.Protocol.Record
|
||||
{
|
||||
/* RFC 1035 (https://tools.ietf.org/html/rfc1035#section-3.3.12)
|
||||
3.3.12. PTR RDATA format
|
||||
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
/ PTRDNAME /
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
|
||||
where:
|
||||
|
||||
PTRDNAME A <domain-name> which points to some location in the
|
||||
domain name space.
|
||||
|
||||
PTR records cause no additional section processing. These RRs are used
|
||||
in special domains to point to some other location in the domain space.
|
||||
These records are simple data, and don't imply any special processing
|
||||
similar to that performed by CNAME, which identifies aliases. See the
|
||||
description of the IN-ADDR.ARPA domain for an example.
|
||||
*/
|
||||
public class PtrRecord : DnsResourceRecord
|
||||
{
|
||||
public string PtrDomainName { get; }
|
||||
|
||||
internal PtrRecord(ResourceRecordInfo info, string ptrDName)
|
||||
: base(info)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ptrDName))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(ptrDName));
|
||||
}
|
||||
|
||||
PtrDomainName = ptrDName;
|
||||
}
|
||||
|
||||
public override string RecordToString()
|
||||
{
|
||||
return PtrDomainName;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using DnsClient.Protocol;
|
||||
using DnsClient.Protocol.Record;
|
||||
|
||||
namespace DnsClient
|
||||
{
|
||||
public static class RecordCollectionExtension
|
||||
{
|
||||
public static IEnumerable<AAAARecord> AaaaRecords(this IEnumerable<DnsResourceRecord> records)
|
||||
{
|
||||
return records.OfType<AAAARecord>();
|
||||
}
|
||||
|
||||
public static IEnumerable<ARecord> ARecords(this IEnumerable<DnsResourceRecord> records)
|
||||
{
|
||||
return records.OfType<ARecord>();
|
||||
}
|
||||
|
||||
public static IEnumerable<CaaRecord> CaaRecords(this IEnumerable<DnsResourceRecord> records)
|
||||
{
|
||||
return records.OfType<CaaRecord>();
|
||||
}
|
||||
|
||||
public static IEnumerable<NsRecord> NsRecords(this IEnumerable<DnsResourceRecord> records)
|
||||
{
|
||||
return records.OfType<NsRecord>();
|
||||
}
|
||||
|
||||
public static IEnumerable<DnsResourceRecord> OfRecordType(this IEnumerable<DnsResourceRecord> records, ResourceRecordType type)
|
||||
{
|
||||
return records.Where(p => p.RecordType == type);
|
||||
}
|
||||
|
||||
public static IEnumerable<PtrRecord> PtrRecords(this IEnumerable<DnsResourceRecord> records)
|
||||
{
|
||||
return records.OfType<PtrRecord>();
|
||||
}
|
||||
|
||||
public static IEnumerable<SoaRecord> SoaRecords(this IEnumerable<DnsResourceRecord> records)
|
||||
{
|
||||
return records.OfType<SoaRecord>();
|
||||
}
|
||||
|
||||
public static IEnumerable<SrvRecord> SrvRecords(this IEnumerable<DnsResourceRecord> records)
|
||||
{
|
||||
return records.OfType<SrvRecord>();
|
||||
}
|
||||
|
||||
public static IEnumerable<TxtRecord> TxtRecords(this IEnumerable<DnsResourceRecord> records)
|
||||
{
|
||||
return records.OfType<TxtRecord>();
|
||||
}
|
||||
}
|
||||
}
|
111
MailServer/MailServer/DNS/Protocol/Record/SoaRecord.cs
Normal file
111
MailServer/MailServer/DNS/Protocol/Record/SoaRecord.cs
Normal file
@ -0,0 +1,111 @@
|
||||
namespace DnsClient.Protocol.Record
|
||||
{
|
||||
/*
|
||||
3.3.13. SOA RDATA format
|
||||
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
/ MNAME /
|
||||
/ /
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
/ RNAME /
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| SERIAL |
|
||||
| |
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| REFRESH |
|
||||
| |
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| RETRY |
|
||||
| |
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| EXPIRE |
|
||||
| |
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| MINIMUM |
|
||||
| |
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
|
||||
where:
|
||||
|
||||
MNAME The <domain-name> of the name server that was the
|
||||
original or primary source of data for this zone.
|
||||
|
||||
RNAME A <domain-name> which specifies the mailbox of the
|
||||
person responsible for this zone.
|
||||
|
||||
SERIAL The unsigned 32 bit version number of the original copy
|
||||
of the zone. Zone transfers preserve this value. This
|
||||
value wraps and should be compared using sequence space
|
||||
arithmetic.
|
||||
|
||||
REFRESH A 32 bit time interval before the zone should be
|
||||
refreshed.
|
||||
|
||||
RETRY A 32 bit time interval that should elapse before a
|
||||
failed refresh should be retried.
|
||||
|
||||
EXPIRE A 32 bit time value that specifies the upper limit on
|
||||
the time interval that can elapse before the zone is no
|
||||
longer authoritative.
|
||||
|
||||
MINIMUM The unsigned 32 bit minimum TTL field that should be
|
||||
exported with any RR from this zone.
|
||||
|
||||
SOA records cause no additional section processing.
|
||||
|
||||
All times are in units of seconds.
|
||||
|
||||
Most of these fields are pertinent only for name server maintenance
|
||||
operations. However, MINIMUM is used in all query operations that
|
||||
retrieve RRs from a zone. Whenever a RR is sent in a response to a
|
||||
query, the TTL field is set to the maximum of the TTL field from the RR
|
||||
and the MINIMUM field in the appropriate SOA. Thus MINIMUM is a lower
|
||||
bound on the TTL field for all RRs in a zone. Note that this use of
|
||||
MINIMUM should occur when the RRs are copied into the response and not
|
||||
when the zone is loaded from a master file or via a zone transfer. The
|
||||
reason for this provison is to allow future dynamic update facilities to
|
||||
change the SOA RR with known semantics.
|
||||
*/
|
||||
|
||||
public class SoaRecord : DnsResourceRecord
|
||||
{
|
||||
public uint Expire { get; }
|
||||
|
||||
public uint Minimum { get; }
|
||||
|
||||
public string MName { get; }
|
||||
|
||||
public uint Refresh { get; }
|
||||
|
||||
public uint Retry { get; }
|
||||
|
||||
public string RName { get; }
|
||||
|
||||
public uint Serial { get; }
|
||||
|
||||
public SoaRecord(ResourceRecordInfo info, string mName, string rName, uint serial, uint refresh, uint retry, uint expire, uint minimum)
|
||||
: base(info)
|
||||
{
|
||||
MName = mName;
|
||||
RName = rName;
|
||||
Serial = serial;
|
||||
Refresh = refresh;
|
||||
Retry = retry;
|
||||
Expire = expire;
|
||||
Minimum = minimum;
|
||||
}
|
||||
|
||||
public override string RecordToString()
|
||||
{
|
||||
return string.Format(
|
||||
"{0} {1} {2} {3} {4} {5} {6}",
|
||||
MName,
|
||||
RName,
|
||||
Serial,
|
||||
Refresh,
|
||||
Retry,
|
||||
Expire,
|
||||
Minimum);
|
||||
}
|
||||
}
|
||||
}
|
147
MailServer/MailServer/DNS/Protocol/Record/SrvRecord.cs
Normal file
147
MailServer/MailServer/DNS/Protocol/Record/SrvRecord.cs
Normal file
@ -0,0 +1,147 @@
|
||||
namespace DnsClient.Protocol.Record
|
||||
{
|
||||
/* RFC 2782 (https://tools.ietf.org/html/rfc2782)
|
||||
|
||||
The format of the SRV RR
|
||||
|
||||
Here is the format of the SRV RR, whose DNS type code is 33:
|
||||
|
||||
_Service._Proto.Name TTL Class SRV Priority Weight Port Target
|
||||
|
||||
(There is an example near the end of this document.)
|
||||
|
||||
Service
|
||||
The symbolic name of the desired service, as defined in Assigned
|
||||
Numbers [STD 2] or locally. An underscore (_) is prepended to
|
||||
the service identifier to avoid collisions with DNS labels that
|
||||
occur in nature.
|
||||
Some widely used services, notably POP, don't have a single
|
||||
universal name. If Assigned Numbers names the service
|
||||
indicated, that name is the only name which is legal for SRV
|
||||
lookups. The Service is case insensitive.
|
||||
|
||||
Proto
|
||||
The symbolic name of the desired protocol, with an underscore
|
||||
(_) prepended to prevent collisions with DNS labels that occur
|
||||
in nature. _TCP and _UDP are at present the most useful values
|
||||
for this field, though any name defined by Assigned Numbers or
|
||||
locally may be used (as for Service). The Proto is case
|
||||
insensitive.
|
||||
|
||||
Name
|
||||
The domain this RR refers to. The SRV RR is unique in that the
|
||||
name one searches for is not this name; the example near the end
|
||||
shows this clearly.
|
||||
|
||||
TTL
|
||||
Standard DNS meaning [RFC 1035].
|
||||
|
||||
Class
|
||||
Standard DNS meaning [RFC 1035]. SRV records occur in the IN
|
||||
Class.
|
||||
|
||||
Priority
|
||||
The priority of this target host. A client MUST attempt to
|
||||
contact the target host with the lowest-numbered priority it can
|
||||
reach; target hosts with the same priority SHOULD be tried in an
|
||||
order defined by the weight field. The range is 0-65535. This
|
||||
is a 16 bit unsigned integer in network byte order.
|
||||
|
||||
Weight
|
||||
A server selection mechanism. The weight field specifies a
|
||||
relative weight for entries with the same priority. Larger
|
||||
weights SHOULD be given a proportionately higher probability of
|
||||
being selected. The range of this number is 0-65535. This is a
|
||||
16 bit unsigned integer in network byte order. Domain
|
||||
administrators SHOULD use Weight 0 when there isn't any server
|
||||
selection to do, to make the RR easier to read for humans (less
|
||||
noisy). In the presence of records containing weights greater
|
||||
than 0, records with weight 0 should have a very small chance of
|
||||
being selected.
|
||||
|
||||
In the absence of a protocol whose specification calls for the
|
||||
use of other weighting information, a client arranges the SRV
|
||||
RRs of the same Priority in the order in which target hosts,
|
||||
|
||||
specified by the SRV RRs, will be contacted. The following
|
||||
algorithm SHOULD be used to order the SRV RRs of the same
|
||||
priority:
|
||||
|
||||
To select a target to be contacted next, arrange all SRV RRs
|
||||
(that have not been ordered yet) in any order, except that all
|
||||
those with weight 0 are placed at the beginning of the list.
|
||||
|
||||
Compute the sum of the weights of those RRs, and with each RR
|
||||
associate the running sum in the selected order. Then choose a
|
||||
uniform random number between 0 and the sum computed
|
||||
(inclusive), and select the RR whose running sum value is the
|
||||
first in the selected order which is greater than or equal to
|
||||
the random number selected. The target host specified in the
|
||||
selected SRV RR is the next one to be contacted by the client.
|
||||
Remove this SRV RR from the set of the unordered SRV RRs and
|
||||
apply the described algorithm to the unordered SRV RRs to select
|
||||
the next target host. Continue the ordering process until there
|
||||
are no unordered SRV RRs. This process is repeated for each
|
||||
Priority.
|
||||
|
||||
Port
|
||||
The port on this target host of this service. The range is 0-
|
||||
65535. This is a 16 bit unsigned integer in network byte order.
|
||||
This is often as specified in Assigned Numbers but need not be.
|
||||
|
||||
Target
|
||||
The domain name of the target host. There MUST be one or more
|
||||
address records for this name, the name MUST NOT be an alias (in
|
||||
the sense of RFC 1034 or RFC 2181). Implementors are urged, but
|
||||
not required, to return the address record(s) in the Additional
|
||||
Data section. Unless and until permitted by future standards
|
||||
action, name compression is not to be used for this field.
|
||||
|
||||
A Target of "." means that the service is decidedly not
|
||||
available at this domain.
|
||||
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// The SRV RR allows administrators to use several servers for a single
|
||||
/// domain, to move services from host to host with little fuss, and to
|
||||
/// designate some hosts as primary servers for a service and others as
|
||||
/// backups.
|
||||
///
|
||||
/// Clients ask for a specific service/protocol for a specific domain
|
||||
/// (the word domain is used here in the strict RFC 1034 sense), and get
|
||||
/// back the names of any available servers.
|
||||
///
|
||||
/// Note that where this document refers to "address records", it means A
|
||||
/// RR's, AAAA RR's, or their most modern equivalent.
|
||||
/// </summary>
|
||||
public class SrvRecord : DnsResourceRecord
|
||||
{
|
||||
public ushort Port { get; }
|
||||
|
||||
public ushort Priority { get; }
|
||||
|
||||
public string Target { get; }
|
||||
|
||||
public ushort Weight { get; }
|
||||
|
||||
public SrvRecord(ResourceRecordInfo info, ushort priority, ushort weigth, ushort port, string target)
|
||||
: base(info)
|
||||
{
|
||||
Priority = priority;
|
||||
Weight = weigth;
|
||||
Port = port;
|
||||
Target = target;
|
||||
}
|
||||
|
||||
public override string RecordToString()
|
||||
{
|
||||
return string.Format(
|
||||
"{0} {1} {2} {3}",
|
||||
Priority,
|
||||
Weight,
|
||||
Port,
|
||||
Target);
|
||||
}
|
||||
}
|
||||
}
|
57
MailServer/MailServer/DNS/Protocol/Record/TxtRecord.cs
Normal file
57
MailServer/MailServer/DNS/Protocol/Record/TxtRecord.cs
Normal file
@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace DnsClient.Protocol.Record
|
||||
{
|
||||
/*
|
||||
* RFC 1464 https://tools.ietf.org/html/rfc1464
|
||||
|
||||
https://tools.ietf.org/html/rfc1035#section-3.3:
|
||||
<character-string> is a single
|
||||
length octet followed by that number of characters. <character-string>
|
||||
is treated as binary information, and can be up to 256 characters in
|
||||
length (including the length octet).
|
||||
|
||||
https://tools.ietf.org/html/rfc1035#section-3.3.14:
|
||||
TXT RDATA format
|
||||
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
/ TXT-DATA /
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
|
||||
where:
|
||||
|
||||
TXT-DATA One or more <character-string>s.
|
||||
|
||||
TXT RRs are used to hold descriptive text. The semantics of the text
|
||||
depends on the domain where it is found.
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// TXT RRs are used to hold descriptive text. The semantics of the text
|
||||
/// depends on the domain where it is found.
|
||||
/// </summary>
|
||||
public class TxtRecord : DnsResourceRecord
|
||||
{
|
||||
/// <summary>
|
||||
/// The list of TXT values of this TXT RR.
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<string> Text { get; }
|
||||
|
||||
public TxtRecord(ResourceRecordInfo info, string[] values)
|
||||
: base(info)
|
||||
{
|
||||
if (values == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(values));
|
||||
}
|
||||
|
||||
Text = values;
|
||||
}
|
||||
|
||||
public override string RecordToString()
|
||||
{
|
||||
return string.Join(" ", Text).Trim();
|
||||
}
|
||||
}
|
||||
}
|
47
MailServer/MailServer/DNS/QueryClass.cs
Normal file
47
MailServer/MailServer/DNS/QueryClass.cs
Normal file
@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
namespace DnsClient
|
||||
{
|
||||
/* RFC 1035 (https://tools.ietf.org/html/rfc1035#section-3.2.4)
|
||||
* 3.2.4. CLASS values
|
||||
*
|
||||
CLASS fields appear in resource records. The following CLASS mnemonics
|
||||
and values are defined:
|
||||
|
||||
IN 1 the Internet
|
||||
|
||||
CS 2 the CSNET class (Obsolete - used only for examples in
|
||||
some obsolete RFCs)
|
||||
|
||||
CH 3 the CHAOS class
|
||||
|
||||
HS 4 Hesiod [Dyer 87]
|
||||
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// CLASS fields appear in resource records.
|
||||
/// </summary>
|
||||
public enum QueryClass : short
|
||||
{
|
||||
/// <summary>
|
||||
/// The Internet.
|
||||
/// </summary>
|
||||
IN = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The CSNET class (Obsolete - used only for examples in some obsolete RFCs).
|
||||
/// </summary>
|
||||
CS = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The CHAOS class.
|
||||
/// </summary>
|
||||
CH = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Hesiod [Dyer 87].
|
||||
/// </summary>
|
||||
HS = 4
|
||||
}
|
||||
}
|
116
MailServer/MailServer/DNS/QueryType.cs
Normal file
116
MailServer/MailServer/DNS/QueryType.cs
Normal file
@ -0,0 +1,116 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
namespace DnsClient
|
||||
{
|
||||
/*
|
||||
* RFC 1035 (https://tools.ietf.org/html/rfc1035#section-3.2.3)
|
||||
* */
|
||||
|
||||
/// <summary>
|
||||
/// QTYPE fields appear in the question part of a query. QTYPES are a superset of TYPEs, hence all TYPEs are valid QTYPEs.
|
||||
/// </summary>
|
||||
public enum QueryType : short
|
||||
{
|
||||
/// <summary>
|
||||
/// A host address [RFC1035].
|
||||
/// </summary>
|
||||
A = 1,
|
||||
|
||||
/// <summary>
|
||||
/// An authoritative name server [RFC1035].
|
||||
/// </summary>
|
||||
NS = 2,
|
||||
|
||||
/// <summary>
|
||||
/// A mail destination (OBSOLETE - use MX) [RFC1035].
|
||||
/// </summary>
|
||||
MD = 3,
|
||||
|
||||
/// <summary>
|
||||
/// A mail forwarder (OBSOLETE - use MX) [RFC1035].
|
||||
/// </summary>
|
||||
MF = 4,
|
||||
|
||||
/// <summary>
|
||||
/// The canonical name for an alias [RFC1035].
|
||||
/// </summary>
|
||||
CNAME = 5,
|
||||
|
||||
/// <summary>
|
||||
/// Marks the start of a zone of authority [RFC1035].
|
||||
/// </summary>
|
||||
SOA = 6,
|
||||
|
||||
/// <summary>
|
||||
/// A mailbox domain name (EXPERIMENTAL) [RFC1035]. TODO:impl
|
||||
/// </summary>
|
||||
MB = 7,
|
||||
|
||||
/// <summary>
|
||||
/// A mail group member (EXPERIMENTAL) [RFC1035]. TODO:impl
|
||||
/// </summary>
|
||||
MG = 8,
|
||||
|
||||
/// <summary>
|
||||
/// A mail rename domain name (EXPERIMENTAL) [RFC1035]. TODO:impl
|
||||
/// </summary>
|
||||
MR = 9,
|
||||
|
||||
/// <summary>
|
||||
/// A null RR (EXPERIMENTAL) [RFC1035]. TODO:impl
|
||||
/// </summary>
|
||||
NULL = 10,
|
||||
|
||||
/// <summary>
|
||||
/// A well known service description [RFC1035] TODO:impl
|
||||
/// </summary>
|
||||
WKS = 11,
|
||||
|
||||
/// <summary>
|
||||
/// A domain name pointer [RFC1035]
|
||||
/// </summary>
|
||||
PTR = 12,
|
||||
|
||||
/// <summary>
|
||||
/// Host information [RFC1035] TODO:impl
|
||||
/// </summary>
|
||||
HINFO = 13,
|
||||
|
||||
/// <summary>
|
||||
/// Mailbox or mail list information [RFC1035] TODO:impl
|
||||
/// </summary>
|
||||
MINFO = 14,
|
||||
|
||||
/// <summary>
|
||||
/// Mail exchange [RFC1035]
|
||||
/// </summary>
|
||||
MX = 15,
|
||||
|
||||
/// <summary>
|
||||
/// Text strings [RFC1035]
|
||||
/// </summary>
|
||||
TXT = 16,
|
||||
|
||||
/// <summary>
|
||||
/// A IPV6 host address, [RFC3596]
|
||||
/// </summary>
|
||||
AAAA = 28,
|
||||
|
||||
/// <summary>
|
||||
/// Location of services [RFC2782]
|
||||
/// </summary>
|
||||
SRV = 33,
|
||||
|
||||
/// <summary>
|
||||
/// RRSIG rfc3755. TODO:impl
|
||||
/// </summary>
|
||||
RRSIG = 46,
|
||||
|
||||
/// <summary>
|
||||
/// Generic any query *.
|
||||
/// </summary>
|
||||
ANY = 255,
|
||||
|
||||
CAA = 257,
|
||||
}
|
||||
}
|
114
MailServer/MailServer/DNS/ResourceRecordType.cs
Normal file
114
MailServer/MailServer/DNS/ResourceRecordType.cs
Normal file
@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
namespace DnsClient
|
||||
{
|
||||
/*
|
||||
* RFC 1035 (https://tools.ietf.org/html/rfc1035#section-3.2.2)
|
||||
* */
|
||||
|
||||
/// <summary>
|
||||
/// TYPE fields are used in resource records. Note that these types are a subset of QTYPEs.
|
||||
/// </summary>
|
||||
public enum ResourceRecordType : short
|
||||
{
|
||||
/// <summary>
|
||||
/// A host address [RFC1035].
|
||||
/// </summary>
|
||||
A = 1,
|
||||
|
||||
/// <summary>
|
||||
/// An authoritative name server [RFC1035].
|
||||
/// </summary>
|
||||
NS = 2,
|
||||
|
||||
/// <summary>
|
||||
/// A mail destination (OBSOLETE - use MX) [RFC1035].
|
||||
/// </summary>
|
||||
MD = 3,
|
||||
|
||||
/// <summary>
|
||||
/// A mail forwarder (OBSOLETE - use MX) [RFC1035].
|
||||
/// </summary>
|
||||
MF = 4,
|
||||
|
||||
/// <summary>
|
||||
/// The canonical name for an alias [RFC1035].
|
||||
/// </summary>
|
||||
CNAME = 5,
|
||||
|
||||
/// <summary>
|
||||
/// Marks the start of a zone of authority [RFC1035].
|
||||
/// </summary>
|
||||
SOA = 6,
|
||||
|
||||
/// <summary>
|
||||
/// A mailbox domain name (EXPERIMENTAL) [RFC1035].
|
||||
/// </summary>
|
||||
MB = 7,
|
||||
|
||||
/// <summary>
|
||||
/// A mail group member (EXPERIMENTAL) [RFC1035].
|
||||
/// </summary>
|
||||
MG = 8,
|
||||
|
||||
/// <summary>
|
||||
/// A mail rename domain name (EXPERIMENTAL) [RFC1035].
|
||||
/// </summary>
|
||||
MR = 9,
|
||||
|
||||
/// <summary>
|
||||
/// A null RR (EXPERIMENTAL) [RFC1035].
|
||||
/// </summary>
|
||||
NULL = 10,
|
||||
|
||||
/// <summary>
|
||||
/// A well known service description [RFC1035]
|
||||
/// </summary>
|
||||
WKS = 11,
|
||||
|
||||
/// <summary>
|
||||
/// A domain name pointer [RFC1035]
|
||||
/// </summary>
|
||||
PTR = 12,
|
||||
|
||||
/// <summary>
|
||||
/// Host information [RFC1035]
|
||||
/// </summary>
|
||||
HINFO = 13,
|
||||
|
||||
/// <summary>
|
||||
/// Mailbox or mail list information [RFC1035]
|
||||
/// </summary>
|
||||
MINFO = 14,
|
||||
|
||||
/// <summary>
|
||||
/// Mail exchange [RFC1035]
|
||||
/// </summary>
|
||||
MX = 15,
|
||||
|
||||
/// <summary>
|
||||
/// Text strings [RFC1035]
|
||||
/// </summary>
|
||||
TXT = 16,
|
||||
|
||||
/// <summary>
|
||||
/// A IPV6 host address, [RFC3596]
|
||||
/// </summary>
|
||||
AAAA = 28,
|
||||
|
||||
/// <summary>
|
||||
/// Location of services [RFC2782]
|
||||
/// </summary>
|
||||
SRV = 33,
|
||||
|
||||
/// <summary>
|
||||
/// RRSIG rfc3755. TODO:impl
|
||||
/// </summary>
|
||||
RRSIG = 46,
|
||||
|
||||
/// <summary>
|
||||
/// TODO:impl
|
||||
/// </summary>
|
||||
CAA = 257,
|
||||
}
|
||||
}
|
154
MailServer/MailServer/DNS/ResponseCache.cs
Normal file
154
MailServer/MailServer/DNS/ResponseCache.cs
Normal file
@ -0,0 +1,154 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DnsClient
|
||||
{
|
||||
internal class ResponseCache
|
||||
{
|
||||
private static readonly long CleanupInterval = (long)TimeSpan.FromMinutes(10).TotalMilliseconds;
|
||||
private ConcurrentDictionary<string, ResponseEntry> _cache = new ConcurrentDictionary<string, ResponseEntry>();
|
||||
private object _cleanupLock = new object();
|
||||
private bool _cleanupRunning = false;
|
||||
private int _lastCleanup = 0;
|
||||
|
||||
public int Count => _cache.Count;
|
||||
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
public TimeSpan? MinimumTimout { get; set; }
|
||||
|
||||
public ResponseCache(bool enabled = true, TimeSpan? minimumTimout = null)
|
||||
{
|
||||
Enabled = enabled;
|
||||
MinimumTimout = minimumTimout;
|
||||
}
|
||||
|
||||
public static string GetCacheKey(DnsQuestion question)
|
||||
{
|
||||
if (question == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(question));
|
||||
}
|
||||
|
||||
return question.QueryName + ":" + question.QuestionClass + ":" + question.QuestionType;
|
||||
}
|
||||
|
||||
public async Task<DnsQueryResponse> GetOrAdd(string key, Func<Task<DnsQueryResponse>> create)
|
||||
{
|
||||
if (create == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(create));
|
||||
}
|
||||
|
||||
if (!Enabled)
|
||||
{
|
||||
return await create();
|
||||
}
|
||||
|
||||
ResponseEntry entry;
|
||||
if (_cache.TryGetValue(key, out entry))
|
||||
{
|
||||
if (entry.IsExpired)
|
||||
{
|
||||
_cache.TryRemove(key, out entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
return entry.Response;
|
||||
}
|
||||
}
|
||||
|
||||
var record = await create();
|
||||
|
||||
// only cache in case the result is valid and does need caching
|
||||
if (record != null)
|
||||
{
|
||||
var newEntry = CreatedEntry(record);
|
||||
|
||||
// respecting minimum expiration value which gets evaluated in CreateEntry
|
||||
if (newEntry.TTL > 0)
|
||||
{
|
||||
_cache.TryAdd(key, newEntry);
|
||||
|
||||
StartCleanup();
|
||||
}
|
||||
}
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
private static void DoCleanup(ResponseCache cache)
|
||||
{
|
||||
cache._cleanupRunning = true;
|
||||
|
||||
foreach (var entry in cache._cache)
|
||||
{
|
||||
if (entry.Value.IsExpired)
|
||||
{
|
||||
ResponseEntry o;
|
||||
cache._cache.TryRemove(entry.Key, out o);
|
||||
}
|
||||
}
|
||||
|
||||
cache._cleanupRunning = false;
|
||||
}
|
||||
|
||||
private ResponseEntry CreatedEntry(DnsQueryResponse response)
|
||||
{
|
||||
var entry = new ResponseEntry(response);
|
||||
|
||||
// minimum timeout
|
||||
if (MinimumTimout.HasValue && entry.TTL < MinimumTimout.Value.TotalMilliseconds)
|
||||
{
|
||||
entry.TTL = (long)MinimumTimout.Value.TotalMilliseconds;
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
private void StartCleanup()
|
||||
{
|
||||
var currentTicks = Environment.TickCount;
|
||||
if (!_cleanupRunning && _lastCleanup + CleanupInterval < currentTicks)
|
||||
{
|
||||
lock (_cleanupLock)
|
||||
{
|
||||
if (!_cleanupRunning && _lastCleanup + CleanupInterval < currentTicks)
|
||||
{
|
||||
_lastCleanup = currentTicks;
|
||||
|
||||
Task.Factory.StartNew(
|
||||
state => DoCleanup((ResponseCache)state),
|
||||
this,
|
||||
CancellationToken.None,
|
||||
TaskCreationOptions.DenyChildAttach,
|
||||
TaskScheduler.Default);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ResponseEntry
|
||||
{
|
||||
public bool IsExpired => Environment.TickCount > TicksCreated + TTL;
|
||||
|
||||
public DnsQueryResponse Response { get; set; }
|
||||
|
||||
public int TicksCreated { get; }
|
||||
|
||||
public long TTL { get; set; }
|
||||
|
||||
public ResponseEntry(DnsQueryResponse response)
|
||||
{
|
||||
var minTtl = response.AllRecords.Min(p => p?.TimeToLive);
|
||||
|
||||
Response = response;
|
||||
TTL = response.HasError || !minTtl.HasValue ? 0 : (int)minTtl.Value * 1000; // ttl is in second, we calculate in millis
|
||||
TicksCreated = Environment.TickCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
35
MailServer/MailServer/DNS/TaskExtensions.cs
Normal file
35
MailServer/MailServer/DNS/TaskExtensions.cs
Normal file
@ -0,0 +1,35 @@
|
||||
namespace System.Threading.Tasks
|
||||
{
|
||||
internal static class TaskExtensions
|
||||
{
|
||||
public static async Task TimeoutAfter(this Task task, TimeSpan timeout)
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
if (task == await Task.WhenAny(task, Task.Delay((int)timeout.TotalMilliseconds, cts.Token)))
|
||||
{
|
||||
cts.Cancel();
|
||||
await task;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new TimeoutException();
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<TResult> TimeoutAfter<TResult>(this Task<TResult> task, TimeSpan timeout)
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
if (task == await Task.WhenAny(task, Task.Delay((int)timeout.TotalMilliseconds, cts.Token)))
|
||||
{
|
||||
cts.Cancel();
|
||||
return await task;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new TimeoutException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
52
MailServer/MailServer/DNS/project.json
Normal file
52
MailServer/MailServer/DNS/project.json
Normal file
@ -0,0 +1,52 @@
|
||||
{
|
||||
"version": "1.0.0-*",
|
||||
"authors": [ "MichaCo" ],
|
||||
"packOptions": {
|
||||
"licenseUrl": "https://github.com/MichaCo/DnsClient.NET/blob/master/LICENSE",
|
||||
"projectUrl": "https://github.com/MichaCo/DnsClient.NET",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/MichaCo/DnsClient.NET"
|
||||
},
|
||||
"summary": "A simple DNS client written in C#.",
|
||||
"tags": [ "DNS", "Name Server", "CSharp", ".NET", ".NET Core" ]
|
||||
},
|
||||
"buildOptions": {
|
||||
"allowUnsafe": false,
|
||||
"languageVersion": "csharp6",
|
||||
"warningsAsErrors": false,
|
||||
"xmlDoc": true,
|
||||
"keyFile": "../../Tools/key.snk"
|
||||
},
|
||||
"copyright": "Copyright (c) 2016 MichaConrad",
|
||||
"configurations": {
|
||||
"Debug": {
|
||||
"buildOptions": {
|
||||
"define": [ "DEBUG" ]
|
||||
}
|
||||
},
|
||||
"Release": {
|
||||
"buildOptions": {
|
||||
"define": [ "RELEASE" ],
|
||||
"optimize": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
},
|
||||
"frameworks": {
|
||||
"netstandard1.3": {
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.6.0",
|
||||
"System.Net.NameResolution": "4.0.0",
|
||||
"System.Net.NetworkInformation": "4.3.0",
|
||||
"System.Runtime": "4.3.0"
|
||||
},
|
||||
"buildOptions": { "define": [ "XPLAT" ] }
|
||||
},
|
||||
"net45": {
|
||||
"frameworkAssemblies": {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
115
MailServer/MailServer/DNSClient/DnsHelpers.cs
Normal file
115
MailServer/MailServer/DNSClient/DnsHelpers.cs
Normal file
@ -0,0 +1,115 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
|
||||
namespace DnDns
|
||||
{
|
||||
internal static class DnsHelpers
|
||||
{
|
||||
private const long Epoch = 621355968000000000;
|
||||
|
||||
internal static byte[] CanonicaliseDnsName(string name, bool lowerCase)
|
||||
{
|
||||
if (!name.EndsWith("."))
|
||||
{
|
||||
name += ".";
|
||||
}
|
||||
|
||||
if (name == ".")
|
||||
{
|
||||
return new byte[1];
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.Append('\0');
|
||||
|
||||
for (int i = 0, j = 0; i < name.Length; i++, j++)
|
||||
{
|
||||
if (lowerCase)
|
||||
{
|
||||
sb.Append(char.ToLower(name[i]));
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(name[i]);
|
||||
}
|
||||
|
||||
if (name[i] == '.')
|
||||
{
|
||||
sb[i - j] = (char) (j & 0xff);
|
||||
j = -1;
|
||||
}
|
||||
}
|
||||
|
||||
sb[sb.Length - 1] = '\0';
|
||||
|
||||
return Encoding.ASCII.GetBytes(sb.ToString());
|
||||
}
|
||||
|
||||
internal static String DumpArrayToString(byte[] bytes)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder.Append("[");
|
||||
|
||||
foreach (byte b in bytes)
|
||||
{
|
||||
builder.Append(" ");
|
||||
builder.Append((sbyte)b);
|
||||
builder.Append(" ");
|
||||
}
|
||||
|
||||
builder.Append("]");
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a instance of a <see cref="DateTime"/> class to a 48 bit format time since epoch.
|
||||
/// Epoch is defined as 1-Jan-70 UTC.
|
||||
/// </summary>
|
||||
/// <param name="dateTimeToConvert">The <see cref="DateTime"/> instance to convert to DNS format.</param>
|
||||
/// <param name="timeHigh">The upper 16 bits of time.</param>
|
||||
/// <param name="timeLow">The lower 32 bits of the time object.</param>
|
||||
internal static void ConvertToDnsTime(DateTime dateTimeToConvert, out int timeHigh, out long timeLow)
|
||||
{
|
||||
long secondsFromEpoch = (dateTimeToConvert.ToUniversalTime().Ticks - Epoch) / 10000000;
|
||||
timeHigh = (int)(secondsFromEpoch >> 32);
|
||||
timeLow = (secondsFromEpoch & 0xFFFFFFFFL);
|
||||
|
||||
Console.WriteLine(String.Format("Date: {0}", dateTimeToConvert));
|
||||
Console.WriteLine(String.Format("secondsFromEpoch: {0}", secondsFromEpoch));
|
||||
Console.WriteLine(String.Format("timeHigh: {0}", timeHigh));
|
||||
Console.WriteLine(String.Format("timeLow: {0}", timeLow));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert from DNS 48 but time format to a <see cref="DateTime"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="timeHigh">The upper 16 bits of time.</param>
|
||||
/// <param name="timeLow">The lower 32 bits of the time object.</param>
|
||||
/// <returns>The converted date time</returns>
|
||||
internal static DateTime ConvertFromDnsTime(long timeLow, long timeHigh)
|
||||
{
|
||||
long time = (timeHigh << 32) + timeLow;
|
||||
time = time*10000000;
|
||||
time += Epoch;
|
||||
|
||||
return new DateTime(time);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert from DNS 48 but time format to a <see cref="DateTime"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="dnsTime">The upper 48 bits of time.</param>
|
||||
/// <returns>The converted date time</returns>
|
||||
internal static DateTime ConvertFromDnsTime(long dnsTime)
|
||||
{
|
||||
dnsTime = dnsTime * 10000000;
|
||||
dnsTime += Epoch;
|
||||
|
||||
return new DateTime(dnsTime);
|
||||
}
|
||||
}
|
||||
}
|
94
MailServer/MailServer/DNSClient/Enums/NsClass.cs
Normal file
94
MailServer/MailServer/DNSClient/Enums/NsClass.cs
Normal file
@ -0,0 +1,94 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace DnDns.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// RFC 1035:
|
||||
///
|
||||
/// 3.2.4. CLASS values
|
||||
///
|
||||
/// CLASS fields appear in resource records. The following CLASS mnemonics
|
||||
/// and values are defined:
|
||||
///
|
||||
/// IN 1 the Internet
|
||||
///
|
||||
/// CS 2 the CSNET class (Obsolete - used only for examples in
|
||||
/// some obsolete RFCs)
|
||||
///
|
||||
/// CH 3 the CHAOS class
|
||||
///
|
||||
/// HS 4 Hesiod [Dyer 87]
|
||||
///
|
||||
/// 3.2.5. QCLASS values
|
||||
///
|
||||
/// QCLASS fields appear in the question section of a query. QCLASS values
|
||||
/// are a superset of CLASS values; every CLASS is a valid QCLASS. In
|
||||
/// addition to CLASS values, the following QCLASSes are defined:
|
||||
///
|
||||
/// * 255 any class
|
||||
/// </summary>
|
||||
public enum NsClass : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Cookie?? - NOT IMPLEMENTED
|
||||
/// </summary>
|
||||
INVALID = 0,
|
||||
/// <summary>
|
||||
/// // Internet (inet), RFC 1035
|
||||
/// </summary>
|
||||
INET = 1,
|
||||
/// <summary>
|
||||
/// MIT Chaos-net, RFC 1035 - NOT IMPLEMENTED
|
||||
/// </summary>
|
||||
CHAOS = 3,
|
||||
/// <summary>
|
||||
/// MIT Hesiod, RFC 1035 - NOT IMPLEMENTED
|
||||
/// </summary>
|
||||
HS = 4,
|
||||
/// <summary>
|
||||
/// RFC 2136 - None
|
||||
/// prereq sections in update requests -- NOT IMPLEMENTED
|
||||
/// </summary>
|
||||
NONE = 254,
|
||||
/// <summary>
|
||||
/// Any QCLASS only, Wildcard match, RFC 1035 - IMPLEMENTED for INET only
|
||||
/// </summary>
|
||||
ANY = 255
|
||||
}
|
||||
}
|
298
MailServer/MailServer/DNSClient/Enums/NsFlags.cs
Normal file
298
MailServer/MailServer/DNSClient/Enums/NsFlags.cs
Normal file
@ -0,0 +1,298 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace DnDns.Enums
|
||||
{
|
||||
// DNS HEADER: http://www.faqs.org/rfcs/rfc1035.html
|
||||
// 1 1 1 1 1 1
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// | Query Identifier |
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// |QR| Opcode |AA|TC|RD|RA| Z|AD|CD| RCODE | <-- The Enums below are combined to create this 16 bit (2 byte) field
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// | QDCOUNT |
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// | ANCOUNT |
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// | NSCOUNT |
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// | ARCOUNT |
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
|
||||
/// <summary>
|
||||
/// FlagMasks are used as a bitmask to isolate bits 16 through 31 of the DNS header to convert
|
||||
/// them to their appropriate Enum types
|
||||
/// </summary>
|
||||
internal enum FlagMasks : ushort
|
||||
{
|
||||
QueryResponseMask = 0x8000,
|
||||
OpCodeMask = 0x7800,
|
||||
NsFlagMask = 0x07F0,
|
||||
RCodeMask = 0x000F
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// |QR| - Starts at bit 16 of DNS Header, size: 1 bit
|
||||
///
|
||||
/// RFC 1035:
|
||||
/// A one bit field that specifies whether this message is a
|
||||
/// query (0), or a response (1).
|
||||
///
|
||||
/// </summary>
|
||||
[Flags()]
|
||||
public enum QueryResponse : ushort
|
||||
{
|
||||
/// <summary>
|
||||
/// // QR Query or Response [RFC1035] ( 0 = Query )
|
||||
/// </summary>
|
||||
Query = 0x0,
|
||||
/// <summary>
|
||||
/// // QR Query or Response [RFC1035] ( 1 = Response )
|
||||
/// </summary>
|
||||
Response = 0x8000
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// | OpCode | - 4 bits of Dns header, Bit 17 - 20, see RFC 1035
|
||||
///
|
||||
/// RFC 1035:
|
||||
///
|
||||
/// A four bit field that specifies kind of query in this
|
||||
/// message. This value is set by the originator of a query
|
||||
/// and copied into the response.
|
||||
///
|
||||
/// The values are:
|
||||
///
|
||||
/// 0 a standard query (QUERY)
|
||||
///
|
||||
/// 1 an inverse query (IQUERY)
|
||||
///
|
||||
/// 2 a server status request (STATUS)
|
||||
///
|
||||
/// 3-15 reserved for future
|
||||
/// </summary>
|
||||
[Flags()]
|
||||
public enum OpCode : ushort
|
||||
{
|
||||
/// <summary>
|
||||
/// Standard query
|
||||
/// [RFC1035] (QUERY)
|
||||
/// </summary>
|
||||
QUERY = 0x0000,
|
||||
/// <summary>
|
||||
/// Inverse query
|
||||
/// [RFC1035] (IQUERY)
|
||||
/// </summary>
|
||||
IQUERY = 0x0800,
|
||||
/// <summary>
|
||||
/// Server status request
|
||||
/// [RFC1035] (STATUS)
|
||||
/// </summary>
|
||||
STATUS = 0x1000,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// |AA|TC|RD|RA| Z|AD|CD| - 8 bits (1 byte) flag fields
|
||||
///
|
||||
/// reference: http://www.networksorcery.com/enp/protocol/dns.htm
|
||||
/// </summary>
|
||||
[Flags()]
|
||||
public enum NsFlags : ushort
|
||||
{
|
||||
/// <summary>
|
||||
/// AA - Authorative Answer [RFC1035] ( 0 = Not authoritative, 1 = Is authoritative )
|
||||
/// Authoritative Answer - this bit is valid in responses,
|
||||
/// and specifies that the responding name server is an
|
||||
/// authority for the domain name in question section.
|
||||
///
|
||||
/// Note that the contents of the answer section may have
|
||||
/// multiple owner names because of aliases. The AA bit
|
||||
/// corresponds to the name which matches the query name, or
|
||||
/// the first owner name in the answer section.
|
||||
/// </summary>
|
||||
AA = 0x0400,
|
||||
/// <summary>
|
||||
/// TC - Truncated Response [RFC1035] ( 0 = Not truncated, 1 = Message truncated )
|
||||
///
|
||||
/// TrunCation - specifies that this message was truncated
|
||||
/// due to length greater than that permitted on the
|
||||
/// transmission channel.
|
||||
/// </summary>
|
||||
TC = 0x0200,
|
||||
/// <summary>
|
||||
/// RD - Recursion Desired [RFC1035] ( 0 = Recursion not desired, 1 = Recursion desired )
|
||||
///
|
||||
/// Recursion Desired - this bit may be set in a query and
|
||||
/// is copied into the response. If RD is set, it directs
|
||||
/// the name server to pursue the query recursively.
|
||||
/// Recursive query support is optional.
|
||||
/// </summary>
|
||||
RD = 0x0100,
|
||||
/// <summary>
|
||||
/// RA - Recursion Allowed [RFC1035] ( 0 = Recursive query support not available, 1 = Recursive query support available )
|
||||
///
|
||||
/// Recursion Available - this be is set or cleared in a
|
||||
/// response, and denotes whether recursive query support is
|
||||
/// available in the name server.
|
||||
/// </summary>
|
||||
RA = 0x0080,
|
||||
/// <summary>
|
||||
/// AD - Authentic Data [RFC4035] ( Authenticated data. 1 bit ) [NOT IMPLEMENTED]
|
||||
///
|
||||
/// Indicates in a response that all data included in the answer and authority
|
||||
/// sections of the response have been authenticated by the server according to
|
||||
/// the policies of that server. It should be set only if all data in the response
|
||||
/// has been cryptographically verified or otherwise meets the server's local security
|
||||
/// policy.
|
||||
/// </summary>
|
||||
AD = 0x0020,
|
||||
/// <summary>
|
||||
/// CD - Checking Disabled [RFC4035] ( Checking Disabled. 1 bit ) [NOT IMPLEMENTED]
|
||||
/// </summary>
|
||||
CD = 0x0010
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// | RCODE | - 4 bits error codes
|
||||
///
|
||||
/// Response code - this 4 bit field is set as part of
|
||||
/// responses. The values have the following interpretation:
|
||||
///
|
||||
/// Fields 6-15 Reserved for future use.
|
||||
///
|
||||
/// reference: http://www.networksorcery.com/enp/protocol/dns.htm
|
||||
/// </summary>
|
||||
[Flags()]
|
||||
public enum RCode : ushort
|
||||
{
|
||||
/// <summary>
|
||||
/// No error condition
|
||||
/// </summary>
|
||||
NoError = 0,
|
||||
/// <summary>
|
||||
/// Format error - The name server was unable to
|
||||
/// interpret the query.
|
||||
/// </summary>
|
||||
FormatError = 1,
|
||||
/// <summary>
|
||||
/// Server failure - The name server was unable to process
|
||||
/// this query due to a problem with the name server.
|
||||
/// </summary>
|
||||
ServerFailure = 2,
|
||||
/// <summary>
|
||||
/// Name Error - Meaningful only for responses from an
|
||||
/// authoritative name server, this code signifies that
|
||||
/// the domain name referenced in the query does not
|
||||
/// exist.
|
||||
/// </summary>
|
||||
NameError = 3,
|
||||
/// <summary>
|
||||
/// Not Implemented - The name server does not support
|
||||
/// the requested kind of query.
|
||||
/// </summary>
|
||||
NotImplemented = 4,
|
||||
/// <summary>
|
||||
/// Refused - The name server refuses to perform the
|
||||
/// specified operation for policy reasons. For example,
|
||||
/// a name server may not wish to provide the information
|
||||
/// to the particular requester, or a name server may not
|
||||
/// wish to perform a particular operation (e.g., zone
|
||||
/// transfer) for particular data.
|
||||
/// </summary>
|
||||
Refused = 5,
|
||||
/// <summary>
|
||||
/// RFC 2136
|
||||
/// Name Exists when it should not.
|
||||
/// </summary>
|
||||
YXDomain = 6,
|
||||
/// <summary>
|
||||
/// RFC 2136
|
||||
/// RR Set Exists when it should not.
|
||||
/// </summary>
|
||||
YXRRSet = 7,
|
||||
/// <summary>
|
||||
/// RFC 2136
|
||||
/// RR Set that should exist does not.
|
||||
/// </summary>
|
||||
NXRRSet = 8,
|
||||
/// <summary>
|
||||
/// RFC 2136
|
||||
/// Server Not Authoritative for zone.
|
||||
/// </summary>
|
||||
NotAuth = 9,
|
||||
/// <summary>
|
||||
/// RFC 2136
|
||||
/// Name not contained in zone.
|
||||
/// </summary>
|
||||
NotZone = 10,
|
||||
/// <summary>
|
||||
/// RFC 2671
|
||||
/// RFC 2845
|
||||
///
|
||||
/// BADVERS Bad OPT Version.
|
||||
/// BADSIG TSIG Signature Failure.
|
||||
/// </summary>
|
||||
BADVERS_BADSIG = 16,
|
||||
/// <summary>
|
||||
/// RFC 2845
|
||||
/// Key not recognized.
|
||||
/// </summary>
|
||||
BADKEY = 17,
|
||||
/// <summary>
|
||||
/// RFC 2845
|
||||
/// Signature out of time window.
|
||||
/// </summary>
|
||||
BADTIME = 18,
|
||||
/// <summary>
|
||||
/// RFC 2930
|
||||
/// Bad TKEY Mode.
|
||||
/// </summary>
|
||||
BADMODE = 19,
|
||||
/// <summary>
|
||||
/// RFC 2930
|
||||
/// Duplicate key name.
|
||||
/// </summary>
|
||||
BADNAME = 20,
|
||||
/// <summary>
|
||||
/// RFC 2930
|
||||
/// Algorithm not supported.
|
||||
/// </summary>
|
||||
BADALG = 21
|
||||
}
|
||||
}
|
305
MailServer/MailServer/DNSClient/Enums/NsType.cs
Normal file
305
MailServer/MailServer/DNSClient/Enums/NsType.cs
Normal file
@ -0,0 +1,305 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace DnDns.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// Currently defined type values for resources and queries.
|
||||
///
|
||||
/// RFC 1034
|
||||
///
|
||||
/// 3.2.2. TYPE values
|
||||
///
|
||||
/// TYPE fields are used in resource records. Note that these types are a
|
||||
/// subset of QTYPEs.
|
||||
///
|
||||
/// TYPE value and meaning
|
||||
///
|
||||
/// A 1 a host address, Implemented
|
||||
///
|
||||
/// NS 2 an authoritative name server, Implemented
|
||||
///
|
||||
/// MD 3 a mail destination (Obsolete - use MX), NOT Implemented
|
||||
///
|
||||
/// MF 4 a mail forwarder (Obsolete - use MX), NOT Implemented
|
||||
///
|
||||
/// CNAME 5 the canonical name for an alias, Implemented
|
||||
///
|
||||
/// SOA 6 marks the start of a zone of authority, Implemented
|
||||
///
|
||||
/// MB 7 a mailbox domain name (EXPERIMENTAL), Implemented
|
||||
///
|
||||
/// MG 8 a mail group member (EXPERIMENTAL), Implemented
|
||||
///
|
||||
/// MR 9 a mail rename domain name (EXPERIMENTAL), Implemented
|
||||
///
|
||||
/// NULL 10 a null RR (EXPERIMENTAL), NOT IMPLEMENTED
|
||||
///
|
||||
/// WKS 11 a well known service description
|
||||
///
|
||||
/// PTR 12 a domain name pointer
|
||||
///
|
||||
/// HINFO 13 host information
|
||||
///
|
||||
/// MINFO 14 mailbox or mail list information
|
||||
///
|
||||
/// MX 15 mail exchange
|
||||
///
|
||||
/// TXT 16 text strings
|
||||
///
|
||||
/// 3.2.3. QTYPE values
|
||||
///
|
||||
/// QTYPE fields appear in the question part of a query. QTYPES are a
|
||||
/// superset of TYPEs, hence all TYPEs are valid QTYPEs. In addition, the
|
||||
/// following QTYPEs are defined:
|
||||
///
|
||||
/// AXFR 252 A request for a transfer of an entire zone
|
||||
///
|
||||
/// MAILB 253 A request for mailbox-related records (MB, MG or MR)
|
||||
///
|
||||
/// MAILA 254 A request for mail agent RRs (Obsolete - see MX)
|
||||
///
|
||||
/// * 255 A request for all records
|
||||
///
|
||||
/// </summary>
|
||||
public enum NsType : uint
|
||||
{
|
||||
/// <summary>
|
||||
/// Invalid
|
||||
/// </summary>
|
||||
INVALID = 0,
|
||||
/// <summary>
|
||||
/// Host address
|
||||
/// </summary>
|
||||
A = 1,
|
||||
/// <summary>
|
||||
/// Authoritative server
|
||||
/// </summary>
|
||||
NS = 2,
|
||||
/// <summary>
|
||||
/// Mail destination - NOT IMPLEMENTED
|
||||
/// </summary>
|
||||
MD = 3,
|
||||
/// <summary>
|
||||
/// Mail forwarder, NOT IMPLEMENTED
|
||||
/// </summary>
|
||||
MF = 4,
|
||||
/// <summary>
|
||||
/// Canonical name
|
||||
/// </summary>
|
||||
CNAME = 5,
|
||||
/// <summary>
|
||||
/// Start of authority zone
|
||||
/// </summary>
|
||||
SOA = 6,
|
||||
// Mailbox domain name
|
||||
MB = 7,
|
||||
/// <summary>
|
||||
/// Mail group member
|
||||
/// </summary>
|
||||
MG = 8,
|
||||
/// <summary>
|
||||
/// Mail rename name
|
||||
/// </summary>
|
||||
MR = 9,
|
||||
/// <summary>
|
||||
/// Null resource record
|
||||
/// </summary>
|
||||
NULL = 10,
|
||||
/// <summary>
|
||||
/// Well known service
|
||||
/// </summary>
|
||||
WKS = 11,
|
||||
/// <summary>
|
||||
/// Domain name pointer
|
||||
/// </summary>
|
||||
PTR = 12,
|
||||
/// <summary>
|
||||
/// Host information
|
||||
/// </summary>
|
||||
HINFO = 13,
|
||||
/// <summary>
|
||||
/// Mailbox information
|
||||
/// </summary>
|
||||
MINFO = 14,
|
||||
/// <summary>
|
||||
/// Mail routing information
|
||||
/// </summary>
|
||||
MX = 15,
|
||||
/// <summary>
|
||||
/// Text strings, RFC 1464
|
||||
/// </summary>
|
||||
TXT = 16,
|
||||
/// <summary>
|
||||
/// Responsible person, RFC 1183, Implemented
|
||||
/// </summary>
|
||||
RP = 17,
|
||||
/// <summary>
|
||||
/// AFS cell database, RFC 1183, Implemented
|
||||
/// </summary>
|
||||
AFSDB = 18,
|
||||
/// <summary>
|
||||
/// X_25 calling address, RFC 1183, Implemented
|
||||
/// </summary>
|
||||
X25 = 19,
|
||||
/// <summary>
|
||||
/// ISDN calling address, RFC 1183, Implemented
|
||||
/// </summary>
|
||||
ISDN = 20,
|
||||
/// <summary>
|
||||
/// Router, RFC 1183, Implemented
|
||||
/// </summary>
|
||||
RT = 21,
|
||||
/// <summary>
|
||||
/// NSAP address, RFC 1706
|
||||
/// </summary>
|
||||
NSAP = 22,
|
||||
/// <summary>
|
||||
/// Reverse NSAP lookup - deprecated by PTR ?
|
||||
/// </summary>
|
||||
NSAP_PTR = 23,
|
||||
/// <summary>
|
||||
/// Security signature, RFC 2535
|
||||
/// </summary>
|
||||
SIG = 24,
|
||||
/// <summary>
|
||||
/// Security key, RFC 2535
|
||||
/// </summary>
|
||||
KEY = 25,
|
||||
/// <summary>
|
||||
/// X.400 mail mapping, RFC ?
|
||||
/// </summary>
|
||||
PX = 26,
|
||||
/// <summary>
|
||||
/// Geographical position - withdrawn, RFC 1712
|
||||
/// </summary>
|
||||
GPOS = 27,
|
||||
/// <summary>
|
||||
/// Ip6 Address, RFC 1886 -- Implemented
|
||||
/// </summary>
|
||||
AAAA = 28,
|
||||
/// <summary>
|
||||
/// Location Information, RFC 1876, Implemented
|
||||
/// </summary>
|
||||
LOC = 29,
|
||||
/// <summary>
|
||||
/// Next domain (security), RFC 2065
|
||||
/// </summary>
|
||||
NXT = 30,
|
||||
/// <summary>
|
||||
/// Endpoint identifier,RFC ?
|
||||
/// </summary>
|
||||
EID = 31,
|
||||
/// <summary>
|
||||
/// Nimrod Locator, RFC ?
|
||||
/// </summary>
|
||||
NIMLOC = 32,
|
||||
/// <summary>
|
||||
/// Server Record, RFC 2052, Implemented
|
||||
/// </summary>
|
||||
SRV = 33,
|
||||
/// <summary>
|
||||
/// ATM Address, RFC ?, Implemented
|
||||
/// </summary>
|
||||
ATMA = 34,
|
||||
/// <summary>
|
||||
/// Naming Authority PoinTeR, RFC 2915
|
||||
/// </summary>
|
||||
MAPTR = 35,
|
||||
/// <summary>
|
||||
/// Key Exchange, RFC 2230
|
||||
/// </summary>
|
||||
KX = 36,
|
||||
/// <summary>
|
||||
/// Certification record, RFC 2538
|
||||
/// </summary>
|
||||
CERT = 37,
|
||||
/// <summary>
|
||||
/// IPv6 address (deprecates AAAA), RFC 3226
|
||||
/// </summary>
|
||||
A6 = 38,
|
||||
/// <summary>
|
||||
/// Non-terminal DNAME (for IPv6), RFC 2874
|
||||
/// </summary>
|
||||
DNAME = 39,
|
||||
/// <summary>
|
||||
/// Kitchen sink (experimentatl), RFC ?
|
||||
/// </summary>
|
||||
SINK = 40,
|
||||
/// <summary>
|
||||
/// EDNS0 option (meta-RR), RFC 2671
|
||||
/// </summary>
|
||||
OPT = 41,
|
||||
/// <summary>
|
||||
/// Transaction key, RFC 2930
|
||||
/// </summary>
|
||||
TKEY = 249,
|
||||
/// <summary>
|
||||
/// Transaction signature, RFC 2845
|
||||
/// </summary>
|
||||
TSIG = 250,
|
||||
/// <summary>
|
||||
/// Incremental zone transfer, RFC 1995
|
||||
/// </summary>
|
||||
IXFR = 251,
|
||||
/// <summary>
|
||||
/// Transfer zone of authority, RFC 1035
|
||||
/// </summary>
|
||||
AXFR = 252,
|
||||
/// <summary>
|
||||
/// Transfer mailbox records, RFC 1035
|
||||
/// </summary>
|
||||
MAILB = 253,
|
||||
/// <summary>
|
||||
/// Transfer mail agent records, RFC 1035
|
||||
/// </summary>
|
||||
MAILA = 254,
|
||||
/// <summary>
|
||||
/// All of the above, RFC 1035
|
||||
/// </summary>
|
||||
ANY = 255,
|
||||
/// <summary>
|
||||
/// DNSSEC Trust Authorities
|
||||
/// </summary>
|
||||
DNSSECTrustAuthorities = 32768,
|
||||
/// <summary>
|
||||
/// DNSSEC Lookaside Validation, RFC4431
|
||||
/// </summary>
|
||||
DNSSECLookasideValidation = 32769
|
||||
}
|
||||
}
|
51
MailServer/MailServer/DNSClient/Enums/TcpServices.cs
Normal file
51
MailServer/MailServer/DNSClient/Enums/TcpServices.cs
Normal file
@ -0,0 +1,51 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace DnDns.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines Well Known TCP Ports for Services
|
||||
/// </summary>
|
||||
public enum TcpServices : short
|
||||
{
|
||||
/// <summary>
|
||||
/// Domain Name Server Port
|
||||
/// </summary>
|
||||
Domain = 53
|
||||
}
|
||||
}
|
51
MailServer/MailServer/DNSClient/Enums/UdpServices.cs
Normal file
51
MailServer/MailServer/DNSClient/Enums/UdpServices.cs
Normal file
@ -0,0 +1,51 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace DnDns.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines Well Known UDP Ports for Services
|
||||
/// </summary>
|
||||
public enum UdpServices : short
|
||||
{
|
||||
/// <summary>
|
||||
/// Domain Name Server Protocol Port
|
||||
/// </summary>
|
||||
Domain = 53
|
||||
}
|
||||
}
|
287
MailServer/MailServer/DNSClient/Query/DnsQueryBase.cs
Normal file
287
MailServer/MailServer/DNSClient/Query/DnsQueryBase.cs
Normal file
@ -0,0 +1,287 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using DnDns.Enums;
|
||||
using DnDns.Records;
|
||||
|
||||
namespace DnDns.Query
|
||||
{
|
||||
/// <summary>
|
||||
/// DnsQueryBase maintains the common state of DNS Queries (both responses and requests)
|
||||
/// </summary>
|
||||
public abstract class DnsQueryBase
|
||||
{
|
||||
#region Fields
|
||||
// RFC 1034
|
||||
//
|
||||
// 4.1.1. Header section format
|
||||
//
|
||||
// 1 1 1 1 1 1
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// | ID |
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// | QDCOUNT |
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// | ANCOUNT |
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// | NSCOUNT |
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// | ARCOUNT |
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
|
||||
/// <summary>
|
||||
/// ID - A 16 bit identifier. This identifier is copied
|
||||
/// the corresponding reply and can be used by the requester
|
||||
/// to match up replies to outstanding queries.
|
||||
/// </summary>
|
||||
protected ushort _transactionId;
|
||||
/// <summary>
|
||||
/// _flags will store a combination of the enums that make up the 16 bits after the
|
||||
/// TransactionID in the DNS protocol header
|
||||
/// </summary>
|
||||
protected ushort _flags;
|
||||
/// <summary>
|
||||
/// A one bit field that specifies whether this message is a
|
||||
/// query (0), or a response (1).
|
||||
/// </summary>
|
||||
protected QueryResponse _queryResponse;
|
||||
/// <summary>
|
||||
/// OPCODE - A four bit field that specifies kind of query in this
|
||||
/// message. This value is set by the originator of a query
|
||||
/// and copied into the response.
|
||||
/// </summary>
|
||||
protected OpCode _opCode;
|
||||
/// <summary>
|
||||
/// - A combination of flag fields in the DNS header (|AA|TC|RD|RA|)
|
||||
/// </summary>
|
||||
protected NsFlags _nsFlags;
|
||||
/// <summary>
|
||||
/// Response code - this 4 bit field is set as part of
|
||||
/// responses only.
|
||||
/// </summary>
|
||||
protected RCode _rCode;
|
||||
/// <summary>
|
||||
/// QDCOUNT - an unsigned 16 bit integer specifying the number of
|
||||
/// entries in the question section.
|
||||
/// </summary>
|
||||
protected ushort _questions;
|
||||
/// <summary>
|
||||
/// ANCOUNT - an unsigned 16 bit integer specifying the number of
|
||||
/// resource records in the answer section.
|
||||
/// </summary>
|
||||
protected ushort _answerRRs;
|
||||
/// <summary>
|
||||
/// NSCOUNT - an unsigned 16 bit integer specifying the number of name
|
||||
/// server resource records in the authority records
|
||||
/// section.
|
||||
/// </summary>
|
||||
protected ushort _authorityRRs;
|
||||
|
||||
// RFC 1034
|
||||
// 4.1.2. Question section format
|
||||
// 1 1 1 1 1 1
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// | |
|
||||
// / QNAME /
|
||||
// / /
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// | QTYPE |
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// | QCLASS |
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
|
||||
/// <summary>
|
||||
/// QNAME - a domain name represented as a sequence of labels, where
|
||||
/// each label consists of a length octet followed by that
|
||||
/// number of octets. The domain name terminates with the
|
||||
/// zero length octet for the null label of the root. Note
|
||||
/// that this field may be an odd number of octets; no
|
||||
/// padding is used
|
||||
/// </summary>
|
||||
protected string _name;
|
||||
/// <summary>
|
||||
/// QTYPE - a two octet code which specifies the type of the query.
|
||||
/// The values for this field include all codes valid for a
|
||||
/// TYPE field, together with some more general codes which
|
||||
/// can match more than one type of RR.
|
||||
/// </summary>
|
||||
protected NsType _nsType;
|
||||
/// <summary>
|
||||
/// QCLASS - a two octet code that specifies the class of the query.
|
||||
/// For example, the QCLASS field is IN for the Internet.
|
||||
/// </summary>
|
||||
protected NsClass _nsClass;
|
||||
|
||||
/// <summary>
|
||||
/// The additional records for the DNS Query
|
||||
/// </summary>
|
||||
protected List<IDnsRecord> _additionalRecords = new List<IDnsRecord>();
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Properties
|
||||
|
||||
/// ID - A 16 bit identifier. This identifier is copied
|
||||
/// the corresponding reply and can be used by the requester
|
||||
/// to match up replies to outstanding queries.
|
||||
/// </summary>
|
||||
public ushort TransactionID
|
||||
{
|
||||
get { return _transactionId; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A one bit field that specifies whether this message is a
|
||||
/// query (0), or a response (1).
|
||||
/// </summary>
|
||||
public QueryResponse QueryResponse
|
||||
{
|
||||
get { return _queryResponse; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// OPCODE - A four bit field that specifies kind of query in this
|
||||
/// message. This value is set by the originator of a query
|
||||
/// and copied into the response.
|
||||
/// </summary>
|
||||
public OpCode OpCode
|
||||
{
|
||||
get { return _opCode; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// NsFlags - A combination of flag fields in the DNS header (|AA|TC|RD|RA|)
|
||||
/// </summary>
|
||||
public NsFlags NsFlags
|
||||
{
|
||||
get { return _nsFlags; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Response code - this 4 bit field is set as part of
|
||||
/// responses only.
|
||||
/// </summary>
|
||||
public RCode RCode
|
||||
{
|
||||
get { return _rCode; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// QDCOUNT - an unsigned 16 bit integer specifying the number of
|
||||
/// entries in the question section.
|
||||
/// </summary>
|
||||
public ushort Questions
|
||||
{
|
||||
get { return _questions; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ANCOUNT - an unsigned 16 bit integer specifying the number of
|
||||
/// resource records in the answer section.
|
||||
/// </summary>
|
||||
public ushort AnswerRRs
|
||||
{
|
||||
get { return _answerRRs; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// NSCOUNT - an unsigned 16 bit integer specifying the number of name
|
||||
/// server resource records in the authority records
|
||||
/// section.
|
||||
/// </summary>
|
||||
public ushort AuthorityRRs
|
||||
{
|
||||
get { return _authorityRRs; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ARCOUNT - an unsigned 16 bit integer specifying the number of
|
||||
/// resource records in the additional records section.
|
||||
/// </summary>
|
||||
public ushort AdditionalRRs
|
||||
{
|
||||
get { return (ushort) _additionalRecords.Count; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// QNAME - a domain name represented as a sequence of labels, where
|
||||
/// each label consists of a length octet followed by that
|
||||
/// number of octets. The domain name terminates with the
|
||||
/// zero length octet for the null label of the root. Note
|
||||
/// that this field may be an odd number of octets; no
|
||||
/// padding is used
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set { _name = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// QTYPE - a two octet code which specifies the type of the query.
|
||||
/// The values for this field include all codes valid for a
|
||||
/// TYPE field, together with some more general codes which
|
||||
/// can match more than one type of RR.
|
||||
/// </summary>
|
||||
public NsType NsType
|
||||
{
|
||||
get { return _nsType; }
|
||||
set { _nsType = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// QCLASS - a two octet code that specifies the class of the query.
|
||||
/// For example, the QCLASS field is IN for the Internet.
|
||||
/// </summary>
|
||||
public NsClass NsClass
|
||||
{
|
||||
get { return _nsClass; }
|
||||
set { _nsClass = value; }
|
||||
}
|
||||
|
||||
public List<IDnsRecord> AdditionalRRecords
|
||||
{
|
||||
get { return _additionalRecords; }
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
385
MailServer/MailServer/DNSClient/Query/DnsQueryRequest.cs
Normal file
385
MailServer/MailServer/DNSClient/Query/DnsQueryRequest.cs
Normal file
@ -0,0 +1,385 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Text;
|
||||
|
||||
using DnDns.Enums;
|
||||
using DnDns.Records;
|
||||
using DnDns.Security;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DnDns.Query
|
||||
{
|
||||
/// <summary>
|
||||
/// Summary description for DnsQueryRequest.
|
||||
/// </summary>
|
||||
public class DnsQueryRequest : DnsQueryBase
|
||||
{
|
||||
private static Random r = new Random();
|
||||
|
||||
private int _bytesSent = 0;
|
||||
private int _socketTimeout = 5000;
|
||||
|
||||
/// <summary>
|
||||
/// The number of bytes sent to query the DNS Server.
|
||||
/// </summary>
|
||||
public int BytesSent
|
||||
{
|
||||
get { return _bytesSent; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the amount of time in milliseconds that a DnsQueryRequest will wait to receive data once a read operation is initiated.
|
||||
/// Defauts to 5 seconds (5000 ms)
|
||||
/// </summary>
|
||||
public int Timeout
|
||||
{
|
||||
get { return _socketTimeout; }
|
||||
set { _socketTimeout = value; }
|
||||
}
|
||||
|
||||
#region Constructors
|
||||
public DnsQueryRequest()
|
||||
{
|
||||
// Construct the class with some defaults
|
||||
_transactionId = (ushort) r.Next();
|
||||
_flags = 0;
|
||||
_queryResponse = QueryResponse.Query;
|
||||
this._opCode = OpCode.QUERY;
|
||||
// Recursion Desired
|
||||
this._nsFlags = NsFlags.RD;
|
||||
this._questions = 1;
|
||||
}
|
||||
|
||||
#endregion Constructors
|
||||
|
||||
private byte[] BuildQuery(string host)
|
||||
{
|
||||
string newHost;
|
||||
int newLocation = 0;
|
||||
int oldLocation = 0;
|
||||
|
||||
MemoryStream ms = new MemoryStream();
|
||||
|
||||
host = host.Trim();
|
||||
// decide how to build this query based on type
|
||||
switch (_nsType)
|
||||
{
|
||||
case NsType.PTR:
|
||||
IPAddress queryIP = IPAddress.Parse(host);
|
||||
|
||||
// pointer should be translated as follows
|
||||
// 209.115.22.3 -> 3.22.115.209.in-addr.arpa
|
||||
char[] ipDelim = new char[] {'.'};
|
||||
|
||||
string[] s = host.Split(ipDelim,4);
|
||||
newHost = String.Format("{0}.{1}.{2}.{3}.in-addr.arpa", s[3], s[2], s[1], s[0]);
|
||||
break;
|
||||
default:
|
||||
newHost = host;
|
||||
break;
|
||||
}
|
||||
|
||||
// Package up the host
|
||||
while(oldLocation < newHost.Length)
|
||||
{
|
||||
newLocation = newHost.IndexOf(".", oldLocation);
|
||||
|
||||
if (newLocation == -1) newLocation = newHost.Length;
|
||||
|
||||
byte subDomainLength = (byte)(newLocation - oldLocation);
|
||||
char[] sub = newHost.Substring(oldLocation, subDomainLength).ToCharArray();
|
||||
|
||||
ms.WriteByte(subDomainLength);
|
||||
ms.Write(Encoding.ASCII.GetBytes(sub, 0, sub.Length), 0, sub.Length);
|
||||
|
||||
oldLocation = newLocation + 1;
|
||||
}
|
||||
|
||||
// Terminate the domain name w/ a 0x00.
|
||||
ms.WriteByte(0x00);
|
||||
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="host"></param>
|
||||
/// <param name="queryType"></param>
|
||||
/// <param name="queryClass"></param>
|
||||
/// <param name="protocol"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<DnsQueryResponse> ResolveAsync(string host, NsType queryType, NsClass queryClass, ProtocolType protocol)
|
||||
{
|
||||
return await ResolveAsync(host, queryType, queryClass, protocol, null);
|
||||
}
|
||||
|
||||
public async Task<DnsQueryResponse> ResolveAsync(string host, NsType queryType, NsClass queryClass, ProtocolType protocol, TsigMessageSecurityProvider provider)
|
||||
{
|
||||
string dnsServer = string.Empty;
|
||||
dnsServer = "8.8.8.8";
|
||||
/*// Test for Unix/Linux OS
|
||||
if (Tools.IsPlatformLinuxUnix())
|
||||
{
|
||||
dnsServer = Tools.DiscoverUnixDnsServerAddress();
|
||||
}
|
||||
else
|
||||
{
|
||||
IPAddressCollection dnsServerCollection = Tools.DiscoverDnsServerAddresses();
|
||||
if (dnsServerCollection.Count == 0)
|
||||
throw new Exception("Couldn't detect local DNS Server.");
|
||||
|
||||
dnsServer = dnsServerCollection[0].ToString();
|
||||
}
|
||||
|
||||
if (String.IsNullOrEmpty(dnsServer))
|
||||
throw new Exception("Couldn't detect local DNS Server.");
|
||||
*/
|
||||
return await ResolveAsync(dnsServer, host, queryType, queryClass, protocol, provider);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="dnsServer"></param>
|
||||
/// <param name="host"></param>
|
||||
/// <param name="queryType"></param>
|
||||
/// <param name="queryClass"></param>
|
||||
/// <param name="protocol"></param>
|
||||
/// <param name="messageSecurityProvider">The instance of the message security provider to use to secure the DNS request.</param>
|
||||
/// <returns>A <see cref="T:DnDns.Net.Dns.DnsQueryResponse"></see> instance that contains the Dns Answer for the request query.</returns>
|
||||
/// <PermissionSet>
|
||||
/// <IPermission class="System.Net.DnsPermission, System, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
|
||||
/// </PermissionSet>
|
||||
public async Task<DnsQueryResponse> ResolveAsync(string dnsServer, string host, NsType queryType, NsClass queryClass, ProtocolType protocol, IMessageSecurityProvider messageSecurityProvider)
|
||||
{
|
||||
byte[] bDnsQuery = this.BuildDnsRequest(host, queryType, queryClass, protocol, messageSecurityProvider);
|
||||
|
||||
// Connect to DNS server and get the record for the current server.
|
||||
IPHostEntry ipe = await Dns.GetHostEntryAsync(dnsServer);
|
||||
IPAddress ipa = ipe.AddressList[0];
|
||||
IPEndPoint ipep = new IPEndPoint(ipa, (int)UdpServices.Domain);
|
||||
|
||||
byte[] recvBytes = null;
|
||||
|
||||
switch (protocol)
|
||||
{
|
||||
case ProtocolType.Tcp:
|
||||
{
|
||||
recvBytes = ResolveTcp(bDnsQuery, ipep);
|
||||
break;
|
||||
}
|
||||
case ProtocolType.Udp:
|
||||
{
|
||||
recvBytes = ResolveUdp(bDnsQuery, ipep);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new InvalidOperationException("Invalid Protocol: " + protocol);
|
||||
}
|
||||
}
|
||||
|
||||
//Console.Assert(recvBytes != null, "Failed to retrieve data from the remote DNS server.");
|
||||
if(recvBytes == null)
|
||||
{
|
||||
Logging.AddLogMessage(Logging.LoggingType.ERROR, "Failed to retrieve data from the remote DNS server.");
|
||||
}
|
||||
|
||||
DnsQueryResponse dnsQR = new DnsQueryResponse();
|
||||
|
||||
dnsQR.ParseResponse(recvBytes, protocol);
|
||||
|
||||
return dnsQR;
|
||||
}
|
||||
|
||||
private byte[] ResolveUdp(byte[] bDnsQuery, IPEndPoint ipep)
|
||||
{
|
||||
// UDP messages, data size = 512 octets or less
|
||||
//UdpClient udpClient = new UdpClient();
|
||||
|
||||
Socket udp = new Socket(SocketType.Dgram, ProtocolType.Udp);
|
||||
byte[] recvBytes = null;
|
||||
|
||||
try
|
||||
{
|
||||
udp.ReceiveTimeout = _socketTimeout;
|
||||
//udpClient.Client.ReceiveTimeout = _socketTimeout;
|
||||
//udpClient.ConnectAsync(ipep);
|
||||
udp.Connect(ipep);
|
||||
//udpClient.Send(bDnsQuery, bDnsQuery.Length);
|
||||
udp.Send(bDnsQuery);
|
||||
//recvBytes = udpClient.Receive(ref ipep);
|
||||
recvBytes = new byte[udp.ReceiveBufferSize];
|
||||
udp.Receive(recvBytes);
|
||||
}
|
||||
finally
|
||||
{
|
||||
//udpClient.Close();
|
||||
}
|
||||
return recvBytes;
|
||||
}
|
||||
|
||||
private static byte[] ResolveTcp(byte[] bDnsQuery, IPEndPoint ipep)
|
||||
{
|
||||
Socket tcp = new Socket(SocketType.Stream, ProtocolType.Tcp);
|
||||
|
||||
//TcpClient tcpClient = new TcpClient();
|
||||
byte[] recvBytes = null;
|
||||
|
||||
try
|
||||
{
|
||||
tcp.Connect(ipep);
|
||||
//tcpClient.ConnectAsync(ipep);
|
||||
//NetworkStream ns = tcp.Receive
|
||||
//NetworkStream netStream = tcpClient.GetStream();
|
||||
//BinaryReader netReader = new System.IO.BinaryReader(netStream);
|
||||
|
||||
//netStream.Write(bDnsQuery, 0, bDnsQuery.Length);
|
||||
tcp.Send(bDnsQuery);
|
||||
// wait until data is avail
|
||||
//while (!netStream.DataAvailable) ;
|
||||
while (tcp.Available < 1) ;
|
||||
|
||||
//if (tcpClient.Connected && netStream.DataAvailable)
|
||||
if (tcp.Connected && tcp.Available > 1)
|
||||
{
|
||||
// Read first two bytes to find out the length of the response
|
||||
byte[] bLen = new byte[2];
|
||||
|
||||
// NOTE: The order of the next two lines matter. Do not reorder
|
||||
// Array indexes are also intentionally reversed
|
||||
tcp.Receive(bLen, bLen.Length, SocketFlags.None);
|
||||
//bLen[1] = (byte)netStream.ReadByte();
|
||||
//bLen[0] = (byte)netStream.ReadByte();
|
||||
|
||||
UInt16 length = BitConverter.ToUInt16(bLen, 0);
|
||||
|
||||
recvBytes = new byte[length];
|
||||
tcp.Receive(recvBytes, length, SocketFlags.None);
|
||||
//netStream.Read(recvBytes, 0, length);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logging.AddException(e);
|
||||
}
|
||||
return recvBytes;
|
||||
}
|
||||
|
||||
private byte[] BuildDnsRequest(string host, NsType queryType, NsClass queryClass, ProtocolType protocol, IMessageSecurityProvider messageSecurityProvider)
|
||||
{
|
||||
// Combind the NsFlags with our constant flags
|
||||
ushort flags = (ushort)((ushort)_queryResponse | (ushort)_opCode | (ushort)_nsFlags);
|
||||
this._flags = flags;
|
||||
|
||||
//NOTE: This limits the librarys ablity to issue multiple queries per request.
|
||||
this._nsType = queryType;
|
||||
this._nsClass = queryClass;
|
||||
this._name = host;
|
||||
|
||||
if(messageSecurityProvider != null)
|
||||
{
|
||||
messageSecurityProvider.SecureMessage(this);
|
||||
}
|
||||
|
||||
byte[] bDnsQuery = GetMessageBytes();
|
||||
|
||||
// Add two byte prefix that contains the packet length per RFC 1035 section 4.2.2
|
||||
if (protocol == ProtocolType.Tcp)
|
||||
{
|
||||
// 4.2.2. TCP usageMessages sent over TCP connections use server port 53 (decimal).
|
||||
// The message is prefixed with a two byte length field which gives the message
|
||||
// length, excluding the two byte length field. This length field allows the
|
||||
// low-level processing to assemble a complete message before beginning to parse
|
||||
// it.
|
||||
int len = bDnsQuery.Length;
|
||||
Array.Resize<byte>(ref bDnsQuery, len + 2);
|
||||
Array.Copy(bDnsQuery, 0, bDnsQuery, 2, len);
|
||||
bDnsQuery[0] = (byte)((len >> 8) & 0xFF);
|
||||
bDnsQuery[1] = (byte)((len & 0xFF));
|
||||
}
|
||||
|
||||
return bDnsQuery;
|
||||
}
|
||||
|
||||
internal byte[] GetMessageBytes()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
byte[] data = new byte[2];
|
||||
|
||||
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder(_transactionId) >> 16));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder(_flags) >> 16));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder(_questions) >> 16));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder(_answerRRs) >> 16));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder(_authorityRRs) >> 16));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder(_additionalRecords.Count) >> 16));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
data = DnsHelpers.CanonicaliseDnsName(_name, false);
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder((ushort)_nsType) >> 16));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder((ushort)_nsClass) >> 16));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
foreach (IDnsRecord dnsRecord in AdditionalRRecords)
|
||||
{
|
||||
data = dnsRecord.GetMessageBytes();
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
}
|
||||
|
||||
Logging.AddLogMessage(Logging.LoggingType.INFO, String.Format("The message bytes: {0}", DnsHelpers.DumpArrayToString(memoryStream.ToArray())));
|
||||
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
168
MailServer/MailServer/DNSClient/Query/DnsQueryResponse.cs
Normal file
168
MailServer/MailServer/DNSClient/Query/DnsQueryResponse.cs
Normal file
@ -0,0 +1,168 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using DnDns.Records;
|
||||
|
||||
using DnDns.Enums;
|
||||
|
||||
namespace DnDns.Query
|
||||
{
|
||||
/// <summary>
|
||||
/// Summary description for DnsQueryResponse.
|
||||
/// </summary>
|
||||
public class DnsQueryResponse : DnsQueryBase
|
||||
{
|
||||
#region Fields
|
||||
private DnsQueryRequest _queryRequest = new DnsQueryRequest();
|
||||
|
||||
private IDnsRecord[] _answers;
|
||||
private IDnsRecord[] _authoritiveNameServers;
|
||||
private int _bytesReceived = 0;
|
||||
#endregion Fields
|
||||
|
||||
#region properties
|
||||
public DnsQueryRequest QueryRequest
|
||||
{
|
||||
get { return _queryRequest; }
|
||||
}
|
||||
|
||||
public IDnsRecord[] Answers
|
||||
{
|
||||
get { return _answers; }
|
||||
}
|
||||
|
||||
public IDnsRecord[] AuthoritiveNameServers
|
||||
{
|
||||
get { return _authoritiveNameServers; }
|
||||
}
|
||||
|
||||
public int BytesReceived
|
||||
{
|
||||
get { return _bytesReceived; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public DnsQueryResponse()
|
||||
{
|
||||
}
|
||||
|
||||
private DnsQueryRequest ParseQuery(ref MemoryStream ms)
|
||||
{
|
||||
DnsQueryRequest queryRequest = new DnsQueryRequest();
|
||||
|
||||
// Read name
|
||||
queryRequest.Name = DnsRecordBase.ParseName(ref ms);
|
||||
|
||||
return queryRequest;
|
||||
}
|
||||
|
||||
internal void ParseResponse(byte[] recvBytes, ProtocolType protocol)
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream(recvBytes);
|
||||
byte[] flagBytes = new byte[2];
|
||||
byte[] transactionId = new byte[2];
|
||||
byte[] questions = new byte[2];
|
||||
byte[] answerRRs = new byte[2];
|
||||
byte[] authorityRRs = new byte[2];
|
||||
byte[] additionalRRCountBytes = new byte[2];
|
||||
byte[] nsType = new byte[2];
|
||||
byte[] nsClass = new byte[2];
|
||||
|
||||
this._bytesReceived = recvBytes.Length;
|
||||
|
||||
// Parse DNS Response
|
||||
memoryStream.Read(transactionId, 0, 2);
|
||||
memoryStream.Read(flagBytes, 0, 2);
|
||||
memoryStream.Read(questions, 0, 2);
|
||||
memoryStream.Read(answerRRs, 0, 2);
|
||||
memoryStream.Read(authorityRRs, 0, 2);
|
||||
memoryStream.Read(additionalRRCountBytes, 0, 2);
|
||||
|
||||
// Parse Header
|
||||
_transactionId = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(transactionId, 0));
|
||||
_flags = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(flagBytes, 0));
|
||||
_queryResponse = (QueryResponse)(_flags & (ushort)FlagMasks.QueryResponseMask);
|
||||
_opCode = (OpCode)(_flags & (ushort)FlagMasks.OpCodeMask);
|
||||
_nsFlags = (NsFlags)(_flags & (ushort)FlagMasks.NsFlagMask);
|
||||
_rCode = (RCode)(_flags & (ushort)FlagMasks.RCodeMask);
|
||||
|
||||
// Parse Questions Section
|
||||
_questions = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(questions, 0));
|
||||
_answerRRs = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(answerRRs, 0));
|
||||
_authorityRRs = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(authorityRRs, 0));
|
||||
ushort additionalRRCount = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(additionalRRCountBytes, 0));
|
||||
_additionalRecords = new List<IDnsRecord>();
|
||||
_answers = new DnsRecordBase[_answerRRs];
|
||||
_authoritiveNameServers = new DnsRecordBase[_authorityRRs];
|
||||
|
||||
// Parse Queries
|
||||
_queryRequest = this.ParseQuery(ref memoryStream);
|
||||
|
||||
// Read dnsType
|
||||
memoryStream.Read(nsType, 0, 2);
|
||||
|
||||
// Read dnsClass
|
||||
memoryStream.Read(nsClass, 0, 2);
|
||||
|
||||
_nsType = (NsType)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(nsType, 0));
|
||||
_nsClass = (NsClass)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(nsClass, 0));
|
||||
|
||||
// Read in Answer Blocks
|
||||
for (int i=0; i < _answerRRs; i++)
|
||||
{
|
||||
_answers[i] = RecordFactory.Create(ref memoryStream);
|
||||
}
|
||||
|
||||
// Parse Authority Records
|
||||
for (int i=0; i < _authorityRRs; i++)
|
||||
{
|
||||
_authoritiveNameServers[i] = RecordFactory.Create(ref memoryStream);
|
||||
}
|
||||
|
||||
// Parse Additional Records
|
||||
for (int i=0; i < additionalRRCount; i++)
|
||||
{
|
||||
_additionalRecords.Add(RecordFactory.Create(ref memoryStream));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
83
MailServer/MailServer/DNSClient/Records/ARecord.cs
Normal file
83
MailServer/MailServer/DNSClient/Records/ARecord.cs
Normal file
@ -0,0 +1,83 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
/// <summary>
|
||||
/// RFC 1035:
|
||||
///
|
||||
/// 3.4.1. A RDATA format
|
||||
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
/// | ADDRESS |
|
||||
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
///
|
||||
/// where:
|
||||
///
|
||||
/// ADDRESS A 32 bit Internet address.
|
||||
///
|
||||
/// Hosts that have multiple Internet addresses will have multiple A
|
||||
/// records.
|
||||
///
|
||||
/// A records cause no additional section processing. The RDATA section of
|
||||
/// an A line in a master file is an Internet address expressed as four
|
||||
/// decimal numbers separated by dots without any imbedded spaces (e.g.,
|
||||
/// "10.2.0.52" or "192.0.5.6").
|
||||
///
|
||||
/// </summary>
|
||||
public sealed class ARecord : DnsRecordBase, IDnsRecord
|
||||
{
|
||||
private string _hostAddress;
|
||||
|
||||
/// <summary>
|
||||
/// The answer host address for the DNS A Record.
|
||||
/// </summary>
|
||||
public string HostAddress
|
||||
{
|
||||
get { return _hostAddress; }
|
||||
}
|
||||
|
||||
internal ARecord(RecordHeader dnsHeader) : base(dnsHeader) { }
|
||||
|
||||
public override void ParseRecord(ref MemoryStream ms)
|
||||
{
|
||||
_hostAddress = ms.ReadByte() + "." + ms.ReadByte() + "." + ms.ReadByte() + "." + ms.ReadByte();
|
||||
_answer = "Address: " + _hostAddress;
|
||||
}
|
||||
}
|
||||
}
|
97
MailServer/MailServer/DNSClient/Records/AaaaRecord.cs
Normal file
97
MailServer/MailServer/DNSClient/Records/AaaaRecord.cs
Normal file
@ -0,0 +1,97 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
public sealed class AaaaRecord : DnsRecordBase
|
||||
{
|
||||
private string m_ipAddress;
|
||||
|
||||
internal AaaaRecord(RecordHeader dnsHeader) : base(dnsHeader) { }
|
||||
|
||||
public override void ParseRecord(ref MemoryStream ms)
|
||||
{
|
||||
// TODO: Test and incorporate BinToHex function below
|
||||
m_ipAddress =
|
||||
ms.ReadByte().ToString("x2") + ms.ReadByte().ToString("x2") + ":" + ms.ReadByte().ToString("x2") + ms.ReadByte().ToString("x2") + ":" +
|
||||
ms.ReadByte().ToString("x2") + ms.ReadByte().ToString("x2") + ":" + ms.ReadByte().ToString("x2") + ms.ReadByte().ToString("x2") + ":" +
|
||||
ms.ReadByte().ToString("x2") + ms.ReadByte().ToString("x2") + ":" + ms.ReadByte().ToString("x2") + ms.ReadByte().ToString("x2") + ":" +
|
||||
ms.ReadByte().ToString("x2") + ms.ReadByte().ToString("x2") + ":" + ms.ReadByte().ToString("x2") + ms.ReadByte().ToString("x2");
|
||||
_answer = "IPv6 Address: " + m_ipAddress;
|
||||
}
|
||||
|
||||
// TODO: converted from VB.NET, test to make sure it works properly
|
||||
private static string BinToHex(byte[] data)
|
||||
{
|
||||
if (data != null)
|
||||
{
|
||||
StringBuilder sb = new System.Text.StringBuilder(1024);
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
sb.Append(data[i].ToString("X2"));
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: converted from VB.NET, test to make sure it works properly
|
||||
private static byte[] HexToBin(string s)
|
||||
{
|
||||
int arraySize = s.Length / 2;
|
||||
byte[] bytes = new byte[arraySize - 1];
|
||||
int counter = 0;
|
||||
|
||||
for (int i = 0; i < s.Length - 1; i = 2)
|
||||
{
|
||||
string hexValue = s.Substring(i, 2);
|
||||
|
||||
// Tell convert to interpret the string as a 16 bit hex value
|
||||
int intValue = Convert.ToInt32(hexValue, 16);
|
||||
// Convert the integer to a byte and store it in the array
|
||||
bytes[counter] = Convert.ToByte(intValue);
|
||||
counter += 1;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
}
|
78
MailServer/MailServer/DNSClient/Records/AfsdbRecord.cs
Normal file
78
MailServer/MailServer/DNSClient/Records/AfsdbRecord.cs
Normal file
@ -0,0 +1,78 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
public sealed class AfsdbRecord : DnsRecordBase
|
||||
{
|
||||
private ushort _port;
|
||||
private string _name;
|
||||
private short _type;
|
||||
|
||||
public ushort Port
|
||||
{
|
||||
get { return _port; }
|
||||
}
|
||||
|
||||
public string AfsdbName
|
||||
{
|
||||
get { return _name; }
|
||||
}
|
||||
|
||||
public short Type
|
||||
{
|
||||
get { return _type; }
|
||||
}
|
||||
|
||||
internal AfsdbRecord(RecordHeader dnsHeader) : base(dnsHeader) { }
|
||||
|
||||
public override void ParseRecord(ref MemoryStream ms)
|
||||
{
|
||||
byte[] type = new byte[2];
|
||||
ms.Read(type, 0, 2);
|
||||
// _port = (ushort)Tools.ByteToUInt(type);
|
||||
_port = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(type, 0));
|
||||
_name = DnsRecordBase.ParseName(ref ms);
|
||||
//_type = (short)Tools.ByteToUInt(type);
|
||||
_type = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(type, 0));
|
||||
_answer = "Name: " + _name + ", Port: " + _port + ", Type: " + _type;
|
||||
}
|
||||
}
|
||||
}
|
74
MailServer/MailServer/DNSClient/Records/AtmaRecord.cs
Normal file
74
MailServer/MailServer/DNSClient/Records/AtmaRecord.cs
Normal file
@ -0,0 +1,74 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
public sealed class AtmaRecord : DnsRecordBase
|
||||
{
|
||||
private string _address;
|
||||
private ATMFormat _format;
|
||||
|
||||
public string Address
|
||||
{
|
||||
get { return _address; }
|
||||
}
|
||||
|
||||
public ATMFormat Format
|
||||
{
|
||||
get { return _format; }
|
||||
}
|
||||
|
||||
internal AtmaRecord(RecordHeader dnsHeader) : base(dnsHeader) { }
|
||||
|
||||
public override void ParseRecord(ref MemoryStream ms)
|
||||
{
|
||||
byte[] address = new byte[this.DnsHeader.DataLength - 1];
|
||||
_format = (ATMFormat)ms.ReadByte();
|
||||
ms.Read(address, 0, this.DnsHeader.DataLength - 1);
|
||||
_address = Encoding.ASCII.GetString(address);
|
||||
_answer = "Address: " + _address + ", Format: " + _format;
|
||||
}
|
||||
|
||||
public enum ATMFormat : byte
|
||||
{
|
||||
E164 = 0x01,
|
||||
NSAP = 0x02
|
||||
}
|
||||
}
|
||||
}
|
346
MailServer/MailServer/DNSClient/Records/BaseDnsRecord.cs
Normal file
346
MailServer/MailServer/DNSClient/Records/BaseDnsRecord.cs
Normal file
@ -0,0 +1,346 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles a basic Dns record
|
||||
///
|
||||
/// From RFC 1035:
|
||||
///
|
||||
/// 3.2.1. Format
|
||||
///
|
||||
/// All RRs have the same top level format shown below:
|
||||
///
|
||||
/// 1 1 1 1 1 1
|
||||
/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
||||
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
/// | |
|
||||
/// / /
|
||||
/// / NAME /
|
||||
/// | |
|
||||
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
/// | TYPE |
|
||||
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
/// | CLASS |
|
||||
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
/// | TTL |
|
||||
/// | |
|
||||
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
/// | RDLENGTH |
|
||||
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
|
||||
/// / RDATA /
|
||||
/// / /
|
||||
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
///
|
||||
/// where:
|
||||
///
|
||||
/// NAME an owner name, i.e., the name of the node to which this
|
||||
/// resource record pertains.
|
||||
///
|
||||
/// TYPE two octets containing one of the RR TYPE codes.
|
||||
///
|
||||
/// CLASS two octets containing one of the RR CLASS codes.
|
||||
///
|
||||
/// TTL a 32 bit signed integer that specifies the time interval
|
||||
/// that the resource record may be cached before the source
|
||||
/// of the information should again be consulted. Zero
|
||||
/// values are interpreted to mean that the RR can only be
|
||||
/// used for the transaction in progress, and should not be
|
||||
/// cached. For example, SOA records are always distributed
|
||||
/// with a zero TTL to prohibit caching. Zero values can
|
||||
/// also be used for extremely volatile data.
|
||||
///
|
||||
/// RDLENGTH an unsigned 16 bit integer that specifies the length in
|
||||
/// octets of the RDATA field.
|
||||
///
|
||||
/// RDATA a variable length string of octets that describes the
|
||||
/// resource. The format of this information varies
|
||||
/// according to the TYPE and CLASS of the resource record.
|
||||
/// </summary>
|
||||
public abstract class DnsRecordBase : IDnsRecord
|
||||
{
|
||||
#region Fields
|
||||
// NAME an owner name, i.e., the name of the node to which this
|
||||
// resource record pertains.
|
||||
//private string _name;
|
||||
// TYPE two octets containing one of the RR TYPE codes.
|
||||
//protected NsType _nsType;
|
||||
// CLASS - two octets containing one of the RR CLASS codes.
|
||||
//private NsClass _nsClass;
|
||||
// TTL - a 32 bit signed integer that specifies the time interval
|
||||
// that the resource record may be cached before the source
|
||||
// of the information should again be consulted. Zero
|
||||
// values are interpreted to mean that the RR can only be
|
||||
// used for the transaction in progress, and should not be
|
||||
// cached. For example, SOA records are always distributed
|
||||
// with a zero TTL to prohibit caching. Zero values can
|
||||
/// also be used for extremely volatile data.
|
||||
//private int _timeToLive;
|
||||
// RDLENGTH - an unsigned 16 bit integer that specifies the length in
|
||||
// octets of the RDATA field.
|
||||
//protected short _dataLength;
|
||||
protected RecordHeader _dnsHeader;
|
||||
protected string _answer;
|
||||
protected string _errorMsg;
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// NAME - an owner name, i.e., the name of the node to which this
|
||||
/// resource record pertains.
|
||||
/// </summary>
|
||||
//public string Name
|
||||
//{
|
||||
// get { return _name; }
|
||||
//}
|
||||
|
||||
public RecordHeader DnsHeader
|
||||
{
|
||||
get { return _dnsHeader; }
|
||||
protected set { _dnsHeader = value; }
|
||||
}
|
||||
|
||||
public string Answer
|
||||
{
|
||||
get { return _answer; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// TYPE two octets containing one of the RR TYPE codes.
|
||||
/// </summary>
|
||||
//public NsType NsType
|
||||
//{
|
||||
// get { return _nsType; }
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// CLASS - two octets containing one of the RR CLASS codes.
|
||||
/// </summary>
|
||||
//public NsClass NsClass
|
||||
//{
|
||||
// get { return _nsClass; }
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// TTL - a 32 bit signed integer that specifies the time interval
|
||||
/// that the resource record may be cached before the source
|
||||
/// of the information should again be consulted. Zero
|
||||
/// values are interpreted to mean that the RR can only be
|
||||
/// used for the transaction in progress, and should not be
|
||||
/// cached. For example, SOA records are always distributed
|
||||
/// with a zero TTL to prohibit caching. Zero values can
|
||||
/// also be used for extremely volatile data.
|
||||
/// </summary>
|
||||
//public int TimeToLive
|
||||
//{
|
||||
// get { return _timeToLive; }
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// RDLENGTH - an unsigned 16 bit integer that specifies the length in
|
||||
/// octets of the RDATA field.
|
||||
/// </summary>
|
||||
//public short DataLength
|
||||
//{
|
||||
// get { return _dataLength; }
|
||||
//}
|
||||
|
||||
public string ErrorMsg
|
||||
{
|
||||
get { return _errorMsg; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
internal DnsRecordBase()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void ParseRecord(ref MemoryStream ms)
|
||||
{
|
||||
// Default implementation - the most common.
|
||||
_answer = DnsRecordBase.ParseName(ref ms);
|
||||
}
|
||||
|
||||
internal DnsRecordBase(RecordHeader dnsHeader)
|
||||
{
|
||||
_dnsHeader = dnsHeader;
|
||||
}
|
||||
|
||||
// RFC
|
||||
// 4.1.4. Message compression
|
||||
//
|
||||
// In order to reduce the size of messages, the domain system utilizes a
|
||||
// compression scheme which eliminates the repetition of domain names in a
|
||||
// message. In this scheme, an entire domain name or a list of labels at
|
||||
// the end of a domain name is replaced with a pointer to a prior occurance
|
||||
// of the same name.
|
||||
//
|
||||
// The pointer takes the form of a two octet sequence:
|
||||
//
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// | 1 1| OFFSET |
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
//
|
||||
// The first two bits are ones. This allows a pointer to be distinguished
|
||||
// from a label, since the label must begin with two zero bits because
|
||||
// labels are restricted to 63 octets or less. (The 10 and 01 combinations
|
||||
// are reserved for future use.) The OFFSET field specifies an offset from
|
||||
// the start of the message (i.e., the first octet of the ID field in the
|
||||
// domain header). A zero offset specifies the first byte of the ID field,
|
||||
// etc.
|
||||
//
|
||||
// The compression scheme allows a domain name in a message to be
|
||||
// represented as either:
|
||||
//
|
||||
// - a sequence of labels ending in a zero octet
|
||||
// - a pointer
|
||||
// - a sequence of labels ending with a pointer
|
||||
//
|
||||
|
||||
internal static string ParseName(ref MemoryStream ms)
|
||||
{
|
||||
Trace.WriteLine("Reading Name...");
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
uint next = (uint)ms.ReadByte();
|
||||
Trace.WriteLine("Next is 0x" + next.ToString("x2"));
|
||||
int bPointer;
|
||||
|
||||
while ((next != 0x00))
|
||||
{
|
||||
// Isolate 2 most significat bits -> e.g. 11xx xxxx
|
||||
// if it's 0xc0 (11000000b} then pointer
|
||||
switch (0xc0 & next)
|
||||
{
|
||||
// 0xc0 -> Name is a pointer.
|
||||
case 0xc0:
|
||||
{
|
||||
// Isolate Offset
|
||||
int offsetMASK = ~0xc0;
|
||||
|
||||
// Example on how to calculate the offset
|
||||
// e.g.
|
||||
//
|
||||
// So if given the following 2 bytes - 0xc1 0x1c (11000001 00011100)
|
||||
//
|
||||
// The pointer takes the form of a two octet sequence:
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// | 1 1| OFFSET |
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
// | 1 1| 0 0 0 0 0 1 0 0 0 1 1 1 0 0|
|
||||
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
//
|
||||
// A pointer is indicated by the a 1 in the two most significant bits
|
||||
// The Offset is the remaining bits.
|
||||
//
|
||||
// The Pointer = 0xc0 (11000000 00000000)
|
||||
// The offset = 0x11c (00000001 00011100)
|
||||
|
||||
// Move offset into the proper position
|
||||
int offset = (int)(offsetMASK & next) << 8;
|
||||
|
||||
// extract the pointer to the data in the stream
|
||||
bPointer = ms.ReadByte() + offset;
|
||||
// store the position so we can resume later
|
||||
long oldPtr = ms.Position;
|
||||
// Move to the specified position in the stream and
|
||||
// parse the name (recursive call)
|
||||
ms.Position = bPointer;
|
||||
sb.Append(DnsRecordBase.ParseName(ref ms));
|
||||
Trace.WriteLine(sb.ToString());
|
||||
// Move back to original position, and continue
|
||||
ms.Position = oldPtr;
|
||||
next = 0x00;
|
||||
break;
|
||||
}
|
||||
case 0x00:
|
||||
{
|
||||
Debug.Assert(next < 0xc0, "Offset cannot be greater then 0xc0.");
|
||||
byte[] buffer = new byte[next];
|
||||
ms.Read(buffer, 0, (int)next);
|
||||
sb.Append(Encoding.ASCII.GetString(buffer) + ".");
|
||||
next = (uint)ms.ReadByte();
|
||||
Trace.WriteLine("0x" + next.ToString("x2"));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new InvalidOperationException("There was a problem decompressing the DNS Message.");
|
||||
}
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
internal string ParseText(ref MemoryStream ms)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int len = ms.ReadByte();
|
||||
byte[] buffer = new byte[len];
|
||||
ms.Read(buffer, 0, len);
|
||||
sb.Append(Encoding.ASCII.GetString(buffer));
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _answer;
|
||||
}
|
||||
|
||||
#region IDnsRecord Members
|
||||
|
||||
public virtual byte[] GetMessageBytes()
|
||||
{
|
||||
return new byte[]{};
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
internal class Trace
|
||||
{
|
||||
public static void WriteLine(string message)
|
||||
{
|
||||
Logging.AddLogMessage(Logging.LoggingType.INFO, message);
|
||||
}
|
||||
}
|
||||
}
|
52
MailServer/MailServer/DNSClient/Records/CNameRecord.cs
Normal file
52
MailServer/MailServer/DNSClient/Records/CNameRecord.cs
Normal file
@ -0,0 +1,52 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
public sealed class CNameRecord : DnsRecordBase
|
||||
{
|
||||
internal CNameRecord(RecordHeader dnsHeader) : base(dnsHeader) {}
|
||||
|
||||
public override void ParseRecord(ref MemoryStream ms)
|
||||
{
|
||||
base.ParseRecord(ref ms);
|
||||
_answer = "Host: " + _answer;
|
||||
}
|
||||
}
|
||||
}
|
67
MailServer/MailServer/DNSClient/Records/HInfoRecord.cs
Normal file
67
MailServer/MailServer/DNSClient/Records/HInfoRecord.cs
Normal file
@ -0,0 +1,67 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
public sealed class HInfoRecord : DnsRecordBase
|
||||
{
|
||||
private string _cpuType;
|
||||
private string _operatingSys;
|
||||
|
||||
public string CpuType
|
||||
{
|
||||
get { return _cpuType; }
|
||||
}
|
||||
|
||||
public string OperatingSys
|
||||
{
|
||||
get { return _operatingSys; }
|
||||
}
|
||||
|
||||
internal HInfoRecord(RecordHeader dnsHeader) : base(dnsHeader) { }
|
||||
|
||||
public override void ParseRecord(ref MemoryStream ms)
|
||||
{
|
||||
_cpuType = base.ParseText(ref ms);
|
||||
_operatingSys = base.ParseText(ref ms);
|
||||
_answer = "CPU: " + _cpuType + ", OS: " + _operatingSys;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
58
MailServer/MailServer/DNSClient/Records/IDnsRecord.cs
Normal file
58
MailServer/MailServer/DNSClient/Records/IDnsRecord.cs
Normal file
@ -0,0 +1,58 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
public interface IDnsRecord
|
||||
{
|
||||
RecordHeader DnsHeader { get; }
|
||||
string Answer { get; }
|
||||
//short DataLength { get; }
|
||||
string ErrorMsg { get; }
|
||||
//string Name { get; }
|
||||
//NsClass NsClass { get; }
|
||||
//NsType NsType { get; }
|
||||
//int TimeToLive { get; }
|
||||
//void ParseRecordHeader(ref MemoryStream ms);
|
||||
void ParseRecord(ref MemoryStream ms);
|
||||
string ToString();
|
||||
|
||||
byte[] GetMessageBytes();
|
||||
}
|
||||
}
|
66
MailServer/MailServer/DNSClient/Records/IsdnRecord.cs
Normal file
66
MailServer/MailServer/DNSClient/Records/IsdnRecord.cs
Normal file
@ -0,0 +1,66 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
public sealed class IsdnRecord : DnsRecordBase
|
||||
{
|
||||
private string _address;
|
||||
private string _subAddress;
|
||||
|
||||
public string Address
|
||||
{
|
||||
get { return _address; }
|
||||
}
|
||||
|
||||
public string SubAddress
|
||||
{
|
||||
get { return _subAddress; }
|
||||
}
|
||||
|
||||
internal IsdnRecord(RecordHeader dnsHeader) : base(dnsHeader) { }
|
||||
|
||||
public override void ParseRecord(ref MemoryStream ms)
|
||||
{
|
||||
_address = base.ParseText(ref ms);
|
||||
_subAddress = base.ParseText(ref ms);
|
||||
_answer = "ISDN Address: " + _address + ", SubAddress: " + _subAddress;
|
||||
}
|
||||
}
|
||||
}
|
194
MailServer/MailServer/DNSClient/Records/LocRecord.cs
Normal file
194
MailServer/MailServer/DNSClient/Records/LocRecord.cs
Normal file
@ -0,0 +1,194 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
public sealed class LocRecord : DnsRecordBase
|
||||
{
|
||||
// For LOC
|
||||
#region Fields
|
||||
private byte _version;
|
||||
private byte _size;
|
||||
private byte _horPrecision;
|
||||
private byte _vertPrecision;
|
||||
private uint _latitude;
|
||||
private uint _longitude;
|
||||
private uint _altitude;
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
public byte Version
|
||||
{
|
||||
get { return _version; }
|
||||
}
|
||||
|
||||
public byte Size
|
||||
{
|
||||
get { return _size; }
|
||||
}
|
||||
|
||||
public byte HorPrecision
|
||||
{
|
||||
get { return _horPrecision; }
|
||||
}
|
||||
|
||||
public byte VertPrecision
|
||||
{
|
||||
get { return _vertPrecision; }
|
||||
}
|
||||
|
||||
public uint Latitude
|
||||
{
|
||||
get { return _latitude; }
|
||||
}
|
||||
|
||||
public uint Longitude
|
||||
{
|
||||
get { return _longitude; }
|
||||
}
|
||||
|
||||
public uint Altitude
|
||||
{
|
||||
get { return _altitude; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
private char[] _latDirection = new char[2] {'N', 'S'};
|
||||
private char[] _longDirection = new char[2] {'E', 'W'};
|
||||
|
||||
internal LocRecord(RecordHeader dnsHeader) : base(dnsHeader) {}
|
||||
|
||||
public override void ParseRecord(ref MemoryStream ms)
|
||||
{
|
||||
byte[] latitude = new Byte[4];
|
||||
byte[] longitude = new Byte[4];
|
||||
byte[] altitude = new Byte[4];
|
||||
|
||||
_version = (byte)ms.ReadByte();
|
||||
_size = (byte)ms.ReadByte();
|
||||
_horPrecision = (byte)ms.ReadByte();
|
||||
_vertPrecision = (byte)ms.ReadByte();
|
||||
|
||||
ms.Read(latitude,0,latitude.Length);
|
||||
// _latitude = Tools.ByteToUInt(latitude);
|
||||
_latitude = (uint)IPAddress.NetworkToHostOrder((int)BitConverter.ToUInt32(latitude, 0));
|
||||
|
||||
ms.Read(longitude,0,longitude.Length);
|
||||
// _longitude = Tools.ByteToUInt(longitude);
|
||||
_longitude = (uint)IPAddress.NetworkToHostOrder((int)BitConverter.ToUInt32(longitude, 0));
|
||||
|
||||
|
||||
ms.Read(altitude,0,altitude.Length);
|
||||
// _altitude = Tools.ByteToUInt(altitude);
|
||||
_altitude = (uint)IPAddress.NetworkToHostOrder((int)BitConverter.ToUInt32(altitude, 0));
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append("Version: ");
|
||||
sb.Append(_version);
|
||||
sb.Append("\r\n");
|
||||
|
||||
sb.Append("Size: ");
|
||||
sb.Append(CalcSize(_size));
|
||||
sb.Append(" m\r\n");
|
||||
|
||||
sb.Append("Horizontal Precision: ");
|
||||
sb.Append(CalcSize(_horPrecision));
|
||||
sb.Append(" m\r\n");
|
||||
|
||||
sb.Append("Vertical Precision: ");
|
||||
sb.Append(CalcSize(_vertPrecision));
|
||||
sb.Append(" m\r\n");
|
||||
|
||||
sb.Append("Latitude: ");
|
||||
sb.Append(CalcLoc(_latitude, _latDirection));
|
||||
sb.Append("\r\n");
|
||||
|
||||
sb.Append("Longitude: ");
|
||||
sb.Append(CalcLoc(_longitude, _longDirection));
|
||||
sb.Append("\r\n");
|
||||
|
||||
sb.Append("Altitude: ");
|
||||
sb.Append((_altitude - 10000000) / 100.0);
|
||||
sb.Append(" m\r\n");
|
||||
|
||||
_answer = sb.ToString();
|
||||
}
|
||||
|
||||
private string CalcLoc(uint angle, char[] nsew)
|
||||
{
|
||||
char direction;
|
||||
if (angle < 0x80000000)
|
||||
{
|
||||
angle = 0x80000000 - angle;
|
||||
direction = nsew[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
angle = angle - 0x80000000;
|
||||
direction = nsew[0];
|
||||
}
|
||||
|
||||
uint tsecs = angle % 1000;
|
||||
angle = angle / 1000;
|
||||
uint secs = angle % 60;
|
||||
angle = angle / 60;
|
||||
uint minutes = angle % 60;
|
||||
uint degrees = angle / 60;
|
||||
|
||||
return degrees + " deg, " + minutes + " min " + secs+ "." + tsecs + " sec " + direction;
|
||||
}
|
||||
|
||||
// return size in meters
|
||||
private double CalcSize(byte val)
|
||||
{
|
||||
double size;
|
||||
int exponent;
|
||||
|
||||
size = (val & 0xF0) >> 4;
|
||||
exponent = (val & 0x0F);
|
||||
while (exponent != 0)
|
||||
{
|
||||
size *= 10;
|
||||
exponent--;
|
||||
}
|
||||
return size / 100;
|
||||
}
|
||||
}
|
||||
}
|
66
MailServer/MailServer/DNSClient/Records/MInfoRecord.cs
Normal file
66
MailServer/MailServer/DNSClient/Records/MInfoRecord.cs
Normal file
@ -0,0 +1,66 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
public sealed class MInfoRecord : DnsRecordBase
|
||||
{
|
||||
private string _responsibleMb;
|
||||
private string _errorMb;
|
||||
|
||||
public string ResponsibleMb
|
||||
{
|
||||
get { return _responsibleMb; }
|
||||
}
|
||||
|
||||
public string ErrorMb
|
||||
{
|
||||
get { return _errorMb; }
|
||||
}
|
||||
|
||||
internal MInfoRecord(RecordHeader dnsHeader) : base(dnsHeader) { }
|
||||
|
||||
public override void ParseRecord(ref MemoryStream ms)
|
||||
{
|
||||
_responsibleMb = DnsRecordBase.ParseName(ref ms);
|
||||
_errorMb = DnsRecordBase.ParseName(ref ms);
|
||||
_answer = "Responsible MailBox: " + _responsibleMb + ", Error MailBox: " + _errorMb;
|
||||
}
|
||||
}
|
||||
}
|
52
MailServer/MailServer/DNSClient/Records/MbRecord.cs
Normal file
52
MailServer/MailServer/DNSClient/Records/MbRecord.cs
Normal file
@ -0,0 +1,52 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
public sealed class MbRecord : DnsRecordBase
|
||||
{
|
||||
internal MbRecord(RecordHeader dnsHeader) : base(dnsHeader) { }
|
||||
|
||||
//public override void ParseRecord(ref MemoryStream ms)
|
||||
//{
|
||||
// _answer = BaseDnsRecord.ParseName(ref ms);
|
||||
//}
|
||||
}
|
||||
|
||||
}
|
51
MailServer/MailServer/DNSClient/Records/MgRecord.cs
Normal file
51
MailServer/MailServer/DNSClient/Records/MgRecord.cs
Normal file
@ -0,0 +1,51 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
public sealed class MgRecord : DnsRecordBase
|
||||
{
|
||||
internal MgRecord(RecordHeader dnsHeader) : base(dnsHeader) { }
|
||||
|
||||
//public override void ParseRecord(ref MemoryStream ms)
|
||||
//{
|
||||
// _answer = BaseDnsRecord.ParseName(ref ms);
|
||||
//}
|
||||
}
|
||||
}
|
51
MailServer/MailServer/DNSClient/Records/MrRecord.cs
Normal file
51
MailServer/MailServer/DNSClient/Records/MrRecord.cs
Normal file
@ -0,0 +1,51 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
public sealed class MrRecord : DnsRecordBase
|
||||
{
|
||||
internal MrRecord(RecordHeader dnsHeader) : base(dnsHeader) { }
|
||||
|
||||
//public override void ParseRecord(ref MemoryStream ms)
|
||||
//{
|
||||
// _answer = BaseDnsRecord.ParseName(ref ms);
|
||||
//}
|
||||
}
|
||||
}
|
75
MailServer/MailServer/DNSClient/Records/MxRecord.cs
Normal file
75
MailServer/MailServer/DNSClient/Records/MxRecord.cs
Normal file
@ -0,0 +1,75 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
public sealed class MxRecord : DnsRecordBase
|
||||
{
|
||||
// For MX
|
||||
private short _preference;
|
||||
private string _mailExchange;
|
||||
|
||||
public short Preference
|
||||
{
|
||||
get { return _preference; }
|
||||
}
|
||||
|
||||
public string MailExchange
|
||||
{
|
||||
get { return _mailExchange; }
|
||||
}
|
||||
|
||||
internal MxRecord(RecordHeader dnsHeader) : base(dnsHeader) { }
|
||||
|
||||
public override void ParseRecord(ref MemoryStream ms)
|
||||
{
|
||||
// Preference is a function of MX records
|
||||
byte[] nsPreference = new byte[2];
|
||||
ms.Read(nsPreference, 0, 2);
|
||||
//_preference = (short)Tools.ByteToUInt(nsPreference);
|
||||
// TODO: Should this be a UShort instead of a short?
|
||||
_preference = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(nsPreference, 0));
|
||||
|
||||
// Parse Name
|
||||
_mailExchange = DnsRecordBase.ParseName(ref ms);
|
||||
_answer = "MX Preference: " + _preference + ", Mail Exchanger: " + _mailExchange;
|
||||
}
|
||||
}
|
||||
}
|
51
MailServer/MailServer/DNSClient/Records/NsRecord.cs
Normal file
51
MailServer/MailServer/DNSClient/Records/NsRecord.cs
Normal file
@ -0,0 +1,51 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
public sealed class NsRecord : DnsRecordBase
|
||||
{
|
||||
internal NsRecord(RecordHeader dnsHeader) : base(dnsHeader) { }
|
||||
|
||||
//public override void ParseRecord(ref MemoryStream ms)
|
||||
//{
|
||||
// _answer = BaseDnsRecord.ParseName(ref ms);
|
||||
//}
|
||||
}
|
||||
}
|
51
MailServer/MailServer/DNSClient/Records/PtrRecord.cs
Normal file
51
MailServer/MailServer/DNSClient/Records/PtrRecord.cs
Normal file
@ -0,0 +1,51 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
public sealed class PtrRecord : DnsRecordBase
|
||||
{
|
||||
internal PtrRecord(RecordHeader dnsHeader) : base(dnsHeader) { }
|
||||
|
||||
//public override void ParseRecord(ref MemoryStream ms)
|
||||
//{
|
||||
// _answer = BaseDnsRecord.ParseName(ref ms);
|
||||
//}
|
||||
}
|
||||
}
|
191
MailServer/MailServer/DNSClient/Records/RecordFactory.cs
Normal file
191
MailServer/MailServer/DNSClient/Records/RecordFactory.cs
Normal file
@ -0,0 +1,191 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
using DnDns.Enums;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
class RecordFactory
|
||||
{
|
||||
public static IDnsRecord Create(ref MemoryStream ms)
|
||||
{
|
||||
IDnsRecord dnsRecord;
|
||||
// Have to start out with an unknown record, since we have to parse the entire
|
||||
// header before we can determine the type of DNS record it is.
|
||||
// TODO: Consider other options.
|
||||
|
||||
// start as an unknown type, then create a known type, parse the response
|
||||
// and return the object.
|
||||
//DnsRecordBase dr = new DnsUnknownRecord();
|
||||
//dr.ParseRecordHeader(ref ms);
|
||||
|
||||
RecordHeader dnsHeader = new RecordHeader();
|
||||
dnsHeader.ParseRecordHeader(ref ms);
|
||||
|
||||
switch (dnsHeader.NsType)
|
||||
{
|
||||
case NsType.A:
|
||||
{
|
||||
dnsRecord = new ARecord(dnsHeader);
|
||||
break;
|
||||
}
|
||||
case NsType.AAAA:
|
||||
{
|
||||
dnsRecord = new AaaaRecord(dnsHeader);
|
||||
break;
|
||||
}
|
||||
case NsType.MX:
|
||||
{
|
||||
dnsRecord = new MxRecord(dnsHeader);
|
||||
break;
|
||||
}
|
||||
case NsType.RP:
|
||||
{
|
||||
dnsRecord = new RpRecord(dnsHeader);
|
||||
break;
|
||||
}
|
||||
case NsType.MR:
|
||||
{
|
||||
dnsRecord = new MrRecord(dnsHeader);
|
||||
break;
|
||||
}
|
||||
case NsType.MB:
|
||||
{
|
||||
dnsRecord = new MbRecord(dnsHeader);
|
||||
break;
|
||||
}
|
||||
case NsType.MG:
|
||||
{
|
||||
dnsRecord = new MgRecord(dnsHeader);
|
||||
break;
|
||||
}
|
||||
case NsType.NS:
|
||||
{
|
||||
dnsRecord = new NsRecord(dnsHeader);
|
||||
break;
|
||||
}
|
||||
case NsType.CNAME:
|
||||
{
|
||||
dnsRecord = new CNameRecord(dnsHeader);
|
||||
break;
|
||||
}
|
||||
case NsType.PTR:
|
||||
{
|
||||
dnsRecord = new PtrRecord(dnsHeader);
|
||||
break;
|
||||
}
|
||||
case NsType.HINFO:
|
||||
{
|
||||
dnsRecord = new HInfoRecord(dnsHeader);
|
||||
break;
|
||||
}
|
||||
case NsType.MINFO:
|
||||
{
|
||||
dnsRecord = new MInfoRecord(dnsHeader);
|
||||
break;
|
||||
}
|
||||
case NsType.X25:
|
||||
{
|
||||
dnsRecord = new X25Record(dnsHeader);
|
||||
break;
|
||||
}
|
||||
case NsType.TXT:
|
||||
{
|
||||
dnsRecord = new TxtRecord(dnsHeader);
|
||||
break;
|
||||
}
|
||||
case NsType.LOC:
|
||||
{
|
||||
dnsRecord = new LocRecord(dnsHeader);
|
||||
break;
|
||||
}
|
||||
case NsType.SOA:
|
||||
{
|
||||
dnsRecord = new SoaRecord(dnsHeader);
|
||||
break;
|
||||
}
|
||||
case NsType.SRV:
|
||||
{
|
||||
dnsRecord = new SrvRecord(dnsHeader);
|
||||
break;
|
||||
}
|
||||
case NsType.AFSDB:
|
||||
{
|
||||
dnsRecord = new AfsdbRecord(dnsHeader);
|
||||
break;
|
||||
}
|
||||
case NsType.ATMA:
|
||||
{
|
||||
dnsRecord = new AtmaRecord(dnsHeader);
|
||||
break;
|
||||
}
|
||||
case NsType.ISDN:
|
||||
{
|
||||
dnsRecord = new IsdnRecord(dnsHeader);
|
||||
break;
|
||||
}
|
||||
case NsType.RT:
|
||||
{
|
||||
dnsRecord = new RtRecord(dnsHeader);
|
||||
break;
|
||||
}
|
||||
case NsType.WKS:
|
||||
{
|
||||
dnsRecord = new WksRecord(dnsHeader);
|
||||
break;
|
||||
}
|
||||
case NsType.TSIG:
|
||||
{
|
||||
dnsRecord = new TSigRecord(dnsHeader);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
// Unknown type. parse and return the DnsUnknownRecord
|
||||
dnsRecord = new UnknownRecord(dnsHeader);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//dnsRecord.ParseRecordHeader(ref ms);
|
||||
dnsRecord.ParseRecord(ref ms);
|
||||
return dnsRecord;
|
||||
}
|
||||
}
|
||||
}
|
242
MailServer/MailServer/DNSClient/Records/RecordHeader.cs
Normal file
242
MailServer/MailServer/DNSClient/Records/RecordHeader.cs
Normal file
@ -0,0 +1,242 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
using DnDns.Enums;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
/// <summary>
|
||||
/// The DnsRecordHeader class contains fields, properties and
|
||||
/// parsing cababilities within the DNS Record except the the
|
||||
/// RDATA. The Name, Type, Class, TTL, and RDLength.
|
||||
///
|
||||
/// This class is used in the DnsRecordFactory to instantiate
|
||||
/// concrete DnsRecord Classes.
|
||||
///
|
||||
/// RFC 1035
|
||||
///
|
||||
/// 3.2.1. Format
|
||||
///
|
||||
/// All RRs have the same top level format shown below:
|
||||
///
|
||||
/// 1 1 1 1 1 1
|
||||
/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
||||
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
/// | |
|
||||
/// / /
|
||||
/// / NAME /
|
||||
/// | |
|
||||
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
/// | TYPE |
|
||||
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
/// | CLASS |
|
||||
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
/// | TTL |
|
||||
/// | |
|
||||
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
/// | RDLENGTH |
|
||||
/// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
|
||||
///
|
||||
/// where:
|
||||
///
|
||||
/// NAME an owner name, i.e., the name of the node to which this
|
||||
/// resource record pertains.
|
||||
///
|
||||
/// TYPE two octets containing one of the RR TYPE codes.
|
||||
///
|
||||
/// CLASS two octets containing one of the RR CLASS codes.
|
||||
///
|
||||
/// TTL a 32 bit signed integer that specifies the time interval
|
||||
/// that the resource record may be cached before the source
|
||||
/// of the information should again be consulted. Zero
|
||||
/// values are interpreted to mean that the RR can only be
|
||||
/// used for the transaction in progress, and should not be
|
||||
/// cached. For example, SOA records are always distributed
|
||||
/// with a zero TTL to prohibit caching. Zero values can
|
||||
/// also be used for extremely volatile data.
|
||||
///
|
||||
/// RDLENGTH an unsigned 16 bit integer that specifies the length in
|
||||
/// octets of the RDATA field.
|
||||
///
|
||||
/// </summary>
|
||||
public class RecordHeader
|
||||
{
|
||||
#region Fields
|
||||
// NAME an owner name, i.e., the name of the node to which this
|
||||
// resource record pertains.
|
||||
private string _name;
|
||||
// TYPE two octets containing one of the RR TYPE codes.
|
||||
private NsType _nsType;
|
||||
// CLASS - two octets containing one of the RR CLASS codes.
|
||||
private NsClass _nsClass;
|
||||
// TTL - a 32 bit signed integer that specifies the time interval
|
||||
// that the resource record may be cached before the source
|
||||
// of the information should again be consulted. Zero
|
||||
// values are interpreted to mean that the RR can only be
|
||||
// used for the transaction in progress, and should not be
|
||||
// cached. For example, SOA records are always distributed
|
||||
// with a zero TTL to prohibit caching. Zero values can
|
||||
/// also be used for extremely volatile data.
|
||||
private int _timeToLive;
|
||||
// RDLENGTH - an unsigned 16 bit integer that specifies the length in
|
||||
// octets of the RDATA field.
|
||||
private short _dataLength;
|
||||
|
||||
/// <summary>
|
||||
/// Initalise the <see cref="RecordHeader"/>
|
||||
/// </summary>
|
||||
/// <param name="name">The header name</param>
|
||||
/// <param name="nsType">The resource type</param>
|
||||
/// <param name="nsClass">The class type</param>
|
||||
/// <param name="timeToLive">The time to live</param>
|
||||
public RecordHeader(string name, NsType nsType, NsClass nsClass, int timeToLive)
|
||||
{
|
||||
_name = name;
|
||||
_nsType = nsType;
|
||||
_nsClass = nsClass;
|
||||
_timeToLive = timeToLive;
|
||||
}
|
||||
|
||||
public RecordHeader()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// NAME - an owner name, i.e., the name of the node to which this
|
||||
/// resource record pertains.
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TYPE two octets containing one of the RR TYPE codes.
|
||||
/// </summary>
|
||||
public NsType NsType
|
||||
{
|
||||
get { return _nsType; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CLASS - two octets containing one of the RR CLASS codes.
|
||||
/// </summary>
|
||||
public NsClass NsClass
|
||||
{
|
||||
get { return _nsClass; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TTL - a 32 bit signed integer that specifies the time interval
|
||||
/// that the resource record may be cached before the source
|
||||
/// of the information should again be consulted. Zero
|
||||
/// values are interpreted to mean that the RR can only be
|
||||
/// used for the transaction in progress, and should not be
|
||||
/// cached. For example, SOA records are always distributed
|
||||
/// with a zero TTL to prohibit caching. Zero values can
|
||||
/// also be used for extremely volatile data.
|
||||
/// </summary>
|
||||
public int TimeToLive
|
||||
{
|
||||
get { return _timeToLive; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RDLENGTH - an unsigned 16 bit integer that specifies the length in
|
||||
/// octets of the RDATA field.
|
||||
/// </summary>
|
||||
public short DataLength
|
||||
{
|
||||
get { return _dataLength; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="ms"></param>
|
||||
public void ParseRecordHeader(ref MemoryStream ms)
|
||||
{
|
||||
byte[] nsType = new byte[2];
|
||||
byte[] nsClass = new byte[2];
|
||||
byte[] nsTTL = new byte[4];
|
||||
byte[] nsDataLength = new byte[2];
|
||||
|
||||
// Read the name
|
||||
_name = DnsRecordBase.ParseName(ref ms);
|
||||
|
||||
// Read the data header
|
||||
ms.Read(nsType, 0, 2);
|
||||
ms.Read(nsClass, 0, 2);
|
||||
ms.Read(nsTTL, 0, 4);
|
||||
ms.Read(nsDataLength, 0, 2);
|
||||
_nsType = (NsType)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(nsType, 0));
|
||||
_nsClass = (NsClass)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(nsClass, 0));
|
||||
|
||||
_timeToLive = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(nsTTL, 0));
|
||||
_dataLength = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(nsDataLength, 0));
|
||||
}
|
||||
|
||||
internal byte[] GetMessageBytes()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
|
||||
byte[] data = DnsHelpers.CanonicaliseDnsName(_name, false);
|
||||
memoryStream.Write(data,0,data.Length);
|
||||
|
||||
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder((ushort)_nsType) >> 16));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder((ushort)_nsClass) >> 16));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
data = BitConverter.GetBytes((uint)(IPAddress.HostToNetworkOrder((ushort)_timeToLive) >> 32));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder((ushort)_dataLength) >> 16));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
68
MailServer/MailServer/DNSClient/Records/RpRecord.cs
Normal file
68
MailServer/MailServer/DNSClient/Records/RpRecord.cs
Normal file
@ -0,0 +1,68 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
public sealed class RpRecord : DnsRecordBase
|
||||
{
|
||||
// For RP
|
||||
private string _name;
|
||||
private string _textLocation;
|
||||
|
||||
public string RpName
|
||||
{
|
||||
get { return _name; }
|
||||
}
|
||||
|
||||
public string TextLocation
|
||||
{
|
||||
get { return _textLocation; }
|
||||
}
|
||||
|
||||
internal RpRecord(RecordHeader dnsHeader) : base(dnsHeader) {}
|
||||
|
||||
public override void ParseRecord(ref MemoryStream ms)
|
||||
{
|
||||
_name = DnsRecordBase.ParseName(ref ms);
|
||||
_textLocation = DnsRecordBase.ParseName(ref ms);
|
||||
_answer = _name + ", " + _textLocation;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
71
MailServer/MailServer/DNSClient/Records/RtRecord.cs
Normal file
71
MailServer/MailServer/DNSClient/Records/RtRecord.cs
Normal file
@ -0,0 +1,71 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
public sealed class RtRecord : DnsRecordBase
|
||||
{
|
||||
private ushort _preference;
|
||||
private string _intermediateHost;
|
||||
|
||||
public ushort Preference
|
||||
{
|
||||
get { return _preference; }
|
||||
}
|
||||
|
||||
public string IntermediateHost
|
||||
{
|
||||
get { return _intermediateHost; }
|
||||
}
|
||||
|
||||
internal RtRecord(RecordHeader dnsHeader) : base(dnsHeader) { }
|
||||
|
||||
public override void ParseRecord(ref MemoryStream ms)
|
||||
{
|
||||
byte[] preference = new byte[2];
|
||||
ms.Read(preference, 0, 2);
|
||||
//_preference = (ushort)Tools.ByteToUInt(preference);
|
||||
_preference = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(preference, 0));
|
||||
_intermediateHost = DnsRecordBase.ParseName(ref ms);
|
||||
_answer = "Preference: " + _preference + ", Intermediate Host: " + _intermediateHost;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
160
MailServer/MailServer/DNSClient/Records/SoaRecord.cs
Normal file
160
MailServer/MailServer/DNSClient/Records/SoaRecord.cs
Normal file
@ -0,0 +1,160 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
public sealed class SoaRecord : DnsRecordBase
|
||||
{
|
||||
// For SOA
|
||||
#region fields
|
||||
private string _primaryNameServer;
|
||||
private string _responsiblePerson;
|
||||
private uint _serial;
|
||||
private uint _refreshInterval;
|
||||
private uint _retryInterval;
|
||||
private uint _expirationLimit;
|
||||
// RFC 1034: TTL - only positive values of a signed 32 bit number.
|
||||
private int _minimumTimeToLive;
|
||||
#endregion
|
||||
|
||||
#region properties
|
||||
public string PrimaryNameServer
|
||||
{
|
||||
get { return _primaryNameServer; }
|
||||
}
|
||||
|
||||
public string ResponsiblePerson
|
||||
{
|
||||
get { return _responsiblePerson; }
|
||||
}
|
||||
|
||||
public uint Serial
|
||||
{
|
||||
get { return _serial; }
|
||||
}
|
||||
|
||||
public uint RefreshInterval
|
||||
{
|
||||
get { return _refreshInterval; }
|
||||
}
|
||||
|
||||
public uint RetryInterval
|
||||
{
|
||||
get { return _retryInterval; }
|
||||
}
|
||||
|
||||
public uint ExpirationLimit
|
||||
{
|
||||
get { return _expirationLimit; }
|
||||
}
|
||||
|
||||
public int MinimumTimeToLive
|
||||
{
|
||||
get { return _minimumTimeToLive; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
internal SoaRecord(RecordHeader dnsHeader) : base(dnsHeader) { }
|
||||
|
||||
public override void ParseRecord(ref MemoryStream ms)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
// Parse Name
|
||||
_primaryNameServer = DnsRecordBase.ParseName(ref ms);
|
||||
sb.Append("Primary NameServer: ");
|
||||
sb.Append(_primaryNameServer);
|
||||
sb.Append("\r\n");
|
||||
|
||||
// Parse Responsible Persons Mailbox (Parse Name)
|
||||
_responsiblePerson = DnsRecordBase.ParseName(ref ms);
|
||||
sb.Append("Responsible Person: ");
|
||||
sb.Append(_responsiblePerson);
|
||||
sb.Append("\r\n");
|
||||
|
||||
byte[] serial = new Byte[4];
|
||||
byte[] refreshInterval = new Byte[4];
|
||||
byte[] retryInterval = new Byte[4];
|
||||
byte[] expirationLimit = new Byte[4];
|
||||
byte[] minTTL = new Byte[4];
|
||||
|
||||
// Parse Serial (4 bytes)
|
||||
ms.Read(serial, 0, 4);
|
||||
//_serial = Tools.ByteToUInt(serial);
|
||||
_serial = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(serial, 0));
|
||||
sb.Append("Serial: ");
|
||||
sb.Append(_serial);
|
||||
sb.Append("\r\n");
|
||||
|
||||
// Parse Refresh Interval (4 bytes)
|
||||
ms.Read(refreshInterval, 0, 4);
|
||||
// _refreshInterval = Tools.ByteToUInt(refreshInterval);
|
||||
_refreshInterval = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(refreshInterval, 0));
|
||||
sb.Append("Refresh Interval: ");
|
||||
sb.Append(_refreshInterval);
|
||||
sb.Append("\r\n");
|
||||
|
||||
// Parse Retry Interval (4 bytes)
|
||||
ms.Read(retryInterval, 0, 4);
|
||||
//_retryInterval = Tools.ByteToUInt(retryInterval);
|
||||
_retryInterval = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(retryInterval, 0));
|
||||
sb.Append("Retry Interval: ");
|
||||
sb.Append(_retryInterval);
|
||||
sb.Append("\r\n");
|
||||
|
||||
// Parse Expiration limit (4 bytes)
|
||||
ms.Read(expirationLimit, 0, 4);
|
||||
// _expirationLimit = Tools.ByteToUInt(expirationLimit);
|
||||
_expirationLimit = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(expirationLimit, 0));
|
||||
sb.Append("Expire: ");
|
||||
sb.Append(_expirationLimit);
|
||||
sb.Append("\r\n");
|
||||
|
||||
// Parse Min TTL (4 bytes)
|
||||
ms.Read(minTTL, 0, 4);
|
||||
// _minTTL = Tools.ByteToUInt(minTTL);
|
||||
_minimumTimeToLive = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(minTTL, 0));
|
||||
sb.Append("TTL: ");
|
||||
sb.Append(_minimumTimeToLive);
|
||||
sb.Append("\r\n");
|
||||
|
||||
_answer = sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
95
MailServer/MailServer/DNSClient/Records/SrvRecord.cs
Normal file
95
MailServer/MailServer/DNSClient/Records/SrvRecord.cs
Normal file
@ -0,0 +1,95 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
public sealed class SrvRecord : DnsRecordBase
|
||||
{
|
||||
// For SRV
|
||||
private ushort _priority;
|
||||
private ushort _weight;
|
||||
private ushort _port;
|
||||
private string _hostName;
|
||||
|
||||
public ushort Priority
|
||||
{
|
||||
get { return _priority; }
|
||||
}
|
||||
public ushort Weight
|
||||
{
|
||||
get { return _weight; }
|
||||
}
|
||||
|
||||
public ushort Port
|
||||
{
|
||||
get { return _port; }
|
||||
}
|
||||
|
||||
public string HostName
|
||||
{
|
||||
get { return _hostName; }
|
||||
}
|
||||
|
||||
internal SrvRecord(RecordHeader dnsHeader) : base(dnsHeader) { }
|
||||
|
||||
public override void ParseRecord(ref MemoryStream ms)
|
||||
{
|
||||
byte[] priority = new byte[2];
|
||||
ms.Read(priority, 0, 2);
|
||||
//_priority = (ushort)Tools.ByteToUInt(Priority);
|
||||
_priority = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(priority, 0));
|
||||
|
||||
byte[] weight = new byte[2];
|
||||
ms.Read(weight, 0, 2);
|
||||
// _weight = (ushort)Tools.ByteToUInt(Weight);
|
||||
_weight = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(weight, 0));
|
||||
|
||||
byte[] port = new byte[2];
|
||||
ms.Read(port, 0, 2);
|
||||
//_port = (ushort)Tools.ByteToUInt(port);
|
||||
_port = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(port, 0));
|
||||
|
||||
_hostName = DnsRecordBase.ParseName(ref ms);
|
||||
|
||||
_answer = "Service Location: \r\nPriority: " + _priority + "\r\nWeight: " +
|
||||
_weight + "\r\nPort: " + _port + "\r\nHostName: " + _hostName + "\r\n";
|
||||
}
|
||||
}
|
||||
}
|
235
MailServer/MailServer/DNSClient/Records/TSigRecord.cs
Normal file
235
MailServer/MailServer/DNSClient/Records/TSigRecord.cs
Normal file
@ -0,0 +1,235 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using DnDns.Enums;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of a TSIG record structure as per RFC 2845
|
||||
/// </summary>
|
||||
public sealed class TSigRecord : DnsRecordBase
|
||||
{
|
||||
private string _algorithmName;
|
||||
private RCode _error;
|
||||
private ushort _fudge;
|
||||
private ushort _originalId;
|
||||
private byte[] _otherData;
|
||||
private byte[] _mac;
|
||||
private DateTime _timeSigned;
|
||||
|
||||
public string AlgorithmName
|
||||
{
|
||||
get { return _algorithmName; }
|
||||
}
|
||||
|
||||
public RCode Error
|
||||
{
|
||||
get { return _error; }
|
||||
}
|
||||
|
||||
public ushort Fudge
|
||||
{
|
||||
get { return _fudge; }
|
||||
}
|
||||
|
||||
public ushort OriginalID
|
||||
{
|
||||
get { return _originalId; }
|
||||
}
|
||||
|
||||
public byte[] OtherData
|
||||
{
|
||||
get { return _otherData; }
|
||||
}
|
||||
|
||||
public byte[] Mac
|
||||
{
|
||||
get { return _mac; }
|
||||
}
|
||||
|
||||
public DateTime TimeSigned
|
||||
{
|
||||
get { return _timeSigned; }
|
||||
}
|
||||
|
||||
public TSigRecord(RecordHeader dnsHeader) : base(dnsHeader)
|
||||
{
|
||||
}
|
||||
|
||||
public TSigRecord(string name, string algorithmName, RCode error, ushort fudge, ushort originalId, byte[] otherData, byte[] mac, DateTime timeSigned)
|
||||
{
|
||||
DnsHeader = new RecordHeader(name, NsType.TSIG, NsClass.ANY, 0);
|
||||
|
||||
_algorithmName = algorithmName;
|
||||
_error = error;
|
||||
_fudge = fudge;
|
||||
_originalId = originalId;
|
||||
_otherData = otherData;
|
||||
_mac = mac;
|
||||
_timeSigned = timeSigned;
|
||||
|
||||
if(otherData == null)
|
||||
{
|
||||
_otherData = new byte[]{};
|
||||
}
|
||||
}
|
||||
|
||||
public override void ParseRecord(ref MemoryStream memoryStream)
|
||||
{
|
||||
Byte[] dataUInt16 = new byte[2];
|
||||
Byte[] dataUInt32 = new byte[4];
|
||||
|
||||
_algorithmName = ParseName(ref memoryStream);
|
||||
|
||||
memoryStream.Read(dataUInt16, 0, dataUInt16.Length);
|
||||
long timeHigh = (ushort) IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(dataUInt16, 0));
|
||||
memoryStream.Read(dataUInt32, 0, dataUInt32.Length);
|
||||
long timeLow = (uint) IPAddress.NetworkToHostOrder((int)BitConverter.ToUInt32(dataUInt32, 0));
|
||||
_timeSigned = DnsHelpers.ConvertFromDnsTime(timeLow, timeHigh);
|
||||
|
||||
memoryStream.Read(dataUInt16, 0, dataUInt16.Length);
|
||||
_fudge = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(dataUInt16, 0));
|
||||
|
||||
memoryStream.Read(dataUInt16, 0, dataUInt16.Length);
|
||||
Int32 macLen = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(dataUInt16, 0));
|
||||
_mac = new byte[macLen];
|
||||
memoryStream.Read(_mac, 0, macLen);
|
||||
|
||||
memoryStream.Read(dataUInt16, 0, dataUInt16.Length);
|
||||
_originalId = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(dataUInt16, 0));
|
||||
|
||||
memoryStream.Read(dataUInt16, 0, dataUInt16.Length);
|
||||
_error = (RCode)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(dataUInt16, 0));
|
||||
|
||||
memoryStream.Read(dataUInt16, 0, dataUInt16.Length);
|
||||
Int32 otherLen = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(dataUInt16, 0));
|
||||
|
||||
if(otherLen > 0)
|
||||
{
|
||||
_otherData = new byte[otherLen];
|
||||
memoryStream.Read(_otherData, 0, otherLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
_otherData = null;
|
||||
}
|
||||
|
||||
_answer = ToString();
|
||||
|
||||
}
|
||||
|
||||
public override byte[] GetMessageBytes()
|
||||
{
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
|
||||
byte[] data = DnsHeader.GetMessageBytes();
|
||||
memoryStream.Write(data,0,data.Length);
|
||||
|
||||
long rLengthPosition = memoryStream.Position;
|
||||
|
||||
data = DnsHelpers.CanonicaliseDnsName(_algorithmName, false);
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
int timeHigh;
|
||||
long timeLow;
|
||||
DnsHelpers.ConvertToDnsTime(_timeSigned.ToUniversalTime(), out timeHigh, out timeLow);
|
||||
|
||||
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder((ushort)timeHigh) >> 16));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
data = BitConverter.GetBytes((uint)(IPAddress.HostToNetworkOrder((uint)timeLow) >> 32));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder(_fudge) >> 16));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder(_mac.Length) >> 16));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
memoryStream.Write(_mac, 0, _mac.Length);
|
||||
|
||||
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder(_originalId) >> 16));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder((ushort)_error) >> 16));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
|
||||
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder((ushort)_otherData.Length) >> 16));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
if(_otherData.Length != 0)
|
||||
{
|
||||
memoryStream.Write(_otherData, 0, _otherData.Length);
|
||||
}
|
||||
|
||||
// Add the rdata lenght
|
||||
long rlength = memoryStream.Position - rLengthPosition;
|
||||
|
||||
memoryStream.Seek(rLengthPosition - 2, SeekOrigin.Begin);
|
||||
|
||||
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder((ushort)rlength) >> 16));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append(_algorithmName);
|
||||
sb.Append(" ");
|
||||
sb.Append(_timeSigned);
|
||||
sb.Append(" ");
|
||||
sb.Append(_fudge);
|
||||
sb.Append(" ");
|
||||
sb.Append(_mac.Length);
|
||||
sb.Append(" ");
|
||||
sb.Append(Convert.ToBase64String(Mac));
|
||||
sb.Append(" ");
|
||||
sb.Append(_error);
|
||||
sb.Append(" ");
|
||||
|
||||
if (_otherData == null)
|
||||
{
|
||||
sb.Append(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(_otherData.Length);
|
||||
sb.Append(" ");
|
||||
|
||||
if (_error == RCode.BADTIME)
|
||||
{
|
||||
if (_otherData.Length != 6)
|
||||
{
|
||||
sb.Append("<invalid BADTIME other data>");
|
||||
}
|
||||
else
|
||||
{
|
||||
long time = ((long)(_otherData[0] & 0xFF) << 40) +
|
||||
((long)(_otherData[1] & 0xFF) << 32) +
|
||||
((_otherData[2] & 0xFF) << 24) +
|
||||
((_otherData[3] & 0xFF) << 16) +
|
||||
((_otherData[4] & 0xFF) << 8) +
|
||||
((_otherData[5] & 0xFF));
|
||||
|
||||
sb.Append("<server time: ");
|
||||
sb.Append(DnsHelpers.ConvertFromDnsTime(time));
|
||||
sb.Append(">");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append("<");
|
||||
sb.Append(Convert.ToBase64String(_otherData));
|
||||
sb.Append(">");
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
63
MailServer/MailServer/DNSClient/Records/TxtRecord.cs
Normal file
63
MailServer/MailServer/DNSClient/Records/TxtRecord.cs
Normal file
@ -0,0 +1,63 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public sealed class TxtRecord : DnsRecordBase
|
||||
{
|
||||
private string _text;
|
||||
|
||||
public string Text
|
||||
{
|
||||
get { return _text; }
|
||||
}
|
||||
|
||||
internal TxtRecord(RecordHeader dnsHeader) : base(dnsHeader) { }
|
||||
|
||||
public override void ParseRecord(ref MemoryStream ms)
|
||||
{
|
||||
_text = base.ParseText(ref ms);
|
||||
_answer = "text: " + _text;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
69
MailServer/MailServer/DNSClient/Records/UnknownRecord.cs
Normal file
69
MailServer/MailServer/DNSClient/Records/UnknownRecord.cs
Normal file
@ -0,0 +1,69 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
class UnknownRecord : DnsRecordBase
|
||||
{
|
||||
public UnknownRecord(RecordHeader dnsHeader) : base(dnsHeader) { }
|
||||
|
||||
public override void ParseRecord(ref MemoryStream ms)
|
||||
{
|
||||
// Type not implemented so we read it into a buffer and print out the data.
|
||||
StringBuilder sb = new StringBuilder(this.DnsHeader.DataLength);
|
||||
byte[] b = new byte[1];
|
||||
// Loop over data, if char is easily converted to ASCII, convert it.
|
||||
// Otherwise print a '.'
|
||||
for (int i = 0; i < this.DnsHeader.DataLength; i++)
|
||||
{
|
||||
ms.Read(b, 0, 1);
|
||||
if ((b[0] > 0x20) && (b[0] < 0x7e))
|
||||
{
|
||||
sb.Append(Encoding.ASCII.GetString(b));
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append('.');
|
||||
}
|
||||
}
|
||||
_answer = sb.ToString();
|
||||
_errorMsg = "Type " + this.DnsHeader.NsType + " not implemented.";
|
||||
}
|
||||
}
|
||||
}
|
115
MailServer/MailServer/DNSClient/Records/WksRecord.cs
Normal file
115
MailServer/MailServer/DNSClient/Records/WksRecord.cs
Normal file
@ -0,0 +1,115 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
public sealed class WksRecord : DnsRecordBase
|
||||
{
|
||||
private ProtocolType _protocolType;
|
||||
private IPAddress _ipAddress;
|
||||
private short[] _ports;
|
||||
|
||||
public ProtocolType ProtocolType
|
||||
{
|
||||
get { return _protocolType; }
|
||||
set { _protocolType = value; }
|
||||
}
|
||||
|
||||
public IPAddress IpAddress
|
||||
{
|
||||
get { return _ipAddress; }
|
||||
set { _ipAddress = value; }
|
||||
}
|
||||
|
||||
public short[] Ports
|
||||
{
|
||||
get { return _ports; }
|
||||
set { _ports = value; }
|
||||
}
|
||||
|
||||
internal WksRecord(RecordHeader dnsHeader) : base(dnsHeader) { }
|
||||
|
||||
public override void ParseRecord(ref MemoryStream ms)
|
||||
{
|
||||
// Bit map is the data length minus the IpAddress (4 bytes) and the Protocol (1 byte), 5 bytes total.
|
||||
int bitMapLen = this.DnsHeader.DataLength - 4 - 1;
|
||||
byte[] ipAddr = new byte[4];
|
||||
byte[] BitMap = new byte[bitMapLen];
|
||||
|
||||
ms.Read(ipAddr, 0, 4);
|
||||
// _ipAddress = new IPAddress(Tools.ToUInt32(ipAddr, 0));
|
||||
_ipAddress = new IPAddress((uint)IPAddress.NetworkToHostOrder(BitConverter.ToUInt32(ipAddr, 0)));
|
||||
_protocolType = (ProtocolType)ms.ReadByte();
|
||||
ms.Read(BitMap, 0, BitMap.Length);
|
||||
_ports = GetKnownServices(BitMap);
|
||||
_answer = _protocolType + ": " + Tools.GetServByPort(_ports, _protocolType);
|
||||
}
|
||||
|
||||
private short[] GetKnownServices(byte[] BitMap)
|
||||
{
|
||||
short[] tempPortArr = new short[1024];
|
||||
int portCount = 0;
|
||||
// mask to isolate left most bit
|
||||
const byte mask = 0x80;
|
||||
// Iterate through each byte
|
||||
for (int i = 0; i < BitMap.Length; i++)
|
||||
{
|
||||
byte currentByte = BitMap[i];
|
||||
int count = 0;
|
||||
// iterate through each bit
|
||||
for (byte j = 0x07; j != 0xFF; j--)
|
||||
{
|
||||
int port = (((i * 8) + count++) + 1);
|
||||
currentByte = (byte)(currentByte << 1);
|
||||
// is the flag set?
|
||||
if ((mask & currentByte) == 0x80)
|
||||
{
|
||||
tempPortArr[portCount] = (short)port;
|
||||
portCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
short[] portArr = new short[portCount];
|
||||
Array.Copy(tempPortArr, 0, portArr, 0, portCount);
|
||||
return portArr;
|
||||
}
|
||||
}
|
||||
}
|
60
MailServer/MailServer/DNSClient/Records/X25Record.cs
Normal file
60
MailServer/MailServer/DNSClient/Records/X25Record.cs
Normal file
@ -0,0 +1,60 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace DnDns.Records
|
||||
{
|
||||
public sealed class X25Record : DnsRecordBase
|
||||
{
|
||||
private string _x25Address;
|
||||
|
||||
public string X25Address
|
||||
{
|
||||
get { return _x25Address; }
|
||||
}
|
||||
|
||||
internal X25Record(RecordHeader dnsHeader) : base(dnsHeader) { }
|
||||
|
||||
public override void ParseRecord(ref MemoryStream ms)
|
||||
{
|
||||
_x25Address = base.ParseText(ref ms);
|
||||
_answer = "X.25 X.121 Address: " + _x25Address;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using DnDns.Query;
|
||||
|
||||
namespace DnDns.Security
|
||||
{
|
||||
public interface IMessageSecurityProvider
|
||||
{
|
||||
DnsQueryRequest SecureMessage(DnsQueryRequest dnsQueryRequest);
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Security.Cryptography;
|
||||
using DnDns.Enums;
|
||||
using DnDns.Query;
|
||||
using DnDns.Records;
|
||||
|
||||
namespace DnDns.Security
|
||||
{
|
||||
/// <summary>
|
||||
/// Implements TSIG signing of DNS messages as per RFC2845
|
||||
/// </summary>
|
||||
/// <remarks>This class only supports the one hashing algorithim, hmac-sha256.
|
||||
/// It would be trivial to add more.</remarks>
|
||||
public class TsigMessageSecurityProvider : IMessageSecurityProvider
|
||||
{
|
||||
private const string Hmacsha1String = "hmac-sha256.";
|
||||
|
||||
private readonly string _name;
|
||||
private readonly string _algorithimName;
|
||||
private readonly ushort _fudge;
|
||||
private readonly byte[] _sharedKey;
|
||||
private readonly HMACSHA256 _hmac;
|
||||
|
||||
/// <summary>
|
||||
/// Initalise the <see cref="TsigMessageSecurityProvider"/>
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the shared key</param>
|
||||
/// <param name="sharedKey">The shared key in base64 string format</param>
|
||||
/// <param name="fudge">The signing time fudge value</param>
|
||||
public TsigMessageSecurityProvider(string name, string sharedKey, ushort fudge)
|
||||
{
|
||||
_name = name;
|
||||
_fudge = fudge;
|
||||
_sharedKey = Convert.FromBase64String(sharedKey);
|
||||
|
||||
if (_sharedKey == null)
|
||||
{
|
||||
throw new ArgumentException("Argument is not a valid base64 string", "sharedKey");
|
||||
}
|
||||
|
||||
_hmac = new HMACSHA256(_sharedKey);
|
||||
|
||||
_algorithimName = Hmacsha1String;
|
||||
}
|
||||
|
||||
#region IMessageSecurityProvider Members
|
||||
/// <summary>
|
||||
/// Apply a TSIG record to the request message.
|
||||
/// </summary>
|
||||
/// <param name="dnsQueryRequest">The <see cref="DnsQueryRequest"/> to add the security headers too.</param>
|
||||
/// <returns>A <see cref="DnsQueryRequest"/> instance with additional security attributes assigned.</returns>
|
||||
public DnsQueryRequest SecureMessage(DnsQueryRequest dnsQueryRequest)
|
||||
{
|
||||
DateTime signDateTime = DateTime.Now;
|
||||
int timeHigh;
|
||||
long timeLow;
|
||||
|
||||
byte[] messageBytes = dnsQueryRequest.GetMessageBytes();
|
||||
Trace.WriteLine(String.Format("Message Header Bytes: {0}", DnsHelpers.DumpArrayToString(messageBytes)));
|
||||
|
||||
MemoryStream memoryStream = new MemoryStream();
|
||||
memoryStream.Write(messageBytes, 0, messageBytes.Length);
|
||||
|
||||
// the shared key name
|
||||
byte[] data = DnsHelpers.CanonicaliseDnsName(_name, false);
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
data = BitConverter.GetBytes((ushort) (IPAddress.HostToNetworkOrder((ushort) NsClass.ANY) >> 16));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
// the TTL value
|
||||
data = BitConverter.GetBytes((uint) (IPAddress.HostToNetworkOrder((uint) 0) >> 32));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
// the algorithim name
|
||||
data = DnsHelpers.CanonicaliseDnsName(_algorithimName, true);
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
DnsHelpers.ConvertToDnsTime(signDateTime.ToUniversalTime(), out timeHigh, out timeLow);
|
||||
|
||||
data = BitConverter.GetBytes((ushort)(IPAddress.HostToNetworkOrder((ushort)timeHigh) >> 16));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
data = BitConverter.GetBytes((uint) (IPAddress.HostToNetworkOrder((uint)timeLow) >> 32));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
data = BitConverter.GetBytes((ushort) (IPAddress.HostToNetworkOrder(_fudge) >> 16));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
data = BitConverter.GetBytes((ushort) (IPAddress.HostToNetworkOrder((ushort) RCode.NoError) >> 16));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
// no other data
|
||||
data = BitConverter.GetBytes((ushort) (IPAddress.HostToNetworkOrder((ushort) 0) >> 16));
|
||||
memoryStream.Write(data, 0, data.Length);
|
||||
|
||||
byte[] dataToHash = memoryStream.ToArray();
|
||||
Trace.WriteLine(String.Format("Data to hash: {0}", DnsHelpers.DumpArrayToString(dataToHash)));
|
||||
byte[] mac = _hmac.ComputeHash(dataToHash);
|
||||
Trace.WriteLine(String.Format("hash: {0}", DnsHelpers.DumpArrayToString(mac)));
|
||||
|
||||
dnsQueryRequest.AdditionalRRecords.Add(new TSigRecord(_name, _algorithimName, RCode.NoError, _fudge, dnsQueryRequest.TransactionID, new byte[] { }, mac, signDateTime));
|
||||
|
||||
return dnsQueryRequest;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
213
MailServer/MailServer/DNSClient/Tools.cs
Normal file
213
MailServer/MailServer/DNSClient/Tools.cs
Normal file
@ -0,0 +1,213 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2010, j. montgomery *
|
||||
* All rights reserved. *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions *
|
||||
* are met: *
|
||||
* *
|
||||
* + Redistributions of source code must retain the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* + Redistributions in binary form must reproduce the above copyright*
|
||||
* notice, this list of conditions and the following disclaimer *
|
||||
* in the documentation and/or other materials provided with the *
|
||||
* distribution. *
|
||||
* *
|
||||
* + Neither the name of j. montgomery's employer nor the names of *
|
||||
* its contributors may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written *
|
||||
* permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS*
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT *
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS *
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE *
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,*
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) *
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,*
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) *
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED*
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
**********************************************************************/
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
|
||||
using DnDns.Enums;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace DnDns
|
||||
{
|
||||
public class Tools
|
||||
{
|
||||
/// <summary>
|
||||
/// Look up the port names for the given array of port numbers.
|
||||
/// </summary>
|
||||
/// <param name="port">An array of port numbers.</param>
|
||||
/// <param name="proto">The protocol type. (TCP or UPD)</param>
|
||||
/// <returns>The name of the port.</returns>
|
||||
public static string GetServByPort(short[] port, ProtocolType proto)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i=0; i < port.Length; i++)
|
||||
{
|
||||
sb.Append(GetServByPort(port[i], proto));
|
||||
sb.Append(", ");
|
||||
}
|
||||
sb.Remove(sb.Length-2,2);
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests to see if this is running on a Linux or Unix Platform
|
||||
/// </summary>
|
||||
/// <returns>true if unix or linux is detected</returns>
|
||||
public static bool IsPlatformLinuxUnix()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Look up the port name for any given port number.
|
||||
/// </summary>
|
||||
/// <param name="port">The port number.</param>
|
||||
/// <param name="proto">The protocol type. (TCP or UPD)</param>
|
||||
/// <returns>The name of the port.</returns>
|
||||
public static string GetServByPort(short port, ProtocolType proto)
|
||||
{
|
||||
StringBuilder ans = new StringBuilder();
|
||||
|
||||
switch (proto)
|
||||
{
|
||||
case ProtocolType.Tcp:
|
||||
{
|
||||
TcpServices tcps;
|
||||
tcps = (TcpServices)port;
|
||||
ans.Append(tcps);
|
||||
ans.Append("(");
|
||||
ans.Append(port);
|
||||
ans.Append(")");
|
||||
break;
|
||||
}
|
||||
case ProtocolType.Udp:
|
||||
{
|
||||
UdpServices udps;
|
||||
udps = (UdpServices)port;
|
||||
ans.Append(udps);
|
||||
ans.Append("(");
|
||||
ans.Append(port);
|
||||
ans.Append(")");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
ans.Append("(");
|
||||
ans.Append(port);
|
||||
ans.Append(")");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ans.ToString();
|
||||
}
|
||||
|
||||
public static string DiscoverUnixDnsServerAddress()
|
||||
{
|
||||
if (System.IO.File.Exists("/etc/resolv.conf"))
|
||||
{
|
||||
using (System.IO.StreamReader sr = new System.IO.StreamReader(new System.IO.FileStream("/etc/resolv.conf", System.IO.FileMode.Open)))
|
||||
{
|
||||
while (!sr.EndOfStream)
|
||||
{
|
||||
string line = sr.ReadLine().TrimStart();
|
||||
|
||||
if (line.StartsWith("nameserver") && line.Length > 11)
|
||||
{
|
||||
line = line.Substring(10).Trim();
|
||||
if (!string.IsNullOrEmpty(line))
|
||||
{
|
||||
sr.Dispose();
|
||||
return line;
|
||||
}
|
||||
}
|
||||
}
|
||||
sr.Dispose();
|
||||
}
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
//public static IPAddressCollection DiscoverDnsServerAddresses()
|
||||
//{
|
||||
// NetworkInterface[] arrNetworkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
|
||||
|
||||
// foreach (NetworkInterface objNetworkInterface in arrNetworkInterfaces)
|
||||
// {
|
||||
// if (
|
||||
// (objNetworkInterface.OperationalStatus == OperationalStatus.Up) &&
|
||||
// (objNetworkInterface.Speed > 0) &&
|
||||
// (objNetworkInterface.NetworkInterfaceType != NetworkInterfaceType.Loopback) &&
|
||||
// (objNetworkInterface.NetworkInterfaceType != NetworkInterfaceType.Tunnel)
|
||||
// )
|
||||
// {
|
||||
// IPAddressCollection candidate = objNetworkInterface.GetIPProperties().DnsAddresses;
|
||||
// bool found = false;
|
||||
// foreach (IPAddress addr in candidate)
|
||||
// {
|
||||
// // Make this collection contains IPv4 addresses only
|
||||
// if (addr.AddressFamily == AddressFamily.InterNetwork)
|
||||
// found = true;
|
||||
// }
|
||||
|
||||
// if (found)
|
||||
// return candidate;
|
||||
// }
|
||||
// }
|
||||
|
||||
// return null;
|
||||
//}
|
||||
|
||||
//public static uint ByteToUInt(byte[] theByte)
|
||||
//{
|
||||
// uint l = 0;
|
||||
|
||||
// for (int i = 0; i < theByte.Length; i++)
|
||||
// {
|
||||
// l += (uint)theByte[(theByte.Length - i) - 1] << i * 8;
|
||||
// }
|
||||
|
||||
// return l;
|
||||
//}
|
||||
|
||||
// Use BitConverter.GetBytes()
|
||||
//public static byte[] IntToByteArray(uint theInt)
|
||||
//{
|
||||
// byte[] byteArray = new byte[4];
|
||||
// int i;
|
||||
// int shift;
|
||||
|
||||
// for (i = 0, shift = 24; i < 4; i++, shift -= 8)
|
||||
// byteArray[i] = (byte)(0xFF & (theInt >> shift));
|
||||
|
||||
// return byteArray;
|
||||
//}
|
||||
|
||||
// use BitConverter.GetBytes()
|
||||
//public static byte[] UshortToByteArray(ushort theShort)
|
||||
//{
|
||||
// byte[] byteArray = new byte[2];
|
||||
// int i;
|
||||
// int shift;
|
||||
|
||||
// for (i = 0, shift = 16; i < 2; i++, shift -= 8)
|
||||
// byteArray[i] = (byte)(0xFF & (theShort >> shift));
|
||||
|
||||
// return byteArray;
|
||||
//}
|
||||
}
|
||||
}
|
40
MailServer/MailServer/Database.cs
Normal file
40
MailServer/MailServer/Database.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace SMTPServer
|
||||
{
|
||||
public class MysqlDB : DbContext
|
||||
{
|
||||
const string Hostname = "192.168.178.148";
|
||||
const string DatabaseName = "vmail";
|
||||
const string Uid = "root";
|
||||
const string Pwd = "fabian.11";
|
||||
|
||||
public DbSet<Domains> Domains { get; set; }
|
||||
|
||||
public DbSet<Accounts> Accounts { get; set; }
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
=> optionsBuilder.UseMySql(@"Server=" + Hostname + ";database=" + DatabaseName + ";uid=" + Uid + ";pwd=" + Pwd + ";");
|
||||
}
|
||||
|
||||
public class Domains
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Domain { get; set; }
|
||||
public bool IsMail { get; set; }
|
||||
}
|
||||
|
||||
public class Accounts
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public int Domain { get; set; }
|
||||
public string Password { get; set; }
|
||||
public bool Active { get; set; }
|
||||
}
|
||||
}
|
24
MailServer/MailServer/Exceptions/NoMailsInQueueException.cs
Normal file
24
MailServer/MailServer/Exceptions/NoMailsInQueueException.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SMTPServer.Exceptions
|
||||
{
|
||||
class NoMailsInQueueException : Exception
|
||||
{
|
||||
public NoMailsInQueueException() : base()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public NoMailsInQueueException(string message) : base(message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public NoMailsInQueueException(string message, Exception inner) : base(message, inner)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
22
MailServer/MailServer/Exceptions/PortUsedException.cs
Normal file
22
MailServer/MailServer/Exceptions/PortUsedException.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System;
|
||||
|
||||
namespace SMTPServer.Exceptions
|
||||
{
|
||||
public class PortUsedException : Exception
|
||||
{
|
||||
public PortUsedException() : base()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public PortUsedException(string message) : base(message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public PortUsedException(string message, Exception inner) : base(message, inner)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
71
MailServer/MailServer/GetDNSEntries.cs
Normal file
71
MailServer/MailServer/GetDNSEntries.cs
Normal file
@ -0,0 +1,71 @@
|
||||
using DnsClient;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace SMTPServer
|
||||
{
|
||||
public class GetDNSEntries
|
||||
{
|
||||
public static async System.Threading.Tasks.Task<string[]> GetMXRecordAsync(string domain) => await GetMXRecordAsync(domain, 0);
|
||||
|
||||
public static async System.Threading.Tasks.Task<string[]> GetMXRecordAsync(string domain, int nr)
|
||||
{
|
||||
var lookup = new LookupClient();
|
||||
var result = await lookup.QueryAsync(domain, QueryType.MX);
|
||||
|
||||
var records = result.AllRecords.ToArray();
|
||||
|
||||
//ToDo priority sorting
|
||||
|
||||
var rec = new string[records.Length];
|
||||
|
||||
for(int i = 0; i < records.Length; i++)
|
||||
{
|
||||
var str = records[i].RecordToString();
|
||||
var s = str.Split(' ');
|
||||
if (s.Length == 1)
|
||||
{
|
||||
rec[i] = s[0];
|
||||
} else if (s.Length == 2)
|
||||
{
|
||||
rec[i] = s[1];
|
||||
} else
|
||||
{
|
||||
rec[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
return rec;
|
||||
/*
|
||||
foreach (var r in result.AllRecords)
|
||||
{
|
||||
Console.WriteLine(r.RecordToString());
|
||||
}*/
|
||||
}
|
||||
|
||||
public static async System.Threading.Tasks.Task<string[]> GetIPAddressFromDnsArrayAsync(string[] dnsnames)
|
||||
{
|
||||
var ips = new string[dnsnames.Length];
|
||||
for(int i = 0; i < dnsnames.Length; i++)
|
||||
{
|
||||
ips[i] = await GetIpFromDnsNameAsync(dnsnames[i]);
|
||||
}
|
||||
|
||||
return ips;
|
||||
}
|
||||
|
||||
public static async System.Threading.Tasks.Task<string> GetIpFromDnsNameAsync(string dnsname)
|
||||
{
|
||||
var lookup = new LookupClient();
|
||||
var result = await lookup.QueryAsync(dnsname, QueryType.A);
|
||||
|
||||
var records = result.AllRecords.ToArray();
|
||||
|
||||
if (records.Length < 1) return null;
|
||||
return records[0].RecordToString();
|
||||
}
|
||||
}
|
||||
}
|
20
MailServer/MailServer/GlobalSuppressions.cs
Normal file
20
MailServer/MailServer/GlobalSuppressions.cs
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
// This file is used by Code Analysis to maintain SuppressMessage
|
||||
// attributes that are applied to this project.
|
||||
// Project-level suppressions either have no target or are given
|
||||
// a specific target and scoped to a namespace, type, member, etc.
|
||||
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "<Ausstehend>", Scope = "member", Target = "~P:SMTPServer.MailQueue.QueueMail._Count")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "<Ausstehend>", Scope = "member", Target = "~P:SMTPServer.MailQueue.QueueMail._Mail")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "<Ausstehend>", Scope = "member", Target = "~P:SMTPServer.MailQueue.QueueMail._QueueEntered")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "<Ausstehend>", Scope = "member", Target = "~P:SMTPServer.MailQueue.QueueMail._DestinationIps")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "<Ausstehend>", Scope = "member", Target = "~P:SMTPServer.MailQueue.QueueMail._DestinationDnsNames")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "<Ausstehend>", Scope = "member", Target = "~P:SMTPServer.Mail._From")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "<Ausstehend>", Scope = "member", Target = "~P:SMTPServer.Mail._To")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "<Ausstehend>", Scope = "member", Target = "~P:SMTPServer.Mail._Subject")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "<Ausstehend>", Scope = "member", Target = "~P:SMTPServer.Mail._Others")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "<Ausstehend>", Scope = "member", Target = "~P:SMTPServer.Mail._Date")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "<Ausstehend>", Scope = "member", Target = "~P:SMTPServer.Mail._MessageId")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "<Ausstehend>", Scope = "member", Target = "~P:SMTPServer.Mail._MIME_Version")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE1006:Benennungsstile", Justification = "<Ausstehend>", Scope = "member", Target = "~P:SMTPServer.MailQueue.QueueMail._DestinationIndex")]
|
||||
|
53
MailServer/MailServer/Logging/Logging.cs
Normal file
53
MailServer/MailServer/Logging/Logging.cs
Normal file
@ -0,0 +1,53 @@
|
||||
using System;
|
||||
|
||||
//namespace Logging
|
||||
//{
|
||||
public class Logging
|
||||
{
|
||||
private static LoggingType[] _ActiveLoggingTypes { get; set; }
|
||||
|
||||
public enum LoggingType
|
||||
{
|
||||
TRACE,
|
||||
ERROR,
|
||||
DEBUG,
|
||||
WARNING,
|
||||
INFO,
|
||||
ALL
|
||||
}
|
||||
|
||||
public static void AddLogMessage(LoggingType messagetype, string message)
|
||||
{
|
||||
if(CheckLoggingType(messagetype)) PrintToConsole(messagetype, message);
|
||||
}
|
||||
|
||||
public static void AddException(Exception e)
|
||||
{
|
||||
AddLogMessage(LoggingType.ERROR, e.Message);
|
||||
}
|
||||
|
||||
private static bool CheckLoggingType(LoggingType lt){
|
||||
if (_ActiveLoggingTypes == null ||_ActiveLoggingTypes.Length < 1) {
|
||||
_ActiveLoggingTypes = new LoggingType[1];
|
||||
_ActiveLoggingTypes[0] = LoggingType.ALL;
|
||||
}
|
||||
bool found = false;
|
||||
foreach(LoggingType l in _ActiveLoggingTypes)
|
||||
{
|
||||
if (l == lt || l == LoggingType.ALL)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
private static void PrintToConsole(LoggingType lt, string message)
|
||||
{
|
||||
Console.WriteLine("[" + lt.ToString() + "]" + message);
|
||||
}
|
||||
}
|
||||
//}
|
109
MailServer/MailServer/MTACommands.cs
Normal file
109
MailServer/MailServer/MTACommands.cs
Normal file
@ -0,0 +1,109 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace SMTPServer
|
||||
{
|
||||
public class MTACommandsDict : Dictionary<MTACommands, String>
|
||||
{
|
||||
public MTACommandsDict()
|
||||
{
|
||||
Add(MTACommands.HELO, "HELO");
|
||||
Add(MTACommands.DATA, "DATA");
|
||||
Add(MTACommands.EXPN, "EXPN");
|
||||
Add(MTACommands.HELP, "HELP");
|
||||
Add(MTACommands.MAIL_FROM, "MAIL FROM");
|
||||
Add(MTACommands.NOOP, "NOOP");
|
||||
Add(MTACommands.QUIT, "QUIT");
|
||||
Add(MTACommands.RCPT_TO, "RCPT TO");
|
||||
Add(MTACommands.RSET, "RSET");
|
||||
Add(MTACommands.SAML_FROM, "SAML FROM");
|
||||
Add(MTACommands.SEND_FROM, "SEND FROM");
|
||||
Add(MTACommands.SOML_FROM, "SOML FROM");
|
||||
Add(MTACommands.TURN, "TURN");
|
||||
Add(MTACommands.VERB, "VERB");
|
||||
Add(MTACommands.VRFY, "VRFY");
|
||||
Add(MTACommands.ATRN, "ATRN");
|
||||
Add(MTACommands.AUTH, "AUTH");
|
||||
Add(MTACommands.BDAT, "BDAT");
|
||||
Add(MTACommands.EHLO, "EHLO");
|
||||
Add(MTACommands.ETRN, "ETRN");
|
||||
Add(MTACommands.RCPT, "RCPT");
|
||||
Add(MTACommands.SAML, "SAML");
|
||||
Add(MTACommands.SEND, "SEND");
|
||||
Add(MTACommands.SOML, "SOML");
|
||||
Add(MTACommands.STARTTL, "STARTTLs");
|
||||
Add(MTACommands.AUTH_LOGIN, "AUTH LOGIN");
|
||||
}
|
||||
}
|
||||
|
||||
public enum MTACommands
|
||||
{
|
||||
HELO,
|
||||
MAIL_FROM,
|
||||
RCPT_TO,
|
||||
DATA,
|
||||
RSET,
|
||||
QUIT,
|
||||
HELP,
|
||||
VRFY,
|
||||
EXPN,
|
||||
VERB,
|
||||
NOOP,
|
||||
TURN,
|
||||
SEND_FROM,
|
||||
SOML_FROM,
|
||||
SAML_FROM,
|
||||
ATRN,
|
||||
AUTH,
|
||||
BDAT,
|
||||
EHLO,
|
||||
ETRN,
|
||||
RCPT,
|
||||
SAML,
|
||||
SEND,
|
||||
SOML,
|
||||
STARTTL,
|
||||
AUTH_LOGIN
|
||||
}
|
||||
|
||||
public enum ResponseCodes
|
||||
{
|
||||
C211 = 211,
|
||||
C214 = 214,
|
||||
C220 = 220,
|
||||
C221 = 221,
|
||||
C250 = 250,
|
||||
C251 = 251,
|
||||
C252 = 252,
|
||||
C253 = 253,
|
||||
C334 = 334,
|
||||
C354 = 354,
|
||||
C355 = 355,
|
||||
C421 = 421,
|
||||
C432 = 432,
|
||||
C450 = 450,
|
||||
C451 = 451,
|
||||
C452 = 452,
|
||||
C453 = 453,
|
||||
C454 = 454,
|
||||
C458 = 458,
|
||||
C459 = 459,
|
||||
C500 = 500,
|
||||
C501 = 501,
|
||||
C502 = 502,
|
||||
C503 = 503,
|
||||
C504 = 504,
|
||||
C521 = 521,
|
||||
C530 = 530,
|
||||
C534 = 534,
|
||||
C538 = 538,
|
||||
C550 = 550,
|
||||
C551 = 551,
|
||||
C552 = 552,
|
||||
C553 = 553,
|
||||
C554 = 554
|
||||
}
|
||||
}
|
86
MailServer/MailServer/MTASession.cs
Normal file
86
MailServer/MailServer/MTASession.cs
Normal file
@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace SMTPServer
|
||||
{
|
||||
class MTASession
|
||||
{
|
||||
private static MTACommandsDict MTACommandsDict = new MTACommandsDict();
|
||||
private ConnectedEventArgs ConnectedEventArgs { get; set; }
|
||||
|
||||
private bool Initialized { get; set; }
|
||||
private string SenderHostname { get; set; }
|
||||
|
||||
private bool AuthActive { get; set; }
|
||||
private string Username { get; set; }
|
||||
private string Password { get; set; }
|
||||
private bool Authenticated { get; set; }
|
||||
|
||||
private bool DATA { get; set; }
|
||||
|
||||
private string Mail_From { get; set; }
|
||||
|
||||
public MTASession(ConnectedEventArgs e)
|
||||
{
|
||||
ConnectedEventArgs = e;
|
||||
Thread th = new Thread(new ThreadStart(StartCommunication));
|
||||
th.Start();
|
||||
}
|
||||
|
||||
private void StartCommunication()
|
||||
{
|
||||
ConnectedEventArgs.SendResponse(ResponseCodes.C220, MailTransferAgent.Hostname);
|
||||
ConnectedEventArgs.NewLine += ConnectedEventArgs_NewLine;
|
||||
}
|
||||
|
||||
private void ConnectedEventArgs_NewLine(string line)
|
||||
{
|
||||
if (line.StartsWith(MTACommandsDict[MTACommands.RSET]))
|
||||
{
|
||||
// Schauen was alles resettet wird
|
||||
}
|
||||
|
||||
if (!Initialized)
|
||||
{
|
||||
if (line.StartsWith(MTACommandsDict[MTACommands.HELO]))
|
||||
{
|
||||
ConnectedEventArgs.SendResponse(ResponseCodes.C250, MailTransferAgent.Hostname);
|
||||
//} else if (line.StartsWith(MTACommandsDict[MTACommands.EHLO])) {
|
||||
// ConnectedEventArgs.SendResponse(ResponseCodes.C250, MailTransferAgent.Hostname);
|
||||
}
|
||||
else
|
||||
{
|
||||
ConnectedEventArgs.SendResponse(ResponseCodes.C503, MailTransferAgent.Hostname);
|
||||
return;
|
||||
}
|
||||
Initialized = true;
|
||||
}
|
||||
|
||||
if (line.StartsWith(MTACommandsDict[MTACommands.AUTH_LOGIN]))
|
||||
{
|
||||
AuthActive = true;
|
||||
ConnectedEventArgs.SendResponse(ResponseCodes.C334);
|
||||
}
|
||||
else if (line.StartsWith(MTACommandsDict[MTACommands.MAIL_FROM]))
|
||||
{
|
||||
var args = line.Split(':');
|
||||
if (args.Length < 2)
|
||||
{
|
||||
ConnectedEventArgs.SendResponse(ResponseCodes.C501);
|
||||
return;
|
||||
}
|
||||
var mailFrom = args[1];
|
||||
mailFrom.Replace('<', ' ');
|
||||
}
|
||||
else if (line.StartsWith(MTACommandsDict[MTACommands.QUIT]))
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
} else
|
||||
{
|
||||
ConnectedEventArgs.SendResponse(ResponseCodes.C500);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
31
MailServer/MailServer/Mail.cs
Normal file
31
MailServer/MailServer/Mail.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SMTPServer
|
||||
{
|
||||
public class Mail
|
||||
{
|
||||
public string To { get; private set; }
|
||||
public string From { get; private set; }
|
||||
|
||||
public string Subject { get; private set; }
|
||||
public string MessageId { get; private set; }
|
||||
public string Date { get; private set; }
|
||||
|
||||
public string MIME_Version { get; private set; }
|
||||
|
||||
public string Others { get; private set; }
|
||||
|
||||
|
||||
public Mail(string mail)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string GetSenderDomain()
|
||||
{
|
||||
return From.Split('@')[1];
|
||||
}
|
||||
}
|
||||
}
|
87
MailServer/MailServer/MailQueue.cs
Normal file
87
MailServer/MailServer/MailQueue.cs
Normal file
@ -0,0 +1,87 @@
|
||||
using DnsClient;
|
||||
using SMTPServer.Exceptions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SMTPServer
|
||||
{
|
||||
public class MailQueue
|
||||
{
|
||||
private static List<QueueMail> Mails = null;
|
||||
|
||||
public static async void AddToMesssageQueueAsync(Mail mail)
|
||||
{
|
||||
var qmail = new QueueMail(mail);
|
||||
|
||||
qmail.DestinationDnsNames = await GetDNSEntries.GetMXRecordAsync(mail.GetSenderDomain());
|
||||
qmail.DestinationIps = await GetDNSEntries.GetIPAddressFromDnsArrayAsync(qmail.DestinationDnsNames);
|
||||
|
||||
lock (Mails)
|
||||
{
|
||||
if (Mails == null)
|
||||
{
|
||||
Mails = new List<QueueMail>();
|
||||
}
|
||||
Mails.Add(qmail);
|
||||
}
|
||||
}
|
||||
|
||||
public static QueueMail GetNextMail()
|
||||
{
|
||||
lock (Mails)
|
||||
{
|
||||
if(Mails.Count < 1)
|
||||
{
|
||||
throw new NoMailsInQueueException();
|
||||
}
|
||||
|
||||
var m = Mails[0];
|
||||
|
||||
Mails.Remove(m);
|
||||
m.Count++;
|
||||
Mails.Add(m);
|
||||
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveMailFromQueue(QueueMail mail)
|
||||
{
|
||||
lock (Mails)
|
||||
{
|
||||
Mails.Remove(mail);
|
||||
}
|
||||
}
|
||||
|
||||
public class QueueMail
|
||||
{
|
||||
public DateTime QueueEntered { get; private set; }
|
||||
public int Count { get; set; }
|
||||
public Mail Mail { get; private set; }
|
||||
public string[] DestinationIps { get; set; }
|
||||
public string[] DestinationDnsNames { get; set; }
|
||||
public int DestinationIndex { get; set; }
|
||||
|
||||
public QueueMail (Mail mail)
|
||||
{
|
||||
Mail = mail;
|
||||
QueueEntered = DateTime.Now;
|
||||
Count = 0;
|
||||
}
|
||||
|
||||
public byte[] GetIpBytes() => GetIpBytes(DestinationIndex);
|
||||
|
||||
public byte[] GetIpBytes(int index)
|
||||
{
|
||||
var parts = DestinationIps[index].Split('.');
|
||||
var bytes = new byte[parts.Length];
|
||||
for(int i = 0; i < parts.Length; i++)
|
||||
{
|
||||
bytes[i] = byte.Parse(parts[i]);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
69
MailServer/MailServer/MailServer.csproj
Normal file
69
MailServer/MailServer/MailServer.csproj
Normal file
@ -0,0 +1,69 @@
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<NoWarn>1701;1702;1705;1006</NoWarn>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp1.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="**\*.cs" />
|
||||
<EmbeddedResource Include="**\*.resx" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Remove="DNSClient\**" />
|
||||
<Compile Remove="DNS\**" />
|
||||
<EmbeddedResource Remove="DNSClient\**" />
|
||||
<EmbeddedResource Remove="DNS\**" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DnsClient">
|
||||
<Version>1.0.0-beta-1011</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.DotNet.Cli.Utils">
|
||||
<Version>1.0.0-preview2-1-003177</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools">
|
||||
<Version>1.1.0-preview4-final</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet">
|
||||
<Version>1.1.0-preview4-final</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NETCore">
|
||||
<Version>5.0.2</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NETCore.App">
|
||||
<Version>1.1.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NET.Sdk">
|
||||
<Version>1.0.0-alpha-20161104-2</Version>
|
||||
<PrivateAssets>All</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NETCore.Platforms">
|
||||
<Version>1.1.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NETCore.Runtime">
|
||||
<Version>1.0.2-rc2-24027</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.NETCore.Targets">
|
||||
<Version>1.1.0</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql">
|
||||
<Version>1.1.0-rtm-10012</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql.Design">
|
||||
<Version>1.1.0-rtm-10012</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.IO.FileSystem">
|
||||
<Version>4.0.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.Net.NameResolution">
|
||||
<Version>4.3.0</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
67
MailServer/MailServer/MailTransferAgent.cs
Normal file
67
MailServer/MailServer/MailTransferAgent.cs
Normal file
@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using SMTPServer.Exceptions;
|
||||
using System.Net;
|
||||
|
||||
namespace SMTPServer
|
||||
{
|
||||
class MailTransferAgent
|
||||
{
|
||||
public const string Hostname = "mail.fstamm.net";
|
||||
private static MTACommandsDict MTACommandsDict = new MTACommandsDict();
|
||||
private static Thread Thread;
|
||||
private static List<MTASession> Sessions { get; set; }
|
||||
|
||||
public static void StartMailTransferAgent()
|
||||
{
|
||||
Thread = new Thread(new ThreadStart(MTA));
|
||||
Thread.Start();
|
||||
|
||||
var portListener = new PortListener(25);
|
||||
portListener.OnConnected += PortListener_OnConnected;
|
||||
}
|
||||
|
||||
private static void PortListener_OnConnected(object source, ConnectedEventArgs e)
|
||||
{
|
||||
var session = new MTASession(e);
|
||||
lock (Sessions)
|
||||
{
|
||||
Sessions.Add(session);
|
||||
}
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static void MTA()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
MailQueue.QueueMail mail = null;
|
||||
try
|
||||
{
|
||||
MailQueue.GetNextMail();
|
||||
}
|
||||
catch (NoMailsInQueueException)
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
continue;
|
||||
}
|
||||
|
||||
var charset = Encoding.UTF8;
|
||||
var client = new StartTcpConnection(25, new IPAddress(mail.GetIpBytes()), charset);
|
||||
|
||||
if (!client.Connected) ; //ToDo Errorfall
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static string WaitForResponseCode(ResponseCodes code)
|
||||
{
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
125
MailServer/MailServer/PortListener.cs
Normal file
125
MailServer/MailServer/PortListener.cs
Normal file
@ -0,0 +1,125 @@
|
||||
using SMTPServer.Exceptions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace SMTPServer
|
||||
{
|
||||
public delegate void ConnectedEventHandler(object source, ConnectedEventArgs e);
|
||||
|
||||
public class ConnectedEventArgs : EventArgs
|
||||
{
|
||||
public delegate void ReceivedLineEventHandler(string line);
|
||||
|
||||
public event ReceivedLineEventHandler NewLine;
|
||||
|
||||
private Encoding Encoding { get; set; }
|
||||
private string Others { get; set; }
|
||||
public TcpClient Client { get; private set; }
|
||||
|
||||
private NetworkStream Stream { get; set; }
|
||||
public ConnectedEventArgs(TcpClient client, Encoding encoding)
|
||||
{
|
||||
Client = client;
|
||||
Encoding = encoding;
|
||||
Stream = client.GetStream();
|
||||
}
|
||||
|
||||
public void SendResponse(ResponseCodes responseCode) => SendResponse(responseCode, "");
|
||||
|
||||
public void SendResponse (ResponseCodes responseCode, string args)
|
||||
{
|
||||
var text = ((int)responseCode).ToString();
|
||||
text += " " + args;
|
||||
var bytes = Encoding.UTF8.GetBytes(text);
|
||||
Stream.Write(bytes, 0 , bytes.Length);
|
||||
}
|
||||
|
||||
private void ReadClientInput()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (Stream.DataAvailable)
|
||||
{
|
||||
byte[] buffer = new byte[Client.ReceiveBufferSize];
|
||||
Stream.Read(buffer, 0, buffer.Length);
|
||||
|
||||
var str = Encoding.GetString(buffer);
|
||||
lock (Others)
|
||||
{
|
||||
Others += str;
|
||||
}
|
||||
|
||||
CheckLines();
|
||||
} else
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckLines()
|
||||
{
|
||||
lock (Others)
|
||||
{
|
||||
var line = "";
|
||||
foreach (char c in Others)
|
||||
{
|
||||
if (c.Equals('\n'))
|
||||
{
|
||||
Console.WriteLine(line);
|
||||
NewLine(line);
|
||||
line = "";
|
||||
}
|
||||
else line += c;
|
||||
}
|
||||
Others = line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class PortListener
|
||||
{
|
||||
static List<int> _Ports = null;
|
||||
TcpListener _Listener;
|
||||
|
||||
public event ConnectedEventHandler OnConnected;
|
||||
|
||||
public PortListener(int port)
|
||||
{
|
||||
if(_Ports == null)
|
||||
{
|
||||
_Ports = new List<int>();
|
||||
}
|
||||
|
||||
foreach(var i in _Ports)
|
||||
{
|
||||
if (i == port)
|
||||
{
|
||||
throw new PortUsedException();
|
||||
}
|
||||
}
|
||||
|
||||
_Ports.Add(port);
|
||||
StartListening(new TcpListener(IPAddress.Any, port));
|
||||
}
|
||||
|
||||
private void StartListening(TcpListener listener)
|
||||
{
|
||||
listener.Start();
|
||||
_Listener = listener;
|
||||
Thread thread = new Thread(new ThreadStart(ListenerAsync));
|
||||
thread.Start();
|
||||
}
|
||||
|
||||
private async void ListenerAsync()
|
||||
{
|
||||
var client = await _Listener.AcceptTcpClientAsync();
|
||||
Console.WriteLine("Connection");
|
||||
OnConnected(this, new ConnectedEventArgs(client, Encoding.UTF8));
|
||||
}
|
||||
}
|
||||
}
|
119
MailServer/MailServer/Program.cs
Normal file
119
MailServer/MailServer/Program.cs
Normal file
@ -0,0 +1,119 @@
|
||||
using DnsClient;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SMTPServer
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
/*using (var context = new MysqlDB())
|
||||
{
|
||||
context.Database.EnsureCreated();
|
||||
|
||||
var domain = new Domains()
|
||||
{
|
||||
Domain = "HI",
|
||||
IsMail = true
|
||||
};
|
||||
context.Add(domain);
|
||||
context.SaveChanges();
|
||||
|
||||
var res = context.Domains.Find();
|
||||
}*/
|
||||
|
||||
|
||||
//Console.WriteLine("####################");
|
||||
|
||||
/*var request = new DnsQueryRequest();
|
||||
var response = request.ResolveAsync("fabianstamm.de", DnDns.Enums.NsType.MX, DnDns.Enums.NsClass.ANY, System.Net.Sockets.ProtocolType.Tcp);
|
||||
|
||||
OutputResults(response);*/
|
||||
//var t = new Thread(new ThreadStart(Test));
|
||||
//t.Start();
|
||||
//TestAsync();
|
||||
|
||||
var listener = new PortListener(5122);
|
||||
listener.OnConnected += Listener_OnConnected;
|
||||
|
||||
while (true)
|
||||
{
|
||||
Thread.Sleep(500);
|
||||
|
||||
}
|
||||
//var listener = new PortListener(5122);
|
||||
//listener.OnConnected += Listener_OnConnected;
|
||||
}
|
||||
|
||||
private static async void TestAsync()
|
||||
{
|
||||
var lookup = new LookupClient();
|
||||
var result = await lookup.QueryAsync("fabianstamm.de.", QueryType.MX);
|
||||
|
||||
foreach (var r in result.AllRecords)
|
||||
{
|
||||
Console.WriteLine(r.RecordToString());
|
||||
}
|
||||
}
|
||||
|
||||
private static void Listener_OnConnected(object source, ConnectedEventArgs e)
|
||||
{
|
||||
var session = new MTASession(e);
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
/*
|
||||
private static async void OutputResults(Task<DnDns.Query.DnsQueryResponse> res)
|
||||
{
|
||||
OutputResults(await res);
|
||||
}
|
||||
|
||||
private static void OutputResults(DnDns.Query.DnsQueryResponse response)
|
||||
{
|
||||
Console.WriteLine("Bytes received: " + response.BytesReceived);
|
||||
|
||||
Console.WriteLine("Name: " + response.Name);
|
||||
Console.WriteLine("OpCode: " + response.NsClass);
|
||||
Console.WriteLine("NsFlags: " + response.NsFlags);
|
||||
Console.WriteLine("NsType: " + response.NsType);
|
||||
Console.WriteLine("RCode: " + response.RCode);
|
||||
Console.WriteLine("OpCode: " + response.OpCode);
|
||||
|
||||
// Enumerate the Answer Records
|
||||
Console.WriteLine("Answers:");
|
||||
foreach (IDnsRecord record in response.Answers)
|
||||
{
|
||||
Console.WriteLine(record.Answer);
|
||||
Console.WriteLine(" |--- RDATA Field Length: " + record.DnsHeader.DataLength);
|
||||
Console.WriteLine(" |--- Name: " + record.DnsHeader.Name);
|
||||
Console.WriteLine(" |--- NS Class: " + record.DnsHeader.NsClass);
|
||||
Console.WriteLine(" |--- NS Type: " + record.DnsHeader.NsType);
|
||||
Console.WriteLine(" |--- TTL: " + record.DnsHeader.TimeToLive);
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
foreach (IDnsRecord record in response.AuthoritiveNameServers)
|
||||
{
|
||||
Console.WriteLine(record.Answer);
|
||||
Console.WriteLine(" |--- RDATA Field Length: " + record.DnsHeader.DataLength);
|
||||
Console.WriteLine(" |--- Name: " + record.DnsHeader.Name);
|
||||
Console.WriteLine(" |--- NS Class: " + record.DnsHeader.NsClass);
|
||||
Console.WriteLine(" |--- NS Type: " + record.DnsHeader.NsType);
|
||||
Console.WriteLine(" |--- TTL: " + record.DnsHeader.TimeToLive);
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
foreach (IDnsRecord record in response.AdditionalRRecords)
|
||||
{
|
||||
Console.WriteLine(record.Answer);
|
||||
Console.WriteLine(" |--- RDATA Field Length: " + record.DnsHeader.DataLength);
|
||||
Console.WriteLine(" |--- Name: " + record.DnsHeader.Name);
|
||||
Console.WriteLine(" |--- NS Class: " + record.DnsHeader.NsClass);
|
||||
Console.WriteLine(" |--- NS Type: " + record.DnsHeader.NsType);
|
||||
Console.WriteLine(" |--- TTL: " + record.DnsHeader.TimeToLive);
|
||||
Console.WriteLine();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
7
MailServer/MailServer/Properties/launchSettings.json
Normal file
7
MailServer/MailServer/Properties/launchSettings.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"profiles": {
|
||||
"SMTPServer": {
|
||||
"commandName": "Project"
|
||||
}
|
||||
}
|
||||
}
|
74
MailServer/MailServer/StartTcpConnection.cs
Normal file
74
MailServer/MailServer/StartTcpConnection.cs
Normal file
@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace SMTPServer
|
||||
{
|
||||
class StartTcpConnection : Socket
|
||||
{
|
||||
private List<string> Lines = new List<string>();
|
||||
private int LinesAvailable { get
|
||||
{
|
||||
return Lines.Count;
|
||||
}
|
||||
}
|
||||
|
||||
private string Others { get; set; }
|
||||
private Encoding Encoding { get; set; }
|
||||
|
||||
public StartTcpConnection(int port, IPAddress destination, Encoding encoding) : base (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
|
||||
{
|
||||
this.Connect(new IPEndPoint(destination, port));
|
||||
Thread readLines = new Thread(new ThreadStart(ReadClientInput));
|
||||
}
|
||||
|
||||
private void ReadClientInput()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
byte[] buffer = new byte[ReceiveBufferSize];
|
||||
Receive(buffer);
|
||||
|
||||
var str = Encoding.GetString(buffer);
|
||||
lock (Others)
|
||||
{
|
||||
Others += str;
|
||||
}
|
||||
|
||||
CheckLines();
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckLines()
|
||||
{
|
||||
lock (Others)
|
||||
{
|
||||
var line = "";
|
||||
foreach (char c in Others)
|
||||
{
|
||||
if (c.Equals('\n'))
|
||||
{
|
||||
lock (Lines)
|
||||
{
|
||||
Lines.Add(line);
|
||||
line = "";
|
||||
}
|
||||
}
|
||||
else line += c;
|
||||
}
|
||||
Others = line;
|
||||
}
|
||||
}
|
||||
|
||||
public string GetLine()
|
||||
{
|
||||
lock (Lines)
|
||||
{
|
||||
return Lines[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user