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
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);
Assert.IsTrue(packet.IsValid, "IsValid");
// 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
dnsLayer.Queries.Add(new DnsQueryResourceRecord(new DnsDomainName(""), DnsType.All, DnsClass.In));
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);
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);
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);
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);
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);
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);
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);
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);
}
[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]
public void SimpleDnsTest()
{
......
......@@ -73,8 +73,19 @@
</ItemGroup>
<ItemGroup>
<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="Properties\AssemblyInfo.cs" />
<Compile Include="RandomTcpExtensions.cs" />
<Compile Include="RandomUdpExtensions.cs" />
</ItemGroup>
<ItemGroup>
<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.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;
namespace PcapDotNet.Packets.TestUtils
......@@ -46,1302 +32,9 @@ namespace PcapDotNet.Packets.TestUtils
};
}
// Ethernet
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())
public static DataSegment NextDataSegment(this Random random, int length)
{
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);
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));
return new DataSegment(random.NextBytes(length));
}
}
}
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
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);
offset += Length;
}
internal void Write(byte[] buffer, int offset)
{
Write(buffer, ref offset);
}
/// <summary>
......@@ -157,9 +165,16 @@ namespace PcapDotNet.Packets
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)
{
return new DataSegment(Buffer, StartOffset + offset, length);
return SubSegment(ref offset, length);
}
internal bool ReadBool(int offset, byte mask)
......@@ -198,7 +213,7 @@ namespace PcapDotNet.Packets
/// <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>
[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);
}
......@@ -278,5 +293,7 @@ namespace PcapDotNet.Packets
sum += (ushort)(buffer[offset] << 8);
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
numBytesRead += MinimumLengthAfterBase;
if (offsetInDns + numBytesRead + dataLength > dns.Length)
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)
return null;
numBytesRead += dataLength;
......
......@@ -13,7 +13,7 @@ namespace PcapDotNet.Packets.Dns
{
private const byte MaxLabelLength = 63;
private const ushort CompressionMarker = 0xC000;
private const ushort OffsetMask = 0x3FFF;
internal const ushort OffsetMask = 0x3FFF;
private static readonly char[] Colon = new[] {'.'};
public DnsDomainName(string domainName)
......@@ -22,6 +22,8 @@ namespace PcapDotNet.Packets.Dns
_labels = labels.Select(label => new DataSegment(Encoding.UTF8.GetBytes(label))).ToList();
}
public static DnsDomainName Root { get { return _root; } }
public int NumLabels
{
get
......@@ -61,11 +63,16 @@ namespace PcapDotNet.Packets.Dns
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>();
ReadLabels(dns, offsetInDns, out numBytesRead, labels);
return new DnsDomainName(labels);
if (!TryReadLabels(dns, offsetInDns, out numBytesRead, labels) || numBytesRead > maximumLength)
{
domainName = null;
return false;
}
domainName = new DnsDomainName(labels);
return true;
}
internal int Write(byte[] buffer, int dnsOffset, DnsDomainNameCompressionData compressionData, int offsetInDns)
......@@ -95,40 +102,45 @@ namespace PcapDotNet.Packets.Dns
_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;
byte labelLength;
do
{
if (offsetInDns >= dns.Length)
return;
return false; // Can't read label's length.
labelLength = dns[offsetInDns];
++numBytesRead;
if (labelLength > MaxLabelLength)
{
// Compression.
if (offsetInDns + 1 >= dns.Length)
return;
offsetInDns = dns.ReadUShort(offsetInDns, Endianity.Big) & OffsetMask;
return false; // Can't read compression pointer.
int newOffsetInDns = dns.ReadUShort(offsetInDns, Endianity.Big) & OffsetMask;
if (newOffsetInDns >= offsetInDns)
return false; // Can't handle pointers that are not back pointers.
++numBytesRead;
int internalBytesRead;
ReadLabels(dns, offsetInDns, out internalBytesRead, labels);
return;
return TryReadLabels(dns, newOffsetInDns, out internalBytesRead, labels);
}
if (labelLength != 0)
{
++offsetInDns;
if (offsetInDns + labelLength >= dns.Length)
return;
return false; // Can't read label.
labels.Add(dns.SubSegment(offsetInDns, labelLength));
numBytesRead += labelLength;
offsetInDns += labelLength;
}
} while (labelLength != 0);
return true;
}
private static readonly DnsDomainName _root = new DnsDomainName("");
private readonly List<DataSegment> _labels;
private string _ascii;
}
......
......@@ -36,6 +36,9 @@ namespace PcapDotNet.Packets.Dns
public void AddCompressionData(ListSegment<DataSegment> labels, int dnsOffset)
{
if (dnsOffset > DnsDomainName.OffsetMask)
return;
switch (DomainNameCompressionMode)
{
case DnsDomainNameCompressionMode.All:
......
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using PcapDotNet.Base;
using PcapDotNet.Packets.IpV4;
namespace PcapDotNet.Packets.Dns
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
internal class DnsTypeRegistrationAttribute : Attribute
{
public DnsType Type { get; set; }
......@@ -34,15 +35,15 @@ namespace PcapDotNet.Packets.Dns
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);
if (prototype != null)
return prototype.CreateInstance(data);
return new DnsResourceDataUnknown(data);
return prototype.CreateInstance(dns, offsetInDns, length);
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)
{
......@@ -56,11 +57,11 @@ namespace PcapDotNet.Packets.Dns
{
var prototypes =
from type in Assembly.GetExecutingAssembly().GetTypes()
where typeof(DnsResourceData).IsAssignableFrom(type) &&
type.GetCustomAttributes<DnsTypeRegistrationAttribute>(false).Any()
from attribute in type.GetCustomAttributes<DnsTypeRegistrationAttribute>(false)
where typeof(DnsResourceData).IsAssignableFrom(type)
select new
{
type.GetCustomAttributes<DnsTypeRegistrationAttribute>(false).First().Type,
attribute.Type,
Prototype = (DnsResourceData)Activator.CreateInstance(type),
};
......@@ -96,12 +97,20 @@ namespace PcapDotNet.Packets.Dns
}
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)]
public class DnsResourceDataIpV4 : DnsResourceDataSimple, IEquatable<DnsResourceDataIpV4>
public sealed class DnsResourceDataIpV4 : DnsResourceDataSimple, IEquatable<DnsResourceDataIpV4>
{
public DnsResourceDataIpV4()
: this(IpV4Address.Zero)
{
}
......@@ -117,25 +126,780 @@ namespace PcapDotNet.Packets.Dns
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);
}
internal sealed override int GetLength()
internal override int GetLength()
{
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);
}
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));
}
}
[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);
}
}
}
......@@ -2,23 +2,29 @@
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;
}
public DataSegment Data { get; private set; }
public bool Equals(DnsResourceDataUnknown other)
public bool Equals(DnsResourceDataAnything other)
{
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()
......@@ -33,7 +39,7 @@ namespace PcapDotNet.Packets.Dns
internal override DnsResourceData CreateInstance(DataSegment data)
{
return new DnsResourceDataUnknown(data);
return new DnsResourceDataAnything(data);
}
}
}
\ No newline at end of file
......@@ -51,7 +51,7 @@ namespace PcapDotNet.Packets.Dns
/// <summary>
/// Two octets containing one of the RR TYPE codes.
/// </summary>
public DnsType Type { get; private set;}
public DnsType Type { get; private set; }
public DnsClass DnsClass { get; private set; }
......@@ -90,8 +90,7 @@ namespace PcapDotNet.Packets.Dns
{
type = DnsType.All;
dnsClass = DnsClass.Any;
domainName = DnsDomainName.Parse(dns, offsetInDns, out numBytesRead);
if (domainName == null)
if (!DnsDomainName.TryParse(dns, offsetInDns, dns.Length - offsetInDns, out domainName, out numBytesRead))
return false;
if (offsetInDns + numBytesRead + MinimumLengthAfterDomainName > dns.Length)
......
......@@ -103,7 +103,7 @@
<Compile Include="Dns\DnsOpcode.cs" />
<Compile Include="Dns\DnsQueryResourceRecord.cs" />
<Compile Include="Dns\DnsResourceData.cs" />
<Compile Include="Dns\DnsResourceDataUnknown.cs" />
<Compile Include="Dns\DnsResourceDataAnything.cs" />
<Compile Include="Dns\DnsResourceRecord.cs" />
<Compile Include="Dns\DnsResponseCode.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