Commit bffe9119 authored by Brickner_cp's avatar Brickner_cp

DNS

parent c61be7c1
......@@ -91,7 +91,7 @@ namespace PcapDotNet.Base
public static explicit operator ulong(UInt128 value)
{
if (value._mostSignificant != 0)
throw new OverflowException("Value was either too large or too small for a UInt64.");
throw new OverflowException("Value was too large for a UInt64.");
return value._leastSignificant;
}
......@@ -359,6 +359,12 @@ namespace PcapDotNet.Base
Equals((UInt128)obj);
}
public bool Smaller(UInt128 other)
{
return _mostSignificant < other._mostSignificant ||
_mostSignificant == other._mostSignificant && _leastSignificant < other._leastSignificant;
}
/// <summary>
/// Returns true iff the two values represent the same value.
/// </summary>
......@@ -381,6 +387,16 @@ namespace PcapDotNet.Base
return !(value1 == value2);
}
public static bool operator <=(UInt128 value1, UInt128 value2)
{
return !value2.Smaller(value1);
}
public static bool operator >=(UInt128 value1, UInt128 value2)
{
return !value1.Smaller(value2);
}
/// <summary>
/// Shifts its first operand right by the number of bits specified by its second operand.
/// </summary>
......@@ -392,6 +408,17 @@ namespace PcapDotNet.Base
return RightShift(value, numberOfBits);
}
/// <summary>
/// Shifts its first operand left by the number of bits specified by its second operand.
/// </summary>
/// <param name="value">The value to shift.</param>
/// <param name="numberOfBits">The number of bits to shift.</param>
/// <returns>The value after it was shifted by the given number of bits.</returns>
public static UInt128 operator <<(UInt128 value, int numberOfBits)
{
return LeftShift(value, numberOfBits);
}
/// <summary>
/// Shifts its first operand right by the number of bits specified by its second operand.
/// </summary>
......@@ -408,6 +435,22 @@ namespace PcapDotNet.Base
return new UInt128(value._mostSignificant >> numberOfBits, (value._leastSignificant >> numberOfBits) + (value._mostSignificant << (64 - numberOfBits)));
}
/// <summary>
/// Shifts its first operand left by the number of bits specified by its second operand.
/// </summary>
/// <param name="value">The value to shift.</param>
/// <param name="numberOfBits">The number of bits to shift.</param>
/// <returns>The value after it was shifted by the given number of bits.</returns>
public static UInt128 LeftShift(UInt128 value, int numberOfBits)
{
numberOfBits %= 128;
if (numberOfBits >= 64)
return new UInt128(value._leastSignificant << (numberOfBits - 64), 0);
if (numberOfBits == 0)
return value;
return new UInt128((value._mostSignificant << numberOfBits) + (value._leastSignificant >> (64 - numberOfBits)) , value._leastSignificant << numberOfBits);
}
/// <summary>
/// Bitwise ands between two values.
/// </summary>
......
using System;
using System.Collections.Generic;
using System.Numerics;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace PcapDotNet.Packets.Test
......@@ -145,5 +146,17 @@ namespace PcapDotNet.Packets.Test
Assert.IsNotNull(buffer);
Assert.Fail();
}
[TestMethod]
public void ByteArrayUnsignedBigIntegerTest()
{
byte[] buffer = new byte[100];
for (BigInteger expectedValue = 1; expectedValue <= ushort.MaxValue; expectedValue *= 10)
{
buffer.WriteUnsigned(5, expectedValue, 2, Endianity.Big);
BigInteger actualValue = buffer.ReadUnsignedBigInteger(5, 2, Endianity.Big);
Assert.AreEqual(expectedValue, actualValue);
}
}
}
}
\ No newline at end of file
......@@ -5,6 +5,7 @@ using System.Text;
using PcapDotNet.Base;
using PcapDotNet.Packets.Dns;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.IpV6;
using PcapDotNet.TestUtils;
namespace PcapDotNet.Packets.TestUtils
......@@ -193,6 +194,15 @@ namespace PcapDotNet.Packets.TestUtils
return new DnsResourceDataCertificate(random.NextEnum<DnsCertificateType>(), random.NextUShort(), random.NextEnum<DnsAlgorithm>(),
random.NextDataSegment(random.Next(100)));
case DnsType.A6:
byte prefixLength = random.NextByte(DnsResourceDataA6.MaxPrefixLength + 1);
UInt128 addressSuffixValue = prefixLength == 0
? random.NextUInt128()
: random.NextUInt128(((UInt128)1) << (128 - prefixLength));
return new DnsResourceDataA6(prefixLength,
new IpV6Address(addressSuffixValue),
random.NextDnsDomainName());
default:
return new DnsResourceDataAnything(random.NextDataSegment(random.Next(100)));
}
......
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Numerics;
using System.Text;
using PcapDotNet.Base;
using PcapDotNet.Packets.Ethernet;
......@@ -333,36 +335,20 @@ namespace PcapDotNet.Packets
return value;
}
/*
/// <summary>
/// Reads 8 bytes from a specific offset as an int with a given endianity.
/// </summary>
/// <param name="buffer">The buffer to read the bytes from.</param>
/// <param name="offset">The offset in the buffer to start reading.</param>
/// <param name="endianity">The endianity to use to translate the bytes to the value.</param>
/// <returns>The value converted from the read bytes according to the endianity.</returns>
// public static long ReadLong(this byte[] buffer, int offset, Endianity endianity)
// {
// long value = ReadLong(buffer, offset);
// if (IsWrongEndianity(endianity))
// value = IPAddress.HostToNetworkOrder(value);
// return value;
// }
*/
public static BigInteger ReadUnsignedBigInteger(this byte[] buffer, int offset, int length, Endianity endianity)
{
BigInteger value = BigInteger.Zero;
for (int i = 0; i != length; ++i)
{
value <<= 8;
if (endianity == Endianity.Big)
value += buffer[offset + i];
else
value += buffer[offset + length - i - 1];
}
return value;
}
/*
/// <summary>
/// Reads 8 bytes from a specific offset as a ulong with a given endianity.
/// </summary>
/// <param name="buffer">The buffer to read the bytes from.</param>
/// <param name="offset">The offset in the buffer to start reading.</param>
/// <param name="endianity">The endianity to use to translate the bytes to the value.</param>
/// <returns>The value converted from the read bytes according to the endianity.</returns>
// public static ulong ReadULong(this byte[] buffer, int offset, Endianity endianity)
// {
// return (ulong)ReadLong(buffer, offset, endianity);
// }
*/
/// <summary>
/// Reads 6 bytes from a specific offset as a MacAddress with a given endianity.
/// </summary>
......@@ -649,6 +635,20 @@ namespace PcapDotNet.Packets
Write(buffer, offset, value);
}
public static void WriteUnsigned(this byte[] buffer, int offset, BigInteger value, int length, Endianity endianity)
{
if (value.Sign < 0)
throw new ArgumentOutOfRangeException("value", value, "Must be non-negative.");
for (int i = 0; i != length && value != BigInteger.Zero; ++i, value >>= 8)
{
byte byteValue = (byte)(value & 0xFF);
if (endianity == Endianity.Small)
buffer[offset + i] = byteValue;
else
buffer[offset + length - i - 1] = byteValue;
}
}
/// <summary>
/// Writes a string to a byte array in a specific offset using the given encoding.
/// Increments the offset by the number of bytes written.
......
......@@ -2,6 +2,8 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Text;
using PcapDotNet.Base;
using PcapDotNet.Packets.Ethernet;
......@@ -163,7 +165,7 @@ namespace PcapDotNet.Packets
/// <param name="offset">The offset in the segment to start reading.</param>
/// <param name="length">The number of bytes to read.</param>
/// <returns>The bytes read from the segment starting from the given offset and in the given length.</returns>
protected byte[] ReadBytes(int offset, int length)
internal byte[] ReadBytes(int offset, int length)
{
return Buffer.ReadBytes(StartOffset + offset, length);
}
......@@ -232,6 +234,11 @@ namespace PcapDotNet.Packets
return Buffer.ReadUInt48(StartOffset + offset, endianity);
}
internal BigInteger ReadUnsignedBigInteger(int offset, int length, Endianity endianity)
{
return Buffer.ReadUnsignedBigInteger(StartOffset + offset, length, endianity);
}
/// <summary>
/// Reads 6 bytes from a specific offset in the segment as a MacAddress with a given endianity.
/// </summary>
......
......@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Numerics;
using System.Reflection;
using System.Text;
using PcapDotNet.Base;
......@@ -2459,7 +2460,7 @@ namespace PcapDotNet.Packets.Dns
/// </pre>
/// </summary>
[DnsTypeRegistration(Type = DnsType.Srv)]
public sealed class DnsResourceDataServerSelection : DnsResourceData, IEquatable<DnsResourceDataServerSelection>
public sealed class DnsResourceDataServerSelection : DnsResourceDataNoCompression, IEquatable<DnsResourceDataServerSelection>
{
private static class Offset
{
......@@ -2541,19 +2542,13 @@ namespace PcapDotNet.Packets.Dns
return Equals(other as DnsResourceDataServerSelection);
}
internal override int GetLength(DnsDomainNameCompressionData compressionData, int offsetInDns)
{
return GetLength();
}
private int GetLength()
internal override int GetLength()
{
return ConstantPartLength + Target.NonCompressedLength;
}
internal override int WriteData(byte[] buffer, int dnsOffset, int offsetInDns, DnsDomainNameCompressionData compressionData)
internal override int WriteData(byte[] buffer, int offset)
{
int offset = dnsOffset + offsetInDns;
buffer.Write(offset + Offset.Priority, Priority, Endianity.Big);
buffer.Write(offset + Offset.Weight, Weight, Endianity.Big);
buffer.Write(offset + Offset.Port, Port, Endianity.Big);
......@@ -2701,7 +2696,7 @@ namespace PcapDotNet.Packets.Dns
/// +-----+--------------------+
/// </summary>
[DnsTypeRegistration(Type = DnsType.NaPtr)]
public sealed class DnsResourceDataNamingAuthorityPointer : DnsResourceData, IEquatable<DnsResourceDataNamingAuthorityPointer>
public sealed class DnsResourceDataNamingAuthorityPointer : DnsResourceDataNoCompression, IEquatable<DnsResourceDataNamingAuthorityPointer>
{
private static class Offset
{
......@@ -2813,19 +2808,13 @@ namespace PcapDotNet.Packets.Dns
return Equals(other as DnsResourceDataNamingAuthorityPointer);
}
internal override int GetLength(DnsDomainNameCompressionData compressionData, int offsetInDns)
{
return GetLength();
}
private int GetLength()
internal override int GetLength()
{
return ConstantPartLength + GetStringLength(Flags) + GetStringLength(Services) + GetStringLength(Regexp) + Replacement.NonCompressedLength;
}
internal override int WriteData(byte[] buffer, int dnsOffset, int offsetInDns, DnsDomainNameCompressionData compressionData)
internal override int WriteData(byte[] buffer, int offset)
{
int offset = dnsOffset + offsetInDns;
buffer.Write(offset + Offset.Order, Order, Endianity.Big);
buffer.Write(offset + Offset.Preference, Preference, Endianity.Big);
offset += Offset.Flags;
......@@ -3015,6 +3004,7 @@ namespace PcapDotNet.Packets.Dns
}
/// <summary>
/// RFC 4398.
/// <pre>
/// +-----+-----------+------+------------+
/// | bit | 0-7 | 8-15 | 16-31 |
......@@ -3119,4 +3109,122 @@ namespace PcapDotNet.Packets.Dns
return new DnsResourceDataCertificate(type, keyTag, algorithm, certificate);
}
}
/// <summary>
/// RFC 2874.
/// <pre>
/// +-------------+----------------+-----------------+
/// | Prefix len. | Address suffix | Prefix name |
/// | (1 octet) | (0..16 octets) | (0..255 octets) |
/// +-------------+----------------+-----------------+
/// </pre>
/// </summary>
[DnsTypeRegistration(Type = DnsType.A6)]
public sealed class DnsResourceDataA6 : DnsResourceDataNoCompression, IEquatable<DnsResourceDataA6>
{
public const byte MaxPrefixLength = 8 * IpV6Address.SizeOf;
private static class Offset
{
public const int PrefixLength = 0;
public const int AddressSuffix = PrefixLength + sizeof(byte);
}
public const int ConstantPartLength = Offset.AddressSuffix;
public DnsResourceDataA6()
: this(0, IpV6Address.Zero, DnsDomainName.Root)
{
}
public DnsResourceDataA6(byte prefixLength, IpV6Address addressSuffix, DnsDomainName prefixName)
{
PrefixLength = prefixLength;
AddressSuffix = addressSuffix;
PrefixName = prefixName;
}
/// <summary>
/// Encoded as an eight-bit unsigned integer with value between 0 and 128 inclusive.
/// </summary>
public byte PrefixLength { get; private set; }
/// <summary>
/// An IPv6 address suffix, encoded in network order (high-order octet first).
/// There must be exactly enough octets in this field to contain a number of bits equal to 128 minus prefix length, with 0 to 7 leading pad bits to make this field an integral number of octets.
/// Pad bits, if present, must be set to zero when loading a zone file and ignored (other than for SIG verification) on reception.
/// </summary>
public IpV6Address AddressSuffix { get; private set; }
/// <summary>
/// The number of bytes the address suffix takes.
/// </summary>
public int AddressSuffixLength { get { return CalculateAddressSuffixLength(PrefixLength); } }
/// <summary>
/// The name of the prefix, encoded as a domain name.
/// This name must not be compressed.
/// </summary>
public DnsDomainName PrefixName { get; private set; }
public bool Equals(DnsResourceDataA6 other)
{
return other != null &&
PrefixLength.Equals(other.PrefixLength) &&
AddressSuffix.Equals(other.AddressSuffix) &&
PrefixName.Equals(other.PrefixName);
}
public override bool Equals(DnsResourceData other)
{
return Equals(other as DnsResourceDataA6);
}
internal override int GetLength()
{
return ConstantPartLength + AddressSuffixLength + PrefixName.NonCompressedLength;
}
internal override int WriteData(byte[] buffer, int offset)
{
buffer.Write(offset + Offset.PrefixLength, PrefixLength);
buffer.WriteUnsigned(offset + Offset.AddressSuffix, AddressSuffix.ToValue(), AddressSuffixLength, Endianity.Big);
PrefixName.WriteUncompressed(buffer, offset + ConstantPartLength + AddressSuffixLength);
return GetLength();
}
internal override DnsResourceData CreateInstance(DnsDatagram dns, int offsetInDns, int length)
{
if (length < ConstantPartLength)
return null;
byte prefixLength = dns[offsetInDns + Offset.PrefixLength];
if (prefixLength > MaxPrefixLength)
return null;
offsetInDns += ConstantPartLength;
length -= ConstantPartLength;
int addressSuffixLength = CalculateAddressSuffixLength(prefixLength);
if (length < addressSuffixLength)
return null;
IpV6Address addressSuffix = new IpV6Address((UInt128)dns.ReadUnsignedBigInteger(offsetInDns, addressSuffixLength, Endianity.Big));
offsetInDns += addressSuffixLength;
length -= addressSuffixLength;
DnsDomainName prefixName;
int prefixNameLength;
if (!DnsDomainName.TryParse(dns, offsetInDns, length, out prefixName, out prefixNameLength))
return null;
if (prefixNameLength != length)
return null;
return new DnsResourceDataA6(prefixLength, addressSuffix, prefixName);
}
private static int CalculateAddressSuffixLength(byte prefixLength)
{
return (MaxPrefixLength - prefixLength + 7) / 8;
}
}
}
......@@ -271,6 +271,7 @@
/// <summary>
/// RFCs 2874, 3226.
/// A6 (Experimental).
/// Payload type: DnsResourceDataA6.
/// </summary>
A6 = 38,
......
......@@ -62,6 +62,7 @@
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
......
......@@ -106,6 +106,13 @@ namespace PcapDotNet.TestUtils
return new UInt128(random.NextULong(), random.NextULong());
}
public static UInt128 NextUInt128(this Random random, UInt128 maximumValue)
{
if (maximumValue <= (UInt128)ulong.MaxValue)
return random.NextULong((ulong)maximumValue);
return new UInt128(random.NextULong((ulong)(maximumValue >> 64)), random.NextULong());
}
public static DateTime NextDateTime(this Random random, DateTime minimumValue, DateTime maximumValue)
{
return new DateTime(random.NextLong(minimumValue.ToUniversalTime().Ticks,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment