Commit 64ffbb1d authored by Brickner_cp's avatar Brickner_cp

DNS.

Separate RandomPacketExtension to different classes by protocol.
parent 066e0511
...@@ -66,14 +66,19 @@ namespace PcapDotNet.Packets.Test ...@@ -66,14 +66,19 @@ namespace PcapDotNet.Packets.Test
for (int i = 0; i != 1000; ++i) for (int i = 0; i != 1000; ++i)
{ {
DnsLayer dnsLayer = random.NextDnsLayer(); DnsLayer dnsLayer;
do
{
dnsLayer = random.NextDnsLayer();
} while (dnsLayer.Length > 65000);
Packet packet = PacketBuilder.Build(DateTime.Now, ethernetLayer, ipV4Layer, udpLayer, dnsLayer); Packet packet = PacketBuilder.Build(DateTime.Now, ethernetLayer, ipV4Layer, udpLayer, dnsLayer);
Assert.IsTrue(packet.IsValid, "IsValid"); Assert.IsTrue(packet.IsValid, "IsValid");
// DNS // DNS
Assert.AreEqual(dnsLayer, packet.Ethernet.IpV4.Udp.Dns.ExtractLayer(), "DNS Layer"); DnsLayer actualLayer = (DnsLayer)packet.Ethernet.IpV4.Udp.Dns.ExtractLayer();
Assert.AreEqual(dnsLayer, actualLayer, "DNS Layer");
} }
} }
...@@ -92,31 +97,53 @@ namespace PcapDotNet.Packets.Test ...@@ -92,31 +97,53 @@ namespace PcapDotNet.Packets.Test
dnsLayer.Queries.Add(new DnsQueryResourceRecord(new DnsDomainName(""), DnsType.All, DnsClass.In)); dnsLayer.Queries.Add(new DnsQueryResourceRecord(new DnsDomainName(""), DnsType.All, DnsClass.In));
TestDomainNameCompression(0, dnsLayer); TestDomainNameCompression(0, dnsLayer);
dnsLayer.Answers.Add(new DnsDataResourceRecord(new DnsDomainName(""), DnsType.All, DnsClass.In, 100, new DnsResourceDataUnknown(new DataSegment(new byte[0])))); dnsLayer.Answers.Add(new DnsDataResourceRecord(new DnsDomainName(""), DnsType.All, DnsClass.In, 100, new DnsResourceDataAnything(DataSegment.Empty)));
TestDomainNameCompression(0, dnsLayer); TestDomainNameCompression(0, dnsLayer);
dnsLayer.Answers.Add(new DnsDataResourceRecord(new DnsDomainName("abc"), DnsType.All, DnsClass.In, 100, new DnsResourceDataUnknown(new DataSegment(new byte[0])))); dnsLayer.Answers.Add(new DnsDataResourceRecord(new DnsDomainName("abc"), DnsType.All, DnsClass.In, 100, new DnsResourceDataAnything(DataSegment.Empty)));
TestDomainNameCompression(0, dnsLayer); TestDomainNameCompression(0, dnsLayer);
dnsLayer.Answers.Add(new DnsDataResourceRecord(new DnsDomainName("abc"), DnsType.All, DnsClass.In, 100, new DnsResourceDataUnknown(new DataSegment(new byte[0])))); dnsLayer.Answers.Add(new DnsDataResourceRecord(new DnsDomainName("abc"), DnsType.All, DnsClass.In, 100, new DnsResourceDataAnything(DataSegment.Empty)));
TestDomainNameCompression(3, dnsLayer); TestDomainNameCompression(3, dnsLayer);
dnsLayer.Answers.Add(new DnsDataResourceRecord(new DnsDomainName("def.abc"), DnsType.All, DnsClass.In, 100, new DnsResourceDataUnknown(new DataSegment(new byte[0])))); dnsLayer.Answers.Add(new DnsDataResourceRecord(new DnsDomainName("def.abc"), DnsType.All, DnsClass.In, 100, new DnsResourceDataAnything(DataSegment.Empty)));
TestDomainNameCompression(6, dnsLayer); TestDomainNameCompression(6, dnsLayer);
dnsLayer.Answers.Add(new DnsDataResourceRecord(new DnsDomainName("abc.def"), DnsType.All, DnsClass.In, 100, new DnsResourceDataUnknown(new DataSegment(new byte[0])))); dnsLayer.Answers.Add(new DnsDataResourceRecord(new DnsDomainName("abc.def"), DnsType.All, DnsClass.In, 100, new DnsResourceDataAnything(DataSegment.Empty)));
TestDomainNameCompression(6, dnsLayer); TestDomainNameCompression(6, dnsLayer);
dnsLayer.Authorities.Add(new DnsDataResourceRecord(new DnsDomainName("abc.def"), DnsType.All, DnsClass.In, 100, new DnsResourceDataUnknown(new DataSegment(new byte[0])))); dnsLayer.Authorities.Add(new DnsDataResourceRecord(new DnsDomainName("abc.def"), DnsType.All, DnsClass.In, 100, new DnsResourceDataAnything(DataSegment.Empty)));
TestDomainNameCompression(13, dnsLayer); TestDomainNameCompression(13, dnsLayer);
dnsLayer.Authorities.Add(new DnsDataResourceRecord(new DnsDomainName("abd.def"), DnsType.All, DnsClass.In, 100, new DnsResourceDataUnknown(new DataSegment(new byte[0])))); dnsLayer.Authorities.Add(new DnsDataResourceRecord(new DnsDomainName("abd.def"), DnsType.All, DnsClass.In, 100, new DnsResourceDataAnything(DataSegment.Empty)));
TestDomainNameCompression(16, dnsLayer); TestDomainNameCompression(16, dnsLayer);
dnsLayer.Additionals.Add(new DnsDataResourceRecord(new DnsDomainName("hello.abd.def"), DnsType.All, DnsClass.In, 100, new DnsResourceDataUnknown(new DataSegment(new byte[0])))); dnsLayer.Additionals.Add(new DnsDataResourceRecord(new DnsDomainName("hello.abd.def"), DnsType.All, DnsClass.In, 100, new DnsResourceDataAnything(DataSegment.Empty)));
TestDomainNameCompression(23, dnsLayer); TestDomainNameCompression(23, dnsLayer);
} }
[TestMethod]
public void DnsDomainNameCompressionTooLongTest()
{
DnsLayer dnsLayer = new DnsLayer();
TestDomainNameCompression(0, dnsLayer);
dnsLayer.Queries = new List<DnsQueryResourceRecord>();
dnsLayer.Answers = new List<DnsDataResourceRecord>();
dnsLayer.Authorities = new List<DnsDataResourceRecord>();
dnsLayer.Additionals = new List<DnsDataResourceRecord>();
TestDomainNameCompression(0, dnsLayer);
dnsLayer.Answers.Add(new DnsDataResourceRecord(new DnsDomainName("aaa"), DnsType.Null, DnsClass.In, 100, new DnsResourceDataAnything(new DataSegment(new byte[20000]))));
TestDomainNameCompression(0, dnsLayer);
dnsLayer.Answers.Add(new DnsDataResourceRecord(new DnsDomainName("bbb.aaa"), DnsType.Null, DnsClass.In, 100, new DnsResourceDataAnything(new DataSegment(new byte[1]))));
TestDomainNameCompression(3, dnsLayer);
dnsLayer.Answers.Add(new DnsDataResourceRecord(new DnsDomainName("bbb.aaa"), DnsType.Null, DnsClass.In, 100, new DnsResourceDataAnything(new DataSegment(new byte[1]))));
TestDomainNameCompression(6, dnsLayer);
}
[TestMethod] [TestMethod]
public void SimpleDnsTest() public void SimpleDnsTest()
{ {
......
...@@ -73,8 +73,19 @@ ...@@ -73,8 +73,19 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="HexEncoding.cs" /> <Compile Include="HexEncoding.cs" />
<Compile Include="RandomArpExtensions.cs" />
<Compile Include="RandomDnsExtensions.cs" />
<Compile Include="RandomEthernetExtensions.cs" />
<Compile Include="RandomGreExtensions.cs" />
<Compile Include="RandomHttpExtensions.cs" />
<Compile Include="RandomIcmpExtensions.cs" />
<Compile Include="RandomIgmpExtensions.cs" />
<Compile Include="RandomIpV4Extensions.cs" />
<Compile Include="RandomIpV6Extensions.cs" />
<Compile Include="RandomPacketsExtensions.cs" /> <Compile Include="RandomPacketsExtensions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RandomTcpExtensions.cs" />
<Compile Include="RandomUdpExtensions.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\PcapDotNet.Base\PcapDotNet.Base.csproj"> <ProjectReference Include="..\PcapDotNet.Base\PcapDotNet.Base.csproj">
......
using System;
using PcapDotNet.Base;
using PcapDotNet.Packets.Arp;
using PcapDotNet.Packets.Ethernet;
using PcapDotNet.TestUtils;
namespace PcapDotNet.Packets.TestUtils
{
public static class RandomArpExtensions
{
public static ArpLayer NextArpLayer(this Random random)
{
byte hardwareAddressLength = random.NextByte();
byte protocolAddressLength = random.NextByte();
return new ArpLayer
{
SenderHardwareAddress = random.NextBytes(hardwareAddressLength).AsReadOnly(),
SenderProtocolAddress = random.NextBytes(protocolAddressLength).AsReadOnly(),
TargetHardwareAddress = random.NextBytes(hardwareAddressLength).AsReadOnly(),
TargetProtocolAddress = random.NextBytes(protocolAddressLength).AsReadOnly(),
ProtocolType = random.NextEnum<EthernetType>(),
Operation = random.NextEnum<ArpOperation>(),
};
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Text;
using PcapDotNet.Base;
using PcapDotNet.Packets.Dns;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.TestUtils;
namespace PcapDotNet.Packets.TestUtils
{
public static class RandomDnsExtensions
{
public static DnsLayer NextDnsLayer(this Random random)
{
DnsLayer dnsLayer = new DnsLayer();
dnsLayer.Id = random.NextUShort();
dnsLayer.IsQuery = random.NextBool();
dnsLayer.Opcode = random.NextEnum<DnsOpcode>();
dnsLayer.IsAuthoritiveAnswer = random.NextBool();
dnsLayer.IsTruncated = random.NextBool();
dnsLayer.IsRecusionDesired = random.NextBool();
dnsLayer.IsRecusionAvailable = random.NextBool();
dnsLayer.FutureUse = random.NextByte(DnsDatagram.MaxFutureUse + 1);
dnsLayer.ResponseCode = random.NextEnum<DnsResponseCode>();
dnsLayer.DomainNameCompressionMode = random.NextEnum<DnsDomainNameCompressionMode>();
int numQueries = random.Next(10);
List<DnsQueryResourceRecord> queries = new List<DnsQueryResourceRecord>();
for (int i = 0; i != numQueries; ++i)
queries.Add(random.NextDnsQueryResourceRecord());
dnsLayer.Queries = queries;
int numAnswers = random.Next(10);
List<DnsDataResourceRecord> answers = new List<DnsDataResourceRecord>();
for (int i = 0; i != numAnswers; ++i)
answers.Add(random.NextDnsDataResourceRecord());
dnsLayer.Answers = answers;
int numAuthorities = random.Next(10);
List<DnsDataResourceRecord> authorities = new List<DnsDataResourceRecord>();
for (int i = 0; i != numAuthorities; ++i)
authorities.Add(random.NextDnsDataResourceRecord());
dnsLayer.Authorities = authorities;
int numAdditionals = random.Next(10);
List<DnsDataResourceRecord> additionals = new List<DnsDataResourceRecord>();
for (int i = 0; i != numAdditionals; ++i)
additionals.Add(random.NextDnsDataResourceRecord());
dnsLayer.Additionals = additionals;
return dnsLayer;
}
public static DnsQueryResourceRecord NextDnsQueryResourceRecord(this Random random)
{
DnsQueryResourceRecord record = new DnsQueryResourceRecord(random.NextDnsDomainName(), random.NextEnum<DnsType>(), random.NextEnum<DnsClass>());
return record;
}
public static DnsDataResourceRecord NextDnsDataResourceRecord(this Random random)
{
DnsType type = random.NextEnum<DnsType>();
DnsDataResourceRecord record = new DnsDataResourceRecord(random.NextDnsDomainName(), type, random.NextEnum<DnsClass>(), random.Next(), random.NextDnsResourceData(type));
return record;
}
public static DnsDomainName NextDnsDomainName(this Random random)
{
List<string> labels = new List<string>();
int numLabels = random.Next(10);
for (int i = 0; i != numLabels; ++i)
{
int labelLength = random.Next(10);
StringBuilder label = new StringBuilder();
for (int j = 0; j != labelLength; ++j)
label.Append(random.NextChar('a', 'z'));
labels.Add(label.ToString());
}
return new DnsDomainName(string.Join(".", labels));
}
public static DnsResourceData NextDnsResourceData(this Random random, DnsType type)
{
switch (type)
{
case DnsType.A:
return new DnsResourceDataIpV4(random.NextIpV4Address());
case DnsType.Ns:
case DnsType.Md:
case DnsType.Mf:
case DnsType.CName:
case DnsType.Mb:
case DnsType.Mg:
case DnsType.Mr:
case DnsType.Ptr:
return new DnsResourceDataDomainName(random.NextDnsDomainName());
case DnsType.Soa:
return new DnsResourceDataStartOfAuthority(random.NextDnsDomainName(), random.NextDnsDomainName(),
random.NextUInt(), random.NextUInt(), random.NextUInt(), random.NextUInt(), random.NextUInt());
case DnsType.Null:
return new DnsResourceDataAnything(random.NextDataSegment(random.Next(65536)));
case DnsType.Wks:
return new DnsResourceDataWellKnownService(random.NextIpV4Address(), random.NextEnum<IpV4Protocol>(),
random.NextDataSegment(random.Next(10)));
case DnsType.HInfo:
return new DnsResourceDataHostInformation(random.NextDataSegment(random.Next(10)), random.NextDataSegment(random.Next(10)));
case DnsType.MInfo:
return new DnsResourceDataMailingListInfo(random.NextDnsDomainName(), random.NextDnsDomainName());
case DnsType.Mx:
return new DnsResourceDataMailExchange(random.NextUShort(), random.NextDnsDomainName());
case DnsType.Txt:
return new DnsResourceDataText(((Func<DataSegment>)(() => random.NextDataSegment(random.Next(10)))).GenerateArray(10).AsReadOnly());
case DnsType.Rp:
return new DnsResourceDataResponsiblePerson(random.NextDnsDomainName(), random.NextDnsDomainName());
case DnsType.AfsDb:
return new DnsResourceDataAfsDb(random.NextUShort(), random.NextDnsDomainName());
default:
return new DnsResourceDataAnything(random.NextDataSegment(random.Next(100)));
}
}
}
}
using System;
using PcapDotNet.Packets.Ethernet;
using PcapDotNet.TestUtils;
namespace PcapDotNet.Packets.TestUtils
{
public static class RandomEthernetExtensions
{
public static EthernetLayer NextEthernetLayer(this Random random, EthernetType etherType)
{
return new EthernetLayer
{
Source = random.NextMacAddress(),
Destination = random.NextMacAddress(),
EtherType = etherType
};
}
public static EthernetLayer NextEthernetLayer(this Random random)
{
return random.NextEthernetLayer(random.NextEnum(EthernetType.None));
}
public static MacAddress NextMacAddress(this Random random)
{
return new MacAddress(random.NextUInt48());
}
public static EthernetType NextEthernetType(this Random random)
{
return random.NextEnum(EthernetType.None);
}
public static Packet NextEthernetPacket(this Random random, int packetSize, DateTime timestamp, MacAddress ethernetSource, MacAddress ethernetDestination)
{
if (packetSize < EthernetDatagram.HeaderLength)
throw new ArgumentOutOfRangeException("packetSize", packetSize, "Must be at least the ethernet header length (" + EthernetDatagram.HeaderLength + ")");
return PacketBuilder.Build(timestamp,
new EthernetLayer
{
Source = ethernetSource,
Destination = ethernetDestination,
EtherType = random.NextEthernetType()
},
random.NextPayloadLayer(packetSize - EthernetDatagram.HeaderLength));
}
public static Packet NextEthernetPacket(this Random random, int packetSize, DateTime timestamp, string ethernetSource, string ethernetDestination)
{
return random.NextEthernetPacket(packetSize, timestamp, new MacAddress(ethernetSource), new MacAddress(ethernetDestination));
}
public static Packet NextEthernetPacket(this Random random, int packetSize, MacAddress ethernetSource, MacAddress ethernetDestination)
{
return random.NextEthernetPacket(packetSize, DateTime.Now, ethernetSource, ethernetDestination);
}
public static Packet NextEthernetPacket(this Random random, int packetSize, string ethernetSource, string ethernetDestination)
{
return random.NextEthernetPacket(packetSize, DateTime.Now, ethernetSource, ethernetDestination);
}
public static Packet NextEthernetPacket(this Random random, int packetSize)
{
return random.NextEthernetPacket(packetSize, DateTime.Now, random.NextMacAddress(), random.NextMacAddress());
}
}
}
\ No newline at end of file
using System;
using System.Linq;
using PcapDotNet.Base;
using PcapDotNet.Packets.Ethernet;
using PcapDotNet.Packets.Gre;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.TestUtils;
namespace PcapDotNet.Packets.TestUtils
{
public static class RandomGreExtensions
{
public static GreLayer NextGreLayer(this Random random)
{
GreVersion version = random.NextEnum<GreVersion>();
bool isChecksum = random.NextBool();
GreSourceRouteEntry[] routing = null;
ushort? routingOffset = null;
bool strictSourceRoute = false;
EthernetType protocolType = random.NextEnum(EthernetType.None);
uint? key = random.NextBool() ? (uint?)random.NextUInt() : null;
if (version == GreVersion.Gre)
{
if (random.NextBool())
{
strictSourceRoute = random.NextBool();
routing = new GreSourceRouteEntry[random.Next(5)];
GreSourceRouteEntryAddressFamily family;
if (random.NextBool())
family = random.NextEnum(GreSourceRouteEntryAddressFamily.None);
else
family = (GreSourceRouteEntryAddressFamily)random.NextUShort();
for (int i = 0; i != routing.Length; ++i)
{
switch (family)
{
case GreSourceRouteEntryAddressFamily.AsSourceRoute:
{
ushort[] asNumbers = new ushort[random.Next(1, 5)];
for (int j = 0; j != asNumbers.Length; ++j)
asNumbers[j] = random.NextUShort();
routing[i] = new GreSourceRouteEntryAs(asNumbers.AsReadOnly(), random.Next(asNumbers.Length + 1));
break;
}
case GreSourceRouteEntryAddressFamily.IpSourceRoute:
{
IpV4Address[] ips = new IpV4Address[random.Next(1, 5)];
for (int j = 0; j != ips.Length; ++j)
ips[j] = random.NextIpV4Address();
routing[i] = new GreSourceRouteEntryIp(ips.AsReadOnly(), random.Next(ips.Length + 1));
break;
}
default:
{
int dataLength = random.Next(1, 100);
routing[i] = new GreSourceRouteEntryUnknown(family, random.NextDatagram(dataLength), random.Next(dataLength + 1));
break;
}
}
}
routingOffset = 0;
if (routing.Any())
{
int routingIndex = random.Next(routing.Length);
for (int i = 0; i != routingIndex; ++i)
routingOffset += (ushort)routing[i].Length;
}
}
}
else
{
protocolType = EthernetType.PointToPointProtocol;
isChecksum = false;
key = random.NextUInt();
}
return new GreLayer
{
Version = version,
ProtocolType = protocolType,
ChecksumPresent = isChecksum,
Checksum = isChecksum && random.NextBool() ? (ushort?)random.NextUShort() : null,
Key = key,
SequenceNumber = random.NextBool() ? (uint?)random.NextUInt() : null,
AcknowledgmentSequenceNumber = version == GreVersion.EnhancedGre && random.NextBool() ? (uint?)random.NextUInt() : null,
RecursionControl = random.NextByte(8),
// Flags = random.NextByte(32),
Routing = routing == null ? null : routing.AsReadOnly(),
RoutingOffset = routingOffset,
StrictSourceRoute = strictSourceRoute,
};
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PcapDotNet.Base;
using PcapDotNet.Packets.Http;
using PcapDotNet.TestUtils;
namespace PcapDotNet.Packets.TestUtils
{
public static class RandomHttpExtensions
{
public static HttpLayer NextHttpLayer(this Random random)
{
if (random.NextBool())
{
HttpRequestLayer httpRequestLayer = new HttpRequestLayer();
if (random.NextBool(10))
{
httpRequestLayer.Method = random.NextHttpRequestMethod();
httpRequestLayer.Uri = httpRequestLayer.Method == null ? null : random.NextHttpUri();
httpRequestLayer.Version = httpRequestLayer.Uri == null || random.NextBool(10) ? null : random.NextHttpVersion();
httpRequestLayer.Header = httpRequestLayer.Version == null ? null : random.NextHttpHeader();
httpRequestLayer.Body = httpRequestLayer.Header == null ? null : random.NextHttpBody(true, null, httpRequestLayer.Header);
}
return httpRequestLayer;
}
HttpResponseLayer httpResponseLayer = new HttpResponseLayer
{
Version = random.NextHttpVersion(),
StatusCode = random.NextBool(10) ? null : (uint?)random.NextUInt(100, 999),
};
httpResponseLayer.ReasonPhrase = httpResponseLayer.StatusCode == null ? null : random.NextHttpReasonPhrase();
httpResponseLayer.Header = httpResponseLayer.ReasonPhrase == null ? null : random.NextHttpHeader();
httpResponseLayer.Body = httpResponseLayer.Header == null ? null : random.NextHttpBody(false , httpResponseLayer.StatusCode, httpResponseLayer.Header);
return httpResponseLayer;
}
public static Datagram NextHttpReasonPhrase(this Random random)
{
int reasonPhraseLength = random.Next(100);
StringBuilder reasonPhrase = new StringBuilder(reasonPhraseLength);
for (int i = 0; i != reasonPhraseLength; ++i)
{
if (random.NextBool())
reasonPhrase.Append(random.NextHttpTextChar());
else if (random.NextBool())
reasonPhrase.Append(' ');
else
reasonPhrase.Append('\t');
}
return new Datagram(EncodingExtensions.Iso88591.GetBytes(reasonPhrase.ToString()));
}
public static HttpRequestMethod NextHttpRequestMethod(this Random random)
{
HttpRequestKnownMethod knownMethod = random.NextEnum<HttpRequestKnownMethod>();
if (knownMethod == HttpRequestKnownMethod.Unknown)
return new HttpRequestMethod(random.NextHttpToken());
return new HttpRequestMethod(knownMethod);
}
public static string NextHttpToken(this Random random)
{
int tokenLength = random.Next(1, 100);
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i != tokenLength; ++i)
stringBuilder.Append(random.NextHttpTokenChar());
return stringBuilder.ToString();
}
public static char NextHttpTokenChar(this Random random)
{
char result;
do
{
result = random.NextChar((char)33, (char)127);
} while (new[] {'(', ')', '<', '>', '@', ',', ';', ':', '\\', '"', '/', '[', ']', '?', '=', '{', '}'}.Contains(result));
return result;
}
public static string NextHttpFieldValue(this Random random)
{
int valueLength = random.Next(1, 100);
StringBuilder stringBuilder = new StringBuilder();
while (stringBuilder.Length < valueLength)
{
switch (random.Next(3))
{
case 0:
stringBuilder.Append(random.NextHttpTextChar());
break;
case 1:
stringBuilder.Append(random.NextHttpQuotedString());
break;
case 2:
if (stringBuilder.Length > 0 && stringBuilder.Length < valueLength - 3)
stringBuilder.Append(random.NextHttpLinearWhiteSpace());
break;
}
}
return stringBuilder.ToString();
}
public static string NextHttpLinearWhiteSpace(this Random random)
{
StringBuilder stringBuilder = new StringBuilder();
if (random.NextBool())
stringBuilder.Append("\r\n");
stringBuilder.Append(random.NextBool() ? ' ' : '\t');
return stringBuilder.ToString();
}
public static char NextHttpTextChar(this Random random)
{
char text = random.NextChar((char)33, (char)254);
if (text == '"')
return (char)254;
if (text == 127)
return (char)255;
return text;
}
public static string NextHttpUri(this Random random)
{
int uriLength = random.Next(100);
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i != uriLength; ++i)
stringBuilder.Append(random.NextChar((char)33, (char)127));
return stringBuilder.ToString();
}
public static HttpVersion NextHttpVersion(this Random random)
{
return new HttpVersion(random.NextUInt(10000000), random.NextUInt(10000000));
}
public static HttpHeader NextHttpHeader(this Random random)
{
int numFields = random.Next(100);
List<HttpField> fields = new List<HttpField>(numFields);
HashSet<string> fieldNames = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
for (int i = 0; i != numFields; ++i)
{
fields.Add(random.NextHttpField(fieldNames));
fieldNames.Add(fields.Last().Name);
}
return new HttpHeader(fields);
}
public static HttpField NextHttpField(this Random random, HashSet<string> fieldNames)
{
const string unknownField = "Unknown Name";
List<string> allOptions = new List<string> { unknownField, HttpTransferEncodingField.FieldNameUpper, HttpContentLengthField.FieldNameUpper, HttpContentTypeField.FieldNameUpper };
List<string> possibleOptions = new List<string>(allOptions.Count);
foreach (string option in allOptions)
{
if (!fieldNames.Contains(option))
possibleOptions.Add(option);
}
string chosenOption = random.NextValue(possibleOptions);
switch (chosenOption)
{
case unknownField:
string fieldName;
do
{
fieldName = random.NextHttpToken();
} while (fieldNames.Contains(fieldName));
return HttpField.CreateField(fieldName, random.NextHttpFieldValue());
case HttpTransferEncodingField.FieldNameUpper:
int numTransferCodings = random.Next(1, 10);
List<string> transferCodings = new List<string>(numTransferCodings);
for (int i = 0; i != numTransferCodings; ++i)
transferCodings.Add(random.NextHttpTransferCoding());
return new HttpTransferEncodingField(transferCodings);
case HttpContentLengthField.FieldNameUpper:
return new HttpContentLengthField(random.NextUInt(1000));
case HttpContentTypeField.FieldNameUpper:
return new HttpContentTypeField(random.NextHttpToken(), random.NextHttpToken(), random.NextHttpFieldParameters());
default:
throw new InvalidOperationException("Invalid option " + chosenOption);
}
}
public static HttpFieldParameters NextHttpFieldParameters(this Random random)
{
int numParameters = random.Next(10);
List<KeyValuePair<string, string>> parameters = new List<KeyValuePair<string, string>>(numParameters);
for (int i = 0; i != numParameters; ++i)
{
string parameterName = random.NextHttpToken();
while (parameters.Any(pair => pair.Key == parameterName))
parameterName = random.NextHttpToken();
parameters.Add(new KeyValuePair<string, string>(parameterName,
random.NextBool() ? random.NextHttpToken() : random.NextHttpQuotedString()));
}
return new HttpFieldParameters(parameters);
}
public static string NextHttpTransferCoding(this Random random)
{
if (random.NextBool())
return "chunked";
StringBuilder transferCoding = new StringBuilder(random.NextHttpToken());
int numParameters = random.Next(5);
for (int i = 0; i != numParameters; ++i)
{
transferCoding.Append(';');
transferCoding.Append(random.NextHttpToken());
transferCoding.Append('=');
if (random.NextBool())
transferCoding.Append(random.NextHttpToken());
else
transferCoding.Append(random.NextHttpQuotedString());
}
return transferCoding.ToString();
}
public static string NextHttpQuotedString(this Random random)
{
StringBuilder quotedString = new StringBuilder();
quotedString.Append('"');
int numQuotedValues = random.Next(100);
for (int i = 0; i != numQuotedValues; ++i)
{
char quotedValue = random.NextHttpTextChar();
if (quotedValue != '\\')
quotedString.Append(quotedValue);
else
{
quotedString.Append('\\');
quotedString.Append(random.NextChar((char)0, (char)128));
}
}
quotedString.Append('"');
return quotedString.ToString();
}
public static Datagram NextHttpBody(this Random random, bool isRequest, uint? statusCode, HttpHeader httpHeader)
{
if (isRequest && httpHeader.ContentLength == null ||
!isRequest && statusCode >= 100 && statusCode <= 199 || statusCode == 204 || statusCode == 205 || statusCode == 304)
return Datagram.Empty;
if (httpHeader.TransferEncoding != null &&
httpHeader.TransferEncoding.TransferCodings.Any(coding => coding != "identity"))
{
// chunked
List<byte> chunkedBody = new List<byte>();
int numChunks = random.Next(10);
for (int i = 0; i != numChunks; ++i)
{
int chunkSize = random.Next(1, 1000);
chunkedBody.AddRange(Encoding.ASCII.GetBytes(chunkSize.ToString("x")));
var chunkExtension = random.NextHttpFieldParameters();
foreach (var parameter in chunkExtension)
{
chunkedBody.Add((byte)';');
chunkedBody.AddRange(Encoding.ASCII.GetBytes(parameter.Key));
chunkedBody.Add((byte)'=');
chunkedBody.AddRange(EncodingExtensions.Iso88591.GetBytes(parameter.Key));
}
chunkedBody.AddRange(Encoding.ASCII.GetBytes("\r\n"));
chunkedBody.AddRange(random.NextDatagram(chunkSize));
chunkedBody.AddRange(Encoding.ASCII.GetBytes("\r\n"));
}
int numZeros = random.Next(1, 10);
for (int i = 0; i != numZeros; ++i)
chunkedBody.Add((byte)'0');
var lastChunkExtension = random.NextHttpFieldParameters();
foreach (var parameter in lastChunkExtension)
{
chunkedBody.Add((byte)';');
chunkedBody.AddRange(Encoding.ASCII.GetBytes(parameter.Key));
chunkedBody.Add((byte)'=');
chunkedBody.AddRange(EncodingExtensions.Iso88591.GetBytes(parameter.Key));
}
chunkedBody.AddRange(Encoding.ASCII.GetBytes("\r\n"));
var trailer = random.NextHttpHeader();
byte[] trailerBuffer = new byte[trailer.BytesLength];
trailer.Write(trailerBuffer, 0);
chunkedBody.AddRange(trailerBuffer);
return new Datagram(chunkedBody.ToArray());
}
if (httpHeader.ContentLength != null)
{
return random.NextDatagram(random.Next((int)(httpHeader.ContentLength.ContentLength + 1)));
}
if (httpHeader.ContentType != null &&
httpHeader.ContentType.MediaType == "multipart" &&
httpHeader.ContentType.MediaSubtype == "byteranges" &&
httpHeader.ContentType.Parameters["boundary"] != null)
{
List<byte> boundedBody = new List<byte>(random.NextDatagram(random.Next(1000)));
boundedBody.AddRange(EncodingExtensions.Iso88591.GetBytes("--" + httpHeader.ContentType.Parameters["boundary"] + "--"));
return new Datagram(boundedBody.ToArray());
}
return random.NextDatagram(random.Next(1000));
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using PcapDotNet.Packets.Icmp;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.TestUtils;
using IEnumerableExtensions = PcapDotNet.Base.IEnumerableExtensions;
namespace PcapDotNet.Packets.TestUtils
{
public static class RandomIcmpExtensions
{
public static IcmpLayer NextIcmpLayer(this Random random)
{
IcmpMessageType icmpMessageType = random.NextEnum(IcmpMessageType.DomainNameReply);
ushort? checksum = random.NextBool() ? (ushort?)random.NextUShort() : null;
switch (icmpMessageType)
{
case IcmpMessageType.DestinationUnreachable:
return new IcmpDestinationUnreachableLayer
{
Code = random.NextEnum<IcmpCodeDestinationUnreachable>(),
Checksum = checksum,
NextHopMaximumTransmissionUnit = random.NextUShort(),
};
case IcmpMessageType.TimeExceeded:
return new IcmpTimeExceededLayer
{
Code = random.NextEnum<IcmpCodeTimeExceeded>(),
Checksum = checksum,
};
case IcmpMessageType.ParameterProblem:
return new IcmpParameterProblemLayer
{
Checksum = checksum,
Pointer = random.NextByte()
};
case IcmpMessageType.SourceQuench:
return new IcmpSourceQuenchLayer
{
Checksum = checksum
};
case IcmpMessageType.Redirect:
return new IcmpRedirectLayer
{
Code = random.NextEnum<IcmpCodeRedirect>(),
Checksum = checksum,
GatewayInternetAddress = random.NextIpV4Address()
};
case IcmpMessageType.Echo:
return new IcmpEchoLayer
{
Checksum = checksum,
Identifier = random.NextUShort(),
SequenceNumber = random.NextUShort()
};
case IcmpMessageType.EchoReply:
return new IcmpEchoReplyLayer
{
Checksum = checksum,
Identifier = random.NextUShort(),
SequenceNumber = random.NextUShort()
};
case IcmpMessageType.Timestamp:
return new IcmpTimestampLayer
{
Checksum = checksum,
Identifier = random.NextUShort(),
SequenceNumber = random.NextUShort(),
OriginateTimestamp = random.NextIpV4TimeOfDay(),
ReceiveTimestamp = random.NextIpV4TimeOfDay(),
TransmitTimestamp = random.NextIpV4TimeOfDay()
};
case IcmpMessageType.TimestampReply:
return new IcmpTimestampReplyLayer
{
Checksum = checksum,
Identifier = random.NextUShort(),
SequenceNumber = random.NextUShort(),
OriginateTimestamp = random.NextIpV4TimeOfDay(),
ReceiveTimestamp = random.NextIpV4TimeOfDay(),
TransmitTimestamp = random.NextIpV4TimeOfDay()
};
case IcmpMessageType.InformationRequest:
return new IcmpInformationRequestLayer
{
Checksum = checksum,
Identifier = random.NextUShort(),
SequenceNumber = random.NextUShort(),
};
case IcmpMessageType.InformationReply:
return new IcmpInformationReplyLayer
{
Checksum = checksum,
Identifier = random.NextUShort(),
SequenceNumber = random.NextUShort(),
};
case IcmpMessageType.RouterAdvertisement:
return new IcmpRouterAdvertisementLayer
{
Entries = random.NextIcmpRouterAdvertisementEntries(random.Next(10)).ToList().AsReadOnly(),
Checksum = checksum,
Lifetime = random.NextTimeSpan(TimeSpan.Zero, TimeSpan.FromSeconds(ushort.MaxValue)),
};
case IcmpMessageType.RouterSolicitation:
return new IcmpRouterSolicitationLayer
{
Checksum = checksum,
};
case IcmpMessageType.AddressMaskRequest:
return new IcmpAddressMaskRequestLayer
{
Checksum = checksum,
Identifier = random.NextUShort(),
SequenceNumber = random.NextUShort(),
AddressMask = random.NextIpV4Address()
};
case IcmpMessageType.AddressMaskReply:
return new IcmpAddressMaskReplyLayer
{
Checksum = checksum,
Identifier = random.NextUShort(),
SequenceNumber = random.NextUShort(),
AddressMask = random.NextIpV4Address()
};
case IcmpMessageType.TraceRoute:
return new IcmpTraceRouteLayer
{
Code = random.NextEnum<IcmpCodeTraceRoute>(),
Checksum = checksum,
Identification = random.NextUShort(),
OutboundHopCount = random.NextUShort(),
ReturnHopCount = random.NextUShort(),
OutputLinkSpeed = random.NextUInt(),
OutputLinkMaximumTransmissionUnit = random.NextUInt(),
};
case IcmpMessageType.ConversionFailed:
return new IcmpConversionFailedLayer
{
Code = random.NextEnum<IcmpCodeConversionFailed>(),
Checksum = checksum,
Pointer = random.NextUInt(),
};
case IcmpMessageType.DomainNameRequest:
return new IcmpDomainNameRequestLayer
{
Checksum = checksum,
Identifier = random.NextUShort(),
SequenceNumber = random.NextUShort(),
};
case IcmpMessageType.DomainNameReply:
throw new NotSupportedException("Message Type " + icmpMessageType + " is not supported");
case IcmpMessageType.SecurityFailures:
return new IcmpSecurityFailuresLayer
{
Code = random.NextEnum<IcmpCodeSecurityFailure>(),
Checksum = checksum,
Pointer = random.NextUShort()
};
default:
throw new InvalidOperationException("Invalid icmpMessageType " + icmpMessageType);
}
}
public static IEnumerable<ILayer> NextIcmpPayloadLayers(this Random random, IcmpLayer icmpLayer)
{
IEnumerable<ILayer> icmpPayloadLayers = new List<ILayer>();
switch (icmpLayer.MessageType)
{
case IcmpMessageType.DestinationUnreachable:
case IcmpMessageType.TimeExceeded:
case IcmpMessageType.ParameterProblem:
case IcmpMessageType.SourceQuench:
case IcmpMessageType.Redirect:
case IcmpMessageType.SecurityFailures:
icmpPayloadLayers = IEnumerableExtensions.Concat(icmpPayloadLayers, random.NextIpV4Layer(), random.NextPayloadLayer(IcmpIpV4HeaderPlus64BitsPayloadDatagram.OriginalDatagramPayloadLength));
break;
case IcmpMessageType.ConversionFailed:
IpV4Layer icmpIpV4Layer = random.NextIpV4Layer();
icmpPayloadLayers = IEnumerableExtensions.Concat(icmpPayloadLayers, icmpIpV4Layer);
if (icmpLayer.MessageTypeAndCode == IcmpMessageTypeAndCode.ConversionFailedUnsupportedTransportProtocol)
{
icmpPayloadLayers =
IEnumerableExtensions.Concat(icmpPayloadLayers, random.NextPayloadLayer(
IcmpConversionFailedDatagram.OriginalDatagramLengthForUnsupportedTransportProtocol -
icmpIpV4Layer.Length));
}
else
{
switch (icmpIpV4Layer.Protocol)
{
case IpV4Protocol.Udp:
icmpPayloadLayers = IEnumerableExtensions.Concat(icmpPayloadLayers, random.NextUdpLayer(),
random.NextPayloadLayer(random.Next(100)));
break;
case IpV4Protocol.Tcp:
icmpPayloadLayers = IEnumerableExtensions.Concat(icmpPayloadLayers, random.NextTcpLayer(),
random.NextPayloadLayer(random.Next(100)));
break;
default:
icmpPayloadLayers = IEnumerableExtensions.Concat(icmpPayloadLayers, random.NextPayloadLayer(random.Next(200)));
break;
}
}
break;
case IcmpMessageType.Echo:
case IcmpMessageType.EchoReply:
case IcmpMessageType.Timestamp:
case IcmpMessageType.TimestampReply:
case IcmpMessageType.InformationRequest:
case IcmpMessageType.InformationReply:
case IcmpMessageType.RouterAdvertisement:
case IcmpMessageType.RouterSolicitation:
case IcmpMessageType.AddressMaskRequest:
case IcmpMessageType.AddressMaskReply:
case IcmpMessageType.TraceRoute:
case IcmpMessageType.DomainNameRequest:
break;
case IcmpMessageType.DomainNameReply:
default:
throw new InvalidOperationException("Invalid icmpMessageType " + icmpLayer.MessageType);
}
return icmpPayloadLayers;
}
public static IEnumerable<IcmpRouterAdvertisementEntry> NextIcmpRouterAdvertisementEntries(this Random random, int numEntries)
{
for (int i = 0; i != numEntries; ++i)
yield return new IcmpRouterAdvertisementEntry(random.NextIpV4Address(), random.Next());
}
}
}
\ No newline at end of file
using System;
using System.Linq;
using PcapDotNet.Base;
using PcapDotNet.Packets.Igmp;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.TestUtils;
namespace PcapDotNet.Packets.TestUtils
{
public static class RandomIgmpExtensions
{
public static IgmpGroupRecord NextIgmpGroupRecord(this Random random)
{
IpV4Address[] sourceAddresses = random.NextIpV4Addresses(random.Next(10));
return new IgmpGroupRecord(random.NextEnum<IgmpRecordType>(), random.NextIpV4Address(), sourceAddresses, random.NextDatagram(random.Next(10) * 4));
}
public static IgmpGroupRecord[] NextIgmpGroupRecords(this Random random, int count)
{
return ((Func<IgmpGroupRecord>)random.NextIgmpGroupRecord).GenerateArray(count);
}
public static IgmpLayer NextIgmpLayer(this Random random)
{
IgmpMessageType igmpMessageType = random.NextEnum(IgmpMessageType.None, IgmpMessageType.CreateGroupRequestVersion0,
IgmpMessageType.CreateGroupReplyVersion0, IgmpMessageType.JoinGroupRequestVersion0,
IgmpMessageType.JoinGroupReplyVersion0, IgmpMessageType.LeaveGroupRequestVersion0,
IgmpMessageType.LeaveGroupReplyVersion0, IgmpMessageType.ConfirmGroupRequestVersion0,
IgmpMessageType.ConfirmGroupReplyVersion0,
IgmpMessageType.MulticastTraceRouteResponse); // todo support IGMP traceroute http://www.ietf.org/proceedings/48/I-D/idmr-traceroute-ipm-07.txt.
IgmpQueryVersion igmpQueryVersion = IgmpQueryVersion.None;
TimeSpan igmpMaxResponseTime = random.NextTimeSpan(TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(256 * 0.1) - TimeSpan.FromTicks(1));
IpV4Address igmpGroupAddress = random.NextIpV4Address();
bool? igmpIsSuppressRouterSideProcessing;
byte? igmpQueryRobustnessVariable;
TimeSpan? igmpQueryInterval;
IpV4Address[] igmpSourceAddresses;
IgmpGroupRecord[] igmpGroupRecords;
switch (igmpMessageType)
{
case IgmpMessageType.MembershipQuery:
igmpQueryVersion = random.NextEnum(IgmpQueryVersion.None, IgmpQueryVersion.Unknown);
switch (igmpQueryVersion)
{
case IgmpQueryVersion.Version1:
return new IgmpQueryVersion1Layer
{
GroupAddress = igmpGroupAddress
};
case IgmpQueryVersion.Version2:
return new IgmpQueryVersion2Layer
{
MaxResponseTime = igmpMaxResponseTime,
GroupAddress = igmpGroupAddress
};
case IgmpQueryVersion.Version3:
igmpIsSuppressRouterSideProcessing = random.NextBool();
igmpQueryRobustnessVariable = random.NextByte(8);
igmpMaxResponseTime = random.NextTimeSpan(TimeSpan.FromSeconds(0.1),
IgmpDatagram.MaxVersion3MaxResponseTime - TimeSpan.FromTicks(1));
igmpQueryInterval = random.NextTimeSpan(TimeSpan.Zero, IgmpDatagram.MaxQueryInterval - TimeSpan.FromTicks(1));
igmpSourceAddresses = random.NextIpV4Addresses(random.Next(1000));
return new IgmpQueryVersion3Layer
{
SourceAddresses = igmpSourceAddresses.AsReadOnly(),
MaxResponseTime = igmpMaxResponseTime,
GroupAddress = igmpGroupAddress,
IsSuppressRouterSideProcessing = igmpIsSuppressRouterSideProcessing.Value,
QueryRobustnessVariable = igmpQueryRobustnessVariable.Value,
QueryInterval = igmpQueryInterval.Value,
};
default:
throw new InvalidOperationException("Invalid Query Version " + igmpQueryVersion);
}
case IgmpMessageType.MembershipReportVersion1:
return new IgmpReportVersion1Layer
{
GroupAddress = igmpGroupAddress
};
case IgmpMessageType.MembershipReportVersion2:
return new IgmpReportVersion2Layer
{
MaxResponseTime = igmpMaxResponseTime,
GroupAddress = igmpGroupAddress
};
case IgmpMessageType.LeaveGroupVersion2:
return new IgmpLeaveGroupVersion2Layer
{
MaxResponseTime = igmpMaxResponseTime,
GroupAddress = igmpGroupAddress
};
case IgmpMessageType.MembershipReportVersion3:
igmpGroupRecords = random.NextIgmpGroupRecords(random.Next(100));
if (igmpGroupRecords.Count() == 0 && random.NextBool())
return new IgmpReportVersion3Layer();
return new IgmpReportVersion3Layer
{
GroupRecords = igmpGroupRecords.AsReadOnly()
};
default:
throw new InvalidOperationException("Invalid message type " + igmpMessageType);
}
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using PcapDotNet.Base;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.TestUtils;
namespace PcapDotNet.Packets.TestUtils
{
public static class RandomIpV4Extensions
{
public static IpV4Layer NextIpV4Layer(this Random random, IpV4Protocol? protocol)
{
return new IpV4Layer
{
TypeOfService = random.NextByte(),
Identification = random.NextUShort(),
Ttl = random.NextByte(),
Protocol = protocol,
HeaderChecksum = random.NextBool() ? (ushort?)random.NextUShort() : null,
Fragmentation = random.NextBool() ? random.NextIpV4Fragmentation() : IpV4Fragmentation.None,
Source = random.NextIpV4Address(),
Destination = random.NextIpV4Address(),
Options = random.NextIpV4Options()
};
}
public static IpV4Layer NextIpV4Layer(this Random random)
{
return random.NextIpV4Layer(random.NextEnum<IpV4Protocol>());
}
public static IpV4Address NextIpV4Address(this Random random)
{
return new IpV4Address(random.NextUInt());
}
public static IpV4Address[] NextIpV4Addresses(this Random random, int count)
{
return ((Func<IpV4Address>)random.NextIpV4Address).GenerateArray(count);
}
public static IpV4Fragmentation NextIpV4Fragmentation(this Random random)
{
IpV4FragmentationOptions ipV4FragmentationFlags = random.NextEnum<IpV4FragmentationOptions>();
ushort ipV4FragmentationOffset = (ushort)(random.NextUShort() / 8 * 8);
return new IpV4Fragmentation(ipV4FragmentationFlags, ipV4FragmentationOffset);
}
public static IpV4TimeOfDay NextIpV4TimeOfDay(this Random random)
{
return new IpV4TimeOfDay(random.NextUInt());
}
public static IpV4OptionUnknown NextIpV4OptionUnknown(this Random random, int maximumOptionLength)
{
IpV4OptionType unknownOptionType;
byte unknownOptionTypeValue;
do
{
unknownOptionTypeValue = random.NextByte();
unknownOptionType = (IpV4OptionType)unknownOptionTypeValue;
} while (unknownOptionType.ToString() != unknownOptionTypeValue.ToString());
Byte[] unknownOptionData = new byte[random.Next(maximumOptionLength - IpV4OptionUnknown.OptionMinimumLength + 1)];
random.NextBytes(unknownOptionData);
return new IpV4OptionUnknown(unknownOptionType, unknownOptionData);
}
public static IpV4Option NextIpV4Option(this Random random, int maximumOptionLength)
{
if (maximumOptionLength == 0)
throw new ArgumentOutOfRangeException("maximumOptionLength", maximumOptionLength, "option length must be positive");
if (maximumOptionLength >= IpV4OptionUnknown.OptionMinimumLength && random.Next(100) > 90)
return random.NextIpV4OptionUnknown(maximumOptionLength);
List<IpV4OptionType> impossibleOptionTypes = new List<IpV4OptionType>();
if (maximumOptionLength < IpV4OptionBasicSecurity.OptionMinimumLength)
impossibleOptionTypes.Add(IpV4OptionType.BasicSecurity);
if (maximumOptionLength < IpV4OptionRoute.OptionMinimumLength)
{
impossibleOptionTypes.Add(IpV4OptionType.LooseSourceRouting);
impossibleOptionTypes.Add(IpV4OptionType.StrictSourceRouting);
impossibleOptionTypes.Add(IpV4OptionType.RecordRoute);
}
if (maximumOptionLength < IpV4OptionStreamIdentifier.OptionLength)
impossibleOptionTypes.Add(IpV4OptionType.StreamIdentifier);
if (maximumOptionLength < IpV4OptionTimestamp.OptionMinimumLength)
impossibleOptionTypes.Add(IpV4OptionType.InternetTimestamp);
if (maximumOptionLength < IpV4OptionTraceRoute.OptionLength)
impossibleOptionTypes.Add(IpV4OptionType.TraceRoute);
if (maximumOptionLength < IpV4OptionQuickStart.OptionLength)
impossibleOptionTypes.Add(IpV4OptionType.QuickStart);
IpV4OptionType optionType = random.NextEnum<IpV4OptionType>(impossibleOptionTypes);
switch (optionType)
{
case IpV4OptionType.EndOfOptionList:
return IpV4Option.End;
case IpV4OptionType.NoOperation:
return IpV4Option.Nop;
case IpV4OptionType.BasicSecurity:
IpV4OptionSecurityProtectionAuthorities protectionAuthorities = IpV4OptionSecurityProtectionAuthorities.None;
int protectionAuthorityLength = random.Next(maximumOptionLength - IpV4OptionBasicSecurity.OptionMinimumLength);
if (protectionAuthorityLength > 0)
protectionAuthorities = random.NextEnum<IpV4OptionSecurityProtectionAuthorities>();
return new IpV4OptionBasicSecurity(random.NextEnum(IpV4OptionSecurityClassificationLevel.None),
protectionAuthorities,
(byte)(IpV4OptionBasicSecurity.OptionMinimumLength + protectionAuthorityLength));
case IpV4OptionType.LooseSourceRouting:
case IpV4OptionType.StrictSourceRouting:
case IpV4OptionType.RecordRoute:
int numAddresses = random.Next((maximumOptionLength - IpV4OptionRoute.OptionMinimumLength) / 4 + 1);
IpV4Address[] addresses = random.NextIpV4Addresses(numAddresses);
byte pointedAddressIndex;
if (random.NextBool())
pointedAddressIndex = random.NextByte(IpV4OptionRoute.PointedAddressIndexMaxValue + 1);
else
pointedAddressIndex = random.NextByte(10);
switch (optionType)
{
case IpV4OptionType.LooseSourceRouting:
return new IpV4OptionLooseSourceRouting(addresses, pointedAddressIndex);
case IpV4OptionType.StrictSourceRouting:
return new IpV4OptionStrictSourceRouting(addresses, pointedAddressIndex);
case IpV4OptionType.RecordRoute:
return new IpV4OptionRecordRoute(pointedAddressIndex, addresses);
default:
throw new InvalidOperationException("optionType = " + optionType);
}
case IpV4OptionType.StreamIdentifier:
return new IpV4OptionStreamIdentifier(random.NextUShort());
case IpV4OptionType.InternetTimestamp:
IpV4OptionTimestampType timestampType = random.NextEnum<IpV4OptionTimestampType>();
byte overflow = random.NextByte(IpV4OptionTimestamp.OverflowMaxValue + 1);
byte pointedIndex;
if (random.NextBool())
pointedIndex = random.NextByte(IpV4OptionTimestamp.PointedIndexMaxValue + 1);
else
pointedIndex = random.NextByte(10);
switch (timestampType)
{
case IpV4OptionTimestampType.TimestampOnly:
int numTimestamps = random.Next((maximumOptionLength - IpV4OptionTimestamp.OptionMinimumLength) / 4 + 1);
IpV4TimeOfDay[] timestamps = ((Func<IpV4TimeOfDay>)random.NextIpV4TimeOfDay).GenerateArray(numTimestamps);
return new IpV4OptionTimestampOnly(overflow, pointedIndex, timestamps);
case IpV4OptionTimestampType.AddressAndTimestamp:
case IpV4OptionTimestampType.AddressPrespecified:
int numPairs = random.Next((maximumOptionLength - IpV4OptionTimestamp.OptionMinimumLength) / 8 + 1);
IpV4OptionTimedAddress[] pairs = new IpV4OptionTimedAddress[numPairs];
for (int i = 0; i != numPairs; ++i)
pairs[i] = new IpV4OptionTimedAddress(random.NextIpV4Address(), random.NextIpV4TimeOfDay());
return new IpV4OptionTimestampAndAddress(timestampType, overflow, pointedIndex, pairs);
default:
throw new InvalidOperationException("timestampType = " + timestampType);
}
case IpV4OptionType.TraceRoute:
return new IpV4OptionTraceRoute(random.NextUShort(), random.NextUShort(), random.NextUShort(), random.NextIpV4Address());
case IpV4OptionType.RouterAlert:
return new IpV4OptionRouterAlert(random.NextUShort());
case IpV4OptionType.QuickStart:
return new IpV4OptionQuickStart(random.NextEnum<IpV4OptionQuickStartFunction>(),
random.NextByte(IpV4OptionQuickStart.RateMaximumValue + 1),
random.NextByte(),
random.NextUInt() & 0xFFFFFFFC);
default:
throw new InvalidOperationException("optionType = " + optionType);
}
}
public static IpV4Options NextIpV4Options(this Random random)
{
int optionsLength = random.Next(IpV4Options.MaximumBytesLength) / 4 * 4;
List<IpV4Option> options = new List<IpV4Option>();
while (optionsLength > 0)
{
IpV4Option option = random.NextIpV4Option(optionsLength);
if (option.IsAppearsAtMostOnce &&
options.FindIndex(option.Equivalent) != -1)
{
continue;
}
options.Add(option);
optionsLength -= option.Length;
if (option.OptionType == IpV4OptionType.EndOfOptionList)
break;
}
return new IpV4Options(options);
}
}
}
\ No newline at end of file
using System;
using PcapDotNet.Packets.IpV6;
using PcapDotNet.TestUtils;
namespace PcapDotNet.Packets.TestUtils
{
public static class RandomIpV6Extensions
{
public static IpV6Address NextIpV6Address(this Random random)
{
return new IpV6Address(random.NextUInt128());
}
}
}
\ No newline at end of file
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PcapDotNet.Base;
using PcapDotNet.Packets.Arp;
using PcapDotNet.Packets.Dns;
using PcapDotNet.Packets.Ethernet;
using PcapDotNet.Packets.Gre;
using PcapDotNet.Packets.Http;
using PcapDotNet.Packets.Icmp;
using PcapDotNet.Packets.Igmp;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.IpV6;
using PcapDotNet.Packets.Transport;
using PcapDotNet.TestUtils; using PcapDotNet.TestUtils;
namespace PcapDotNet.Packets.TestUtils namespace PcapDotNet.Packets.TestUtils
...@@ -46,1302 +32,9 @@ namespace PcapDotNet.Packets.TestUtils ...@@ -46,1302 +32,9 @@ namespace PcapDotNet.Packets.TestUtils
}; };
} }
// Ethernet public static DataSegment NextDataSegment(this Random random, int length)
public static EthernetLayer NextEthernetLayer(this Random random, EthernetType etherType)
{
return new EthernetLayer
{
Source = random.NextMacAddress(),
Destination = random.NextMacAddress(),
EtherType = etherType
};
}
public static EthernetLayer NextEthernetLayer(this Random random)
{
return random.NextEthernetLayer(random.NextEnum(EthernetType.None));
}
public static MacAddress NextMacAddress(this Random random)
{
return new MacAddress(random.NextUInt48());
}
public static EthernetType NextEthernetType(this Random random)
{
return random.NextEnum(EthernetType.None);
}
public static Packet NextEthernetPacket(this Random random, int packetSize, DateTime timestamp, MacAddress ethernetSource, MacAddress ethernetDestination)
{
if (packetSize < EthernetDatagram.HeaderLength)
throw new ArgumentOutOfRangeException("packetSize", packetSize, "Must be at least the ethernet header length (" + EthernetDatagram.HeaderLength + ")");
return PacketBuilder.Build(timestamp,
new EthernetLayer
{
Source = ethernetSource,
Destination = ethernetDestination,
EtherType = random.NextEthernetType()
},
random.NextPayloadLayer(packetSize - EthernetDatagram.HeaderLength));
}
public static Packet NextEthernetPacket(this Random random, int packetSize, DateTime timestamp, string ethernetSource, string ethernetDestination)
{
return random.NextEthernetPacket(packetSize, timestamp, new MacAddress(ethernetSource), new MacAddress(ethernetDestination));
}
public static Packet NextEthernetPacket(this Random random, int packetSize, MacAddress ethernetSource, MacAddress ethernetDestination)
{
return random.NextEthernetPacket(packetSize, DateTime.Now, ethernetSource, ethernetDestination);
}
public static Packet NextEthernetPacket(this Random random, int packetSize, string ethernetSource, string ethernetDestination)
{
return random.NextEthernetPacket(packetSize, DateTime.Now, ethernetSource, ethernetDestination);
}
public static Packet NextEthernetPacket(this Random random, int packetSize)
{
return random.NextEthernetPacket(packetSize, DateTime.Now, random.NextMacAddress(), random.NextMacAddress());
}
// ARP
public static ArpLayer NextArpLayer(this Random random)
{
byte hardwareAddressLength = random.NextByte();
byte protocolAddressLength = random.NextByte();
return new ArpLayer
{
SenderHardwareAddress = random.NextBytes(hardwareAddressLength).AsReadOnly(),
SenderProtocolAddress = random.NextBytes(protocolAddressLength).AsReadOnly(),
TargetHardwareAddress = random.NextBytes(hardwareAddressLength).AsReadOnly(),
TargetProtocolAddress = random.NextBytes(protocolAddressLength).AsReadOnly(),
ProtocolType = random.NextEnum<EthernetType>(),
Operation = random.NextEnum<ArpOperation>(),
};
}
// IPv4
public static IpV4Layer NextIpV4Layer(this Random random, IpV4Protocol? protocol)
{
return new IpV4Layer
{
TypeOfService = random.NextByte(),
Identification = random.NextUShort(),
Ttl = random.NextByte(),
Protocol = protocol,
HeaderChecksum = random.NextBool() ? (ushort?)random.NextUShort() : null,
Fragmentation = random.NextBool() ? random.NextIpV4Fragmentation() : IpV4Fragmentation.None,
Source = random.NextIpV4Address(),
Destination = random.NextIpV4Address(),
Options = random.NextIpV4Options()
};
}
public static IpV4Layer NextIpV4Layer(this Random random)
{
return random.NextIpV4Layer(random.NextEnum<IpV4Protocol>());
}
public static IpV4Address NextIpV4Address(this Random random)
{
return new IpV4Address(random.NextUInt());
}
public static IpV4Address[] NextIpV4Addresses(this Random random, int count)
{
return ((Func<IpV4Address>)random.NextIpV4Address).GenerateArray(count);
}
public static IpV4Fragmentation NextIpV4Fragmentation(this Random random)
{
IpV4FragmentationOptions ipV4FragmentationFlags = random.NextEnum<IpV4FragmentationOptions>();
ushort ipV4FragmentationOffset = (ushort)(random.NextUShort() / 8 * 8);
return new IpV4Fragmentation(ipV4FragmentationFlags, ipV4FragmentationOffset);
}
public static IpV4TimeOfDay NextIpV4TimeOfDay(this Random random)
{
return new IpV4TimeOfDay(random.NextUInt());
}
public static IpV4OptionUnknown NextIpV4OptionUnknown(this Random random, int maximumOptionLength)
{
IpV4OptionType unknownOptionType;
byte unknownOptionTypeValue;
do
{
unknownOptionTypeValue = random.NextByte();
unknownOptionType = (IpV4OptionType)unknownOptionTypeValue;
} while (unknownOptionType.ToString() != unknownOptionTypeValue.ToString());
Byte[] unknownOptionData = new byte[random.Next(maximumOptionLength - IpV4OptionUnknown.OptionMinimumLength + 1)];
random.NextBytes(unknownOptionData);
return new IpV4OptionUnknown(unknownOptionType, unknownOptionData);
}
public static IpV4Option NextIpV4Option(this Random random, int maximumOptionLength)
{
if (maximumOptionLength == 0)
throw new ArgumentOutOfRangeException("maximumOptionLength", maximumOptionLength, "option length must be positive");
if (maximumOptionLength >= IpV4OptionUnknown.OptionMinimumLength && random.Next(100) > 90)
return random.NextIpV4OptionUnknown(maximumOptionLength);
List<IpV4OptionType> impossibleOptionTypes = new List<IpV4OptionType>();
if (maximumOptionLength < IpV4OptionBasicSecurity.OptionMinimumLength)
impossibleOptionTypes.Add(IpV4OptionType.BasicSecurity);
if (maximumOptionLength < IpV4OptionRoute.OptionMinimumLength)
{
impossibleOptionTypes.Add(IpV4OptionType.LooseSourceRouting);
impossibleOptionTypes.Add(IpV4OptionType.StrictSourceRouting);
impossibleOptionTypes.Add(IpV4OptionType.RecordRoute);
}
if (maximumOptionLength < IpV4OptionStreamIdentifier.OptionLength)
impossibleOptionTypes.Add(IpV4OptionType.StreamIdentifier);
if (maximumOptionLength < IpV4OptionTimestamp.OptionMinimumLength)
impossibleOptionTypes.Add(IpV4OptionType.InternetTimestamp);
if (maximumOptionLength < IpV4OptionTraceRoute.OptionLength)
impossibleOptionTypes.Add(IpV4OptionType.TraceRoute);
if (maximumOptionLength < IpV4OptionQuickStart.OptionLength)
impossibleOptionTypes.Add(IpV4OptionType.QuickStart);
IpV4OptionType optionType = random.NextEnum<IpV4OptionType>(impossibleOptionTypes);
switch (optionType)
{
case IpV4OptionType.EndOfOptionList:
return IpV4Option.End;
case IpV4OptionType.NoOperation:
return IpV4Option.Nop;
case IpV4OptionType.BasicSecurity:
IpV4OptionSecurityProtectionAuthorities protectionAuthorities = IpV4OptionSecurityProtectionAuthorities.None;
int protectionAuthorityLength = random.Next(maximumOptionLength - IpV4OptionBasicSecurity.OptionMinimumLength);
if (protectionAuthorityLength > 0)
protectionAuthorities = random.NextEnum<IpV4OptionSecurityProtectionAuthorities>();
return new IpV4OptionBasicSecurity(random.NextEnum(IpV4OptionSecurityClassificationLevel.None),
protectionAuthorities,
(byte)(IpV4OptionBasicSecurity.OptionMinimumLength + protectionAuthorityLength));
case IpV4OptionType.LooseSourceRouting:
case IpV4OptionType.StrictSourceRouting:
case IpV4OptionType.RecordRoute:
int numAddresses = random.Next((maximumOptionLength - IpV4OptionRoute.OptionMinimumLength) / 4 + 1);
IpV4Address[] addresses = random.NextIpV4Addresses(numAddresses);
byte pointedAddressIndex;
if (random.NextBool())
pointedAddressIndex = random.NextByte(IpV4OptionRoute.PointedAddressIndexMaxValue + 1);
else
pointedAddressIndex = random.NextByte(10);
switch (optionType)
{
case IpV4OptionType.LooseSourceRouting:
return new IpV4OptionLooseSourceRouting(addresses, pointedAddressIndex);
case IpV4OptionType.StrictSourceRouting:
return new IpV4OptionStrictSourceRouting(addresses, pointedAddressIndex);
case IpV4OptionType.RecordRoute:
return new IpV4OptionRecordRoute(pointedAddressIndex, addresses);
default:
throw new InvalidOperationException("optionType = " + optionType);
}
case IpV4OptionType.StreamIdentifier:
return new IpV4OptionStreamIdentifier(random.NextUShort());
case IpV4OptionType.InternetTimestamp:
IpV4OptionTimestampType timestampType = random.NextEnum<IpV4OptionTimestampType>();
byte overflow = random.NextByte(IpV4OptionTimestamp.OverflowMaxValue + 1);
byte pointedIndex;
if (random.NextBool())
pointedIndex = random.NextByte(IpV4OptionTimestamp.PointedIndexMaxValue + 1);
else
pointedIndex = random.NextByte(10);
switch (timestampType)
{
case IpV4OptionTimestampType.TimestampOnly:
int numTimestamps = random.Next((maximumOptionLength - IpV4OptionTimestamp.OptionMinimumLength) / 4 + 1);
IpV4TimeOfDay[] timestamps = ((Func<IpV4TimeOfDay>)random.NextIpV4TimeOfDay).GenerateArray(numTimestamps);
return new IpV4OptionTimestampOnly(overflow, pointedIndex, timestamps);
case IpV4OptionTimestampType.AddressAndTimestamp:
case IpV4OptionTimestampType.AddressPrespecified:
int numPairs = random.Next((maximumOptionLength - IpV4OptionTimestamp.OptionMinimumLength) / 8 + 1);
IpV4OptionTimedAddress[] pairs = new IpV4OptionTimedAddress[numPairs];
for (int i = 0; i != numPairs; ++i)
pairs[i] = new IpV4OptionTimedAddress(random.NextIpV4Address(), random.NextIpV4TimeOfDay());
return new IpV4OptionTimestampAndAddress(timestampType, overflow, pointedIndex, pairs);
default:
throw new InvalidOperationException("timestampType = " + timestampType);
}
case IpV4OptionType.TraceRoute:
return new IpV4OptionTraceRoute(random.NextUShort(), random.NextUShort(), random.NextUShort(), random.NextIpV4Address());
case IpV4OptionType.RouterAlert:
return new IpV4OptionRouterAlert(random.NextUShort());
case IpV4OptionType.QuickStart:
return new IpV4OptionQuickStart(random.NextEnum<IpV4OptionQuickStartFunction>(),
random.NextByte(IpV4OptionQuickStart.RateMaximumValue + 1),
random.NextByte(),
random.NextUInt() & 0xFFFFFFFC);
default:
throw new InvalidOperationException("optionType = " + optionType);
}
}
public static IpV4Options NextIpV4Options(this Random random)
{
int optionsLength = random.Next(IpV4Options.MaximumBytesLength) / 4 * 4;
List<IpV4Option> options = new List<IpV4Option>();
while (optionsLength > 0)
{
IpV4Option option = random.NextIpV4Option(optionsLength);
if (option.IsAppearsAtMostOnce &&
options.FindIndex(option.Equivalent) != -1)
{
continue;
}
options.Add(option);
optionsLength -= option.Length;
if (option.OptionType == IpV4OptionType.EndOfOptionList)
break;
}
return new IpV4Options(options);
}
// IPv6
public static IpV6Address NextIpV6Address(this Random random)
{
return new IpV6Address(random.NextUInt128());
}
// UDP
public static UdpLayer NextUdpLayer(this Random random)
{
return new UdpLayer
{
Checksum = random.NextUShort(),
SourcePort = random.NextUShort(),
DestinationPort = random.NextUShort(),
CalculateChecksumValue = random.NextBool()
};
}
// TCP
public static TcpLayer NextTcpLayer(this Random random)
{
return new TcpLayer
{
SourcePort = random.NextUShort(),
DestinationPort = random.NextUShort(),
SequenceNumber = random.NextUInt(),
AcknowledgmentNumber = random.NextUInt(),
ControlBits = random.NextFlags<TcpControlBits>(),
Window = random.NextUShort(),
UrgentPointer = random.NextUShort(),
Options = random.NextTcpOptions(),
};
}
public static TcpOptions NextTcpOptions(this Random random)
{
int optionsLength = random.Next(TcpOptions.MaximumBytesLength) / 4 * 4;
List<TcpOption> options = new List<TcpOption>();
while (optionsLength > 0)
{
TcpOption option = random.NextTcpOption(optionsLength);
if (option.IsAppearsAtMostOnce &&
options.FindIndex(option.Equivalent) != -1)
{
continue;
}
options.Add(option);
optionsLength -= option.Length;
if (option.OptionType == TcpOptionType.EndOfOptionList)
break;
}
return new TcpOptions(options);
}
public static TcpOptionUnknown NextTcpOptionUnknown(this Random random, int maximumOptionLength)
{
TcpOptionType unknownOptionType;
byte unknownOptionTypeValue;
do
{
unknownOptionTypeValue = random.NextByte();
unknownOptionType = (TcpOptionType)unknownOptionTypeValue;
} while (unknownOptionType.ToString() != unknownOptionTypeValue.ToString());
byte[] unknownOptionData = random.NextBytes(maximumOptionLength - TcpOptionUnknown.OptionMinimumLength + 1);
return new TcpOptionUnknown(unknownOptionType, unknownOptionData);
}
public static TcpOption NextTcpOption(this Random random, int maximumOptionLength)
{
if (maximumOptionLength == 0)
throw new ArgumentOutOfRangeException("maximumOptionLength", maximumOptionLength, "option length must be positive");
if (maximumOptionLength >= TcpOptionUnknown.OptionMinimumLength && random.Next(100) > 90)
return random.NextTcpOptionUnknown(maximumOptionLength);
List<TcpOptionType> impossibleOptionTypes = new List<TcpOptionType>();
if (maximumOptionLength < TcpOptionMaximumSegmentSize.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.MaximumSegmentSize);
if (maximumOptionLength < TcpOptionWindowScale.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.WindowScale);
if (maximumOptionLength < TcpOptionSelectiveAcknowledgment.OptionMinimumLength)
impossibleOptionTypes.Add(TcpOptionType.SelectiveAcknowledgment);
if (maximumOptionLength < TcpOptionSelectiveAcknowledgmentPermitted.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.SelectiveAcknowledgmentPermitted);
if (maximumOptionLength < TcpOptionEcho.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.Echo);
if (maximumOptionLength < TcpOptionEchoReply.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.EchoReply);
if (maximumOptionLength < TcpOptionTimestamp.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.Timestamp);
if (maximumOptionLength < TcpOptionPartialOrderServiceProfile.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.PartialOrderServiceProfile);
if (maximumOptionLength < TcpOptionPartialOrderConnectionPermitted.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.PartialOrderConnectionPermitted);
if (maximumOptionLength < TcpOptionConnectionCountBase.OptionLength)
{
impossibleOptionTypes.Add(TcpOptionType.ConnectionCount);
impossibleOptionTypes.Add(TcpOptionType.ConnectionCountNew);
impossibleOptionTypes.Add(TcpOptionType.ConnectionCountEcho);
}
if (maximumOptionLength < TcpOptionAlternateChecksumRequest.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.AlternateChecksumRequest);
if (maximumOptionLength < TcpOptionAlternateChecksumData.OptionMinimumLength)
impossibleOptionTypes.Add(TcpOptionType.AlternateChecksumData);
if (maximumOptionLength < TcpOptionMd5Signature.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.Md5Signature);
if (maximumOptionLength < TcpOptionMood.OptionMaximumLength)
impossibleOptionTypes.Add(TcpOptionType.Mood);
impossibleOptionTypes.Add(TcpOptionType.QuickStartResponse);
impossibleOptionTypes.Add(TcpOptionType.UserTimeout);
TcpOptionType optionType = random.NextEnum<TcpOptionType>(impossibleOptionTypes);
switch (optionType)
{
case TcpOptionType.EndOfOptionList:
return TcpOption.End;
case TcpOptionType.NoOperation:
return TcpOption.Nop;
case TcpOptionType.MaximumSegmentSize:
return new TcpOptionMaximumSegmentSize(random.NextUShort());
case TcpOptionType.WindowScale:
return new TcpOptionWindowScale(random.NextByte());
case TcpOptionType.SelectiveAcknowledgment:
int numBlocks = random.Next((maximumOptionLength - TcpOptionSelectiveAcknowledgment.OptionMinimumLength) / 8 + 1);
TcpOptionSelectiveAcknowledgmentBlock[] blocks = new TcpOptionSelectiveAcknowledgmentBlock[numBlocks];
for (int i = 0; i != numBlocks; ++i)
blocks[i] = new TcpOptionSelectiveAcknowledgmentBlock(random.NextUInt(), random.NextUInt());
return new TcpOptionSelectiveAcknowledgment(blocks);
case TcpOptionType.SelectiveAcknowledgmentPermitted:
return new TcpOptionSelectiveAcknowledgmentPermitted();
case TcpOptionType.Echo:
return new TcpOptionEcho(random.NextUInt());
case TcpOptionType.EchoReply:
return new TcpOptionEchoReply(random.NextUInt());
case TcpOptionType.Timestamp:
return new TcpOptionTimestamp(random.NextUInt(), random.NextUInt());
case TcpOptionType.PartialOrderServiceProfile:
return new TcpOptionPartialOrderServiceProfile(random.NextBool(), random.NextBool());
case TcpOptionType.PartialOrderConnectionPermitted:
return new TcpOptionPartialOrderConnectionPermitted();
case TcpOptionType.ConnectionCount:
return new TcpOptionConnectionCount(random.NextUInt());
case TcpOptionType.ConnectionCountEcho:
return new TcpOptionConnectionCountEcho(random.NextUInt());
case TcpOptionType.ConnectionCountNew:
return new TcpOptionConnectionCountNew(random.NextUInt());
case TcpOptionType.AlternateChecksumRequest:
return new TcpOptionAlternateChecksumRequest(random.NextEnum<TcpOptionAlternateChecksumType>());
case TcpOptionType.AlternateChecksumData:
return new TcpOptionAlternateChecksumData(random.NextBytes(random.Next(maximumOptionLength - TcpOptionAlternateChecksumData.OptionMinimumLength + 1)));
case TcpOptionType.Md5Signature:
return new TcpOptionMd5Signature(random.NextBytes(TcpOptionMd5Signature.OptionValueLength));
case TcpOptionType.Mood:
return new TcpOptionMood(random.NextEnum(TcpOptionMoodEmotion.None));
default:
throw new InvalidOperationException("optionType = " + optionType);
}
}
// IGMP
public static IgmpGroupRecord NextIgmpGroupRecord(this Random random)
{
IpV4Address[] sourceAddresses = random.NextIpV4Addresses(random.Next(10));
return new IgmpGroupRecord(random.NextEnum<IgmpRecordType>(), random.NextIpV4Address(), sourceAddresses, random.NextDatagram(random.Next(10) * 4));
}
public static IgmpGroupRecord[] NextIgmpGroupRecords(this Random random, int count)
{
return ((Func<IgmpGroupRecord>)random.NextIgmpGroupRecord).GenerateArray(count);
}
public static IgmpLayer NextIgmpLayer(this Random random)
{
IgmpMessageType igmpMessageType = random.NextEnum(IgmpMessageType.None, IgmpMessageType.CreateGroupRequestVersion0,
IgmpMessageType.CreateGroupReplyVersion0, IgmpMessageType.JoinGroupRequestVersion0,
IgmpMessageType.JoinGroupReplyVersion0, IgmpMessageType.LeaveGroupRequestVersion0,
IgmpMessageType.LeaveGroupReplyVersion0, IgmpMessageType.ConfirmGroupRequestVersion0,
IgmpMessageType.ConfirmGroupReplyVersion0,
IgmpMessageType.MulticastTraceRouteResponse); // todo support IGMP traceroute http://www.ietf.org/proceedings/48/I-D/idmr-traceroute-ipm-07.txt.
IgmpQueryVersion igmpQueryVersion = IgmpQueryVersion.None;
TimeSpan igmpMaxResponseTime = random.NextTimeSpan(TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(256 * 0.1) - TimeSpan.FromTicks(1));
IpV4Address igmpGroupAddress = random.NextIpV4Address();
bool? igmpIsSuppressRouterSideProcessing;
byte? igmpQueryRobustnessVariable;
TimeSpan? igmpQueryInterval;
IpV4Address[] igmpSourceAddresses;
IgmpGroupRecord[] igmpGroupRecords;
switch (igmpMessageType)
{
case IgmpMessageType.MembershipQuery:
igmpQueryVersion = random.NextEnum(IgmpQueryVersion.None, IgmpQueryVersion.Unknown);
switch (igmpQueryVersion)
{
case IgmpQueryVersion.Version1:
return new IgmpQueryVersion1Layer
{
GroupAddress = igmpGroupAddress
};
case IgmpQueryVersion.Version2:
return new IgmpQueryVersion2Layer
{
MaxResponseTime = igmpMaxResponseTime,
GroupAddress = igmpGroupAddress
};
case IgmpQueryVersion.Version3:
igmpIsSuppressRouterSideProcessing = random.NextBool();
igmpQueryRobustnessVariable = random.NextByte(8);
igmpMaxResponseTime = random.NextTimeSpan(TimeSpan.FromSeconds(0.1),
IgmpDatagram.MaxVersion3MaxResponseTime - TimeSpan.FromTicks(1));
igmpQueryInterval = random.NextTimeSpan(TimeSpan.Zero, IgmpDatagram.MaxQueryInterval - TimeSpan.FromTicks(1));
igmpSourceAddresses = random.NextIpV4Addresses(random.Next(1000));
return new IgmpQueryVersion3Layer
{
SourceAddresses = igmpSourceAddresses.AsReadOnly(),
MaxResponseTime = igmpMaxResponseTime,
GroupAddress = igmpGroupAddress,
IsSuppressRouterSideProcessing = igmpIsSuppressRouterSideProcessing.Value,
QueryRobustnessVariable = igmpQueryRobustnessVariable.Value,
QueryInterval = igmpQueryInterval.Value,
};
default:
throw new InvalidOperationException("Invalid Query Version " + igmpQueryVersion);
}
case IgmpMessageType.MembershipReportVersion1:
return new IgmpReportVersion1Layer
{
GroupAddress = igmpGroupAddress
};
case IgmpMessageType.MembershipReportVersion2:
return new IgmpReportVersion2Layer
{
MaxResponseTime = igmpMaxResponseTime,
GroupAddress = igmpGroupAddress
};
case IgmpMessageType.LeaveGroupVersion2:
return new IgmpLeaveGroupVersion2Layer
{
MaxResponseTime = igmpMaxResponseTime,
GroupAddress = igmpGroupAddress
};
case IgmpMessageType.MembershipReportVersion3:
igmpGroupRecords = random.NextIgmpGroupRecords(random.Next(100));
if (igmpGroupRecords.Count() == 0 && random.NextBool())
return new IgmpReportVersion3Layer();
return new IgmpReportVersion3Layer
{
GroupRecords = igmpGroupRecords.AsReadOnly()
};
default:
throw new InvalidOperationException("Invalid message type " + igmpMessageType);
}
}
// GRE
public static GreLayer NextGreLayer(this Random random)
{
GreVersion version = random.NextEnum<GreVersion>();
bool isChecksum = random.NextBool();
GreSourceRouteEntry[] routing = null;
ushort? routingOffset = null;
bool strictSourceRoute = false;
EthernetType protocolType = random.NextEnum(EthernetType.None);
uint? key = random.NextBool() ? (uint?)random.NextUInt() : null;
if (version == GreVersion.Gre)
{
if (random.NextBool())
{
strictSourceRoute = random.NextBool();
routing = new GreSourceRouteEntry[random.Next(5)];
GreSourceRouteEntryAddressFamily family;
if (random.NextBool())
family = random.NextEnum(GreSourceRouteEntryAddressFamily.None);
else
family = (GreSourceRouteEntryAddressFamily)random.NextUShort();
for (int i = 0; i != routing.Length; ++i)
{
switch (family)
{
case GreSourceRouteEntryAddressFamily.AsSourceRoute:
{
ushort[] asNumbers = new ushort[random.Next(1, 5)];
for (int j = 0; j != asNumbers.Length; ++j)
asNumbers[j] = random.NextUShort();
routing[i] = new GreSourceRouteEntryAs(asNumbers.AsReadOnly(), random.Next(asNumbers.Length + 1));
break;
}
case GreSourceRouteEntryAddressFamily.IpSourceRoute:
{
IpV4Address[] ips = new IpV4Address[random.Next(1, 5)];
for (int j = 0; j != ips.Length; ++j)
ips[j] = random.NextIpV4Address();
routing[i] = new GreSourceRouteEntryIp(ips.AsReadOnly(), random.Next(ips.Length + 1));
break;
}
default:
{
int dataLength = random.Next(1, 100);
routing[i] = new GreSourceRouteEntryUnknown(family, random.NextDatagram(dataLength), random.Next(dataLength + 1));
break;
}
}
}
routingOffset = 0;
if (routing.Any())
{
int routingIndex = random.Next(routing.Length);
for (int i = 0; i != routingIndex; ++i)
routingOffset += (ushort)routing[i].Length;
}
}
}
else
{
protocolType = EthernetType.PointToPointProtocol;
isChecksum = false;
key = random.NextUInt();
}
return new GreLayer
{
Version = version,
ProtocolType = protocolType,
ChecksumPresent = isChecksum,
Checksum = isChecksum && random.NextBool() ? (ushort?)random.NextUShort() : null,
Key = key,
SequenceNumber = random.NextBool() ? (uint?)random.NextUInt() : null,
AcknowledgmentSequenceNumber = version == GreVersion.EnhancedGre && random.NextBool() ? (uint?)random.NextUInt() : null,
RecursionControl = random.NextByte(8),
// Flags = random.NextByte(32),
Routing = routing == null ? null : routing.AsReadOnly(),
RoutingOffset = routingOffset,
StrictSourceRoute = strictSourceRoute,
};
}
// ICMP
public static IcmpLayer NextIcmpLayer(this Random random)
{
IcmpMessageType icmpMessageType = random.NextEnum(IcmpMessageType.DomainNameReply);
ushort? checksum = random.NextBool() ? (ushort?)random.NextUShort() : null;
switch (icmpMessageType)
{
case IcmpMessageType.DestinationUnreachable:
return new IcmpDestinationUnreachableLayer
{
Code = random.NextEnum<IcmpCodeDestinationUnreachable>(),
Checksum = checksum,
NextHopMaximumTransmissionUnit = random.NextUShort(),
};
case IcmpMessageType.TimeExceeded:
return new IcmpTimeExceededLayer
{
Code = random.NextEnum<IcmpCodeTimeExceeded>(),
Checksum = checksum,
};
case IcmpMessageType.ParameterProblem:
return new IcmpParameterProblemLayer
{
Checksum = checksum,
Pointer = random.NextByte()
};
case IcmpMessageType.SourceQuench:
return new IcmpSourceQuenchLayer
{
Checksum = checksum
};
case IcmpMessageType.Redirect:
return new IcmpRedirectLayer
{
Code = random.NextEnum<IcmpCodeRedirect>(),
Checksum = checksum,
GatewayInternetAddress = random.NextIpV4Address()
};
case IcmpMessageType.Echo:
return new IcmpEchoLayer
{
Checksum = checksum,
Identifier = random.NextUShort(),
SequenceNumber = random.NextUShort()
};
case IcmpMessageType.EchoReply:
return new IcmpEchoReplyLayer
{
Checksum = checksum,
Identifier = random.NextUShort(),
SequenceNumber = random.NextUShort()
};
case IcmpMessageType.Timestamp:
return new IcmpTimestampLayer
{
Checksum = checksum,
Identifier = random.NextUShort(),
SequenceNumber = random.NextUShort(),
OriginateTimestamp = random.NextIpV4TimeOfDay(),
ReceiveTimestamp = random.NextIpV4TimeOfDay(),
TransmitTimestamp = random.NextIpV4TimeOfDay()
};
case IcmpMessageType.TimestampReply:
return new IcmpTimestampReplyLayer
{
Checksum = checksum,
Identifier = random.NextUShort(),
SequenceNumber = random.NextUShort(),
OriginateTimestamp = random.NextIpV4TimeOfDay(),
ReceiveTimestamp = random.NextIpV4TimeOfDay(),
TransmitTimestamp = random.NextIpV4TimeOfDay()
};
case IcmpMessageType.InformationRequest:
return new IcmpInformationRequestLayer
{
Checksum = checksum,
Identifier = random.NextUShort(),
SequenceNumber = random.NextUShort(),
};
case IcmpMessageType.InformationReply:
return new IcmpInformationReplyLayer
{
Checksum = checksum,
Identifier = random.NextUShort(),
SequenceNumber = random.NextUShort(),
};
case IcmpMessageType.RouterAdvertisement:
return new IcmpRouterAdvertisementLayer
{
Entries = random.NextIcmpRouterAdvertisementEntries(random.Next(10)).ToList().AsReadOnly(),
Checksum = checksum,
Lifetime = random.NextTimeSpan(TimeSpan.Zero, TimeSpan.FromSeconds(ushort.MaxValue)),
};
case IcmpMessageType.RouterSolicitation:
return new IcmpRouterSolicitationLayer
{
Checksum = checksum,
};
case IcmpMessageType.AddressMaskRequest:
return new IcmpAddressMaskRequestLayer
{
Checksum = checksum,
Identifier = random.NextUShort(),
SequenceNumber = random.NextUShort(),
AddressMask = random.NextIpV4Address()
};
case IcmpMessageType.AddressMaskReply:
return new IcmpAddressMaskReplyLayer
{
Checksum = checksum,
Identifier = random.NextUShort(),
SequenceNumber = random.NextUShort(),
AddressMask = random.NextIpV4Address()
};
case IcmpMessageType.TraceRoute:
return new IcmpTraceRouteLayer
{
Code = random.NextEnum<IcmpCodeTraceRoute>(),
Checksum = checksum,
Identification = random.NextUShort(),
OutboundHopCount = random.NextUShort(),
ReturnHopCount = random.NextUShort(),
OutputLinkSpeed = random.NextUInt(),
OutputLinkMaximumTransmissionUnit = random.NextUInt(),
};
case IcmpMessageType.ConversionFailed:
return new IcmpConversionFailedLayer
{
Code = random.NextEnum<IcmpCodeConversionFailed>(),
Checksum = checksum,
Pointer = random.NextUInt(),
};
case IcmpMessageType.DomainNameRequest:
return new IcmpDomainNameRequestLayer
{
Checksum = checksum,
Identifier = random.NextUShort(),
SequenceNumber = random.NextUShort(),
};
case IcmpMessageType.DomainNameReply:
throw new NotSupportedException("Message Type " + icmpMessageType + " is not supported");
case IcmpMessageType.SecurityFailures:
return new IcmpSecurityFailuresLayer
{
Code = random.NextEnum<IcmpCodeSecurityFailure>(),
Checksum = checksum,
Pointer = random.NextUShort()
};
default:
throw new InvalidOperationException("Invalid icmpMessageType " + icmpMessageType);
}
}
public static IEnumerable<ILayer> NextIcmpPayloadLayers(this Random random, IcmpLayer icmpLayer)
{
IEnumerable<ILayer> icmpPayloadLayers = new List<ILayer>();
switch (icmpLayer.MessageType)
{
case IcmpMessageType.DestinationUnreachable:
case IcmpMessageType.TimeExceeded:
case IcmpMessageType.ParameterProblem:
case IcmpMessageType.SourceQuench:
case IcmpMessageType.Redirect:
case IcmpMessageType.SecurityFailures:
icmpPayloadLayers = icmpPayloadLayers.Concat(random.NextIpV4Layer(), random.NextPayloadLayer(IcmpIpV4HeaderPlus64BitsPayloadDatagram.OriginalDatagramPayloadLength));
break;
case IcmpMessageType.ConversionFailed:
IpV4Layer icmpIpV4Layer = random.NextIpV4Layer();
icmpPayloadLayers = icmpPayloadLayers.Concat(icmpIpV4Layer);
if (icmpLayer.MessageTypeAndCode == IcmpMessageTypeAndCode.ConversionFailedUnsupportedTransportProtocol)
{
icmpPayloadLayers =
icmpPayloadLayers.Concat(random.NextPayloadLayer(
IcmpConversionFailedDatagram.OriginalDatagramLengthForUnsupportedTransportProtocol -
icmpIpV4Layer.Length));
}
else
{
switch (icmpIpV4Layer.Protocol)
{
case IpV4Protocol.Udp:
icmpPayloadLayers = icmpPayloadLayers.Concat(random.NextUdpLayer(),
random.NextPayloadLayer(random.Next(100)));
break;
case IpV4Protocol.Tcp:
icmpPayloadLayers = icmpPayloadLayers.Concat(random.NextTcpLayer(),
random.NextPayloadLayer(random.Next(100)));
break;
default:
icmpPayloadLayers = icmpPayloadLayers.Concat(random.NextPayloadLayer(random.Next(200)));
break;
}
}
break;
case IcmpMessageType.Echo:
case IcmpMessageType.EchoReply:
case IcmpMessageType.Timestamp:
case IcmpMessageType.TimestampReply:
case IcmpMessageType.InformationRequest:
case IcmpMessageType.InformationReply:
case IcmpMessageType.RouterAdvertisement:
case IcmpMessageType.RouterSolicitation:
case IcmpMessageType.AddressMaskRequest:
case IcmpMessageType.AddressMaskReply:
case IcmpMessageType.TraceRoute:
case IcmpMessageType.DomainNameRequest:
break;
case IcmpMessageType.DomainNameReply:
default:
throw new InvalidOperationException("Invalid icmpMessageType " + icmpLayer.MessageType);
}
return icmpPayloadLayers;
}
public static IEnumerable<IcmpRouterAdvertisementEntry> NextIcmpRouterAdvertisementEntries(this Random random, int numEntries)
{
for (int i = 0; i != numEntries; ++i)
yield return new IcmpRouterAdvertisementEntry(random.NextIpV4Address(), random.Next());
}
// DNS
public static DnsLayer NextDnsLayer(this Random random)
{
DnsLayer dnsLayer = new DnsLayer();
dnsLayer.Id = random.NextUShort();
dnsLayer.IsQuery = random.NextBool();
dnsLayer.Opcode = random.NextEnum<DnsOpcode>();
dnsLayer.IsAuthoritiveAnswer = random.NextBool();
dnsLayer.IsTruncated = random.NextBool();
dnsLayer.IsRecusionDesired = random.NextBool();
dnsLayer.IsRecusionAvailable = random.NextBool();
dnsLayer.FutureUse = random.NextByte(DnsDatagram.MaxFutureUse + 1);
dnsLayer.ResponseCode = random.NextEnum<DnsResponseCode>();
dnsLayer.DomainNameCompressionMode = random.NextEnum<DnsDomainNameCompressionMode>();
int numQueries = random.Next(10);
List<DnsQueryResourceRecord> queries = new List<DnsQueryResourceRecord>();
for (int i = 0; i != numQueries; ++i)
queries.Add(random.NextDnsQueryResourceRecord());
dnsLayer.Queries = queries;
int numAnswers = random.Next(10);
List<DnsDataResourceRecord> answers = new List<DnsDataResourceRecord>();
for (int i = 0; i != numAnswers; ++i)
answers.Add(random.NextDnsDataResourceRecord());
dnsLayer.Answers = answers;
int numAuthorities = random.Next(10);
List<DnsDataResourceRecord> authorities = new List<DnsDataResourceRecord>();
for (int i = 0; i != numAuthorities; ++i)
authorities.Add(random.NextDnsDataResourceRecord());
dnsLayer.Authorities = authorities;
int numAdditionals = random.Next(10);
List<DnsDataResourceRecord> additionals = new List<DnsDataResourceRecord>();
for (int i = 0; i != numAdditionals; ++i)
additionals.Add(random.NextDnsDataResourceRecord());
dnsLayer.Additionals = additionals;
return dnsLayer;
}
public static DnsQueryResourceRecord NextDnsQueryResourceRecord(this Random random)
{
DnsQueryResourceRecord record = new DnsQueryResourceRecord(random.NextDnsDomainName(), random.NextEnum<DnsType>(), random.NextEnum<DnsClass>());
return record;
}
public static DnsDataResourceRecord NextDnsDataResourceRecord(this Random random)
{
DnsType type = random.NextEnum<DnsType>();
DnsDataResourceRecord record = new DnsDataResourceRecord(random.NextDnsDomainName(), type, random.NextEnum<DnsClass>(), random.Next(), random.NextDnsResourceData(type));
return record;
}
public static DnsDomainName NextDnsDomainName(this Random random)
{
List<string> labels = new List<string>();
int numLabels = random.Next(10);
for (int i = 0; i != numLabels; ++i)
{
int labelLength = random.Next(10);
StringBuilder label = new StringBuilder();
for (int j = 0; j != labelLength; ++j)
label.Append(random.NextChar('a', 'z'));
labels.Add(label.ToString());
}
return new DnsDomainName(string.Join(".", labels));
}
public static DnsResourceData NextDnsResourceData(this Random random, DnsType type)
{
switch (type)
{
case DnsType.A:
return new DnsResourceDataIpV4(random.NextIpV4Address());
default:
return new DnsResourceDataUnknown(new DataSegment(random.NextBytes(random.Next(100))));
}
}
// HTTP
public static HttpLayer NextHttpLayer(this Random random)
{
if (random.NextBool())
{
HttpRequestLayer httpRequestLayer = new HttpRequestLayer();
if (random.NextBool(10))
{
httpRequestLayer.Method = random.NextHttpRequestMethod();
httpRequestLayer.Uri = httpRequestLayer.Method == null ? null : random.NextHttpUri();
httpRequestLayer.Version = httpRequestLayer.Uri == null || random.NextBool(10) ? null : random.NextHttpVersion();
httpRequestLayer.Header = httpRequestLayer.Version == null ? null : random.NextHttpHeader();
httpRequestLayer.Body = httpRequestLayer.Header == null ? null : random.NextHttpBody(true, null, httpRequestLayer.Header);
}
return httpRequestLayer;
}
HttpResponseLayer httpResponseLayer = new HttpResponseLayer
{
Version = random.NextHttpVersion(),
StatusCode = random.NextBool(10) ? null : (uint?)random.NextUInt(100, 999),
};
httpResponseLayer.ReasonPhrase = httpResponseLayer.StatusCode == null ? null : random.NextHttpReasonPhrase();
httpResponseLayer.Header = httpResponseLayer.ReasonPhrase == null ? null : random.NextHttpHeader();
httpResponseLayer.Body = httpResponseLayer.Header == null ? null : random.NextHttpBody(false , httpResponseLayer.StatusCode, httpResponseLayer.Header);
return httpResponseLayer;
}
public static Datagram NextHttpReasonPhrase(this Random random)
{
int reasonPhraseLength = random.Next(100);
StringBuilder reasonPhrase = new StringBuilder(reasonPhraseLength);
for (int i = 0; i != reasonPhraseLength; ++i)
{
if (random.NextBool())
reasonPhrase.Append(random.NextHttpTextChar());
else if (random.NextBool())
reasonPhrase.Append(' ');
else
reasonPhrase.Append('\t');
}
return new Datagram(EncodingExtensions.Iso88591.GetBytes(reasonPhrase.ToString()));
}
public static HttpRequestMethod NextHttpRequestMethod(this Random random)
{
HttpRequestKnownMethod knownMethod = random.NextEnum<HttpRequestKnownMethod>();
if (knownMethod == HttpRequestKnownMethod.Unknown)
return new HttpRequestMethod(random.NextHttpToken());
return new HttpRequestMethod(knownMethod);
}
public static string NextHttpToken(this Random random)
{
int tokenLength = random.Next(1, 100);
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i != tokenLength; ++i)
stringBuilder.Append(random.NextHttpTokenChar());
return stringBuilder.ToString();
}
public static char NextHttpTokenChar(this Random random)
{
char result;
do
{
result = random.NextChar((char)33, (char)127);
} while (new[] {'(', ')', '<', '>', '@', ',', ';', ':', '\\', '"', '/', '[', ']', '?', '=', '{', '}'}.Contains(result));
return result;
}
public static string NextHttpFieldValue(this Random random)
{
int valueLength = random.Next(1, 100);
StringBuilder stringBuilder = new StringBuilder();
while (stringBuilder.Length < valueLength)
{
switch (random.Next(3))
{
case 0:
stringBuilder.Append(random.NextHttpTextChar());
break;
case 1:
stringBuilder.Append(random.NextHttpQuotedString());
break;
case 2:
if (stringBuilder.Length > 0 && stringBuilder.Length < valueLength - 3)
stringBuilder.Append(random.NextHttpLinearWhiteSpace());
break;
}
}
return stringBuilder.ToString();
}
public static string NextHttpLinearWhiteSpace(this Random random)
{
StringBuilder stringBuilder = new StringBuilder();
if (random.NextBool())
stringBuilder.Append("\r\n");
stringBuilder.Append(random.NextBool() ? ' ' : '\t');
return stringBuilder.ToString();
}
public static char NextHttpTextChar(this Random random)
{
char text = random.NextChar((char)33, (char)254);
if (text == '"')
return (char)254;
if (text == 127)
return (char)255;
return text;
}
public static string NextHttpUri(this Random random)
{
int uriLength = random.Next(100);
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i != uriLength; ++i)
stringBuilder.Append(random.NextChar((char)33, (char)127));
return stringBuilder.ToString();
}
public static HttpVersion NextHttpVersion(this Random random)
{
return new HttpVersion(random.NextUInt(10000000), random.NextUInt(10000000));
}
public static HttpHeader NextHttpHeader(this Random random)
{
int numFields = random.Next(100);
List<HttpField> fields = new List<HttpField>(numFields);
HashSet<string> fieldNames = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
for (int i = 0; i != numFields; ++i)
{
fields.Add(random.NextHttpField(fieldNames));
fieldNames.Add(fields.Last().Name);
}
return new HttpHeader(fields);
}
public static HttpField NextHttpField(this Random random, HashSet<string> fieldNames)
{
const string unknownField = "Unknown Name";
List<string> allOptions = new List<string> { unknownField, HttpTransferEncodingField.FieldNameUpper, HttpContentLengthField.FieldNameUpper, HttpContentTypeField.FieldNameUpper };
List<string> possibleOptions = new List<string>(allOptions.Count);
foreach (string option in allOptions)
{
if (!fieldNames.Contains(option))
possibleOptions.Add(option);
}
string chosenOption = random.NextValue(possibleOptions);
switch (chosenOption)
{
case unknownField:
string fieldName;
do
{
fieldName = random.NextHttpToken();
} while (fieldNames.Contains(fieldName));
return HttpField.CreateField(fieldName, random.NextHttpFieldValue());
case HttpTransferEncodingField.FieldNameUpper:
int numTransferCodings = random.Next(1, 10);
List<string> transferCodings = new List<string>(numTransferCodings);
for (int i = 0; i != numTransferCodings; ++i)
transferCodings.Add(random.NextHttpTransferCoding());
return new HttpTransferEncodingField(transferCodings);
case HttpContentLengthField.FieldNameUpper:
return new HttpContentLengthField(random.NextUInt(1000));
case HttpContentTypeField.FieldNameUpper:
return new HttpContentTypeField(random.NextHttpToken(), random.NextHttpToken(), random.NextHttpFieldParameters());
default:
throw new InvalidOperationException("Invalid option " + chosenOption);
}
}
public static HttpFieldParameters NextHttpFieldParameters(this Random random)
{ {
int numParameters = random.Next(10); return new DataSegment(random.NextBytes(length));
List<KeyValuePair<string, string>> parameters = new List<KeyValuePair<string, string>>(numParameters);
for (int i = 0; i != numParameters; ++i)
{
string parameterName = random.NextHttpToken();
while (parameters.Any(pair => pair.Key == parameterName))
parameterName = random.NextHttpToken();
parameters.Add(new KeyValuePair<string, string>(parameterName,
random.NextBool() ? random.NextHttpToken() : random.NextHttpQuotedString()));
}
return new HttpFieldParameters(parameters);
}
public static string NextHttpTransferCoding(this Random random)
{
if (random.NextBool())
return "chunked";
StringBuilder transferCoding = new StringBuilder(random.NextHttpToken());
int numParameters = random.Next(5);
for (int i = 0; i != numParameters; ++i)
{
transferCoding.Append(';');
transferCoding.Append(random.NextHttpToken());
transferCoding.Append('=');
if (random.NextBool())
transferCoding.Append(random.NextHttpToken());
else
transferCoding.Append(random.NextHttpQuotedString());
}
return transferCoding.ToString();
}
public static string NextHttpQuotedString(this Random random)
{
StringBuilder quotedString = new StringBuilder();
quotedString.Append('"');
int numQuotedValues = random.Next(100);
for (int i = 0; i != numQuotedValues; ++i)
{
char quotedValue = random.NextHttpTextChar();
if (quotedValue != '\\')
quotedString.Append(quotedValue);
else
{
quotedString.Append('\\');
quotedString.Append(random.NextChar((char)0, (char)128));
}
}
quotedString.Append('"');
return quotedString.ToString();
}
public static Datagram NextHttpBody(this Random random, bool isRequest, uint? statusCode, HttpHeader httpHeader)
{
if (isRequest && httpHeader.ContentLength == null ||
!isRequest && statusCode >= 100 && statusCode <= 199 || statusCode == 204 || statusCode == 205 || statusCode == 304)
return Datagram.Empty;
if (httpHeader.TransferEncoding != null &&
httpHeader.TransferEncoding.TransferCodings.Any(coding => coding != "identity"))
{
// chunked
List<byte> chunkedBody = new List<byte>();
int numChunks = random.Next(10);
for (int i = 0; i != numChunks; ++i)
{
int chunkSize = random.Next(1, 1000);
chunkedBody.AddRange(Encoding.ASCII.GetBytes(chunkSize.ToString("x")));
var chunkExtension = random.NextHttpFieldParameters();
foreach (var parameter in chunkExtension)
{
chunkedBody.Add((byte)';');
chunkedBody.AddRange(Encoding.ASCII.GetBytes(parameter.Key));
chunkedBody.Add((byte)'=');
chunkedBody.AddRange(EncodingExtensions.Iso88591.GetBytes(parameter.Key));
}
chunkedBody.AddRange(Encoding.ASCII.GetBytes("\r\n"));
chunkedBody.AddRange(random.NextDatagram(chunkSize));
chunkedBody.AddRange(Encoding.ASCII.GetBytes("\r\n"));
}
int numZeros = random.Next(1, 10);
for (int i = 0; i != numZeros; ++i)
chunkedBody.Add((byte)'0');
var lastChunkExtension = random.NextHttpFieldParameters();
foreach (var parameter in lastChunkExtension)
{
chunkedBody.Add((byte)';');
chunkedBody.AddRange(Encoding.ASCII.GetBytes(parameter.Key));
chunkedBody.Add((byte)'=');
chunkedBody.AddRange(EncodingExtensions.Iso88591.GetBytes(parameter.Key));
}
chunkedBody.AddRange(Encoding.ASCII.GetBytes("\r\n"));
var trailer = random.NextHttpHeader();
byte[] trailerBuffer = new byte[trailer.BytesLength];
trailer.Write(trailerBuffer, 0);
chunkedBody.AddRange(trailerBuffer);
return new Datagram(chunkedBody.ToArray());
}
if (httpHeader.ContentLength != null)
{
return random.NextDatagram(random.Next((int)(httpHeader.ContentLength.ContentLength + 1)));
}
if (httpHeader.ContentType != null &&
httpHeader.ContentType.MediaType == "multipart" &&
httpHeader.ContentType.MediaSubtype == "byteranges" &&
httpHeader.ContentType.Parameters["boundary"] != null)
{
List<byte> boundedBody = new List<byte>(random.NextDatagram(random.Next(1000)));
boundedBody.AddRange(EncodingExtensions.Iso88591.GetBytes("--" + httpHeader.ContentType.Parameters["boundary"] + "--"));
return new Datagram(boundedBody.ToArray());
}
return random.NextDatagram(random.Next(1000));
} }
} }
} }
using System;
using System.Collections.Generic;
using PcapDotNet.Packets.Transport;
using PcapDotNet.TestUtils;
namespace PcapDotNet.Packets.TestUtils
{
public static class RandomTcpExtensions
{
public static TcpLayer NextTcpLayer(this Random random)
{
return new TcpLayer
{
SourcePort = random.NextUShort(),
DestinationPort = random.NextUShort(),
SequenceNumber = random.NextUInt(),
AcknowledgmentNumber = random.NextUInt(),
ControlBits = random.NextFlags<TcpControlBits>(),
Window = random.NextUShort(),
UrgentPointer = random.NextUShort(),
Options = random.NextTcpOptions(),
};
}
public static TcpOptions NextTcpOptions(this Random random)
{
int optionsLength = random.Next(TcpOptions.MaximumBytesLength) / 4 * 4;
List<TcpOption> options = new List<TcpOption>();
while (optionsLength > 0)
{
TcpOption option = random.NextTcpOption(optionsLength);
if (option.IsAppearsAtMostOnce &&
options.FindIndex(option.Equivalent) != -1)
{
continue;
}
options.Add(option);
optionsLength -= option.Length;
if (option.OptionType == TcpOptionType.EndOfOptionList)
break;
}
return new TcpOptions(options);
}
public static TcpOptionUnknown NextTcpOptionUnknown(this Random random, int maximumOptionLength)
{
TcpOptionType unknownOptionType;
byte unknownOptionTypeValue;
do
{
unknownOptionTypeValue = random.NextByte();
unknownOptionType = (TcpOptionType)unknownOptionTypeValue;
} while (unknownOptionType.ToString() != unknownOptionTypeValue.ToString());
byte[] unknownOptionData = random.NextBytes(maximumOptionLength - TcpOptionUnknown.OptionMinimumLength + 1);
return new TcpOptionUnknown(unknownOptionType, unknownOptionData);
}
public static TcpOption NextTcpOption(this Random random, int maximumOptionLength)
{
if (maximumOptionLength == 0)
throw new ArgumentOutOfRangeException("maximumOptionLength", maximumOptionLength, "option length must be positive");
if (maximumOptionLength >= TcpOptionUnknown.OptionMinimumLength && random.Next(100) > 90)
return random.NextTcpOptionUnknown(maximumOptionLength);
List<TcpOptionType> impossibleOptionTypes = new List<TcpOptionType>();
if (maximumOptionLength < TcpOptionMaximumSegmentSize.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.MaximumSegmentSize);
if (maximumOptionLength < TcpOptionWindowScale.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.WindowScale);
if (maximumOptionLength < TcpOptionSelectiveAcknowledgment.OptionMinimumLength)
impossibleOptionTypes.Add(TcpOptionType.SelectiveAcknowledgment);
if (maximumOptionLength < TcpOptionSelectiveAcknowledgmentPermitted.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.SelectiveAcknowledgmentPermitted);
if (maximumOptionLength < TcpOptionEcho.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.Echo);
if (maximumOptionLength < TcpOptionEchoReply.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.EchoReply);
if (maximumOptionLength < TcpOptionTimestamp.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.Timestamp);
if (maximumOptionLength < TcpOptionPartialOrderServiceProfile.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.PartialOrderServiceProfile);
if (maximumOptionLength < TcpOptionPartialOrderConnectionPermitted.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.PartialOrderConnectionPermitted);
if (maximumOptionLength < TcpOptionConnectionCountBase.OptionLength)
{
impossibleOptionTypes.Add(TcpOptionType.ConnectionCount);
impossibleOptionTypes.Add(TcpOptionType.ConnectionCountNew);
impossibleOptionTypes.Add(TcpOptionType.ConnectionCountEcho);
}
if (maximumOptionLength < TcpOptionAlternateChecksumRequest.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.AlternateChecksumRequest);
if (maximumOptionLength < TcpOptionAlternateChecksumData.OptionMinimumLength)
impossibleOptionTypes.Add(TcpOptionType.AlternateChecksumData);
if (maximumOptionLength < TcpOptionMd5Signature.OptionLength)
impossibleOptionTypes.Add(TcpOptionType.Md5Signature);
if (maximumOptionLength < TcpOptionMood.OptionMaximumLength)
impossibleOptionTypes.Add(TcpOptionType.Mood);
impossibleOptionTypes.Add(TcpOptionType.QuickStartResponse);
impossibleOptionTypes.Add(TcpOptionType.UserTimeout);
TcpOptionType optionType = random.NextEnum<TcpOptionType>(impossibleOptionTypes);
switch (optionType)
{
case TcpOptionType.EndOfOptionList:
return TcpOption.End;
case TcpOptionType.NoOperation:
return TcpOption.Nop;
case TcpOptionType.MaximumSegmentSize:
return new TcpOptionMaximumSegmentSize(random.NextUShort());
case TcpOptionType.WindowScale:
return new TcpOptionWindowScale(random.NextByte());
case TcpOptionType.SelectiveAcknowledgment:
int numBlocks = random.Next((maximumOptionLength - TcpOptionSelectiveAcknowledgment.OptionMinimumLength) / 8 + 1);
TcpOptionSelectiveAcknowledgmentBlock[] blocks = new TcpOptionSelectiveAcknowledgmentBlock[numBlocks];
for (int i = 0; i != numBlocks; ++i)
blocks[i] = new TcpOptionSelectiveAcknowledgmentBlock(random.NextUInt(), random.NextUInt());
return new TcpOptionSelectiveAcknowledgment(blocks);
case TcpOptionType.SelectiveAcknowledgmentPermitted:
return new TcpOptionSelectiveAcknowledgmentPermitted();
case TcpOptionType.Echo:
return new TcpOptionEcho(random.NextUInt());
case TcpOptionType.EchoReply:
return new TcpOptionEchoReply(random.NextUInt());
case TcpOptionType.Timestamp:
return new TcpOptionTimestamp(random.NextUInt(), random.NextUInt());
case TcpOptionType.PartialOrderServiceProfile:
return new TcpOptionPartialOrderServiceProfile(random.NextBool(), random.NextBool());
case TcpOptionType.PartialOrderConnectionPermitted:
return new TcpOptionPartialOrderConnectionPermitted();
case TcpOptionType.ConnectionCount:
return new TcpOptionConnectionCount(random.NextUInt());
case TcpOptionType.ConnectionCountEcho:
return new TcpOptionConnectionCountEcho(random.NextUInt());
case TcpOptionType.ConnectionCountNew:
return new TcpOptionConnectionCountNew(random.NextUInt());
case TcpOptionType.AlternateChecksumRequest:
return new TcpOptionAlternateChecksumRequest(random.NextEnum<TcpOptionAlternateChecksumType>());
case TcpOptionType.AlternateChecksumData:
return new TcpOptionAlternateChecksumData(random.NextBytes(random.Next(maximumOptionLength - TcpOptionAlternateChecksumData.OptionMinimumLength + 1)));
case TcpOptionType.Md5Signature:
return new TcpOptionMd5Signature(random.NextBytes(TcpOptionMd5Signature.OptionValueLength));
case TcpOptionType.Mood:
return new TcpOptionMood(random.NextEnum(TcpOptionMoodEmotion.None));
default:
throw new InvalidOperationException("optionType = " + optionType);
}
}
}
}
\ No newline at end of file
using System;
using PcapDotNet.Packets.Transport;
using PcapDotNet.TestUtils;
namespace PcapDotNet.Packets.TestUtils
{
public static class RandomUdpExtensions
{
public static UdpLayer NextUdpLayer(this Random random)
{
return new UdpLayer
{
Checksum = random.NextUShort(),
SourcePort = random.NextUShort(),
DestinationPort = random.NextUShort(),
CalculateChecksumValue = random.NextBool()
};
}
}
}
\ No newline at end of file
...@@ -130,9 +130,17 @@ namespace PcapDotNet.Packets ...@@ -130,9 +130,17 @@ namespace PcapDotNet.Packets
return encoding.GetString(Buffer, StartOffset, Length); return encoding.GetString(Buffer, StartOffset, Length);
} }
internal void Write(byte[] buffer, int offset) public static DataSegment Empty { get { return _empty; } }
internal void Write(byte[] buffer, ref int offset)
{ {
Buffer.BlockCopy(StartOffset, buffer, offset, Length); Buffer.BlockCopy(StartOffset, buffer, offset, Length);
offset += Length;
}
internal void Write(byte[] buffer, int offset)
{
Write(buffer, ref offset);
} }
/// <summary> /// <summary>
...@@ -157,9 +165,16 @@ namespace PcapDotNet.Packets ...@@ -157,9 +165,16 @@ namespace PcapDotNet.Packets
return Buffer.ReadBytes(StartOffset + offset, length); return Buffer.ReadBytes(StartOffset + offset, length);
} }
internal DataSegment SubSegment(ref int offset, int length)
{
DataSegment subSegemnt = new DataSegment(Buffer, StartOffset + offset, length);
offset += length;
return subSegemnt;
}
internal DataSegment SubSegment(int offset, int length) internal DataSegment SubSegment(int offset, int length)
{ {
return new DataSegment(Buffer, StartOffset + offset, length); return SubSegment(ref offset, length);
} }
internal bool ReadBool(int offset, byte mask) internal bool ReadBool(int offset, byte mask)
...@@ -198,7 +213,7 @@ namespace PcapDotNet.Packets ...@@ -198,7 +213,7 @@ namespace PcapDotNet.Packets
/// <param name="endianity">The endianity to use to translate the bytes to the value.</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> /// <returns>The value converted from the read bytes according to the endianity.</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "uint")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "uint")]
protected uint ReadUInt(int offset, Endianity endianity) internal uint ReadUInt(int offset, Endianity endianity)
{ {
return Buffer.ReadUInt(StartOffset + offset, endianity); return Buffer.ReadUInt(StartOffset + offset, endianity);
} }
...@@ -278,5 +293,7 @@ namespace PcapDotNet.Packets ...@@ -278,5 +293,7 @@ namespace PcapDotNet.Packets
sum += (ushort)(buffer[offset] << 8); sum += (ushort)(buffer[offset] << 8);
return sum; return sum;
} }
private static readonly DataSegment _empty = new DataSegment(new byte[0]);
} }
} }
\ No newline at end of file
...@@ -68,7 +68,7 @@ namespace PcapDotNet.Packets.Dns ...@@ -68,7 +68,7 @@ namespace PcapDotNet.Packets.Dns
numBytesRead += MinimumLengthAfterBase; numBytesRead += MinimumLengthAfterBase;
if (offsetInDns + numBytesRead + dataLength > dns.Length) if (offsetInDns + numBytesRead + dataLength > dns.Length)
return null; return null;
DnsResourceData data = DnsResourceData.Read(type, dnsClass, dns.SubSegment(offsetInDns + numBytesRead, dataLength)); DnsResourceData data = DnsResourceData.Read(dns, type, dnsClass, offsetInDns + numBytesRead, dataLength);
if (data == null) if (data == null)
return null; return null;
numBytesRead += dataLength; numBytesRead += dataLength;
......
...@@ -13,7 +13,7 @@ namespace PcapDotNet.Packets.Dns ...@@ -13,7 +13,7 @@ namespace PcapDotNet.Packets.Dns
{ {
private const byte MaxLabelLength = 63; private const byte MaxLabelLength = 63;
private const ushort CompressionMarker = 0xC000; private const ushort CompressionMarker = 0xC000;
private const ushort OffsetMask = 0x3FFF; internal const ushort OffsetMask = 0x3FFF;
private static readonly char[] Colon = new[] {'.'}; private static readonly char[] Colon = new[] {'.'};
public DnsDomainName(string domainName) public DnsDomainName(string domainName)
...@@ -22,6 +22,8 @@ namespace PcapDotNet.Packets.Dns ...@@ -22,6 +22,8 @@ namespace PcapDotNet.Packets.Dns
_labels = labels.Select(label => new DataSegment(Encoding.UTF8.GetBytes(label))).ToList(); _labels = labels.Select(label => new DataSegment(Encoding.UTF8.GetBytes(label))).ToList();
} }
public static DnsDomainName Root { get { return _root; } }
public int NumLabels public int NumLabels
{ {
get get
...@@ -61,11 +63,16 @@ namespace PcapDotNet.Packets.Dns ...@@ -61,11 +63,16 @@ namespace PcapDotNet.Packets.Dns
return length + sizeof(byte); return length + sizeof(byte);
} }
internal static DnsDomainName Parse(DnsDatagram dns, int offsetInDns, out int numBytesRead) internal static bool TryParse(DnsDatagram dns, int offsetInDns, int maximumLength, out DnsDomainName domainName, out int numBytesRead)
{ {
List<DataSegment> labels = new List<DataSegment>(); List<DataSegment> labels = new List<DataSegment>();
ReadLabels(dns, offsetInDns, out numBytesRead, labels); if (!TryReadLabels(dns, offsetInDns, out numBytesRead, labels) || numBytesRead > maximumLength)
return new DnsDomainName(labels); {
domainName = null;
return false;
}
domainName = new DnsDomainName(labels);
return true;
} }
internal int Write(byte[] buffer, int dnsOffset, DnsDomainNameCompressionData compressionData, int offsetInDns) internal int Write(byte[] buffer, int dnsOffset, DnsDomainNameCompressionData compressionData, int offsetInDns)
...@@ -95,40 +102,45 @@ namespace PcapDotNet.Packets.Dns ...@@ -95,40 +102,45 @@ namespace PcapDotNet.Packets.Dns
_labels = labels; _labels = labels;
} }
private static void ReadLabels(DnsDatagram dns, int offsetInDns, out int numBytesRead, List<DataSegment> labels) private static bool TryReadLabels(DnsDatagram dns, int offsetInDns, out int numBytesRead, List<DataSegment> labels)
{ {
numBytesRead = 0; numBytesRead = 0;
byte labelLength; byte labelLength;
do do
{ {
if (offsetInDns >= dns.Length) if (offsetInDns >= dns.Length)
return; return false; // Can't read label's length.
labelLength = dns[offsetInDns]; labelLength = dns[offsetInDns];
++numBytesRead; ++numBytesRead;
if (labelLength > MaxLabelLength) if (labelLength > MaxLabelLength)
{ {
// Compression. // Compression.
if (offsetInDns + 1 >= dns.Length) if (offsetInDns + 1 >= dns.Length)
return; return false; // Can't read compression pointer.
offsetInDns = dns.ReadUShort(offsetInDns, Endianity.Big) & OffsetMask; int newOffsetInDns = dns.ReadUShort(offsetInDns, Endianity.Big) & OffsetMask;
if (newOffsetInDns >= offsetInDns)
return false; // Can't handle pointers that are not back pointers.
++numBytesRead; ++numBytesRead;
int internalBytesRead; int internalBytesRead;
ReadLabels(dns, offsetInDns, out internalBytesRead, labels); return TryReadLabels(dns, newOffsetInDns, out internalBytesRead, labels);
return;
} }
if (labelLength != 0) if (labelLength != 0)
{ {
++offsetInDns; ++offsetInDns;
if (offsetInDns + labelLength >= dns.Length) if (offsetInDns + labelLength >= dns.Length)
return; return false; // Can't read label.
labels.Add(dns.SubSegment(offsetInDns, labelLength)); labels.Add(dns.SubSegment(offsetInDns, labelLength));
numBytesRead += labelLength; numBytesRead += labelLength;
offsetInDns += labelLength; offsetInDns += labelLength;
} }
} while (labelLength != 0); } while (labelLength != 0);
return true;
} }
private static readonly DnsDomainName _root = new DnsDomainName("");
private readonly List<DataSegment> _labels; private readonly List<DataSegment> _labels;
private string _ascii; private string _ascii;
} }
......
...@@ -36,6 +36,9 @@ namespace PcapDotNet.Packets.Dns ...@@ -36,6 +36,9 @@ namespace PcapDotNet.Packets.Dns
public void AddCompressionData(ListSegment<DataSegment> labels, int dnsOffset) public void AddCompressionData(ListSegment<DataSegment> labels, int dnsOffset)
{ {
if (dnsOffset > DnsDomainName.OffsetMask)
return;
switch (DomainNameCompressionMode) switch (DomainNameCompressionMode)
{ {
case DnsDomainNameCompressionMode.All: case DnsDomainNameCompressionMode.All:
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using PcapDotNet.Base; using PcapDotNet.Base;
using PcapDotNet.Packets.IpV4; using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Packets.Dns namespace PcapDotNet.Packets.Dns
{ {
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
internal class DnsTypeRegistrationAttribute : Attribute internal class DnsTypeRegistrationAttribute : Attribute
{ {
public DnsType Type { get; set; } public DnsType Type { get; set; }
...@@ -34,15 +35,15 @@ namespace PcapDotNet.Packets.Dns ...@@ -34,15 +35,15 @@ namespace PcapDotNet.Packets.Dns
internal abstract int WriteData(byte[] buffer, int dnsOffset, int offsetInDns, DnsDomainNameCompressionData compressionData); internal abstract int WriteData(byte[] buffer, int dnsOffset, int offsetInDns, DnsDomainNameCompressionData compressionData);
internal static DnsResourceData Read(DnsType type, DnsClass dnsClass, DataSegment data) internal static DnsResourceData Read(DnsDatagram dns, DnsType type, DnsClass dnsClass, int offsetInDns, int length)
{ {
DnsResourceData prototype = TryGetPrototype(type, dnsClass); DnsResourceData prototype = TryGetPrototype(type, dnsClass);
if (prototype != null) if (prototype != null)
return prototype.CreateInstance(data); return prototype.CreateInstance(dns, offsetInDns, length);
return new DnsResourceDataUnknown(data); return new DnsResourceDataAnything(dns.SubSegment(offsetInDns, length));
} }
internal abstract DnsResourceData CreateInstance(DataSegment data); internal abstract DnsResourceData CreateInstance(DnsDatagram dns, int offsetInDns, int length);
private static DnsResourceData TryGetPrototype(DnsType type, DnsClass dnsClass) private static DnsResourceData TryGetPrototype(DnsType type, DnsClass dnsClass)
{ {
...@@ -56,13 +57,13 @@ namespace PcapDotNet.Packets.Dns ...@@ -56,13 +57,13 @@ namespace PcapDotNet.Packets.Dns
{ {
var prototypes = var prototypes =
from type in Assembly.GetExecutingAssembly().GetTypes() from type in Assembly.GetExecutingAssembly().GetTypes()
where typeof(DnsResourceData).IsAssignableFrom(type) && from attribute in type.GetCustomAttributes<DnsTypeRegistrationAttribute>(false)
type.GetCustomAttributes<DnsTypeRegistrationAttribute>(false).Any() where typeof(DnsResourceData).IsAssignableFrom(type)
select new select new
{ {
type.GetCustomAttributes<DnsTypeRegistrationAttribute>(false).First().Type, attribute.Type,
Prototype = (DnsResourceData)Activator.CreateInstance(type), Prototype = (DnsResourceData)Activator.CreateInstance(type),
}; };
return prototypes.ToDictionary(prototype => prototype.Type, prototype => prototype.Prototype); return prototypes.ToDictionary(prototype => prototype.Type, prototype => prototype.Prototype);
} }
...@@ -96,12 +97,20 @@ namespace PcapDotNet.Packets.Dns ...@@ -96,12 +97,20 @@ namespace PcapDotNet.Packets.Dns
} }
internal abstract void WriteDataSimple(byte[] buffer, int offset); internal abstract void WriteDataSimple(byte[] buffer, int offset);
internal sealed override DnsResourceData CreateInstance(DnsDatagram dns, int offsetInDns, int length)
{
return CreateInstance(dns.SubSegment(offsetInDns, length));
}
internal abstract DnsResourceData CreateInstance(DataSegment data);
} }
[DnsTypeRegistration(Type = DnsType.A)] [DnsTypeRegistration(Type = DnsType.A)]
public class DnsResourceDataIpV4 : DnsResourceDataSimple, IEquatable<DnsResourceDataIpV4> public sealed class DnsResourceDataIpV4 : DnsResourceDataSimple, IEquatable<DnsResourceDataIpV4>
{ {
public DnsResourceDataIpV4() public DnsResourceDataIpV4()
: this(IpV4Address.Zero)
{ {
} }
...@@ -117,25 +126,780 @@ namespace PcapDotNet.Packets.Dns ...@@ -117,25 +126,780 @@ namespace PcapDotNet.Packets.Dns
return other != null && Data.Equals(other.Data); return other != null && Data.Equals(other.Data);
} }
public sealed override bool Equals(DnsResourceData other) public override bool Equals(DnsResourceData other)
{ {
return Equals(other as DnsResourceDataIpV4); return Equals(other as DnsResourceDataIpV4);
} }
internal sealed override int GetLength() internal override int GetLength()
{ {
return IpV4Address.SizeOf; return IpV4Address.SizeOf;
} }
internal sealed override void WriteDataSimple(byte[] buffer, int offset) internal override void WriteDataSimple(byte[] buffer, int offset)
{ {
buffer.Write(offset, Data, Endianity.Big); buffer.Write(offset, Data, Endianity.Big);
} }
internal sealed override DnsResourceData CreateInstance(DataSegment data) internal override DnsResourceData CreateInstance(DataSegment data)
{ {
if (data.Length != IpV4Address.SizeOf)
return null;
return new DnsResourceDataIpV4(data.ReadIpV4Address(0, Endianity.Big)); return new DnsResourceDataIpV4(data.ReadIpV4Address(0, Endianity.Big));
} }
}
[DnsTypeRegistration(Type = DnsType.Ns)]
[DnsTypeRegistration(Type = DnsType.Md)]
[DnsTypeRegistration(Type = DnsType.Mf)]
[DnsTypeRegistration(Type = DnsType.CName)]
[DnsTypeRegistration(Type = DnsType.Mb)]
[DnsTypeRegistration(Type = DnsType.Mg)]
[DnsTypeRegistration(Type = DnsType.Mr)]
[DnsTypeRegistration(Type = DnsType.Ptr)]
public sealed class DnsResourceDataDomainName : DnsResourceData, IEquatable<DnsResourceDataDomainName>
{
public DnsResourceDataDomainName()
: this(DnsDomainName.Root)
{
}
public DnsResourceDataDomainName(DnsDomainName data)
{
Data = data;
}
public DnsDomainName Data { get; private set; }
public bool Equals(DnsResourceDataDomainName other)
{
return other != null && Data.Equals(other.Data);
}
public override bool Equals(DnsResourceData other)
{
return Equals(other as DnsResourceDataDomainName);
}
internal override int GetLength(DnsDomainNameCompressionData compressionData, int offsetInDns)
{
return Data.GetLength(compressionData, offsetInDns);
}
internal override int WriteData(byte[] buffer, int dnsOffset, int offsetInDns, DnsDomainNameCompressionData compressionData)
{
return Data.Write(buffer, dnsOffset, compressionData, offsetInDns);
}
internal override DnsResourceData CreateInstance(DnsDatagram dns, int offsetInDns, int length)
{
int numBytesRead;
DnsDomainName domainName;
if (!DnsDomainName.TryParse(dns, offsetInDns, length, out domainName, out numBytesRead))
return null;
length -= numBytesRead;
if (length != 0)
return null;
return new DnsResourceDataDomainName(domainName);
}
}
/// <summary>
/// +-------+---------+
/// | bit | 0-31 |
/// +-------+---------+
/// | 0 | MNAME |
/// +-------+---------+
/// | X | RNAME |
/// +-------+---------+
/// | Y | SERIAL |
/// +-------+---------+
/// | Y+32 | REFRESH |
/// +-------+---------+
/// | Y+64 | RETRY |
/// +-------+---------+
/// | Y+96 | EXPIRE |
/// +-------+---------+
/// | Y+128 | MINIMUM |
/// +-------+---------+
/// </summary>
[DnsTypeRegistration(Type = DnsType.Soa)]
public sealed class DnsResourceDataStartOfAuthority : DnsResourceData, IEquatable<DnsResourceDataStartOfAuthority>
{
private static class Offset
{
public const int Serial = 0;
public const int Refresh = Serial + sizeof(uint);
public const int Retry = Refresh + sizeof(uint);
public const int Expire = Retry + sizeof(uint);
public const int MinimumTtl = Expire + sizeof(uint);
}
private const int ConstantPartLength = Offset.MinimumTtl + sizeof(uint);
public DnsResourceDataStartOfAuthority()
: this(DnsDomainName.Root, DnsDomainName.Root, 0, 0, 0, 0, 0)
{
}
public DnsResourceDataStartOfAuthority(DnsDomainName mainNameServer, DnsDomainName responsibleMailBox,
uint serial, uint refresh, uint retry, uint expire, uint minimumTtl)
{
MainNameServer = mainNameServer;
ResponsibleMailBox = responsibleMailBox;
Serial = serial;
Refresh = refresh;
Retry = retry;
Expire = expire;
MinimumTtl = minimumTtl;
}
/// <summary>
/// The domain-name of the name server that was the original or primary source of data for this zone.
/// </summary>
public DnsDomainName MainNameServer { get; private set; }
/// <summary>
/// A domain-name which specifies the mailbox of the person responsible for this zone.
/// </summary>
public DnsDomainName ResponsibleMailBox { get; private set; }
/// <summary>
/// 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>
public uint Serial { get; private set; }
/// <summary>
/// A 32 bit time interval before the zone should be refreshed.
/// </summary>
public uint Refresh { get; private set; }
/// <summary>
/// A 32 bit time interval that should elapse before a failed refresh should be retried.
/// </summary>
public uint Retry { get; private set; }
/// <summary>
/// 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>
public uint Expire { get; private set; }
/// <summary>
/// The unsigned 32 bit minimum TTL field that should be exported with any RR from this zone.
/// </summary>
public uint MinimumTtl { get; private set; }
public bool Equals(DnsResourceDataStartOfAuthority other)
{
return other != null &&
MainNameServer.Equals(other.MainNameServer) &&
ResponsibleMailBox.Equals(other.ResponsibleMailBox) &&
Serial.Equals(other.Serial) &&
Refresh.Equals(other.Refresh) &&
Retry.Equals(other.Retry) &&
Expire.Equals(other.Expire) &&
MinimumTtl.Equals(other.MinimumTtl);
}
public override bool Equals(DnsResourceData other)
{
return Equals(other as DnsResourceDataStartOfAuthority);
}
internal override int GetLength(DnsDomainNameCompressionData compressionData, int offsetInDns)
{
return MainNameServer.GetLength(compressionData, offsetInDns) +
ResponsibleMailBox.GetLength(compressionData, offsetInDns) +
ConstantPartLength;
}
internal override int WriteData(byte[] buffer, int dnsOffset, int offsetInDns, DnsDomainNameCompressionData compressionData)
{
int numBytesWritten = MainNameServer.Write(buffer, dnsOffset, compressionData, offsetInDns);
numBytesWritten += ResponsibleMailBox.Write(buffer, dnsOffset, compressionData, offsetInDns + numBytesWritten);
buffer.Write(dnsOffset + offsetInDns + numBytesWritten + Offset.Serial, Serial, Endianity.Big);
buffer.Write(dnsOffset + offsetInDns + numBytesWritten + Offset.Refresh, Refresh, Endianity.Big);
buffer.Write(dnsOffset + offsetInDns + numBytesWritten + Offset.Retry, Retry, Endianity.Big);
buffer.Write(dnsOffset + offsetInDns + numBytesWritten + Offset.Expire, Expire, Endianity.Big);
buffer.Write(dnsOffset + offsetInDns + numBytesWritten + Offset.MinimumTtl, MinimumTtl, Endianity.Big);
return numBytesWritten + ConstantPartLength;
}
internal override DnsResourceData CreateInstance(DnsDatagram dns, int offsetInDns, int length)
{
DnsDomainName mainNameServer;
int domainNameLength;
if (!DnsDomainName.TryParse(dns, offsetInDns, length, out mainNameServer, out domainNameLength))
return null;
offsetInDns += domainNameLength;
length -= domainNameLength;
DnsDomainName responsibleMailBox;
if (!DnsDomainName.TryParse(dns, offsetInDns, length, out responsibleMailBox, out domainNameLength))
return null;
offsetInDns += domainNameLength;
length -= domainNameLength;
if (length != ConstantPartLength)
return null;
uint serial = dns.ReadUInt(offsetInDns + Offset.Serial, Endianity.Big); ;
uint refresh = dns.ReadUInt(offsetInDns + Offset.Refresh, Endianity.Big); ;
uint retry = dns.ReadUInt(offsetInDns + Offset.Retry, Endianity.Big); ;
uint expire = dns.ReadUInt(offsetInDns + Offset.Expire, Endianity.Big); ;
uint minimumTtl = dns.ReadUInt(offsetInDns + Offset.MinimumTtl, Endianity.Big); ;
return new DnsResourceDataStartOfAuthority(mainNameServer, responsibleMailBox, serial, refresh, retry, expire, minimumTtl);
}
}
/// <summary>
/// +-----+----------+---------+
/// | bit | 0-7 | 8-31 |
/// +-----+----------+---------+
/// | 0 | Address |
/// +-----+----------+---------+
/// | 32 | Protocol | Bit Map | (Bit Map is variable multiple of 8 bits length)
/// +-----+----------+---------+
/// </summary>
[DnsTypeRegistration(Type = DnsType.Wks)]
public sealed class DnsResourceDataWellKnownService : DnsResourceDataSimple, IEquatable<DnsResourceDataWellKnownService>
{
private static class Offset
{
public const int Address = 0;
public const int Protocol = Address + IpV4Address.SizeOf;
public const int BitMap = Protocol + sizeof(byte);
}
private const int ConstantPartLength = Offset.BitMap;
public DnsResourceDataWellKnownService()
: this(IpV4Address.Zero, IpV4Protocol.Ip, DataSegment.Empty)
{
}
public DnsResourceDataWellKnownService(IpV4Address address, IpV4Protocol protocol, DataSegment bitMap)
{
Address = address;
Protocol = protocol;
BitMap = bitMap;
}
/// <summary>
/// The service address.
/// </summary>
public IpV4Address Address { get; private set; }
/// <summary>
/// Specifies an IP protocol number.
/// </summary>
public IpV4Protocol Protocol { get; private set; }
/// <summary>
/// Has one bit per port of the specified protocol.
/// </summary>
public DataSegment BitMap { get; private set; }
public bool Equals(DnsResourceDataWellKnownService other)
{
return other != null &&
Address.Equals(other.Address) &&
Protocol.Equals(other.Protocol) &&
BitMap.Equals(other.BitMap);
}
public override bool Equals(DnsResourceData other)
{
return Equals(other as DnsResourceDataWellKnownService);
}
internal override int GetLength()
{
return ConstantPartLength + BitMap.Length;
}
internal override void WriteDataSimple(byte[] buffer, int offset)
{
buffer.Write(offset + Offset.Address, Address, Endianity.Big);
buffer.Write(offset + Offset.Protocol, (byte)Protocol);
BitMap.Write(buffer, offset + Offset.BitMap);
}
internal override DnsResourceData CreateInstance(DataSegment data)
{
if (data.Length < ConstantPartLength)
return null;
IpV4Address address = data.ReadIpV4Address(Offset.Address, Endianity.Big);
IpV4Protocol protocol = (IpV4Protocol)data[Offset.Protocol];
DataSegment bitMap = data.SubSegment(Offset.BitMap, data.Length - Offset.BitMap);
return new DnsResourceDataWellKnownService(address, protocol, bitMap);
}
}
public abstract class DnsResourceDataStrings : DnsResourceDataSimple, IEquatable<DnsResourceDataStrings>
{
public bool Equals(DnsResourceDataStrings other)
{
return other != null &&
GetType() == other.GetType() &&
Strings.SequenceEqual(other.Strings);
}
public sealed override bool Equals(DnsResourceData other)
{
return Equals(other as DnsResourceDataStrings);
}
internal DnsResourceDataStrings(ReadOnlyCollection<DataSegment> strings)
{
Strings = strings;
}
internal DnsResourceDataStrings(params DataSegment[] strings)
: this(strings.AsReadOnly())
{
}
internal ReadOnlyCollection<DataSegment> Strings { get; private set; }
internal sealed override int GetLength()
{
return Strings.Sum(str => sizeof(byte) + str.Length);
}
internal sealed override void WriteDataSimple(byte[] buffer, int offset)
{
foreach (DataSegment str in Strings)
{
buffer.Write(ref offset, (byte)str.Length);
str.Write(buffer, ref offset);
}
}
internal static List<DataSegment> ReadStrings(DataSegment data, int numExpected = 0)
{
List<DataSegment> strings = new List<DataSegment>(numExpected);
int offset = 0;
while (offset != data.Length)
{
int stringLength = data[offset++];
if (data.Length < offset + stringLength)
return null;
strings.Add(data.SubSegment(ref offset, stringLength));
}
return strings;
}
}
/// <summary>
/// +-----+
/// | CPU |
/// +-----+
/// | OS |
/// +-----+
/// </summary>
[DnsTypeRegistration(Type = DnsType.HInfo)]
public sealed class DnsResourceDataHostInformation : DnsResourceDataStrings
{
private const int NumStrings = 2;
public DnsResourceDataHostInformation()
: this(DataSegment.Empty, DataSegment.Empty)
{
}
public DnsResourceDataHostInformation(DataSegment cpu, DataSegment os)
: base(cpu, os)
{
}
public DataSegment Cpu { get { return Strings[0]; } }
public DataSegment Os { get { return Strings[1]; } }
internal override DnsResourceData CreateInstance(DataSegment data)
{
List<DataSegment> strings = ReadStrings(data, NumStrings);
if (strings == null || strings.Count != NumStrings)
return null;
return new DnsResourceDataHostInformation(strings[0], strings[1]);
}
}
public abstract class DnsResourceDataDomainNames : DnsResourceData, IEquatable<DnsResourceDataDomainNames>
{
public bool Equals(DnsResourceDataDomainNames other)
{
return other != null &&
GetType() == other.GetType() &&
DomainNames.SequenceEqual(other.DomainNames);
}
public sealed override bool Equals(DnsResourceData other)
{
return Equals(other as DnsResourceDataDomainNames);
}
internal DnsResourceDataDomainNames(ReadOnlyCollection<DnsDomainName> domainNames)
{
DomainNames = domainNames;
}
internal DnsResourceDataDomainNames(params DnsDomainName[] domainNames)
: this(domainNames.AsReadOnly())
{
}
internal ReadOnlyCollection<DnsDomainName> DomainNames { get; private set; }
internal override int GetLength(DnsDomainNameCompressionData compressionData, int offsetInDns)
{
int totalLength = 0;
foreach (DnsDomainName domainName in DomainNames)
{
int length = domainName.GetLength(compressionData, offsetInDns);
offsetInDns += length;
totalLength += length;
}
return totalLength;
}
internal override int WriteData(byte[] buffer, int dnsOffset, int offsetInDns, DnsDomainNameCompressionData compressionData)
{
int numBytesWritten = 0;
foreach (DnsDomainName domainName in DomainNames)
numBytesWritten += domainName.Write(buffer, dnsOffset, compressionData, offsetInDns + numBytesWritten);
return numBytesWritten;
}
internal static List<DnsDomainName> ReadDomainNames(DnsDatagram dns, int offsetInDns, int length, int numExpected = 0)
{
List<DnsDomainName> domainNames = new List<DnsDomainName>(numExpected);
while (length != 0)
{
DnsDomainName domainName;
int domainNameLength;
if (!DnsDomainName.TryParse(dns, offsetInDns, length, out domainName, out domainNameLength))
return null;
offsetInDns += domainNameLength;
length -= domainNameLength;
domainNames.Add(domainName);
}
return domainNames;
}
}
public abstract class DnsResourceData2DomainNames : DnsResourceDataDomainNames
{
private const int NumDomains = 2;
public DnsResourceData2DomainNames(DnsDomainName first, DnsDomainName second)
: base(first, second)
{
}
internal DnsDomainName First { get { return DomainNames[0]; } }
internal DnsDomainName Second { get { return DomainNames[1]; } }
internal static bool TryRead(out DnsDomainName first, out DnsDomainName second,
DnsDatagram dns, int offsetInDns, int length)
{
List<DnsDomainName> domainNames = ReadDomainNames(dns, offsetInDns, length, NumDomains);
if (domainNames == null || domainNames.Count != NumDomains)
{
first = null;
second = null;
return false;
}
first = domainNames[0];
second = domainNames[1];
return true;
}
}
/// <summary>
/// +---------+
/// | RMAILBX |
/// +---------+
/// | EMAILBX |
/// +---------+
/// </summary>
[DnsTypeRegistration(Type = DnsType.MInfo)]
public sealed class DnsResourceDataMailingListInfo : DnsResourceData2DomainNames
{
public DnsResourceDataMailingListInfo()
: this(DnsDomainName.Root, DnsDomainName.Root)
{
}
public DnsResourceDataMailingListInfo(DnsDomainName mailingList, DnsDomainName errorMailBox)
: base(mailingList, errorMailBox)
{
}
/// <summary>
/// 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.
/// </summary>
public DnsDomainName MailingList { get { return First; } }
/// <summary>
/// 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.
/// </summary>
public DnsDomainName ErrorMailBox { get { return Second; } }
internal override DnsResourceData CreateInstance(DnsDatagram dns, int offsetInDns, int length)
{
DnsDomainName mailingList;
DnsDomainName errorMailBox;
if (!TryRead(out mailingList, out errorMailBox, dns, offsetInDns, length))
return null;
return new DnsResourceDataMailingListInfo(mailingList, errorMailBox);
}
}
/// <summary>
/// +-----+--------+
/// | bit | 0-15 |
/// +-----+--------+
/// | 0 | Value |
/// +-----+--------+
/// | 16 | Domain |
/// +-----+--------+
/// </summary>
public abstract class DnsResourceDataUShortDomainName : DnsResourceData, IEquatable<DnsResourceDataUShortDomainName>
{
private static class Offset
{
public const int Value = 0;
public const int DomainName = Value + sizeof(ushort);
}
private const int ConstantPartLength = Offset.DomainName;
public bool Equals(DnsResourceDataUShortDomainName other)
{
return other != null &&
GetType().Equals(other.GetType()) &&
Value.Equals(other.Value) &&
DomainName.Equals(other.DomainName);
}
public override bool Equals(DnsResourceData other)
{
return Equals(other as DnsResourceDataUShortDomainName);
}
internal DnsResourceDataUShortDomainName(ushort value, DnsDomainName domainName)
{
Value = value;
DomainName = domainName;
}
internal ushort Value { get; private set; }
internal DnsDomainName DomainName { get; private set; }
internal override int GetLength(DnsDomainNameCompressionData compressionData, int offsetInDns)
{
return ConstantPartLength +
DomainName.GetLength(compressionData, offsetInDns);
}
internal override int WriteData(byte[] buffer, int dnsOffset, int offsetInDns, DnsDomainNameCompressionData compressionData)
{
buffer.Write(dnsOffset + offsetInDns + Offset.Value, Value, Endianity.Big);
int numBytesWritten = DomainName.Write(buffer, dnsOffset, compressionData, offsetInDns + Offset.DomainName);
return ConstantPartLength + numBytesWritten;
}
internal static bool TryRead(out ushort value, out DnsDomainName domainName,
DnsDatagram dns, int offsetInDns, int length)
{
if (length < ConstantPartLength)
{
value = 0;
domainName = null;
return false;
}
value = dns.ReadUShort(offsetInDns + Offset.Value, Endianity.Big);
length -= ConstantPartLength;
int domainNameLength;
if (!DnsDomainName.TryParse(dns, offsetInDns + Offset.DomainName, length, out domainName, out domainNameLength))
return false;
length -= domainNameLength;
if (length != 0)
return false;
return true;
}
}
/// <summary>
/// +-----+------------+
/// | bit | 0-15 |
/// +-----+------------+
/// | 0 | PREFERENCE |
/// +-----+------------+
/// | 16 | EXCHANGE |
/// +-----+------------+
/// </summary>
[DnsTypeRegistration(Type = DnsType.Mx)]
public sealed class DnsResourceDataMailExchange : DnsResourceDataUShortDomainName
{
public DnsResourceDataMailExchange()
: this(0, DnsDomainName.Root)
{
}
public DnsResourceDataMailExchange(ushort preference, DnsDomainName mailExchangeHost)
: base(preference, mailExchangeHost)
{
}
public ushort Preference { get { return Value; } }
public DnsDomainName MailExchangeHost { get { return DomainName; } }
internal override DnsResourceData CreateInstance(DnsDatagram dns, int offsetInDns, int length)
{
ushort preference;
DnsDomainName mailExchangeHost;
if (!TryRead(out preference, out mailExchangeHost, dns, offsetInDns, length))
return null;
return new DnsResourceDataMailExchange(preference, mailExchangeHost);
}
}
/// <summary>
/// +---------+
/// | Strings |
/// +---------+
/// </summary>
[DnsTypeRegistration(Type = DnsType.Txt)]
public sealed class DnsResourceDataText : DnsResourceDataStrings
{
public DnsResourceDataText()
{
}
public DnsResourceDataText(ReadOnlyCollection<DataSegment> strings)
: base(strings)
{
}
public ReadOnlyCollection<DataSegment> Text { get { return Strings; } }
internal override DnsResourceData CreateInstance(DataSegment data)
{
List<DataSegment> strings = ReadStrings(data);
return new DnsResourceDataText(strings.AsReadOnly());
}
}
/// <summary>
/// +------------+
/// | mbox-dname |
/// +------------+
/// | txt-dname |
/// +------------+
/// </summary>
[DnsTypeRegistration(Type = DnsType.Rp)]
public sealed class DnsResourceDataResponsiblePerson : DnsResourceData2DomainNames
{
public DnsResourceDataResponsiblePerson()
: this(DnsDomainName.Root, DnsDomainName.Root)
{
}
public DnsResourceDataResponsiblePerson(DnsDomainName mailBox, DnsDomainName textDomain)
: base(mailBox, textDomain)
{
}
/// <summary>
/// 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 MailBox to indicate that no mailbox is available.
/// </summary>
public DnsDomainName MailBox { get { return First; } }
/// <summary>
/// A domain name for which TXT RR's exist.
/// A subsequent query can be performed to retrieve the associated TXT resource records at TextDomain.
/// 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 TextDomain to indicate that the TXT_DNAME is absent, and no associated TXT RR exists.
/// </summary>
public DnsDomainName TextDomain { get { return Second; } }
internal override DnsResourceData CreateInstance(DnsDatagram dns, int offsetInDns, int length)
{
DnsDomainName mailBox;
DnsDomainName textDomain;
if (!TryRead(out mailBox, out textDomain, dns, offsetInDns, length))
return null;
return new DnsResourceDataResponsiblePerson(mailBox, textDomain);
}
}
/// <summary>
/// +-----+----------+
/// | bit | 0-15 |
/// +-----+----------+
/// | 0 | subtype |
/// +-----+----------+
/// | 16 | hostname |
/// +-----+----------+
/// </summary>
[DnsTypeRegistration(Type = DnsType.AfsDb)]
public sealed class DnsResourceDataAfsDb : DnsResourceDataUShortDomainName
{
public DnsResourceDataAfsDb()
: this(0, DnsDomainName.Root)
{
}
public DnsResourceDataAfsDb(ushort subType, DnsDomainName hostname)
: base(subType, hostname)
{
}
public ushort SubType { get { return Value; } }
public DnsDomainName Hostname { get { return DomainName; } }
internal override DnsResourceData CreateInstance(DnsDatagram dns, int offsetInDns, int length)
{
ushort subType;
DnsDomainName hostName;
if (!TryRead(out subType, out hostName, dns, offsetInDns, length))
return null;
return new DnsResourceDataAfsDb(subType, hostName);
}
} }
} }
\ No newline at end of file
...@@ -2,23 +2,29 @@ ...@@ -2,23 +2,29 @@
namespace PcapDotNet.Packets.Dns namespace PcapDotNet.Packets.Dns
{ {
public sealed class DnsResourceDataUnknown : DnsResourceDataSimple, IEquatable<DnsResourceDataUnknown> [DnsTypeRegistration(Type = DnsType.Null)]
public sealed class DnsResourceDataAnything : DnsResourceDataSimple, IEquatable<DnsResourceDataAnything>
{ {
public DnsResourceDataUnknown(DataSegment data) public DnsResourceDataAnything()
{
Data = DataSegment.Empty;
}
public DnsResourceDataAnything(DataSegment data)
{ {
Data = data; Data = data;
} }
public DataSegment Data { get; private set; } public DataSegment Data { get; private set; }
public bool Equals(DnsResourceDataUnknown other) public bool Equals(DnsResourceDataAnything other)
{ {
return other != null && Data.Equals(other.Data); return other != null && Data.Equals(other.Data);
} }
public sealed override bool Equals(DnsResourceData other) public override bool Equals(DnsResourceData other)
{ {
return Equals(other as DnsResourceDataUnknown); return Equals(other as DnsResourceDataAnything);
} }
internal override int GetLength() internal override int GetLength()
...@@ -33,7 +39,7 @@ namespace PcapDotNet.Packets.Dns ...@@ -33,7 +39,7 @@ namespace PcapDotNet.Packets.Dns
internal override DnsResourceData CreateInstance(DataSegment data) internal override DnsResourceData CreateInstance(DataSegment data)
{ {
return new DnsResourceDataUnknown(data); return new DnsResourceDataAnything(data);
} }
} }
} }
\ No newline at end of file
...@@ -36,7 +36,7 @@ namespace PcapDotNet.Packets.Dns ...@@ -36,7 +36,7 @@ namespace PcapDotNet.Packets.Dns
private const int MinimumLengthAfterDomainName = 4; private const int MinimumLengthAfterDomainName = 4;
public DnsResourceRecord(DnsDomainName domainName, DnsType type, DnsClass dnsClass) public DnsResourceRecord(DnsDomainName domainName, DnsType type, DnsClass dnsClass)
{ {
DomainName = domainName; DomainName = domainName;
Type = type; Type = type;
...@@ -51,7 +51,7 @@ namespace PcapDotNet.Packets.Dns ...@@ -51,7 +51,7 @@ namespace PcapDotNet.Packets.Dns
/// <summary> /// <summary>
/// Two octets containing one of the RR TYPE codes. /// Two octets containing one of the RR TYPE codes.
/// </summary> /// </summary>
public DnsType Type { get; private set;} public DnsType Type { get; private set; }
public DnsClass DnsClass { get; private set; } public DnsClass DnsClass { get; private set; }
...@@ -85,13 +85,12 @@ namespace PcapDotNet.Packets.Dns ...@@ -85,13 +85,12 @@ namespace PcapDotNet.Packets.Dns
DnsClass.Equals(other.DnsClass); DnsClass.Equals(other.DnsClass);
} }
internal static bool TryParseBase(DnsDatagram dns, int offsetInDns, internal static bool TryParseBase(DnsDatagram dns, int offsetInDns,
out DnsDomainName domainName, out DnsType type, out DnsClass dnsClass, out int numBytesRead) out DnsDomainName domainName, out DnsType type, out DnsClass dnsClass, out int numBytesRead)
{ {
type = DnsType.All; type = DnsType.All;
dnsClass = DnsClass.Any; dnsClass = DnsClass.Any;
domainName = DnsDomainName.Parse(dns, offsetInDns, out numBytesRead); if (!DnsDomainName.TryParse(dns, offsetInDns, dns.Length - offsetInDns, out domainName, out numBytesRead))
if (domainName == null)
return false; return false;
if (offsetInDns + numBytesRead + MinimumLengthAfterDomainName > dns.Length) if (offsetInDns + numBytesRead + MinimumLengthAfterDomainName > dns.Length)
......
...@@ -103,7 +103,7 @@ ...@@ -103,7 +103,7 @@
<Compile Include="Dns\DnsOpcode.cs" /> <Compile Include="Dns\DnsOpcode.cs" />
<Compile Include="Dns\DnsQueryResourceRecord.cs" /> <Compile Include="Dns\DnsQueryResourceRecord.cs" />
<Compile Include="Dns\DnsResourceData.cs" /> <Compile Include="Dns\DnsResourceData.cs" />
<Compile Include="Dns\DnsResourceDataUnknown.cs" /> <Compile Include="Dns\DnsResourceDataAnything.cs" />
<Compile Include="Dns\DnsResourceRecord.cs" /> <Compile Include="Dns\DnsResourceRecord.cs" />
<Compile Include="Dns\DnsResponseCode.cs" /> <Compile Include="Dns\DnsResponseCode.cs" />
<Compile Include="Dns\DnsType.cs" /> <Compile Include="Dns\DnsType.cs" />
......
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