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

View File

@@ -0,0 +1,36 @@
using System.Net;
namespace DnsClient.Protocol
{
/*
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 <see cref="DnsResourceRecord"/> represending an IPv4 <see cref="IPAddress"/>.
/// Hosts that have multiple Internet addresses will have multiple A records.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035">RFC 1035</seealso>
public class ARecord : AddressRecord
{
/// <summary>
/// Initializes a new instance of the <see cref="ARecord"/> class.
/// </summary>
/// <inheritdoc />
public ARecord(ResourceRecordInfo info, IPAddress address) : base(info, address)
{
}
}
}

View File

@@ -0,0 +1,23 @@
using System.Net;
namespace DnsClient.Protocol
{
/// <summary>
/// A <see cref="DnsResourceRecord"/> represending an IPv6 <see cref="IPAddress"/>.
/// <para>
/// A 128 bit IPv6 address is encoded in the data portion of an AAAA
/// resource record in network byte order(high-order byte first).
/// </para>
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc3596#section-2.2">RFC 3596</seealso>
public class AaaaRecord : AddressRecord
{
/// <summary>
/// Initializes a new instance of the <see cref="AaaaRecord"/> class.
/// </summary>
/// <inheritdoc />
public AaaaRecord(ResourceRecordInfo info, IPAddress address) : base(info, address)
{
}
}
}

View File

@@ -0,0 +1,39 @@
using System;
using System.Net;
namespace DnsClient.Protocol
{
/// <summary>
/// Base class for <see cref="DnsResourceRecord"/>s transporting an <see cref="IPAddress"/>.
/// </summary>
/// <seealso cref="ARecord"/>
/// <seealso cref="AaaaRecord"/>
public class AddressRecord : DnsResourceRecord
{
/// <summary>
/// Gets the <see cref="IPAddress"/>.
/// </summary>
/// <value>
/// The address.
/// </value>
public IPAddress Address { get; }
/// <summary>
/// Initializes a new instance of the <see cref="AddressRecord"/> class.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="address">The address.</param>
/// <exception cref="ArgumentNullException">If <paramref name="info"/> is null.</exception>
/// <exception cref="System.ArgumentNullException">If <paramref name="address"/> or <paramref name="info"/> is null</exception>
public AddressRecord(ResourceRecordInfo info, IPAddress address)
: base(info)
{
Address = address ?? throw new ArgumentNullException(nameof(address));
}
private protected override string RecordToString()
{
return Address.ToString();
}
}
}

View File

@@ -0,0 +1,83 @@
using System;
namespace DnsClient.Protocol
{
/* https://tools.ietf.org/html/rfc1183#section-1, https://tools.ietf.org/html/rfc5864
1. AFS Data Base location
This section defines an extension of the DNS to locate servers both
for AFS (AFS is a registered trademark of Transarc Corporation) and
for the Open Software Foundation's (OSF) Distributed Computing
Environment (DCE) authenticated naming system using HP/Apollo's NCA,
both to be components of the OSF DCE. The discussion assumes that
the reader is familiar with AFS [5] and NCA [6].
The AFS (originally the Andrew File System) system uses the DNS to
map from a domain name to the name of an AFS cell database server.
The DCE Naming service uses the DNS for a similar function: mapping
from the domain name of a cell to authenticated name servers for that
cell. The method uses a new RR type with mnemonic AFSDB and type
code of 18 (decimal).
AFSDB has the following format:
<owner> <ttl> <class> AFSDB <subtype> <hostname>
*/
/// <summary>
/// A <see cref="DnsResourceRecord"/> representing an AFS database location.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1183#section-1">RFC 1183</seealso>
/// <seealso href="https://tools.ietf.org/html/rfc5864">RFC 5864</seealso>
public class AfsDbRecord : DnsResourceRecord
{
/// <summary>
/// Gets the <see cref="AfsType"/>.
/// </summary>
/// <value>
/// The sub type.
/// </value>
public AfsType SubType { get; }
/// <summary>
/// Gets the hostname.
/// </summary>
/// <value>
/// The hostname.
/// </value>
public DnsString Hostname { get; }
/// <summary>
/// Initializes a new instance of the <see cref="AfsDbRecord"/> class.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="type">The type.</param>
/// <param name="name">The name.</param>
/// <exception cref="System.ArgumentNullException">If <paramref name="info"/> or <paramref name="name"/> is null.</exception>
public AfsDbRecord(ResourceRecordInfo info, AfsType type, DnsString name) : base(info)
{
SubType = type;
Hostname = name ?? throw new ArgumentNullException(nameof(name));
}
private protected override string RecordToString()
{
return $"{(int)SubType} {Hostname}";
}
}
/// <summary>
/// Type used by <see cref="AfsDbRecord"/>.
/// </summary>
public enum AfsType
{
/// <summary>
/// AFS is a registered trademark of Transarc Corporation
/// </summary>
Afs = 1,
/// <summary>
/// The Distributed Computing Environment
/// </summary>
Dce = 2
}
}

View File

@@ -0,0 +1,56 @@
using System;
namespace DnsClient.Protocol
{
/*
https://tools.ietf.org/html/rfc1035#section-3.3.1:
3.3.1. CNAME RDATA format
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
/ CNAME /
/ /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
where:
CNAME A <domain-name> which specifies the canonical or primary
name for the owner. The owner name is an alias.
CNAME RRs cause no additional section processing, but name servers may
choose to restart the query at the canonical name in certain cases. See
the description of name server logic in [RFC-1034] for details.
*/
/// <summary>
/// A <see cref="DnsResourceRecord"/> repesenting the canonical name for an alias.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035#section-3.3.1">RFC 1035</seealso>
public class CNameRecord : DnsResourceRecord
{
/// <summary>
/// Gets the canonical name for an alias.
/// </summary>
/// <value>
/// The canonical name.
/// </value>
public DnsString CanonicalName { get; }
/// <summary>
/// Initializes a new instance of the <see cref="CNameRecord"/> class.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="canonicalName">The canonical name.</param>
/// <exception cref="System.ArgumentNullException">If <paramref name="canonicalName"/> or <paramref name="info"/> is null.</exception>
public CNameRecord(ResourceRecordInfo info, DnsString canonicalName)
: base(info)
{
CanonicalName = canonicalName ?? throw new ArgumentNullException(nameof(canonicalName));
}
private protected override string RecordToString()
{
return CanonicalName.Value;
}
}
}

View File

@@ -0,0 +1,130 @@
using System;
namespace DnsClient.Protocol
{
/* 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>
/// A <see cref="DnsResourceRecord"/> representing a certification authority authorization.
/// <para>
/// 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.
/// </para>
/// <para>
/// 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.
/// </para>
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc6844">RFC 6844</seealso>
public class CaaRecord : DnsResourceRecord
{
/// <summary>
/// One octet containing the flags.
/// </summary>
public byte Flags { get; }
/// <summary>
/// The property identifier, a sequence of US-ASCII characters.
/// </summary>
public string Tag { get; }
/// <summary>
/// A sequence of octets representing the property value.
/// Property values are encoded as binary values and MAY employ sub-formats.
/// </summary>
public string Value { get; }
/// <summary>
/// Initializes a new instance of the <see cref="CaaRecord"/> class.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="flags">The flags.</param>
/// <param name="tag">The tag.</param>
/// <param name="value">The value.</param>
/// <exception cref="System.ArgumentNullException">If <paramref name="info"/> or <paramref name="tag"/> or <paramref name="value"/> is null.</exception>
public CaaRecord(ResourceRecordInfo info, byte flags, string tag, string value) : base(info)
{
Flags = flags;
Tag = tag ?? throw new ArgumentNullException(nameof(tag));
Value = value ?? throw new ArgumentNullException(nameof(value));
}
private protected override string RecordToString()
{
return $"{Flags} {Tag} \"{Value}\"";
}
}
}

View File

@@ -0,0 +1,140 @@
using System;
namespace DnsClient.Protocol
{
/// <summary>
/// Base class for all resource records.
/// </summary>
/// <seealso cref="DnsClient.Protocol.ResourceRecordInfo" />
public abstract class DnsResourceRecord : ResourceRecordInfo
{
/// <summary>
/// Initializes a new instance of the <see cref="DnsResourceRecord" /> class.
/// </summary>
/// <param name="info">The information.</param>
/// <exception cref="ArgumentNullException">If <paramref name="info"/> is null.</exception>
public DnsResourceRecord(ResourceRecordInfo info)
: base(
info?.DomainName ?? throw new ArgumentNullException(nameof(info)),
info?.RecordType ?? throw new ArgumentNullException(nameof(info)),
info?.RecordClass ?? throw new ArgumentNullException(nameof(info)),
info?.InitialTimeToLive ?? throw new ArgumentNullException(nameof(info)),
info?.RawDataLength ?? throw new ArgumentNullException(nameof(info)))
{
}
/// <inheritdoc />
public override string ToString()
{
return ToString(0);
}
/// <summary>
/// Same as <c>ToString</c> but offsets the <see cref="ResourceRecordInfo.DomainName"/>
/// 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}",
DomainName,
TimeToLive,
RecordClass,
RecordType,
RecordToString());
}
/// <summary>
/// Returns a string representation of the record's value only.
/// <see cref="ToString(int)"/> uses this to compose the full string value of this instance.
/// </summary>
/// <returns>A string representing this record.</returns>
private protected abstract string RecordToString();
}
/// <summary>
/// The type represents a <see cref="DnsResourceRecord"/>.
/// </summary>
public class ResourceRecordInfo
{
private readonly int _ticks;
/// <summary>
/// The domain name used to query.
/// </summary>
public DnsString DomainName { 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>
/// Gets the current time to live value for the record.
/// </summary>
public int TimeToLive
{
get
{
var curTicks = Environment.TickCount & int.MaxValue;
if (curTicks < _ticks)
{
return 0;
}
var ttl = InitialTimeToLive - ((curTicks - _ticks) / 1000);
return ttl < 0 ? 0 : ttl;
}
}
/// <summary>
/// Gets or sets the original time to live returned from the server.
/// </summary>
public int InitialTimeToLive { get; internal set; }
/// <summary>
/// Gets the number of bytes for this resource record stored in RDATA
/// </summary>
public int RawDataLength { get; }
/// <summary>
/// Initializes a new instance of the <see cref="ResourceRecordInfo" /> class.
/// </summary>
/// <param name="domainName">The domain name used by the query.</param>
/// <param name="recordType">Type of the record.</param>
/// <param name="recordClass">The record class.</param>
/// <param name="timeToLive">The time to live.</param>
/// <param name="rawDataLength">Length of the raw data.</param>
/// <exception cref="ArgumentNullException">If <paramref name="domainName"/> is null.</exception>
public ResourceRecordInfo(string domainName, ResourceRecordType recordType, QueryClass recordClass, int timeToLive, int rawDataLength)
: this(DnsString.Parse(domainName), recordType, recordClass, timeToLive, rawDataLength)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ResourceRecordInfo" /> class.
/// </summary>
/// <param name="domainName">The <see cref="DnsString" /> used by the query.</param>
/// <param name="recordType">Type of the record.</param>
/// <param name="recordClass">The record class.</param>
/// <param name="timeToLive">The time to live.</param>
/// <param name="rawDataLength">Length of the raw data.</param>
/// <exception cref="System.ArgumentNullException">If <paramref name="domainName" /> is null or empty.</exception>
public ResourceRecordInfo(DnsString domainName, ResourceRecordType recordType, QueryClass recordClass, int timeToLive, int rawDataLength)
{
DomainName = domainName ?? throw new ArgumentNullException(nameof(domainName));
RecordType = recordType;
RecordClass = recordClass;
RawDataLength = rawDataLength;
InitialTimeToLive = timeToLive;
_ticks = Environment.TickCount;
}
}
}

View File

@@ -0,0 +1,24 @@
namespace DnsClient.Protocol
{
/// <summary>
/// A <see cref="DnsResourceRecord"/> not representing any specifc resource record.
/// Used if unsupported <see cref="ResourceRecordType"/>s are found in the result.
/// </summary>
/// <seealso cref="DnsClient.Protocol.DnsResourceRecord" />
public class EmptyRecord : DnsResourceRecord
{
/// <summary>
/// Initializes a new instance of the <see cref="EmptyRecord"/> class.
/// </summary>
/// <param name="info">The information.</param>
/// <exception cref="System.ArgumentNullException">If <paramref name="info"/> is null.</exception>
public EmptyRecord(ResourceRecordInfo info) : base(info)
{
}
private protected override string RecordToString()
{
return string.Empty;
}
}
}

View File

@@ -0,0 +1,63 @@
namespace DnsClient.Protocol
{
/*
https://tools.ietf.org/html/rfc1035#section-3.3.11:
3.3.2. HINFO RDATA format
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
/ CPU /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
/ OS /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
where:
CPU A <character-string> which specifies the CPU type.
OS A <character-string> which specifies the operating
system type.
*/
/// <summary>
/// A <see cref="DnsResourceRecord"/> used to acquire general information about a host.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035#section-3.3.11">RFC 1035</seealso>
/// <seealso href="https://tools.ietf.org/html/rfc1010">RFC 1010</seealso>
public class HInfoRecord : DnsResourceRecord
{
/// <summary>
/// Gets a <c>string</c> which specifies the CPU type.
/// </summary>
/// <value>
/// The cpu.
/// </value>
public string Cpu { get; }
/// <summary>
/// Gets a <c>string</c> which specifies the operating system type.
/// </summary>
/// <value>
/// The os.
/// </value>
public string OS { get; }
/// <summary>
/// Initializes a new instance of the <see cref="HInfoRecord"/> class.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="cpu">The cpu.</param>
/// <param name="os">The os.</param>
/// <exception cref="System.ArgumentNullException">If <paramref name="info"/> is null.</exception>
public HInfoRecord(ResourceRecordInfo info, string cpu, string os)
: base(info)
{
Cpu = cpu;
OS = os;
}
private protected override string RecordToString()
{
return $"\"{Cpu}\" \"{OS}\"";
}
}
}

View File

@@ -0,0 +1,77 @@
using System;
namespace DnsClient.Protocol
{
/*
https://tools.ietf.org/html/rfc1035#section-3.3.11:
3.3.7. MINFO RDATA format (EXPERIMENTAL)
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
/ RMAILBX /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
/ EMAILBX /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
where:
RMAILBX A <domain-name> which specifies a mailbox which is
responsible for the mailing list or mailbox. If this
domain name names the root, the owner of the MINFO RR is
responsible for itself. Note that many existing mailing
lists use a mailbox X-request for the RMAILBX field of
mailing list X, e.g., Msgroup-request for Msgroup. This
field provides a more general mechanism.
EMAILBX A <domain-name> which specifies a mailbox which is to
receive error messages related to the mailing list or
mailbox specified by the owner of the MINFO RR (similar
to the ERRORS-TO: field which has been proposed). If
this domain name names the root, errors should be
returned to the sender of the message.
MINFO records cause no additional section processing. Although these
records can be associated with a simple mailbox, they are usually used
with a mailing list.
*/
/// <summary>
/// A <see cref="DnsResourceRecord"/> represending mailbox or mail list information.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035#section-3.3.11">RFC 1035</seealso>
public class MInfoRecord : DnsResourceRecord
{
/// <summary>
/// Gets the domain name which specifies a mailbox which is responsible for the mailing list or mailbox.
/// </summary>
/// <value>
/// The domain name.
/// </value>
public DnsString RMailBox { get; }
/// <summary>
/// Gets the domain name which specifies a mailbox which is to receive error messages related to the mailing list or mailbox.
/// </summary>
/// <value>
/// The domain name.
/// </value>
public DnsString EmailBox { get; }
/// <summary>
/// Initializes a new instance of the <see cref="MInfoRecord"/> class.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="rmailBox">The <c>RMAILBX</c>.</param>
/// <param name="emailBox">The <c>EMAILBX</c>.</param>
/// <exception cref="ArgumentNullException">If <paramref name="info"/> or <paramref name="rmailBox"/> or <paramref name="emailBox"/> is null.</exception>
public MInfoRecord(ResourceRecordInfo info, DnsString rmailBox, DnsString emailBox)
: base(info)
{
RMailBox = rmailBox ?? throw new ArgumentNullException(nameof(rmailBox));
EmailBox = emailBox ?? throw new ArgumentNullException(nameof(emailBox));
}
private protected override string RecordToString()
{
return $"{RMailBox} {EmailBox}";
}
}
}

View File

@@ -0,0 +1,67 @@
using System;
namespace DnsClient.Protocol
{
/* https://tools.ietf.org/html/rfc1035#section-3.3.9
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>
/// A <see cref="DnsResourceRecord"/> represending a mail exchange.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035#section-3.3.9">RFC 1035</seealso>
/// <seealso href="https://tools.ietf.org/html/rfc974">RFC 974</seealso>
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 DnsString Exchange { get; }
/// <summary>
/// Initializes a new instance of the <see cref="MxRecord"/> class.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="preference">The preference.</param>
/// <param name="domainName">Name of the domain.</param>
/// <exception cref="System.ArgumentNullException">If <paramref name="domainName"/> or <paramref name="info"/> is null.</exception>
public MxRecord(ResourceRecordInfo info, ushort preference, DnsString domainName)
: base(info)
{
Preference = preference;
Exchange = domainName ?? throw new ArgumentNullException(nameof(domainName));
}
private protected override string RecordToString()
{
return string.Format("{0} {1}", Preference, Exchange);
}
}
}

View File

@@ -0,0 +1,52 @@
using System;
namespace DnsClient.Protocol
{
/*
https://tools.ietf.org/html/rfc1035#section-3.3.3:
3.3.3. MB RDATA format (EXPERIMENTAL)
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
/ MADNAME /
/ /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
where:
MADNAME A <domain-name> which specifies a host which has the
specified mailbox.
*/
/// <summary>
/// A <see cref="DnsResourceRecord"/> represending a domain name which specifies a host which has the specified mailbox.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035#section-3.3.3">RFC 1035</seealso>
public class MbRecord : DnsResourceRecord
{
/// <summary>
/// Gets the domain name which specifies a host which has the specified mailbox.
/// </summary>
/// <value>
/// The domain name.
/// </value>
public DnsString MadName { get; }
/// <summary>
/// Initializes a new instance of the <see cref="MbRecord"/> class.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="domainName">The domain name.</param>
/// <exception cref="System.ArgumentNullException">If <paramref name="domainName"/> or <paramref name="info"/> is null.</exception>
public MbRecord(ResourceRecordInfo info, DnsString domainName)
: base(info)
{
MadName = domainName ?? throw new ArgumentNullException(nameof(domainName));
}
private protected override string RecordToString()
{
return MadName.Value;
}
}
}

View File

@@ -0,0 +1,54 @@
using System;
namespace DnsClient.Protocol
{
/*
https://tools.ietf.org/html/rfc1035#section-3.3.6:
3.3.6. MG RDATA format (EXPERIMENTAL)
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
/ MGMNAME /
/ /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
where:
MGMNAME A <domain-name> which specifies a mailbox which is a
member of the mail group specified by the domain name.
MG records cause no additional section processing.
*/
/// <summary>
/// A <see cref="DnsResourceRecord"/> represending a domain name which specifies a mailbox which is a member of the mail group specified by the domain name.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035#section-3.3.6">RFC 1035</seealso>
public class MgRecord : DnsResourceRecord
{
/// <summary>
/// Gets a domain name which specifies a mailbox which is a member of the mail group specified by the domain nam.
/// </summary>
/// <value>
/// The domain name.
/// </value>
public DnsString MgName { get; }
/// <summary>
/// Initializes a new instance of the <see cref="MgRecord"/> class.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="domainName">The domain name.</param>
/// <exception cref="System.ArgumentNullException">If <paramref name="domainName"/> or <paramref name="info"/> is null.</exception>
public MgRecord(ResourceRecordInfo info, DnsString domainName)
: base(info)
{
MgName = domainName ?? throw new ArgumentNullException(nameof(domainName));
}
private protected override string RecordToString()
{
return MgName.Value;
}
}
}

View File

@@ -0,0 +1,55 @@
using System;
namespace DnsClient.Protocol
{
/*
https://tools.ietf.org/html/rfc1035#section-3.3.8:
3.3.8. MR RDATA format (EXPERIMENTAL)
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
/ NEWNAME /
/ /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
where:
NEWNAME A <domain-name> which specifies a mailbox which is the
proper rename of the specified mailbox.
MR records cause no additional section processing. The main use for MR
is as a forwarding entry for a user who has moved to a different
mailbox.
*/
/// <summary>
/// A <see cref="DnsResourceRecord"/> represending a mailbox rename domain name.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035#section-3.3.8">RFC 1035</seealso>
public class MrRecord : DnsResourceRecord
{
/// <summary>
/// Gets the domain name which specifies a mailbox which is the proper rename of the specified mailbox.
/// </summary>
/// <value>
/// The domain name.
/// </value>
public DnsString NewName { get; }
/// <summary>
/// Initializes a new instance of the <see cref="MrRecord"/> class.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="name">The domain name.</param>
/// <exception cref="System.ArgumentNullException">If <paramref name="name"/> or <paramref name="info"/> is null.</exception>
public MrRecord(ResourceRecordInfo info, DnsString name)
: base(info)
{
NewName = name ?? throw new ArgumentNullException(nameof(name));
}
private protected override string RecordToString()
{
return NewName.Value;
}
}
}

View File

@@ -0,0 +1,62 @@
using System;
namespace DnsClient.Protocol
{
/*
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.
*/
/// <summary>
/// A <see cref="DnsResourceRecord"/> represending an authoritative name server.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035#section-3.3.11">RFC 1035</seealso>
public class NsRecord : DnsResourceRecord
{
/// <summary>
/// Gets the domain name which specifies a host which should be authoritative for the specified class and domain.
/// </summary>
/// <value>
/// The domain name.
/// </value>
public DnsString NSDName { get; }
/// <summary>
/// Initializes a new instance of the <see cref="NsRecord"/> class.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="name">The name.</param>
/// <exception cref="System.ArgumentNullException">If <paramref name="name"/> or <paramref name="info"/> is null.</exception>
public NsRecord(ResourceRecordInfo info, DnsString name)
: base(info)
{
NSDName = name ?? throw new ArgumentNullException(nameof(name));
}
private protected override string RecordToString()
{
return NSDName.Value;
}
}
}

View File

@@ -0,0 +1,63 @@
using System;
using System.Text;
namespace DnsClient.Protocol
{
/*
https://tools.ietf.org/html/rfc1035#section-3.3.10:
3.3.10. NULL RDATA format (EXPERIMENTAL)
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
/ <anything> /
/ /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
Anything at all may be in the RDATA field so long as it is 65535 octets
or less.
*/
/// <summary>
/// Experimental RR, not sure if the implementation is actually correct either (not tested).
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035#section-3.3.10">RFC 1035</seealso>
public class NullRecord : DnsResourceRecord
{
/// <summary>
/// Gets any data stored in this record.
/// </summary>
/// <value>
/// The byte array.
/// </value>
public byte[] Anything { get; }
/// <summary>
/// Gets the raw data of this record as UTF8 string.
/// </summary>
public string AsString { get; }
/// <summary>
/// Initializes a new instance of the <see cref="NullRecord" /> class.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="anything">Anything.</param>
/// <exception cref="System.ArgumentNullException">If <paramref name="info"/> or <paramref name="anything"/> is null.</exception>
public NullRecord(ResourceRecordInfo info, byte[] anything)
: base(info)
{
Anything = anything ?? throw new ArgumentNullException(nameof(anything));
try
{
AsString = Encoding.UTF8.GetString(anything);
}
catch
{
// ignore errors.
}
}
private protected override string RecordToString()
{
return $"\\# {Anything.Length} {AsString}";
}
}
}

View File

@@ -0,0 +1,128 @@
namespace DnsClient.Protocol.Options
{
/* https://tools.ietf.org/html/rfc6891#section-4.3
6.1.2. Wire Format
An OPT RR has a fixed part and a variable set of options expressed as
{attribute, value} pairs. The fixed part holds some DNS metadata,
and also a small collection of basic extension elements that we
expect to be so popular that it would be a waste of wire space to
encode them as {attribute, value} pairs.
The fixed part of an OPT RR is structured as follows:
+------------+--------------+------------------------------+
| Field Name | Field Type | Description |
+------------+--------------+------------------------------+
| NAME | domain name | MUST be 0 (root domain) |
| TYPE | u_int16_t | OPT (41) |
| CLASS | u_int16_t | requestor's UDP payload size |
| TTL | u_int32_t | extended RCODE and flags |
| RDLEN | u_int16_t | length of all RDATA |
| RDATA | octet stream | {attribute,value} pairs |
+------------+--------------+------------------------------+
6.1.3. OPT Record TTL Field Use
The extended RCODE and flags, which OPT stores in the RR Time to Live
(TTL) field, are structured as follows:
+0 (MSB) +1 (LSB)
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
0: | EXTENDED-RCODE | VERSION |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
2: | DO| Z |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
EXTENDED-RCODE
Forms the upper 8 bits of extended 12-bit RCODE (together with the
4 bits defined in [RFC1035]. Note that EXTENDED-RCODE value 0
indicates that an unextended RCODE is in use (values 0 through
15).
VERSION
Indicates the implementation level of the setter. Full
conformance with this specification is indicated by version '0'.
Requestors are encouraged to set this to the lowest implemented
level capable of expressing a transaction, to minimise the
responder and network load of discovering the greatest common
implementation level between requestor and responder. A
requestor's version numbering strategy MAY ideally be a run-time
configuration option.
If a responder does not implement the VERSION level of the
request, then it MUST respond with RCODE=BADVERS. All responses
MUST be limited in format to the VERSION level of the request, but
the VERSION of each response SHOULD be the highest implementation
level of the responder. In this way, a requestor will learn the
implementation level of a responder as a side effect of every
response, including error responses and including RCODE=BADVERS.
*/
/// <summary>
/// A options resource record.
/// </summary>
internal class OptRecord : DnsResourceRecord
{
private const uint ResponseCodeMask = 0xff000000;
private const int ResponseCodeShift = 20;
private const uint VersionMask = 0x00ff0000;
private const int VersionShift = 16;
public DnsResponseCode ResponseCodeEx
{
get
{
return (DnsResponseCode)((InitialTimeToLive & ResponseCodeMask) >> ResponseCodeShift);
}
set
{
InitialTimeToLive &= (int)~ResponseCodeMask;
InitialTimeToLive |= (int)(((int)value << ResponseCodeShift) & ResponseCodeMask);
}
}
public short UdpSize
{
get { return (short)RecordClass; }
}
public byte Version
{
get
{
return (byte)((InitialTimeToLive & VersionMask) >> VersionShift);
}
set
{
InitialTimeToLive = (int)((uint)InitialTimeToLive & ~VersionMask);
InitialTimeToLive |= (int)((value << VersionShift) & VersionMask);
}
}
public bool IsDnsSecOk
{
get { return (InitialTimeToLive & 0x8000) != 0; }
set
{
if (value)
{
InitialTimeToLive |= 0x8000;
}
else
{
InitialTimeToLive &= 0x7fff;
}
}
}
public OptRecord(int size = 4096, int version = 0, int length = 0)
: base(new ResourceRecordInfo(DnsString.RootLabel, ResourceRecordType.OPT, (QueryClass)size, version, length))
{
}
private protected override string RecordToString()
{
return $"OPT {RecordClass}.";
}
}
}

View File

@@ -0,0 +1,57 @@
using System;
namespace DnsClient.Protocol
{
/* 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.
*/
/// <summary>
/// A <see cref="DnsResourceRecord"/> represending a pointer. These RRs are used
/// in special domains to point to some other location in the domain space.
/// </summary>
/// <seealso cref="DnsClient.Protocol.DnsResourceRecord" />
/// <seealso href="https://tools.ietf.org/html/rfc1035#section-3.3.12">RFC 1035</seealso>
public class PtrRecord : DnsResourceRecord
{
/// <summary>
/// Gets the domain name which points to some location in the domain name space.
/// </summary>
/// <value>
/// The domain name.
/// </value>
public DnsString PtrDomainName { get; }
/// <summary>
/// Initializes a new instance of the <see cref="PtrRecord"/> class.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="ptrDomainName">The domain name.</param>
/// <exception cref="System.ArgumentNullException">If <paramref name="info"/> or <paramref name="ptrDomainName"/> is null.</exception>
public PtrRecord(ResourceRecordInfo info, DnsString ptrDomainName)
: base(info)
{
PtrDomainName = ptrDomainName ?? throw new ArgumentNullException(nameof(ptrDomainName));
}
private protected override string RecordToString()
{
return PtrDomainName.Value;
}
}
}

View File

@@ -0,0 +1,196 @@
using System;
namespace DnsClient.Protocol
{
/*
* RFC 1035 (https://tools.ietf.org/html/rfc1035#section-3.2.2)
* */
/// <summary>
/// The resource record types. The <c>enum</c> contains only the types supported by this library at this moment.
/// The <see cref="ResourceRecordType"/> is used to identify any <see cref="DnsResourceRecord"/>.
/// <para>
/// Resource record types are a subset of <see cref="QueryType"/>.
/// </para>
/// </summary>
/// <seealso cref="DnsResourceRecord"/>
/// <seealso cref="ResourceRecordType"/>
public enum ResourceRecordType : short
{
/// <summary>
/// A host address.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035">RFC 1035</seealso>
/// <seealso cref="ARecord"/>
A = 1,
/// <summary>
/// An authoritative name server.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035#section-3.3.11">RFC 1035</seealso>
/// <seealso cref="NsRecord"/>
NS = 2,
/// <summary>
/// A mail destination (OBSOLETE - use MX).
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035">RFC 1035</seealso>
[Obsolete("Use MX")]
MD = 3,
/// <summary>
/// A mail forwarder (OBSOLETE - use MX).
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035">RFC 1035</seealso>
[Obsolete("Use MX")]
MF = 4,
/// <summary>
/// The canonical name for an alias.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035#section-3.3.1">RFC 1035</seealso>
/// <seealso cref="CNameRecord"/>
CNAME = 5,
/// <summary>
/// Marks the start of a zone of authority.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035#section-3.3.13">RFC 1035</seealso>
/// <seealso cref="SoaRecord"/>
SOA = 6,
/// <summary>
/// A mailbox domain name (EXPERIMENTAL).
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035#section-3.3.3">RFC 1035</seealso>
/// <seealso cref="MbRecord"/>
MB = 7,
/// <summary>
/// A mail group member (EXPERIMENTAL).
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035#section-3.3.6">RFC 1035</seealso>
/// <seealso cref="MgRecord"/>
MG = 8,
/// <summary>
/// A mailbox rename domain name (EXPERIMENTAL).
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035#section-3.3.8">RFC 1035</seealso>
/// <seealso cref="MrRecord"/>
MR = 9,
/// <summary>
/// A Null resource record (EXPERIMENTAL).
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035#section-3.3.8">RFC 1035</seealso>
/// <seealso cref="NullRecord"/>
NULL = 10,
/// <summary>
/// A well known service description.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc3232">RFC 3232</seealso>
/// <seealso cref="WksRecord"/>
WKS = 11,
/// <summary>
/// A domain name pointer.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035#section-3.3.12">RFC 1035</seealso>
/// <seealso cref="PtrRecord"/>
PTR = 12,
/// <summary>
/// Host information.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035#section-3.3.11">RFC 1035</seealso>
/// <seealso href="https://tools.ietf.org/html/rfc1010">RFC 1010</seealso>
/// <seealso cref="HInfoRecord"/>
HINFO = 13,
/// <summary>
/// Mailbox or mail list information.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035#section-3.3.11">RFC 1035</seealso>
/// <seealso cref="MInfoRecord"/>
MINFO = 14,
/// <summary>
/// Mail exchange.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035#section-3.3.9">RFC 1035</seealso>
/// <seealso href="https://tools.ietf.org/html/rfc974">RFC 974</seealso>
/// <seealso cref="MxRecord"/>
MX = 15,
/// <summary>
/// Text resources.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035#section-3.3">RFC 1035</seealso>
/// <seealso href="https://tools.ietf.org/html/rfc1464">RFC 1464</seealso>
/// <seealso cref="TxtRecord"/>
TXT = 16,
/// <summary>
/// Responsible Person.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1183">RFC 1183</seealso>
/// <seealso cref="RpRecord"/>
RP = 17,
/// <summary>
/// AFS Data Base location.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1183#section-1">RFC 1183</seealso>
/// <seealso href="https://tools.ietf.org/html/rfc5864">RFC 5864</seealso>
/// <seealso cref="AfsDbRecord"/>
AFSDB = 18,
/// <summary>
/// An IPv6 host address.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc3596#section-2.2">RFC 3596</seealso>
/// <seealso cref="AaaaRecord"/>
AAAA = 28,
/// <summary>
/// A resource record which specifies the location of the server(s) for a specific protocol and domain.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc2782">RFC 2782</seealso>
/// <seealso cref="SrvRecord"/>
SRV = 33,
/// <summary>
/// Option record.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc6891">RFC 6891</seealso>
///// <seealso cref="DnsClient.Protocol.Options.OptRecord"/>
OPT = 41,
/// <summary>
/// SSH finger print record
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc4255">RFC 4255</seealso>
SSHFP = 44,
/// <summary>
/// RRSIG rfc3755.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc3755">RFC 3755</seealso>
RRSIG = 46,
/// <summary>
/// A Uniform Resource Identifier (URI) resource record.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc7553">RFC 7553</seealso>
/// <seealso cref="UriRecord"/>
URI = 256,
/// <summary>
/// A certification authority authorization.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc6844">RFC 6844</seealso>
/// <seealso cref="CaaRecord"/>
CAA = 257,
}
}

View File

@@ -0,0 +1,108 @@
using System;
namespace DnsClient.Protocol
{
/*
https://tools.ietf.org/html/rfc1183#section-2.2:
2. Responsible Person
The purpose of this section is to provide a standard method for
associating responsible person identification to any name in the DNS.
The domain name system functions as a distributed database which
contains many different form of information. For a particular name
or host, you can discover it's Internet address, mail forwarding
information, hardware type and operating system among others.
A key aspect of the DNS is that the tree-structured namespace can be
divided into pieces, called zones, for purposes of distributing
control and responsibility. The responsible person for zone database
purposes is named in the SOA RR for that zone. This section
describes an extension which allows different responsible persons to
be specified for different names in a zone.
2.2. The Responsible Person RR
The method uses a new RR type with mnemonic RP and type code of 17
(decimal).
RP has the following format:
<owner> <ttl> <class> RP <mbox-dname> <txt-dname>
Both RDATA fields are required in all RP RRs.
The first field, <mbox-dname>, is a domain name that specifies the
mailbox for the responsible person. Its format in master files uses
the DNS convention for mailbox encoding, identical to that used for
the RNAME mailbox field in the SOA RR. The root domain name (just
".") may be specified for <mbox-dname> to indicate that no mailbox is
available.
The second field, <txt-dname>, is a domain name for which TXT RR's
exist. A subsequent query can be performed to retrieve the
associated TXT resource records at <txt-dname>. This provides a
level of indirection so that the entity can be referred to from
multiple places in the DNS. The root domain name (just ".") may be
specified for <txt-dname> to indicate that the TXT_DNAME is absent,
and no associated TXT RR exists.
The format of the RP RR is class insensitive. RP records cause no
additional section processing. (TXT additional section processing
for <txt-dname> is allowed as an option, but only if it is disabled
for the root, i.e., ".").
The Responsible Person RR can be associated with any node in the
Domain Name System hierarchy, not just at the leaves of the tree.
The TXT RR associated with the TXT_DNAME contain free format text
suitable for humans. Refer to [4] for more details on the TXT RR.
Multiple RP records at a single name may be present in the database.
They should have identical TTLs.
*/
/// <summary>
/// A <see cref="DnsResourceRecord"/> represending a responsible person.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1183#section-2.2">RFC 1183</seealso>
public class RpRecord : DnsResourceRecord
{
/// <summary>
/// Gets a domain name that specifies the mailbox for the responsible person.
/// </summary>
/// <value>
/// The mailbox domain.
/// </value>
public DnsString MailboxDomainName { get; }
/// <summary>
/// Gets a domain name for which TXT RR's exist.
/// </summary>
/// <value>
/// The text domain.
/// </value>
public DnsString TextDomainName { get; }
/// <summary>
/// Initializes a new instance of the <see cref="RpRecord"/> class.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="mailbox">The mailbox domain.</param>
/// <param name="textName">The text domain.</param>
/// <exception cref="System.ArgumentNullException">
/// If <paramref name="info"/> or <paramref name="mailbox"/> or <paramref name="textName"/> is null.
/// </exception>
public RpRecord(ResourceRecordInfo info, DnsString mailbox, DnsString textName)
: base(info)
{
MailboxDomainName = mailbox ?? throw new ArgumentNullException(nameof(mailbox));
TextDomainName = textName ?? throw new ArgumentNullException(nameof(textName));
}
private protected override string RecordToString()
{
return $"{MailboxDomainName} {TextDomainName}";
}
}
}

View File

@@ -0,0 +1,177 @@
using System;
namespace DnsClient.Protocol
{
/*
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.
*/
/// <summary>
/// A <see cref="DnsResourceRecord"/> represending a SOA (Start Of Authority) record.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035#section-3.3.13">RFC 1035</seealso>
public class SoaRecord : DnsResourceRecord
{
/// <summary>
/// Gets a 32 bit time value that specifies the upper limit on
/// the time interval that can elapse before the zone is no
/// longer authoritative.
/// </summary>
/// <value>
/// The expiration.
/// </value>
public uint Expire { get; }
/// <summary>
/// Gets the unsigned 32 bit minimum TTL field that should be
/// exported with any RR from this zone.
/// </summary>
/// <value>
/// The minimum TTL.
/// </value>
public uint Minimum { get; }
/// <summary>
/// Gets the domain name of the name server that was the original or primary source of data for this zone.
/// </summary>
/// <value>
/// The doman name.
/// </value>
public DnsString MName { get; }
/// <summary>
/// Gets a 32 bit time interval before the zone should be refreshed.
/// </summary>
/// <value>
/// The refresh time.
/// </value>
public uint Refresh { get; }
/// <summary>
/// Gets a 32 bit time interval that should elapse before a failed refresh should be retried.
/// </summary>
/// <value>
/// The retry time.
/// </value>
public uint Retry { get; }
/// <summary>
/// Gets a domain name which specifies the mailbox of the person responsible for this zone.
/// </summary>
/// <value>
/// The responsible mailbox domain name.
/// </value>
public DnsString RName { get; }
/// <summary>
/// Gets 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.
/// </summary>
/// <value>
/// The serial number.
/// </value>
public uint Serial { get; }
/// <summary>
/// Initializes a new instance of the <see cref="SoaRecord" /> class.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="mName">Name original domain name.</param>
/// <param name="rName">Name responsible domain name.</param>
/// <param name="serial">The serial number.</param>
/// <param name="refresh">The refresh time.</param>
/// <param name="retry">The retry time.</param>
/// <param name="expire">The expire time.</param>
/// <param name="minimum">The minimum TTL.</param>
/// <exception cref="System.ArgumentNullException">
/// If <paramref name="info"/> or <paramref name="mName"/> or <paramref name="rName"/> is null.
/// </exception>
public SoaRecord(ResourceRecordInfo info, DnsString mName, DnsString rName, uint serial, uint refresh, uint retry, uint expire, uint minimum)
: base(info)
{
MName = mName ?? throw new ArgumentNullException(nameof(mName));
RName = rName ?? throw new ArgumentNullException(nameof(rName));
Serial = serial;
Refresh = refresh;
Retry = retry;
Expire = expire;
Minimum = minimum;
}
private protected override string RecordToString()
{
return string.Format(
"{0} {1} {2} {3} {4} {5} {6}",
MName,
RName,
Serial,
Refresh,
Retry,
Expire,
Minimum);
}
}
}

View File

@@ -0,0 +1,173 @@
using System;
namespace DnsClient.Protocol
{
/* 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>
/// A <see cref="DnsResourceRecord"/> represending a location of the server(s) for a specific protocol and domain.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc2782">RFC 2782</seealso>
public class SrvRecord : DnsResourceRecord
{
/// <summary>
/// Gets the port.
/// </summary>
/// <value>
/// The port.
/// </value>
public ushort Port { get; }
/// <summary>
/// Gets the priority.
/// </summary>
/// <value>
/// The priority.
/// </value>
public ushort Priority { get; }
/// <summary>
/// Gets the target domain name.
/// </summary>
/// <value>
/// The target.
/// </value>
public DnsString Target { get; }
/// <summary>
/// Gets the weight.
/// </summary>
/// <value>
/// The weight.
/// </value>
public ushort Weight { get; }
/// <summary>
/// Initializes a new instance of the <see cref="SrvRecord" /> class.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="priority">The priority.</param>
/// <param name="weigth">The weigth.</param>
/// <param name="port">The port.</param>
/// <param name="target">The target.</param>
/// <exception cref="System.ArgumentNullException">If <paramref name="info"/> or <paramref name="target"/> is null.</exception>
public SrvRecord(ResourceRecordInfo info, ushort priority, ushort weigth, ushort port, DnsString target)
: base(info)
{
Priority = priority;
Weight = weigth;
Port = port;
Target = target ?? throw new ArgumentNullException(nameof(target));
}
private protected override string RecordToString()
{
return string.Format(
"{0} {1} {2} {3}",
Priority,
Weight,
Port,
Target);
}
}
}

View File

@@ -0,0 +1,101 @@
namespace DnsClient.Protocol
{
/// <summary>
/// A <see cref="DnsResourceRecord"/> represending an SSH fingerprint
/// <para>
/// SSHFP RRs are used to hold SSH fingerprints. Upon connecting to a
/// host an SSH client may choose to query for this to check the fingerprint(s)
/// </para>
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc4255">RFC 4255</seealso>
/// <seealso href="https://tools.ietf.org/html/rfc6594">RFC 6594</seealso>
/// <seealso href="https://tools.ietf.org/html/rfc7479">RFC 7479</seealso>
public class SshfpRecord : DnsResourceRecord
{
/// <summary>
///
/// </summary>
/// <param name="info">The information.</param>
/// <param name="algorithm">The algorithm.</param>
/// <param name="fingerprintType">The fingerprint type.</param>
/// <param name="fingerprint">The fingerprint.</param>
public SshfpRecord(ResourceRecordInfo info, SshfpAlgorithm algorithm, SshfpFingerprintType fingerprintType, string fingerprint) : base(info)
{
Algorithm = algorithm;
FingerprintType = fingerprintType;
Fingerprint = fingerprint;
}
/// <summary>
/// Algorithm used for the fingerprint
/// </summary>
public SshfpAlgorithm Algorithm { get; }
/// <summary>
/// Fingerprint type used for the fingerprint
/// </summary>
public SshfpFingerprintType FingerprintType { get; }
/// <summary>
/// Fingerprint as defined in the RR
/// </summary>
public string Fingerprint { get; }
private protected override string RecordToString()
{
return $"{(int)Algorithm} {(int)FingerprintType} {Fingerprint}";
}
}
/// <summary>
/// Algorithm used by <see cref="SshfpRecord"/>
/// </summary>
public enum SshfpAlgorithm
{
/// <summary>
/// Reserved for later use
/// </summary>
Reserved = 0,
/// <summary>
/// RSA
/// </summary>
RSA = 1,
/// <summary>
/// DSS
/// </summary>
DSS = 2,
/// <summary>
/// Eliptic Curve DSA
/// </summary>
ECDSA = 3,
/// <summary>
/// Edwards-curve DSA
/// </summary>
Ed25519 = 4,
}
/// <summary>
/// Fingerprint type used by <see cref="SshfpRecord"/>
/// </summary>
public enum SshfpFingerprintType
{
/// <summary>
/// Reserved for later use
/// </summary>
Reserved = 0,
/// <summary>
/// SHA-1 fingerprint
/// </summary>
SHA1 = 1,
/// <summary>
/// SHA-256 fingerprint
/// </summary>
SHA256 = 2,
}
}

View File

@@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace DnsClient.Protocol
{
/*
* 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>
/// A <see cref="DnsResourceRecord"/> represending a text resource.
/// <para>
/// TXT RRs are used to hold descriptive text. The semantics of the text
/// depends on the domain where it is found.
/// </para>
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc1035#section-3.3">RFC 1035</seealso>
/// <seealso href="https://tools.ietf.org/html/rfc1464">RFC 1464</seealso>
public class TxtRecord : DnsResourceRecord
{
/// <summary>
/// Gets the list of TXT values of this resource record in escaped form, valid for root file.
/// </summary>
/// <remarks>
/// See https://tools.ietf.org/html/rfc1035#section-5.1 for escape details.
/// </remarks>
public ICollection<string> EscapedText { get; }
/// <summary>
/// Gets the actual <c>UTF8</c> representation of the text values of this record.
/// </summary>
public ICollection<string> Text { get; }
/// <summary>
/// Initializes a new instance of the <see cref="TxtRecord"/> class.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="values">The values.</param>
/// <param name="utf8Values">The UTF8 values.</param>
/// <exception cref="System.ArgumentNullException">
/// If <paramref name="info"/> or <paramref name="utf8Values"/> or <paramref name="values"/> is null.
/// </exception>
public TxtRecord(ResourceRecordInfo info, string[] values, string[] utf8Values)
: base(info)
{
EscapedText = values ?? throw new ArgumentNullException(nameof(values));
Text = utf8Values ?? throw new ArgumentNullException(nameof(utf8Values));
}
private protected override string RecordToString()
{
return string.Join(" ", EscapedText.Select(p => "\"" + p + "\"")).Trim();
}
}
}

View File

@@ -0,0 +1,83 @@
using System;
namespace DnsClient.Protocol
{
/*
* RFC 7553 https://tools.ietf.org/html/rfc7553
4.5. URI RDATA Wire Format
The RDATA for a URI RR consists of a 2-octet Priority field, a
2-octet Weight field, and a variable-length Target field.
Priority and Weight are unsigned integers in network byte order.
The remaining data in the RDATA contains the Target field. The
Target field contains the URI as a sequence of octets (without the
enclosing double-quote characters used in the presentation format).
The length of the Target field MUST be greater than zero.
1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Priority | Weight |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/ /
/ Target /
/ /
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
/// <summary>
/// A <see cref="DnsResourceRecord"/> represending a Uniform Resource Identifier (URI) resource.
/// </summary>
/// <seealso href="https://tools.ietf.org/html/rfc7553">RFC 7553</seealso>
public class UriRecord : DnsResourceRecord
{
/// <summary>
/// Gets or sets the target Uri.
/// </summary>
/// <value>
/// The target.
/// </value>
public string Target { get; set; }
/// <summary>
/// Gets or sets the priority.
/// </summary>
/// <value>
/// The priority.
/// </value>
public int Priority { get; set; }
/// <summary>
/// Gets or sets the weigth.
/// </summary>
/// <value>
/// The weigth.
/// </value>
public int Weigth { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="UriRecord"/> class.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="priority">The priority.</param>
/// <param name="weight">The weight.</param>
/// <param name="target">The target.</param>
/// <exception cref="System.ArgumentNullException">If <paramref name="info"/> or <paramref name="target"/> is null.</exception>
public UriRecord(ResourceRecordInfo info, ushort priority, ushort weight, string target)
: base(info)
{
Target = target ?? throw new ArgumentNullException(nameof(target));
Priority = priority;
Weigth = weight;
}
private protected override string RecordToString()
{
return $"{Priority} {Weigth} \"{Target}\"";
}
}
}

View File

@@ -0,0 +1,158 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
namespace DnsClient.Protocol
{
/*
https://tools.ietf.org/html/rfc1035#section-3.4.2:
3.4.2. WKS RDATA format
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ADDRESS |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| PROTOCOL | |
+--+--+--+--+--+--+--+--+ |
| |
/ <BIT MAP> /
/ /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
where:
ADDRESS An 32 bit Internet address
PROTOCOL An 8 bit IP protocol number
<BIT MAP> A variable length bit map. The bit map must be a
multiple of 8 bits long.
The WKS record is used to describe the well known services supported by
a particular protocol on a particular internet address. The PROTOCOL
field specifies an IP protocol number, and the bit map has one bit per
port of the specified protocol. The first bit corresponds to port 0,
the second to port 1, etc. If the bit map does not include a bit for a
protocol of interest, that bit is assumed zero. The appropriate values
and mnemonics for ports and protocols are specified in [RFC-1010].
For example, if PROTOCOL=TCP (6), the 26th bit corresponds to TCP port
25 (SMTP). If this bit is set, a SMTP server should be listening on TCP
port 25; if zero, SMTP service is not supported on the specified
address.
The purpose of WKS RRs is to provide availability information for
servers for TCP and UDP. If a server supports both TCP and UDP, or has
multiple Internet addresses, then multiple WKS RRs are used.
WKS RRs cause no additional section processing.
In master files, both ports and protocols are expressed using mnemonics
or decimal numbers.
** remark:
* RFS-1010 is obsolete/history.
* The most current one is https://tools.ietf.org/html/rfc3232
* The lists of protocols and ports are now handled via the online database on http://www.iana.org/.
*
* Also, see https://tools.ietf.org/html/rfc6335
* For clarification which protocols are supported etc.
*/
/// <summary>
/// A <see cref="DnsResourceRecord"/> represending a Well Known Service description.
/// </summary>
/// <remarks>
/// Instead of describing the supported protocols in RFCs, the list is now published on http://www.iana.org/.
/// </remarks>
/// <seealso href="http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml"/>
/// <seealso href="https://tools.ietf.org/html/rfc3232">RFC 3232, the most current update.</seealso>
public class WksRecord : DnsResourceRecord
{
/// <summary>
/// Gets the address.
/// </summary>
/// <value>
/// The address.
/// </value>
public IPAddress Address { get; }
/// <summary>
/// Gets the Protocol.
/// </summary>
/// <remarks>
/// According to https://tools.ietf.org/html/rfc6335, only ports for TCP, UDP, DCCP and SCTP services will be assigned.
/// </remarks>
public ProtocolType Protocol { get; }
/// <summary>
/// Gets the binary raw bitmap.
/// Use <see cref="Ports"/> to determine which ports are actually configured.
/// </summary>
public byte[] Bitmap { get; }
/// <summary>
/// Gets the list of assigned ports.
/// <para>
/// For example, if this list contains port 25, which is assigned to
/// the <c>SMTP</c> service. This means that a SMTP services
/// is running on <see cref="Address"/> with transport <see cref="Protocol"/>.
/// </para>
/// </summary>
/// <seealso href="http://www.iana.org/assignments/port-numbers">Port numbers</seealso>
public int[] Ports { get; }
/// <summary>
/// Initializes a new instance of the <see cref="WksRecord" /> class.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="address">The address.</param>
/// <param name="protocol">The protocol.</param>
/// <param name="bitmap">The raw data.</param>
/// <exception cref="System.ArgumentNullException">
/// If <paramref name="address"/> or <paramref name="info"/> or <paramref name="bitmap"/> is null.
/// </exception>
public WksRecord(ResourceRecordInfo info, IPAddress address, int protocol, byte[] bitmap)
: base(info)
{
Address = address ?? throw new ArgumentNullException(nameof(address));
Protocol = (ProtocolType)protocol;
Bitmap = bitmap ?? throw new ArgumentNullException(nameof(bitmap));
Ports = GetPorts(bitmap);
}
private protected override string RecordToString()
{
return $"{Address} {Protocol} {string.Join(" ", Ports)}";
}
private static int[] GetPorts(byte[] data)
{
int pos = 0, len = data.Length;
var result = new List<int>();
if (data.Length == 0)
{
return result.ToArray();
}
while (pos < len)
{
byte b = data[pos++];
if (b != 0)
{
for (int bit = 7; bit >= 0; bit--)
{
if ((b & (1 << bit)) != 0)
{
result.Add(pos * 8 - bit - 1);
}
}
}
}
return result.ToArray();
}
}
}