diff --git a/PcapDotNet/src/PcapDotNet.Core.Test/WiresharkCompareTests.cs b/PcapDotNet/src/PcapDotNet.Core.Test/WiresharkCompareTests.cs index 25a23052..b9d7c9aa 100644 --- a/PcapDotNet/src/PcapDotNet.Core.Test/WiresharkCompareTests.cs +++ b/PcapDotNet/src/PcapDotNet.Core.Test/WiresharkCompareTests.cs @@ -9,6 +9,7 @@ using System.Xml.Linq; using Microsoft.VisualStudio.TestTools.UnitTesting; using PcapDotNet.Packets; +using PcapDotNet.Packets.Dhcp; using PcapDotNet.Packets.Dns; using PcapDotNet.Packets.Ethernet; using PcapDotNet.Packets.Gre; @@ -390,24 +391,53 @@ private static void CreateRandomIpPayload(Random random, Layer ipLayer, List layers) - { - if (random.NextBool(20)) - { - // Finish with payload. - PayloadLayer payloadLayer = random.NextPayloadLayer(random.Next(100)); - layers.Add(payloadLayer); - return; - } - - DnsLayer dnsLayer = random.NextDnsLayer(); - layers.Add(dnsLayer); - - ushort specialPort = (ushort)(random.NextBool() ? 53 : 5355); - if (dnsLayer.IsQuery) - udpLayer.DestinationPort = specialPort; - else - udpLayer.SourcePort = specialPort; + private static void CreateRandomUdpPayload(Random random, UdpLayer udpLayer, List layers) + { + if (random.NextBool(20)) + { + // Finish with payload. + PayloadLayer payloadLayer = random.NextPayloadLayer(random.Next(100)); + layers.Add(payloadLayer); + return; + } + + switch (random.Next(0, 2)) + { + case 0: + { + DnsLayer dnsLayer = random.NextDnsLayer(); + layers.Add(dnsLayer); + + ushort specialPort = (ushort)(random.NextBool() ? 53 : 5355); + if (dnsLayer.IsQuery) + udpLayer.DestinationPort = specialPort; + else + udpLayer.SourcePort = specialPort; + break; + } + + case 1: + { + DhcpLayer dhcpLayer = random.NextDhcpLayer(); + layers.Add(dhcpLayer); + + if (random.NextBool()) + { + udpLayer.SourcePort = 67 ; + udpLayer.DestinationPort = 68; + } + else + { + udpLayer.SourcePort = 68; + udpLayer.DestinationPort = 67; + } + + break; + } + + default: + throw new InvalidOperationException("Invalid value."); + } } private static void CreateRandomTcpPayload(Random random, TcpLayer tcpLayer, List layers) diff --git a/PcapDotNet/src/PcapDotNet.Packets.Test/DhcpTests.cs b/PcapDotNet/src/PcapDotNet.Packets.Test/DhcpTests.cs new file mode 100644 index 00000000..a3bf9f25 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets.Test/DhcpTests.cs @@ -0,0 +1,2185 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using PcapDotNet.Packets.Dhcp; +using PcapDotNet.Packets.Dhcp.Options; +using PcapDotNet.Packets.Ethernet; +using PcapDotNet.Packets.IpV4; +using PcapDotNet.Packets.TestUtils; +using PcapDotNet.Packets.Transport; + +namespace PcapDotNet.Packets.Test +{ + /// + /// Summary description for ArpTests + /// + [TestClass] + [ExcludeFromCodeCoverage] + public class DhcpTests + { + /// + /// Gets or sets the test context which provides + /// information about and functionality for the current test run. + /// + public TestContext TestContext { get; set; } + + #region Additional test attributes + + // + // You can use the following additional attributes as you write your tests: + // + // Use ClassInitialize to run code before running the first test in the class + // [ClassInitialize()] + // public static void MyClassInitialize(TestContext testContext) { } + // + // Use ClassCleanup to run code after all tests in a class have run + // [ClassCleanup()] + // public static void MyClassCleanup() { } + // + // Use TestInitialize to run code before running each test + // [TestInitialize()] + // public void MyTestInitialize() { } + // + // Use TestCleanup to run code after each test has run + // [TestCleanup()] + // public void MyTestCleanup() { } + // + + #endregion Additional test attributes + + [TestMethod] + public void RandomDhcpTest() + { + int seed = new Random().Next(); + Console.WriteLine("Seed: " + seed); + Random random = new Random(seed); + + for (int i = 0; i != 1000; ++i) + { + EthernetLayer ethernetLayer = random.NextEthernetLayer(EthernetType.None); + + IpV4Layer ipV4Layer = random.NextIpV4Layer(null); + ipV4Layer.HeaderChecksum = null; + + UdpLayer udpLayer = random.NextUdpLayer(); + udpLayer.Checksum = null; + + DhcpLayer dhcpLayer = random.NextDhcpLayer(); + + Packet packet = PacketBuilder.Build(DateTime.Now, ethernetLayer, ipV4Layer, udpLayer, dhcpLayer); + + Assert.IsTrue(packet.IsValid, "IsValid"); + DhcpLayer actualLayer = (DhcpLayer)packet.Ethernet.Ip.Udp.Dhcp.ExtractLayer(); + if (!dhcpLayer.Equals(actualLayer)) + { + Console.WriteLine(""); + } + + Assert.AreEqual(dhcpLayer, actualLayer, "DHCP Layer"); + } + } + + [TestMethod] + public void DhcpDatagramClientMacAddressTest() + { + Random random = new Random(4711); + + EthernetLayer ethernetLayer = random.NextEthernetLayer(EthernetType.None); + + IpV4Layer ipV4Layer = random.NextIpV4Layer(null); + ipV4Layer.HeaderChecksum = null; + + UdpLayer udpLayer = random.NextUdpLayer(); + udpLayer.Checksum = null; + + DhcpLayer dhcpLayer = new DhcpLayer() + { + HardwareAddressLength = 6, + ClientHardwareAddress = new Packets.DataSegment(new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xED, 0xCB, 0xA9, 0x87, 0x65, 0x43, 0x21 }) + }; + + Packet packet = PacketBuilder.Build(DateTime.Now, ethernetLayer, ipV4Layer, udpLayer, dhcpLayer); + + Assert.AreEqual(new MacAddress("01:23:45:67:89:AB"), packet.Ethernet.IpV4.Udp.Dhcp.ClientMacAddress); + + Assert.AreEqual(new MacAddress("01:23:45:67:89:AB"), ((DhcpLayer)packet.Ethernet.IpV4.Udp.Dhcp.ExtractLayer()).ClientMacAddress); + } + + [TestMethod] + public void DhcpLayerClientMacAddressTest() + { + DhcpLayer dhcpLayer = new DhcpLayer() + { + HardwareAddressLength = 6, + ClientHardwareAddress = new Packets.DataSegment(new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xED, 0xCB, 0xA9, 0x87, 0x65, 0x43, 0x21 }) + }; + + Assert.AreEqual(new MacAddress("01:23:45:67:89:AB"), dhcpLayer.ClientMacAddress); + + dhcpLayer = new DhcpLayer(); + + Assert.AreEqual(MacAddress.Zero, dhcpLayer.ClientMacAddress); + + dhcpLayer.ClientMacAddress = new MacAddress("01:23:45:67:89:AB"); + Assert.AreEqual(new MacAddress("01:23:45:67:89:AB"), dhcpLayer.ClientMacAddress); + } + + [TestMethod] + public void DhcpOptionEqualsTest() + { + DhcpBootfileNameOption option = new DhcpBootfileNameOption("file1"); + Assert.IsFalse(option.Equals(null)); + Assert.AreNotEqual(option, new DhcpAnyOption(new DataSegment(Encoding.ASCII.GetBytes("file1")), DhcpOptionCode.AllSubnetsAreLocal)); + Assert.AreNotEqual(option, new DhcpAnyOption(new DataSegment(Encoding.ASCII.GetBytes("filelong")), DhcpOptionCode.BootfileName)); + Assert.AreNotEqual(option, new DhcpAnyOption(new DataSegment(Encoding.ASCII.GetBytes("file2")), DhcpOptionCode.BootfileName)); + Assert.AreEqual(option, new DhcpBootfileNameOption("file1")); + Assert.AreEqual(option, new DhcpAnyOption(new DataSegment(Encoding.ASCII.GetBytes("file1")), DhcpOptionCode.BootfileName)); + } + + [TestMethod] + public void DhcpAllSubnetsAreLocalOptionTest() + { + DhcpAllSubnetsAreLocalOption option = new DhcpAllSubnetsAreLocalOption(true); + Assert.AreEqual(DhcpOptionCode.AllSubnetsAreLocal, option.OptionCode); + Assert.AreEqual(1, option.Length); + Assert.IsTrue(option.Value); + option.Value = false; + Assert.IsFalse(option.Value); + + option = new DhcpAllSubnetsAreLocalOption(false); + Assert.AreEqual(DhcpOptionCode.AllSubnetsAreLocal, option.OptionCode); + Assert.AreEqual(1, option.Length); + Assert.IsFalse(option.Value); + + TestOption(option); + } + + [TestMethod] + public void DhcpAnyOptionTest() + { + DataSegment data = new DataSegment(new byte[10]); + DhcpAnyOption option = new DhcpAnyOption(data, (DhcpOptionCode)240); + Assert.AreEqual((DhcpOptionCode)240, option.OptionCode); + Assert.AreEqual(10, option.Length); + Assert.IsNotNull(option.Data); + Assert.AreEqual(data, option.Data); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpAnyOptionCtorNullTest() + { + new DhcpAnyOption(null, (DhcpOptionCode)240); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpAnyOptionCtorToLargeTest() + { + new DhcpAnyOption(new DataSegment(new byte[byte.MaxValue + 1]), (DhcpOptionCode)240); + } + + [TestMethod] + public void DhcpArpCacheTimeoutOptionTest() + { + DhcpArpCacheTimeoutOption option = new DhcpArpCacheTimeoutOption(4711); + Assert.AreEqual(DhcpOptionCode.ArpCacheTimeout, option.OptionCode); + Assert.AreEqual(4, option.Length); + Assert.AreEqual(4711, option.Time); + + option.Time = 801; + Assert.AreEqual(801, option.Time); + + TestOption(option); + } + + [TestMethod] + public void DhcpBootfileNameOptionTest() + { + DhcpBootfileNameOption option = new DhcpBootfileNameOption("bootfile"); + Assert.AreEqual(DhcpOptionCode.BootfileName, option.OptionCode); + Assert.AreEqual("bootfile", option.BootfileName); + + option.BootfileName = "changed"; + Assert.AreEqual("changed", option.BootfileName); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpBootfileNameOptionCtorNullTest() + { + new DhcpBootfileNameOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpBootfileNameOptionCtorEmptryTest() + { + new DhcpBootfileNameOption(""); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpBootfileNameOptionCtorToLongTest() + { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < byte.MaxValue; i++) + sb.Append('a'); + new DhcpBootfileNameOption(sb.ToString()); + } + + [TestMethod] + public void DhcpBootFileSizeOptionTest() + { + DhcpBootFileSizeOption option = new DhcpBootFileSizeOption(4711); + Assert.AreEqual(DhcpOptionCode.BootFileSize, option.OptionCode); + Assert.AreEqual(4711, option.FileSize); + + option.FileSize = 999; + Assert.AreEqual(999, option.FileSize); + + TestOption(option); + } + + [TestMethod] + public void DhcpBroadcastAddressOptionTest() + { + DhcpBroadcastAddressOption option = new DhcpBroadcastAddressOption(new IpV4Address("10.20.30.40")); + Assert.AreEqual(DhcpOptionCode.BroadcastAddress, option.OptionCode); + Assert.AreEqual(new IpV4Address("10.20.30.40"), option.BroadcastAddress); + + option.BroadcastAddress = new IpV4Address("11.12.13.14"); + Assert.AreEqual(new IpV4Address("11.12.13.14"), option.BroadcastAddress); + + TestOption(option); + } + + [TestMethod] + public void DhcpClientIdentifierOptionTest() + { + DataSegment testData = new DataSegment(new byte[] { 1, 4, 5, 6, 3, 2 }); + DhcpClientIdentifierOption option = new DhcpClientIdentifierOption(5, testData); + Assert.AreEqual(DhcpOptionCode.ClientIdentifier, option.OptionCode); + Assert.AreEqual(5, option.ClientIdentifierType); + Assert.AreEqual(testData, option.ClientIdentifier); + + testData = new DataSegment(new byte[] { 3, 2, 4, 52, 2, 3, 4 }); + option.ClientIdentifierType = 47; + option.ClientIdentifier = testData; + Assert.AreEqual(47, option.ClientIdentifierType); + Assert.AreEqual(testData, option.ClientIdentifier); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpClientIdentifierOptionCtorNullTest() + { + new DhcpClientIdentifierOption(5, null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpClientIdentifierOptionCtorEmptyTest() + { + new DhcpClientIdentifierOption(5, new DataSegment(new byte[0])); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpClientIdentifierOptionCtorToLongest() + { + new DhcpClientIdentifierOption(5, new DataSegment(new byte[byte.MaxValue - 1])); + } + + [TestMethod] + public void DhcpCookieServerOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpCookieServerOption option = new DhcpCookieServerOption(addresses); + Assert.AreEqual(DhcpOptionCode.CookieServer, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpCookieServerOptionCtorNullTest() + { + new DhcpCookieServerOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpCookieServerOptionCtorEmptyTest() + { + new DhcpCookieServerOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpCookieServerOptionCtorToLongest() + { + new DhcpCookieServerOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + [TestMethod] + public void DhcpDefaultFingerServerOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpDefaultFingerServerOption option = new DhcpDefaultFingerServerOption(addresses); + Assert.AreEqual(DhcpOptionCode.DefaultFingerServer, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpDefaultFingerServerOptionCtorNullTest() + { + new DhcpCookieServerOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpDefaultFingerServerOptionCtorEmptyTest() + { + new DhcpCookieServerOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpDefaultFingerServerOptionCtorToLongest() + { + new DhcpCookieServerOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + [TestMethod] + public void DhcpDefaultInternetRelayChatServerOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpDefaultInternetRelayChatServerOption option = new DhcpDefaultInternetRelayChatServerOption(addresses); + Assert.AreEqual(DhcpOptionCode.DefaultInternetRelayChatServer, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpDefaultInternetRelayChatServerOptionCtorNullTest() + { + new DhcpDefaultInternetRelayChatServerOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpDefaultInternetRelayChatServerOptionCtorEmptyTest() + { + new DhcpDefaultInternetRelayChatServerOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpDefaultInternetRelayChatServerOptionCtorToLongest() + { + new DhcpDefaultInternetRelayChatServerOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + [TestMethod] + public void DhcpDefaultIPTimeToLiveOptionTest() + { + DhcpDefaultIPTimeToLiveOption option = new DhcpDefaultIPTimeToLiveOption(47); + Assert.AreEqual(DhcpOptionCode.DefaultIpTimeToLive, option.OptionCode); + Assert.AreEqual(47, option.Ttl); + + option.Ttl = 200; + Assert.AreEqual(200, option.Ttl); + + TestOption(option); + } + + [TestMethod] + public void DhcpDefaultWorldWideWebServerOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpDefaultWorldWideWebServerOption option = new DhcpDefaultWorldWideWebServerOption(addresses); + Assert.AreEqual(DhcpOptionCode.DefaultWorldWideWebServer, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpDefaultWorldWideWebServerOptionCtorNullTest() + { + new DhcpDefaultWorldWideWebServerOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpDefaultWorldWideWebServerOptionCtorEmptyTest() + { + new DhcpDefaultWorldWideWebServerOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpDefaultWorldWideWebServerOptionCtorToLongest() + { + new DhcpDefaultWorldWideWebServerOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + [TestMethod] + public void DhcpDomainNameOptionTest() + { + DhcpDomainNameOption option = new DhcpDomainNameOption("domainName"); + Assert.AreEqual(DhcpOptionCode.DomainName, option.OptionCode); + Assert.AreEqual("domainName", option.DomainName); + + option.DomainName = "changed"; + Assert.AreEqual("changed", option.DomainName); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpDomainNameOptionCtorNullTest() + { + new DhcpDomainNameOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpDomainNameOptionCtorEmptyTest() + { + new DhcpDomainNameOption(""); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpDomainNameOptionCtorToLongest() + { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < byte.MaxValue; i++) + sb.Append('a'); + new DhcpDomainNameOption(sb.ToString()); + } + + [TestMethod] + public void DhcpDomainNameServerOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpDomainNameServerOption option = new DhcpDomainNameServerOption(addresses); + Assert.AreEqual(DhcpOptionCode.DomainNameServerServer, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpDomainNameServerOptionCtorNullTest() + { + new DhcpDomainNameServerOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpDomainNameServerOptionCtorEmptyTest() + { + new DhcpDomainNameServerOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpDomainNameServerOptionCtorToLongest() + { + new DhcpDomainNameServerOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + [TestMethod] + public void DhcpEndOptionTest() + { + DhcpEndOption option = new DhcpEndOption(); + Assert.AreEqual(DhcpOptionCode.End, option.OptionCode); + + TestOption(option); + } + + [TestMethod] + public void DhcpEthernetEncapsulationOptionTest() + { + DhcpEthernetEncapsulationOption option = new DhcpEthernetEncapsulationOption(true); + Assert.AreEqual(DhcpOptionCode.EthernetEncapsulation, option.OptionCode); + Assert.AreEqual(1, option.Length); + Assert.IsTrue(option.Value); + option.Value = false; + Assert.IsFalse(option.Value); + + option = new DhcpEthernetEncapsulationOption(false); + Assert.AreEqual(DhcpOptionCode.EthernetEncapsulation, option.OptionCode); + Assert.AreEqual(1, option.Length); + Assert.IsFalse(option.Value); + + TestOption(option); + } + + [TestMethod] + public void DhcpExtensionsPathOptionTest() + { + DhcpExtensionsPathOption option = new DhcpExtensionsPathOption("extensionPathname"); + Assert.AreEqual(DhcpOptionCode.ExtensionsPath, option.OptionCode); + Assert.AreEqual("extensionPathname", option.ExtensionsPathname); + + option.ExtensionsPathname = "changed"; + Assert.AreEqual("changed", option.ExtensionsPathname); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpExtensionsPathOptionCtorNullTest() + { + new DhcpExtensionsPathOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpExtensionsPathOptionCtorEmptyTest() + { + new DhcpExtensionsPathOption(""); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpExtensionsPathOptionCtorToLongest() + { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < byte.MaxValue; i++) + sb.Append('a'); + new DhcpExtensionsPathOption(sb.ToString()); + } + + [TestMethod] + public void DhcpHostNameOptionTest() + { + DhcpHostNameOption option = new DhcpHostNameOption("hostName"); + Assert.AreEqual(DhcpOptionCode.HostName, option.OptionCode); + Assert.AreEqual("hostName", option.HostName); + + option.HostName = "changed"; + Assert.AreEqual("changed", option.HostName); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpHostNameOptionCtorNullTest() + { + new DhcpHostNameOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpHostNameOptionCtorEmptyTest() + { + new DhcpHostNameOption(""); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpHostNameOptionCtorToLongest() + { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < byte.MaxValue; i++) + sb.Append('a'); + new DhcpHostNameOption(sb.ToString()); + } + + [TestMethod] + public void DhcpImpressServerOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpImpressServerOption option = new DhcpImpressServerOption(addresses); + Assert.AreEqual(DhcpOptionCode.ImpressServer, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpImpressServerOptionCtorNullTest() + { + new DhcpImpressServerOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpImpressServerOptionCtorEmptyTest() + { + new DhcpImpressServerOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpImpressServerOptionCtorToLongest() + { + new DhcpImpressServerOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + [TestMethod] + public void DhcpInterfaceMtuOptionTest() + { + DhcpInterfaceMtuOption option = new DhcpInterfaceMtuOption(100); + Assert.AreEqual(DhcpOptionCode.InterfaceMtu, option.OptionCode); + Assert.AreEqual(100, option.Mtu); + + option.Mtu = 200; + Assert.AreEqual(200, option.Mtu); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpInterfaceMtuOptionCtorMinMTUTest() + { + new DhcpInterfaceMtuOption(67); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpInterfaceMtuOptionMinMTUTest() + { + new DhcpInterfaceMtuOption(500).Mtu = 67; + } + + [TestMethod] + public void DhcpIPAddressLeaseTimeOptionTest() + { + DhcpIPAddressLeaseTimeOption option = new DhcpIPAddressLeaseTimeOption(100); + Assert.AreEqual(DhcpOptionCode.IPAddressLeaseTime, option.OptionCode); + Assert.AreEqual(100, option.LeaseTime); + + option.LeaseTime = 200; + Assert.AreEqual(200, option.LeaseTime); + + TestOption(option); + } + + [TestMethod] + public void DhcpIPForwardingEnableOptionTest() + { + DhcpIPForwardingEnableOption option = new DhcpIPForwardingEnableOption(true); + Assert.AreEqual(DhcpOptionCode.IPForwardingEnable, option.OptionCode); + Assert.AreEqual(1, option.Length); + Assert.IsTrue(option.Value); + option.Value = false; + Assert.IsFalse(option.Value); + + option = new DhcpIPForwardingEnableOption(false); + Assert.AreEqual(DhcpOptionCode.IPForwardingEnable, option.OptionCode); + Assert.AreEqual(1, option.Length); + Assert.IsFalse(option.Value); + + TestOption(option); + } + + [TestMethod] + public void DhcpLogServerOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpLogServerOption option = new DhcpLogServerOption(addresses); + Assert.AreEqual(DhcpOptionCode.LogServer, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpLogServerOptionCtorNullTest() + { + new DhcpLogServerOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpLogServerOptionCtorEmptyTest() + { + new DhcpLogServerOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpLogServerOptionCtorToLongest() + { + new DhcpLogServerOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + [TestMethod] + public void DhcpLprServerOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpLprServerOption option = new DhcpLprServerOption(addresses); + Assert.AreEqual(DhcpOptionCode.LprServer, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpLprServerOptionCtorNullTest() + { + new DhcpLprServerOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpLprServerOptionCtorEmptyTest() + { + new DhcpLprServerOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpLprServerOptionCtorToLongest() + { + new DhcpLprServerOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + [TestMethod] + public void DhcpMaskSupplierOptionTest() + { + DhcpMaskSupplierOption option = new DhcpMaskSupplierOption(true); + Assert.AreEqual(DhcpOptionCode.MaskSupplier, option.OptionCode); + Assert.AreEqual(1, option.Length); + Assert.IsTrue(option.Value); + option.Value = false; + Assert.IsFalse(option.Value); + + option = new DhcpMaskSupplierOption(false); + Assert.AreEqual(DhcpOptionCode.MaskSupplier, option.OptionCode); + Assert.AreEqual(1, option.Length); + Assert.IsFalse(option.Value); + + TestOption(option); + } + + [TestMethod] + public void DhcpMaximumDatagramReassemblySizeOptionTest() + { + DhcpMaximumDatagramReassemblySizeOption option = new DhcpMaximumDatagramReassemblySizeOption(600); + Assert.AreEqual(DhcpOptionCode.MaximumDatagramReassemblySize, option.OptionCode); + Assert.AreEqual(600, option.Size); + + option.Size = 8000; + Assert.AreEqual(8000, option.Size); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpMaximumDatagramReassemblySizeOptionCtorMinSizeTest() + { + new DhcpMaximumDatagramReassemblySizeOption(575); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpMaximumDatagramReassemblySizeOptionMinSizeTest() + { + new DhcpMaximumDatagramReassemblySizeOption(600).Size = 575; + } + + [TestMethod] + public void DhcpMaximumDhcpMessageSizeOptionTest() + { + DhcpMaximumDhcpMessageSizeOption option = new DhcpMaximumDhcpMessageSizeOption(600); + Assert.AreEqual(DhcpOptionCode.MaximumDhcpMessageSize, option.OptionCode); + Assert.AreEqual(600, option.MaxLength); + + option.MaxLength = 8000; + Assert.AreEqual(8000, option.MaxLength); + + TestOption(option); + } + + [TestMethod] + public void DhcpMeritDumpFileOptionTest() + { + DhcpMeritDumpFileOption option = new DhcpMeritDumpFileOption("DumpFilePathname"); + Assert.AreEqual(DhcpOptionCode.MeritDumpFile, option.OptionCode); + Assert.AreEqual("DumpFilePathname", option.DumpFilePathname); + + option.DumpFilePathname = "changed"; + Assert.AreEqual("changed", option.DumpFilePathname); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpMeritDumpFileOptionCtorNullTest() + { + new DhcpMeritDumpFileOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpMeritDumpFileOptionCtorEmptryTest() + { + new DhcpMeritDumpFileOption(""); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpMeritDumpFileOptionCtorToLongTest() + { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < byte.MaxValue; i++) + sb.Append('a'); + new DhcpMeritDumpFileOption(sb.ToString()); + } + + [TestMethod] + public void DhcpMessageOptionTest() + { + DhcpMessageOption option = new DhcpMessageOption("Text"); + Assert.AreEqual(DhcpOptionCode.Message, option.OptionCode); + Assert.AreEqual("Text", option.Text); + + option.Text = "changed"; + Assert.AreEqual("changed", option.Text); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpMessageOptionCtorNullTest() + { + new DhcpMessageOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpMessageOptionCtorEmptryTest() + { + new DhcpMessageOption(""); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpMessageOptionCtorToLongTest() + { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < byte.MaxValue; i++) + sb.Append('a'); + new DhcpMessageOption(sb.ToString()); + } + + [TestMethod] + public void DhcpMessageTypeOptionTest() + { + DhcpMessageTypeOption option = new DhcpMessageTypeOption(DhcpMessageTypeOption.MessageType.Ack); + Assert.AreEqual(DhcpOptionCode.MessageType, option.OptionCode); + Assert.AreEqual(DhcpMessageTypeOption.MessageType.Ack, option.Type); + + option.Type = DhcpMessageTypeOption.MessageType.Release; + Assert.AreEqual(DhcpMessageTypeOption.MessageType.Release, option.Type); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpBootfileNameCtorInvalidTest() + { + new DhcpMessageTypeOption((DhcpMessageTypeOption.MessageType)77); + } + + [TestMethod] + public void DhcpMobileIPHomeAgentOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpMobileIPHomeAgentOption option = new DhcpMobileIPHomeAgentOption(addresses); + Assert.AreEqual(DhcpOptionCode.MobileIPHomeAgent, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpMobileIPHomeAgentOptionCtorNullTest() + { + new DhcpMobileIPHomeAgentOption(null); + } + + [TestMethod] + public void DhcpMobileIPHomeAgentOptionCtorEmptyTest() + { + new DhcpMobileIPHomeAgentOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpMobileIPHomeAgentOptionCtorToLongest() + { + new DhcpMobileIPHomeAgentOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + [TestMethod] + public void DhcpNameServerOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpNameServerOption option = new DhcpNameServerOption(addresses); + Assert.AreEqual(DhcpOptionCode.NameServer, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpNameServerOptionCtorNullTest() + { + new DhcpNameServerOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpNameServerOptionCtorEmptyTest() + { + new DhcpNameServerOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpNameServerOptionCtorToLongest() + { + new DhcpNameServerOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + [TestMethod] + public void DhcpNetBiosOverTcpIpDatagramDistributionServerOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpNetBiosOverTcpIpDatagramDistributionServerOption option = new DhcpNetBiosOverTcpIpDatagramDistributionServerOption(addresses); + Assert.AreEqual(DhcpOptionCode.NetBiosOverTcpIpDatagramDistributionServer, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpNetBiosOverTcpIpDatagramDistributionServerOptionCtorNullTest() + { + new DhcpNetBiosOverTcpIpDatagramDistributionServerOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpNetBiosOverTcpIpDatagramDistributionServerOptionCtorEmptyTest() + { + new DhcpNetBiosOverTcpIpDatagramDistributionServerOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpNetBiosOverTcpIpDatagramDistributionServerOptionCtorToLongest() + { + new DhcpNetBiosOverTcpIpDatagramDistributionServerOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + [TestMethod] + public void DhcpNetBiosOverTcpIpNameServerOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpNetBiosOverTcpIpNameServerOption option = new DhcpNetBiosOverTcpIpNameServerOption(addresses); + Assert.AreEqual(DhcpOptionCode.NetBiosOverTcpIpNameServer, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpNetBiosOverTcpIpNameServerOptionCtorNullTest() + { + new DhcpNetBiosOverTcpIpNameServerOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpNetBiosOverTcpIpNameServerOptionCtorEmptyTest() + { + new DhcpNetBiosOverTcpIpNameServerOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpNetBiosOverTcpIpNameServerOptionCtorToLongest() + { + new DhcpNetBiosOverTcpIpNameServerOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + [TestMethod] + public void DhcpNetBiosOverTcpIpNodeTypeOptionTest() + { + DhcpNetBiosOverTcpIpNodeTypeOption option = new DhcpNetBiosOverTcpIpNodeTypeOption(DhcpNetBiosOverTcpIpNodeTypeOption.NodeType.BNode); + Assert.AreEqual(DhcpOptionCode.NetBiosOverTcpIpNodeType, option.OptionCode); + Assert.AreEqual(DhcpNetBiosOverTcpIpNodeTypeOption.NodeType.BNode, option.Type); + + option.Type = DhcpNetBiosOverTcpIpNodeTypeOption.NodeType.HNode | DhcpNetBiosOverTcpIpNodeTypeOption.NodeType.PNode; + Assert.AreEqual(DhcpNetBiosOverTcpIpNodeTypeOption.NodeType.HNode | DhcpNetBiosOverTcpIpNodeTypeOption.NodeType.PNode, option.Type); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpNetBiosOverTcpIpNodeTypeOptionCtorInvalidTest() + { + new DhcpNetBiosOverTcpIpNodeTypeOption(0); + } + + [TestMethod] + public void DhcpNetBiosOverTcpIpScopeOptionTest() + { + DataSegment data = new DataSegment(new byte[10]); + DhcpNetBiosOverTcpIpScopeOption option = new DhcpNetBiosOverTcpIpScopeOption(data); + Assert.IsNotNull(option.NetBiosScope); + Assert.AreEqual(data, option.NetBiosScope); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpNetBiosOverTcpIpScopeOptionCtorNullTest() + { + new DhcpNetBiosOverTcpIpScopeOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpNetBiosOverTcpIpScopeOptionToLargeTest() + { + new DhcpNetBiosOverTcpIpScopeOption(new DataSegment(new byte[byte.MaxValue + 1])); + } + + [TestMethod] + public void DhcpNetworkInformationServersOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpNetworkInformationServersOption option = new DhcpNetworkInformationServersOption(addresses); + Assert.AreEqual(DhcpOptionCode.NetworkInformationServers, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpNetworkInformationServersOptionCtorNullTest() + { + new DhcpNetworkInformationServersOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpNetworkInformationServersOptionCtorEmptyTest() + { + new DhcpNetworkInformationServersOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpNetworkInformationServersOptionCtorToLongest() + { + new DhcpNetworkInformationServersOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + [TestMethod] + public void DhcpNetworkInformationServiceDomainOptionTest() + { + DhcpNetworkInformationServiceDomainOption option = new DhcpNetworkInformationServiceDomainOption("NIS Domain Name"); + Assert.AreEqual(DhcpOptionCode.NetworkInformationServiceDomain, option.OptionCode); + Assert.AreEqual("NIS Domain Name", option.NisDomainName); + + option.NisDomainName = "changed"; + Assert.AreEqual("changed", option.NisDomainName); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpNetworkInformationServiceDomainOptionCtorNullTest() + { + new DhcpNetworkInformationServiceDomainOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpNetworkInformationServiceDomainOptionCtorEmptryTest() + { + new DhcpNetworkInformationServiceDomainOption(""); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpNetworkInformationServiceDomainOptionCtorToLongTest() + { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < byte.MaxValue; i++) + sb.Append('a'); + new DhcpNetworkInformationServiceDomainOption(sb.ToString()); + } + + [TestMethod] + public void DhcpNetworkInformationServicePlusDomainOptionOptionTest() + { + DhcpNetworkInformationServicePlusDomainOption option = new DhcpNetworkInformationServicePlusDomainOption("NIS Client Domain Name"); + Assert.AreEqual(DhcpOptionCode.NetworkInformationServicePlusDomain, option.OptionCode); + Assert.AreEqual("NIS Client Domain Name", option.NisClientDomainName); + + option.NisClientDomainName = "changed"; + Assert.AreEqual("changed", option.NisClientDomainName); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpNetworkInformationServicePlusDomainOptionCtorNullTest() + { + new DhcpNetworkInformationServicePlusDomainOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpNetworkInformationServicePlusDomainOptionCtorEmptryTest() + { + new DhcpNetworkInformationServicePlusDomainOption(""); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpNetworkInformationServicePlusDomainOptionCtorToLongTest() + { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < byte.MaxValue; i++) + sb.Append('a'); + new DhcpNetworkInformationServicePlusDomainOption(sb.ToString()); + } + + [TestMethod] + public void DhcpNetworkInformationServicePlusServersOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpNetworkInformationServicePlusServersOption option = new DhcpNetworkInformationServicePlusServersOption(addresses); + Assert.AreEqual(DhcpOptionCode.NetworkInformationServicePlusServers, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpNetworkInformationServicePlusServersOptionCtorNullTest() + { + new DhcpNetworkInformationServicePlusServersOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpNetworkInformationServicePlusServersOptionCtorEmptyTest() + { + new DhcpNetworkInformationServicePlusServersOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpNetworkInformationServicePlusServersOptionCtorToLongest() + { + new DhcpNetworkInformationServicePlusServersOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + [TestMethod] + public void DhcpNetworkNewsTransportProtocolServerOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpNetworkNewsTransportProtocolServerOption option = new DhcpNetworkNewsTransportProtocolServerOption(addresses); + Assert.AreEqual(DhcpOptionCode.NetworkNewsTransportProtocolServer, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpNetworkNewsTransportProtocolServerOptionCtorNullTest() + { + new DhcpNetworkNewsTransportProtocolServerOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpNetworkNewsTransportProtocolServerOptionCtorEmptyTest() + { + new DhcpNetworkNewsTransportProtocolServerOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpNetworkNewsTransportProtocolServerOptionCtorToLongest() + { + new DhcpNetworkNewsTransportProtocolServerOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + [TestMethod] + public void DhcpNetworkTimeProtocolServersOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpNetworkTimeProtocolServersOption option = new DhcpNetworkTimeProtocolServersOption(addresses); + Assert.AreEqual(DhcpOptionCode.NetworkTimeProtocolServers, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpNetworkTimeProtocolServersOptionCtorNullTest() + { + new DhcpNetworkTimeProtocolServersOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpNetworkTimeProtocolServersOptionCtorEmptyTest() + { + new DhcpNetworkTimeProtocolServersOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpNetworkTimeProtocolServersOptionCtorToLongest() + { + new DhcpNetworkTimeProtocolServersOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + [TestMethod] + public void DhcpNonLocalSourceRoutingEnableOptionnTest() + { + DhcpNonLocalSourceRoutingEnableOption option = new DhcpNonLocalSourceRoutingEnableOption(true); + Assert.AreEqual(DhcpOptionCode.NonLocalSourceRoutingEnable, option.OptionCode); + Assert.AreEqual(1, option.Length); + Assert.IsTrue(option.Value); + option.Value = false; + Assert.IsFalse(option.Value); + + option = new DhcpNonLocalSourceRoutingEnableOption(false); + Assert.AreEqual(DhcpOptionCode.NonLocalSourceRoutingEnable, option.OptionCode); + Assert.AreEqual(1, option.Length); + Assert.IsFalse(option.Value); + + TestOption(option); + } + + [TestMethod] + public void DhcpOptionOverloadOptionTest() + { + DhcpOptionOverloadOption option = new DhcpOptionOverloadOption(DhcpOptionOverloadOption.OptionOverloadValue.SName); + Assert.AreEqual(DhcpOptionCode.OptionOverload, option.OptionCode); + Assert.AreEqual(DhcpOptionOverloadOption.OptionOverloadValue.SName, option.Value); + + option.Value = DhcpOptionOverloadOption.OptionOverloadValue.Both; + Assert.AreEqual(DhcpOptionOverloadOption.OptionOverloadValue.Both, option.Value); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpOptionOverloadOptionCtorInvalidTest() + { + new DhcpOptionOverloadOption(0); + } + + [TestMethod] + public void DhcpPadOptionTest() + { + DhcpPadOption option = new DhcpPadOption(); + Assert.AreEqual(DhcpOptionCode.Pad, option.OptionCode); + + TestOption(option); + } + + [TestMethod] + public void DhcpParameterRequestListOptionTest() + { + DhcpOptionCode[] options = new DhcpOptionCode[] { DhcpOptionCode.End, DhcpOptionCode.ParameterRequestList }; + DhcpParameterRequestListOption option = new DhcpParameterRequestListOption(options); + Assert.AreEqual(DhcpOptionCode.ParameterRequestList, option.OptionCode); + CollectionAssert.AreEqual(options, option.OptionCodes.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpParameterRequestListOptionCtorNullTest() + { + new DhcpParameterRequestListOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpParameterRequestListOptionCtorEmptyTest() + { + new DhcpParameterRequestListOption(new DhcpOptionCode[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpParameterRequestListOptionCtorToLongest() + { + new DhcpParameterRequestListOption(new DhcpOptionCode[255 / sizeof(DhcpOptionCode) + 1]); + } + + [TestMethod] + public void DhcpPathMtuAgingTimeoutOptionTest() + { + DhcpPathMtuAgingTimeoutOption option = new DhcpPathMtuAgingTimeoutOption(4711); + Assert.AreEqual(DhcpOptionCode.PathMtuAgingTimeout, option.OptionCode); + Assert.AreEqual(4711, option.Timeout); + + option.Timeout = 999; + Assert.AreEqual(999, option.Timeout); + + TestOption(option); + } + + [TestMethod] + public void DhcpPathMtuPlateauTableOptionTest() + { + ushort[] sizes = new ushort[] { 4711, 666 }; + DhcpPathMtuPlateauTableOption option = new DhcpPathMtuPlateauTableOption(sizes); + Assert.AreEqual(DhcpOptionCode.PathMtuPlateauTable, option.OptionCode); + CollectionAssert.AreEqual(sizes, option.Sizes.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpPathMtuPlateauTableOptionCtorNullTest() + { + new DhcpPathMtuPlateauTableOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpPathMtuPlateauTableOptionCtorEmptyTest() + { + new DhcpPathMtuPlateauTableOption(new ushort[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpPathMtuPlateauTableOptionCtorToLongest() + { + new DhcpPathMtuPlateauTableOption(new ushort[255 / sizeof(ushort) + 1]); + } + + [TestMethod] + public void DhcpPerformMaskDiscoveryOptionTest() + { + DhcpPerformMaskDiscoveryOption option = new DhcpPerformMaskDiscoveryOption(true); + Assert.AreEqual(DhcpOptionCode.PerformMaskDiscovery, option.OptionCode); + Assert.AreEqual(1, option.Length); + Assert.IsTrue(option.Value); + option.Value = false; + Assert.IsFalse(option.Value); + + option = new DhcpPerformMaskDiscoveryOption(false); + Assert.AreEqual(DhcpOptionCode.PerformMaskDiscovery, option.OptionCode); + Assert.AreEqual(1, option.Length); + Assert.IsFalse(option.Value); + + TestOption(option); + } + + [TestMethod] + public void DhcpPerformRouterDiscoveryOptionTest() + { + DhcpPerformRouterDiscoveryOption option = new DhcpPerformRouterDiscoveryOption(true); + Assert.AreEqual(DhcpOptionCode.PerformRouterDiscovery, option.OptionCode); + Assert.AreEqual(1, option.Length); + Assert.IsTrue(option.Value); + option.Value = false; + Assert.IsFalse(option.Value); + + option = new DhcpPerformRouterDiscoveryOption(false); + Assert.AreEqual(DhcpOptionCode.PerformRouterDiscovery, option.OptionCode); + Assert.AreEqual(1, option.Length); + Assert.IsFalse(option.Value); + + TestOption(option); + } + + [TestMethod] + public void DhcpPolicyFilterOptionTest() + { + DhcpPolicyFilterOption.IpV4AddressWithMask[] filters = new DhcpPolicyFilterOption.IpV4AddressWithMask[] { new DhcpPolicyFilterOption.IpV4AddressWithMask(new IpV4Address("10.20.30.40"), new IpV4Address("255.255.255.0")), new DhcpPolicyFilterOption.IpV4AddressWithMask(new IpV4Address("1.2.3.4"), new IpV4Address("222.0.0.0")) }; + DhcpPolicyFilterOption option = new DhcpPolicyFilterOption(filters); + Assert.AreEqual(DhcpOptionCode.PolicyFilter, option.OptionCode); + CollectionAssert.AreEqual(filters, option.Filters.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpPolicyFilterOptionCtorNullTest() + { + new DhcpPolicyFilterOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpPolicyFilterOptionCtorEmptyTest() + { + new DhcpPolicyFilterOption(new DhcpPolicyFilterOption.IpV4AddressWithMask[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpPolicyFilterOptionCtorToLongest() + { + new DhcpPolicyFilterOption(new DhcpPolicyFilterOption.IpV4AddressWithMask[255 / DhcpPolicyFilterOption.IpV4AddressWithMask.SizeOf + 1]); + } + + [TestMethod] + public void DhcpPolicyFilterOptionIpV4AddressWithMaskEqualsTest() + { + DhcpPolicyFilterOption.IpV4AddressWithMask a = new DhcpPolicyFilterOption.IpV4AddressWithMask(new IpV4Address("10.20.30.40"), new IpV4Address("255.255.255.0")); + DhcpPolicyFilterOption.IpV4AddressWithMask a2 = new DhcpPolicyFilterOption.IpV4AddressWithMask(new IpV4Address("10.20.30.40"), new IpV4Address("255.255.255.0")); + DhcpPolicyFilterOption.IpV4AddressWithMask b = new DhcpPolicyFilterOption.IpV4AddressWithMask(new IpV4Address("1.2.3.4"), new IpV4Address("222.0.0.0")); + DhcpPolicyFilterOption.IpV4AddressWithMask b2 = new DhcpPolicyFilterOption.IpV4AddressWithMask(new IpV4Address("10.20.30.40"), new IpV4Address("222.0.0.0")); + DhcpPolicyFilterOption.IpV4AddressWithMask b3 = new DhcpPolicyFilterOption.IpV4AddressWithMask(new IpV4Address("1.2.3.4"), new IpV4Address("255.255.255.0")); + + Assert.IsTrue(a.Equals(a2)); + Assert.IsFalse(a.Equals(null)); + Assert.IsFalse(a.Equals(new object())); + Assert.IsFalse(a.Equals(b)); + Assert.IsFalse(a.Equals(b2)); + Assert.IsFalse(a.Equals(b3)); + + Assert.IsTrue(a == a2); + Assert.IsFalse(a == null); + Assert.IsFalse(null == a); + Assert.IsFalse(a == b); + Assert.IsFalse(a == b2); + Assert.IsFalse(a == b3); + + Assert.IsFalse(a != a2); + Assert.IsTrue(a != null); + Assert.IsTrue(null != a); + Assert.IsTrue(a != b); + Assert.IsTrue(a != b2); + Assert.IsTrue(a != b3); + } + + [TestMethod] + public void DhcpPostOfficeProtocolServerOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpPostOfficeProtocolServerOption option = new DhcpPostOfficeProtocolServerOption(addresses); + Assert.AreEqual(DhcpOptionCode.PostOfficeProtocolServer, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpPostOfficeProtocolServerOptionCtorNullTest() + { + new DhcpPostOfficeProtocolServerOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpPostOfficeProtocolServerOptionCtorEmptyTest() + { + new DhcpPostOfficeProtocolServerOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpPostOfficeProtocolServerOptionCtorToLongest() + { + new DhcpPostOfficeProtocolServerOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + [TestMethod] + public void DhcpRebindingTimeValueOptionTest() + { + DhcpRebindingTimeValueOption option = new DhcpRebindingTimeValueOption(4711); + Assert.AreEqual(DhcpOptionCode.RebindingTimeValue, option.OptionCode); + Assert.AreEqual(4711, option.T2Interval); + + option.T2Interval = 999; + Assert.AreEqual(999, option.T2Interval); + + TestOption(option); + } + + [TestMethod] + public void DhcpRenewalTimeValueOptionTest() + { + DhcpRenewalTimeValueOption option = new DhcpRenewalTimeValueOption(4711); + Assert.AreEqual(DhcpOptionCode.RenewalTimeValue, option.OptionCode); + Assert.AreEqual(4711, option.T1Interval); + + option.T1Interval = 999; + Assert.AreEqual(999, option.T1Interval); + + TestOption(option); + } + + [TestMethod] + public void DhcpRequestedIPAddressOptionTest() + { + DhcpRequestedIPAddressOption option = new DhcpRequestedIPAddressOption(new IpV4Address("10.20.30.40")); + Assert.AreEqual(DhcpOptionCode.RequestedIPAddress, option.OptionCode); + Assert.AreEqual(new IpV4Address("10.20.30.40"), option.Address); + + option.Address = new IpV4Address("1.2.3.4"); + Assert.AreEqual(new IpV4Address("1.2.3.4"), option.Address); + + TestOption(option); + } + + [TestMethod] + public void DhcpResourceLocationServerOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpResourceLocationServerOption option = new DhcpResourceLocationServerOption(addresses); + Assert.AreEqual(DhcpOptionCode.ResourceLocationServer, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpResourceLocationServerOptionCtorNullTest() + { + new DhcpResourceLocationServerOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpResourceLocationServerOptionCtorEmptyTest() + { + new DhcpResourceLocationServerOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpResourceLocationServerOptionCtorToLongest() + { + new DhcpResourceLocationServerOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + [TestMethod] + public void DhcpRootPathOptionTest() + { + DhcpRootPathOption option = new DhcpRootPathOption("Root Disk Pathname"); + Assert.AreEqual(DhcpOptionCode.RootPath, option.OptionCode); + Assert.AreEqual("Root Disk Pathname", option.RootDiskPathname); + + option.RootDiskPathname = "changed"; + Assert.AreEqual("changed", option.RootDiskPathname); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpRootPathOptionCtorNullTest() + { + new DhcpRootPathOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpRootPathOptionCtorEmptryTest() + { + new DhcpRootPathOption(""); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpRootPathOptionCtorToLongTest() + { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < byte.MaxValue; i++) + sb.Append('a'); + new DhcpRootPathOption(sb.ToString()); + } + + [TestMethod] + public void DhcpRouterOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpRouterOption option = new DhcpRouterOption(addresses); + Assert.AreEqual(DhcpOptionCode.Router, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpRouterOptionCtorNullTest() + { + new DhcpRouterOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpRouterOptionCtorEmptyTest() + { + new DhcpRouterOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpRouterOptionCtorToLongest() + { + new DhcpRouterOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + [TestMethod] + public void DhcpRouterSolicitationAddressOptionTest() + { + DhcpRouterSolicitationAddressOption option = new DhcpRouterSolicitationAddressOption(new IpV4Address("10.20.30.40")); + Assert.AreEqual(DhcpOptionCode.RouterSolicitationAddress, option.OptionCode); + Assert.AreEqual(new IpV4Address("10.20.30.40"), option.Address); + + option.Address = new IpV4Address("1.2.3.4"); + Assert.AreEqual(new IpV4Address("1.2.3.4"), option.Address); + + TestOption(option); + } + + [TestMethod] + public void DhcpServerIdentifierOptionTest() + { + DhcpServerIdentifierOption option = new DhcpServerIdentifierOption(new IpV4Address("10.20.30.40")); + Assert.AreEqual(DhcpOptionCode.ServerIdentifier, option.OptionCode); + Assert.AreEqual(new IpV4Address("10.20.30.40"), option.Address); + + option.Address = new IpV4Address("1.2.3.4"); + Assert.AreEqual(new IpV4Address("1.2.3.4"), option.Address); + + TestOption(option); + } + + [TestMethod] + public void DhcpSimpleMailTransportProtocolServerOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpSimpleMailTransportProtocolServerOption option = new DhcpSimpleMailTransportProtocolServerOption(addresses); + Assert.AreEqual(DhcpOptionCode.SimpleMailTransportProtocolServer, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpSimpleMailTransportProtocolServerOptionCtorNullTest() + { + new DhcpSimpleMailTransportProtocolServerOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpSimpleMailTransportProtocolServerOptionCtorEmptyTest() + { + new DhcpSimpleMailTransportProtocolServerOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpSimpleMailTransportProtocolServerOptionCtorToLongest() + { + new DhcpSimpleMailTransportProtocolServerOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + [TestMethod] + public void DhcpStaticRouteOptionTest() + { + DhcpStaticRouteOption.IpV4AddressRoute[] filters = new DhcpStaticRouteOption.IpV4AddressRoute[] { new DhcpStaticRouteOption.IpV4AddressRoute(new IpV4Address("10.20.30.40"), new IpV4Address("255.255.255.0")), new DhcpStaticRouteOption.IpV4AddressRoute(new IpV4Address("1.2.3.4"), new IpV4Address("222.0.0.0")) }; + DhcpStaticRouteOption option = new DhcpStaticRouteOption(filters); + Assert.AreEqual(DhcpOptionCode.StaticRoute, option.OptionCode); + CollectionAssert.AreEqual(filters, option.Routes.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpStaticRouteOptionCtorNullTest() + { + new DhcpStaticRouteOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpStaticRouteOptionCtorEmptyTest() + { + new DhcpStaticRouteOption(new DhcpStaticRouteOption.IpV4AddressRoute[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpStaticRouteOptionCtorToLongest() + { + new DhcpStaticRouteOption(new DhcpStaticRouteOption.IpV4AddressRoute[255 / DhcpStaticRouteOption.IpV4AddressRoute.SizeOf + 1]); + } + + [TestMethod] + public void DhcpStaticRouteOptionIpV4AddressRouteEqualsTest() + { + DhcpStaticRouteOption.IpV4AddressRoute a = new DhcpStaticRouteOption.IpV4AddressRoute(new IpV4Address("10.20.30.40"), new IpV4Address("255.255.255.0")); + DhcpStaticRouteOption.IpV4AddressRoute a2 = new DhcpStaticRouteOption.IpV4AddressRoute(new IpV4Address("10.20.30.40"), new IpV4Address("255.255.255.0")); + DhcpStaticRouteOption.IpV4AddressRoute b = new DhcpStaticRouteOption.IpV4AddressRoute(new IpV4Address("1.2.3.4"), new IpV4Address("222.0.0.0")); + DhcpStaticRouteOption.IpV4AddressRoute b2 = new DhcpStaticRouteOption.IpV4AddressRoute(new IpV4Address("10.20.30.40"), new IpV4Address("222.0.0.0")); + DhcpStaticRouteOption.IpV4AddressRoute b3 = new DhcpStaticRouteOption.IpV4AddressRoute(new IpV4Address("1.2.3.4"), new IpV4Address("255.255.255.0")); + + Assert.IsTrue(a.Equals(a2)); + Assert.IsFalse(a.Equals(null)); + Assert.IsFalse(a.Equals(new object())); + Assert.IsFalse(a.Equals(b)); + Assert.IsFalse(a.Equals(b2)); + Assert.IsFalse(a.Equals(b3)); + + Assert.IsTrue(a == a2); + Assert.IsFalse(a == null); + Assert.IsFalse(null == a); + Assert.IsFalse(a == b); + Assert.IsFalse(a == b2); + Assert.IsFalse(a == b3); + + Assert.IsFalse(a != a2); + Assert.IsTrue(a != null); + Assert.IsTrue(null != a); + Assert.IsTrue(a != b); + Assert.IsTrue(a != b2); + Assert.IsTrue(a != b3); + } + + [TestMethod] + public void DhcpStreetTalkDirectoryAssistanceServerOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpStreetTalkDirectoryAssistanceServerOption option = new DhcpStreetTalkDirectoryAssistanceServerOption(addresses); + Assert.AreEqual(DhcpOptionCode.StreetTalkDirectoryAssistanceServer, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpStreetTalkDirectoryAssistanceServerOptionCtorNullTest() + { + new DhcpStreetTalkDirectoryAssistanceServerOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpStreetTalkDirectoryAssistanceServerOptionCtorEmptyTest() + { + new DhcpStreetTalkDirectoryAssistanceServerOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpStreetTalkDirectoryAssistanceServerOptionCtorToLongest() + { + new DhcpStreetTalkDirectoryAssistanceServerOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + [TestMethod] + public void DhcpStreetTalkServerOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpStreetTalkServerOption option = new DhcpStreetTalkServerOption(addresses); + Assert.AreEqual(DhcpOptionCode.StreetTalkServer, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpStreetTalkServerOptionCtorNullTest() + { + new DhcpStreetTalkServerOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpStreetTalkServerOptionCtorEmptyTest() + { + new DhcpStreetTalkServerOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpStreetTalkServerOptionCtorToLongest() + { + new DhcpStreetTalkServerOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + [TestMethod] + public void DhcpSubnetMaskOptionTest() + { + DhcpSubnetMaskOption option = new DhcpSubnetMaskOption(new IpV4Address("10.20.30.40")); + Assert.AreEqual(DhcpOptionCode.SubnetMask, option.OptionCode); + Assert.AreEqual(new IpV4Address("10.20.30.40"), option.SubnetMask); + + option.SubnetMask = new IpV4Address("255.255.255.255"); + Assert.AreEqual(new IpV4Address("255.255.255.255"), option.SubnetMask); + + TestOption(option); + } + + [TestMethod] + public void DhcpSwapServerOptionTest() + { + DhcpSwapServerOption option = new DhcpSwapServerOption(new IpV4Address("10.20.30.40")); + Assert.AreEqual(DhcpOptionCode.SwapServer, option.OptionCode); + Assert.AreEqual(new IpV4Address("10.20.30.40"), option.SwapServerAddress); + + option.SwapServerAddress = new IpV4Address("1.2.3.4"); + Assert.AreEqual(new IpV4Address("1.2.3.4"), option.SwapServerAddress); + + TestOption(option); + } + + [TestMethod] + public void DhcpTcpDefaultTtlOptionTest() + { + DhcpTcpDefaultTtlOption option = new DhcpTcpDefaultTtlOption(100); + Assert.AreEqual(DhcpOptionCode.TcpDefaultTtl, option.OptionCode); + Assert.AreEqual(100, option.Ttl); + + option.Ttl = 42; + Assert.AreEqual(42, option.Ttl); + + TestOption(option); + } + + [TestMethod] + public void DhcpTcpKeepaliveGarbageOptionTest() + { + DhcpTcpKeepaliveGarbageOption option = new DhcpTcpKeepaliveGarbageOption(true); + Assert.AreEqual(DhcpOptionCode.TcpKeepaliveGarbage, option.OptionCode); + Assert.AreEqual(1, option.Length); + Assert.IsTrue(option.Value); + option.Value = false; + Assert.IsFalse(option.Value); + + option = new DhcpTcpKeepaliveGarbageOption(false); + Assert.AreEqual(DhcpOptionCode.TcpKeepaliveGarbage, option.OptionCode); + Assert.AreEqual(1, option.Length); + Assert.IsFalse(option.Value); + + TestOption(option); + } + + [TestMethod] + public void DhcpTcpKeepaliveIntervalOptionTest() + { + DhcpTcpKeepaliveIntervalOption option = new DhcpTcpKeepaliveIntervalOption(4711); + Assert.AreEqual(DhcpOptionCode.TcpKeepaliveInterval, option.OptionCode); + Assert.AreEqual(4711, option.Time); + + option.Time = 42; + Assert.AreEqual(42, option.Time); + + TestOption(option); + } + + [TestMethod] + public void DhcpTFtpServerNameOptionTest() + { + DhcpTFtpServerNameOption option = new DhcpTFtpServerNameOption("TFTP server"); + Assert.AreEqual(DhcpOptionCode.TfptServerName, option.OptionCode); + Assert.AreEqual("TFTP server", option.TFtpServer); + + option.TFtpServer = "changed"; + Assert.AreEqual("changed", option.TFtpServer); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpTFtpServerNameOptionCtorNullTest() + { + new DhcpTFtpServerNameOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpTFtpServerNameOptionCtorEmptryTest() + { + new DhcpTFtpServerNameOption(""); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpTFtpServerNameOptionCtorToLongTest() + { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < byte.MaxValue; i++) + sb.Append('a'); + new DhcpTFtpServerNameOption(sb.ToString()); + } + + [TestMethod] + public void DhcpTimeOffsetOptionTest() + { + DhcpTimeOffsetOption option = new DhcpTimeOffsetOption(4711); + Assert.AreEqual(DhcpOptionCode.TimeOffset, option.OptionCode); + Assert.AreEqual(4711, option.TimeOffset); + + option.TimeOffset = -42; + Assert.AreEqual(-42, option.TimeOffset); + + TestOption(option); + } + + [TestMethod] + public void DhcpTimeServerOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpTimeServerOption option = new DhcpTimeServerOption(addresses); + Assert.AreEqual(DhcpOptionCode.TimeServer, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpTimeServerOptionCtorNullTest() + { + new DhcpTimeServerOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpTimeServerOptionCtorEmptyTest() + { + new DhcpTimeServerOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpTimeServerOptionCtorToLongest() + { + new DhcpTimeServerOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + [TestMethod] + public void DhcpTrailerEncapsulationOptionTest() + { + DhcpTrailerEncapsulationOption option = new DhcpTrailerEncapsulationOption(true); + Assert.AreEqual(DhcpOptionCode.TrailerEncapsulation, option.OptionCode); + Assert.AreEqual(1, option.Length); + Assert.IsTrue(option.Value); + option.Value = false; + Assert.IsFalse(option.Value); + + option = new DhcpTrailerEncapsulationOption(false); + Assert.AreEqual(DhcpOptionCode.TrailerEncapsulation, option.OptionCode); + Assert.AreEqual(1, option.Length); + Assert.IsFalse(option.Value); + + TestOption(option); + } + + [TestMethod] + public void DhcpVendorClassidentifierOptionTest() + { + DataSegment data = new DataSegment(new byte[10]); + DhcpVendorClassidentifierOption option = new DhcpVendorClassidentifierOption(data); + Assert.AreEqual(DhcpOptionCode.VendorClassidentifier, option.OptionCode); + Assert.AreEqual(10, option.Length); + Assert.AreEqual(data, option.VendorClassIdentifier); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpVendorClassidentifierOptionCtorNullTest() + { + new DhcpVendorClassidentifierOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpVendorClassidentifierOptionCtorToLargeTest() + { + new DhcpVendorClassidentifierOption(new DataSegment(new byte[byte.MaxValue + 1])); + } + + [TestMethod] + public void DhcpVendorSpecificInformationOptionTest() + { + DataSegment data = new DataSegment(new byte[10]); + DhcpVendorSpecificInformationOption option = new DhcpVendorSpecificInformationOption(data); + Assert.AreEqual(DhcpOptionCode.VendorSpecificInformation, option.OptionCode); + Assert.AreEqual(10, option.Length); + Assert.AreEqual(data, option.VendorSpecificInformation); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpVendorSpecificInformationOptionCtorNullTest() + { + new DhcpVendorSpecificInformationOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpVendorSpecificInformationOptionCtorToLargeTest() + { + new DhcpVendorSpecificInformationOption(new DataSegment(new byte[byte.MaxValue + 1])); + } + + [TestMethod] + public void DhcpXWindowSystemDisplayManagerOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpXWindowSystemDisplayManagerOption option = new DhcpXWindowSystemDisplayManagerOption(addresses); + Assert.AreEqual(DhcpOptionCode.XWindowSystemDisplayManager, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpXWindowSystemDisplayManagerOptionCtorNullTest() + { + new DhcpXWindowSystemDisplayManagerOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpXWindowSystemDisplayManagerOptionCtorEmptyTest() + { + new DhcpXWindowSystemDisplayManagerOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpXWindowSystemDisplayManagerOptionCtorToLongest() + { + new DhcpXWindowSystemDisplayManagerOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + [TestMethod] + public void DhcpXWindowSystemFontServerOptionTest() + { + IpV4Address[] addresses = new IpV4Address[] { new IpV4Address("10.20.30.40"), new IpV4Address("11.22.33.44") }; + DhcpXWindowSystemFontServerOption option = new DhcpXWindowSystemFontServerOption(addresses); + Assert.AreEqual(DhcpOptionCode.XWindowSystemFontServer, option.OptionCode); + CollectionAssert.AreEqual(addresses, option.Addresses.ToArray()); + + TestOption(option); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void DhcpXWindowSystemFontServerOptionCtorNullTest() + { + new DhcpXWindowSystemFontServerOption(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpXWindowSystemFontServerOptionCtorEmptyTest() + { + new DhcpXWindowSystemFontServerOption(new IpV4Address[0]); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void DhcpXWindowSystemFontServerOptionCtorToLongest() + { + new DhcpXWindowSystemFontServerOption(new IpV4Address[255 / IpV4Address.SizeOf + 1]); + } + + private void TestOption(DhcpOption option) + { + int seed = new Random().Next(); + Console.WriteLine("Seed-TestOption: " + seed); + Random random = new Random(seed); + + EthernetLayer ethernetLayer = random.NextEthernetLayer(EthernetType.None); + + IpV4Layer ipV4Layer = random.NextIpV4Layer(null); + ipV4Layer.HeaderChecksum = null; + + UdpLayer udpLayer = random.NextUdpLayer(); + udpLayer.Checksum = null; + + DhcpLayer dhcpLayer = random.NextDhcpLayer(); + dhcpLayer.Options.Clear(); + dhcpLayer.Options.Add(option); + + Packet packet = PacketBuilder.Build(DateTime.Now, ethernetLayer, ipV4Layer, udpLayer, dhcpLayer); + + Assert.AreEqual(option, packet.Ethernet.IpV4.Udp.Dhcp.Options.Single()); + Assert.AreEqual(option.GetHashCode(), packet.Ethernet.IpV4.Udp.Dhcp.Options.Single().GetHashCode()); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets.Test/PcapDotNet.Packets.Test.csproj b/PcapDotNet/src/PcapDotNet.Packets.Test/PcapDotNet.Packets.Test.csproj index 42728d0f..bf4214f1 100644 --- a/PcapDotNet/src/PcapDotNet.Packets.Test/PcapDotNet.Packets.Test.csproj +++ b/PcapDotNet/src/PcapDotNet.Packets.Test/PcapDotNet.Packets.Test.csproj @@ -75,6 +75,7 @@ + diff --git a/PcapDotNet/src/PcapDotNet.Packets.TestUtils/PcapDotNet.Packets.TestUtils.csproj b/PcapDotNet/src/PcapDotNet.Packets.TestUtils/PcapDotNet.Packets.TestUtils.csproj index 50328411..f4d40d4b 100644 --- a/PcapDotNet/src/PcapDotNet.Packets.TestUtils/PcapDotNet.Packets.TestUtils.csproj +++ b/PcapDotNet/src/PcapDotNet.Packets.TestUtils/PcapDotNet.Packets.TestUtils.csproj @@ -76,6 +76,7 @@ + diff --git a/PcapDotNet/src/PcapDotNet.Packets.TestUtils/RandomDhcpExtensions.cs b/PcapDotNet/src/PcapDotNet.Packets.TestUtils/RandomDhcpExtensions.cs new file mode 100644 index 00000000..bcbe3960 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets.TestUtils/RandomDhcpExtensions.cs @@ -0,0 +1,332 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using PcapDotNet.Base; +using PcapDotNet.Packets.Arp; +using PcapDotNet.Packets.Dhcp; +using PcapDotNet.Packets.Dhcp.Options; +using PcapDotNet.Packets.IpV4; +using PcapDotNet.Packets.IpV6; +using PcapDotNet.TestUtils; + +namespace PcapDotNet.Packets.TestUtils +{ + [ExcludeFromCodeCoverage] + public static class RandomDhcpExtensions + { + public static DhcpLayer NextDhcpLayer(this Random random) + { + const int MaxOptions = 10; + + DhcpLayer dhcpLayer = new DhcpLayer(); + dhcpLayer.MessageOPCode = random.NextEnum(); + dhcpLayer.HardwareType = random.NextEnum(Enum.GetValues(typeof(ArpHardwareType)).Cast().Where(p => ((short)p) > byte.MaxValue)); + dhcpLayer.HardwareAddressLength = random.NextByte(16); + dhcpLayer.Hops = random.NextByte(); + dhcpLayer.TransactionId = random.NextUInt(); + dhcpLayer.SecondsElapsed = random.NextUShort(); + dhcpLayer.DhcpFlags = random.NextEnum(); + dhcpLayer.ClientIpAddress = random.NextIpV4Address(); + dhcpLayer.YourClientIpAddress = random.NextIpV4Address(); + dhcpLayer.NextServerIpAddress = random.NextIpV4Address(); + dhcpLayer.RelayAgentIpAddress = random.NextIpV4Address(); + dhcpLayer.ClientHardwareAddress = random.NextDataSegment(16); + if (random.NextBool()) + { + dhcpLayer.ServerHostName = random.NextCString(1, 64); + } + else + { + dhcpLayer.ServerHostName = ""; + } + if (random.NextBool()) + { + dhcpLayer.BootFileName = random.NextCString(1, 128); + } + else + { + dhcpLayer.BootFileName = ""; + } + dhcpLayer.IsDhcp = random.NextBool(); + int numQueries = random.Next(MaxOptions + 1); + List options = new List(); + for (int i = 0; i != numQueries; ++i) + options.Add(random.NextDhcpOption()); + dhcpLayer.Options = options; + + return dhcpLayer; + } + + public static DhcpOption NextDhcpOption(this Random random) + { + switch (random.NextEnum()) + { + #region 3. RFC 1497 Vendor Extensions + + case DhcpOptionCode.Pad: + return new DhcpPadOption(); + + case DhcpOptionCode.End: + return new DhcpEndOption(); + + case DhcpOptionCode.SubnetMask: + return new DhcpSubnetMaskOption(random.NextIpV4Address()); + + case DhcpOptionCode.TimeOffset: + return new DhcpTimeOffsetOption(random.NextInt()); + + case DhcpOptionCode.Router: + return new DhcpRouterOption(random.NextIpV4Addresses(random.Next(1, byte.MaxValue / IpV4Address.SizeOf))); + + case DhcpOptionCode.TimeServer: + return new DhcpTimeServerOption(random.NextIpV4Addresses(random.Next(1, byte.MaxValue / IpV4Address.SizeOf))); + + case DhcpOptionCode.NameServer: + return new DhcpNameServerOption(random.NextIpV4Addresses(random.Next(1, byte.MaxValue / IpV4Address.SizeOf))); + + case DhcpOptionCode.DomainNameServerServer: + return new DhcpDomainNameServerOption(random.NextIpV4Addresses(random.Next(1, byte.MaxValue / IpV4Address.SizeOf))); + + case DhcpOptionCode.LogServer: + return new DhcpLogServerOption(random.NextIpV4Addresses(random.Next(1, byte.MaxValue / IpV4Address.SizeOf))); + + case DhcpOptionCode.CookieServer: + return new DhcpCookieServerOption(random.NextIpV4Addresses(random.Next(1, byte.MaxValue / IpV4Address.SizeOf))); + + case DhcpOptionCode.LprServer: + return new DhcpLprServerOption(random.NextIpV4Addresses(random.Next(1, byte.MaxValue / IpV4Address.SizeOf))); + + case DhcpOptionCode.ImpressServer: + return new DhcpImpressServerOption(random.NextIpV4Addresses(random.Next(1, byte.MaxValue / IpV4Address.SizeOf))); + + case DhcpOptionCode.ResourceLocationServer: + return new DhcpResourceLocationServerOption(random.NextIpV4Addresses(random.Next(1, byte.MaxValue / IpV4Address.SizeOf))); + + case DhcpOptionCode.HostName: + return new DhcpHostNameOption(random.NextCString(1, 254)); + + case DhcpOptionCode.BootFileSize: + return new DhcpBootFileSizeOption(random.NextUShort()); + + case DhcpOptionCode.MeritDumpFile: + return new DhcpMeritDumpFileOption(random.NextCString(1, 254)); + + case DhcpOptionCode.DomainName: + return new DhcpDomainNameOption(random.NextCString(1, 254)); + + case DhcpOptionCode.SwapServer: + return new DhcpSwapServerOption(random.NextIpV4Address()); + + case DhcpOptionCode.RootPath: + return new DhcpRootPathOption(random.NextCString(1, 254)); + + case DhcpOptionCode.ExtensionsPath: + return new DhcpExtensionsPathOption(random.NextCString(1, 254)); + + #endregion 3. RFC 1497 Vendor Extensions + + #region 4. IP Layer Parameters per Host + + case DhcpOptionCode.IPForwardingEnable: + return new DhcpIPForwardingEnableOption(random.NextBool()); + + case DhcpOptionCode.NonLocalSourceRoutingEnable: + return new DhcpNonLocalSourceRoutingEnableOption(random.NextBool()); + + case DhcpOptionCode.PolicyFilter: + return new DhcpPolicyFilterOption(Enumerable.Range(0, random.NextByte(DhcpPolicyFilterOption.IpV4AddressWithMask.SizeOf, byte.MaxValue) / DhcpPolicyFilterOption.IpV4AddressWithMask.SizeOf).Select(p => new DhcpPolicyFilterOption.IpV4AddressWithMask(random.NextIpV4Address(), random.NextIpV4Address())).ToList()); + + case DhcpOptionCode.MaximumDatagramReassemblySize: + return new DhcpMaximumDatagramReassemblySizeOption(random.NextUShort(576, ushort.MaxValue)); + + case DhcpOptionCode.DefaultIpTimeToLive: + return new DhcpDefaultIPTimeToLiveOption(random.NextByte()); + + case DhcpOptionCode.PathMtuAgingTimeout: + return new DhcpPathMtuAgingTimeoutOption(random.NextUInt()); + + case DhcpOptionCode.PathMtuPlateauTable: + return new DhcpPathMtuPlateauTableOption(Enumerable.Range(0, random.NextByte(sizeof(ushort), byte.MaxValue) / sizeof(ushort)).Select(p => random.NextUShort()).ToList()); + + #endregion 4. IP Layer Parameters per Host + + #region 5. IP Layer Parameters per Interface + + case DhcpOptionCode.InterfaceMtu: + return new DhcpInterfaceMtuOption(random.NextUShort(68, ushort.MaxValue)); + + case DhcpOptionCode.AllSubnetsAreLocal: + return new DhcpAllSubnetsAreLocalOption(random.NextBool()); + + case DhcpOptionCode.BroadcastAddress: + return new DhcpBroadcastAddressOption(random.NextIpV4Address()); + + case DhcpOptionCode.PerformMaskDiscovery: + return new DhcpPerformMaskDiscoveryOption(random.NextBool()); + + case DhcpOptionCode.MaskSupplier: + return new DhcpMaskSupplierOption(random.NextBool()); + + case DhcpOptionCode.PerformRouterDiscovery: + return new DhcpPerformRouterDiscoveryOption(random.NextBool()); + + case DhcpOptionCode.RouterSolicitationAddress: + return new DhcpRouterSolicitationAddressOption(random.NextIpV4Address()); + + case DhcpOptionCode.StaticRoute: + return new DhcpStaticRouteOption(Enumerable.Range(0, random.NextByte(IpV4Address.SizeOf * 2, byte.MaxValue) / IpV4Address.SizeOf / 2).Select(p => new DhcpStaticRouteOption.IpV4AddressRoute(random.NextIpV4Address(), random.NextIpV4Address())).ToList()); + + #endregion 5. IP Layer Parameters per Interface + + #region 6. Link Layer Parameters per Interface + + case DhcpOptionCode.TrailerEncapsulation: + return new DhcpTrailerEncapsulationOption(random.NextBool()); + + case DhcpOptionCode.ArpCacheTimeout: + return new DhcpArpCacheTimeoutOption(random.NextUInt()); + + case DhcpOptionCode.EthernetEncapsulation: + return new DhcpEthernetEncapsulationOption(random.NextBool()); + + #endregion 6. Link Layer Parameters per Interface + + #region 7. TCP Parameters + + case DhcpOptionCode.TcpDefaultTtl: + return new DhcpTcpDefaultTtlOption(random.NextByte()); + + case DhcpOptionCode.TcpKeepaliveInterval: + return new DhcpTcpKeepaliveIntervalOption(random.NextUInt()); + + case DhcpOptionCode.TcpKeepaliveGarbage: + return new DhcpTcpKeepaliveGarbageOption(random.NextBool()); + + #endregion 7. TCP Parameters + + #region 8. Application and Service Parameters + + case DhcpOptionCode.NetworkInformationServiceDomain: + return new DhcpNetworkInformationServiceDomainOption(random.NextCString(1, 254)); + + case DhcpOptionCode.NetworkInformationServers: + return new DhcpNetworkInformationServersOption(random.NextIpV4Addresses(random.Next(1, byte.MaxValue / IpV4Address.SizeOf))); + + case DhcpOptionCode.NetworkTimeProtocolServers: + return new DhcpNetworkTimeProtocolServersOption(random.NextIpV4Addresses(random.Next(1, byte.MaxValue / IpV4Address.SizeOf))); + + case DhcpOptionCode.VendorSpecificInformation: + return new DhcpVendorSpecificInformationOption(random.NextDataSegment(random.NextByte(1, 254))); + + case DhcpOptionCode.NetBiosOverTcpIpNameServer: + return new DhcpNetBiosOverTcpIpNameServerOption(random.NextIpV4Addresses(random.Next(1, byte.MaxValue / IpV4Address.SizeOf))); ; + + case DhcpOptionCode.NetBiosOverTcpIpDatagramDistributionServer: + return new DhcpNetBiosOverTcpIpDatagramDistributionServerOption(random.NextIpV4Addresses(random.Next(1, byte.MaxValue / IpV4Address.SizeOf))); + + case DhcpOptionCode.NetBiosOverTcpIpNodeType: + DhcpNetBiosOverTcpIpNodeTypeOption.NodeType flag; + do + { + flag = random.NextFlags(); + } while (flag == 0); + return new DhcpNetBiosOverTcpIpNodeTypeOption(flag); + + case DhcpOptionCode.NetBiosOverTcpIpScope: + return new DhcpNetBiosOverTcpIpScopeOption(random.NextDataSegment(random.NextByte(1, 254))); + + case DhcpOptionCode.XWindowSystemFontServer: + return new DhcpXWindowSystemFontServerOption(random.NextIpV4Addresses(random.Next(1, byte.MaxValue / IpV4Address.SizeOf))); + + case DhcpOptionCode.XWindowSystemDisplayManager: + return new DhcpXWindowSystemDisplayManagerOption(random.NextIpV4Addresses(random.Next(1, byte.MaxValue / IpV4Address.SizeOf))); + + case DhcpOptionCode.NetworkInformationServicePlusDomain: + return new DhcpNetworkInformationServicePlusDomainOption(random.NextCString(1, 254)); + + case DhcpOptionCode.NetworkInformationServicePlusServers: + return new DhcpNetworkInformationServicePlusServersOption(random.NextIpV4Addresses(random.Next(1, byte.MaxValue / IpV4Address.SizeOf))); + + case DhcpOptionCode.MobileIPHomeAgent: + return new DhcpMobileIPHomeAgentOption(random.NextIpV4Addresses(random.Next(0, byte.MaxValue / IpV4Address.SizeOf))); + + case DhcpOptionCode.SimpleMailTransportProtocolServer: + return new DhcpSimpleMailTransportProtocolServerOption(random.NextIpV4Addresses(random.Next(1, byte.MaxValue / IpV4Address.SizeOf))); + + case DhcpOptionCode.PostOfficeProtocolServer: + return new DhcpPostOfficeProtocolServerOption(random.NextIpV4Addresses(random.Next(1, byte.MaxValue / IpV4Address.SizeOf))); + + case DhcpOptionCode.NetworkNewsTransportProtocolServer: + return new DhcpNetworkNewsTransportProtocolServerOption(random.NextIpV4Addresses(random.Next(1, byte.MaxValue / IpV4Address.SizeOf))); + + case DhcpOptionCode.DefaultWorldWideWebServer: + return new DhcpDefaultWorldWideWebServerOption(random.NextIpV4Addresses(random.Next(1, byte.MaxValue / IpV4Address.SizeOf))); + + case DhcpOptionCode.DefaultFingerServer: + return new DhcpDefaultFingerServerOption(random.NextIpV4Addresses(random.Next(1, byte.MaxValue / IpV4Address.SizeOf))); + + case DhcpOptionCode.DefaultInternetRelayChatServer: + return new DhcpDefaultInternetRelayChatServerOption(random.NextIpV4Addresses(random.Next(1, byte.MaxValue / IpV4Address.SizeOf))); + + case DhcpOptionCode.StreetTalkServer: + return new DhcpStreetTalkServerOption(random.NextIpV4Addresses(random.Next(1, byte.MaxValue / IpV4Address.SizeOf))); + + case DhcpOptionCode.StreetTalkDirectoryAssistanceServer: + return new DhcpStreetTalkDirectoryAssistanceServerOption(random.NextIpV4Addresses(random.Next(1, byte.MaxValue / IpV4Address.SizeOf))); + + #endregion 8. Application and Service Parameters + + #region 9.DHCP Extensions + + case DhcpOptionCode.RequestedIPAddress: + return new DhcpRequestedIPAddressOption(random.NextIpV4Address()); + + case DhcpOptionCode.IPAddressLeaseTime: + return new DhcpIPAddressLeaseTimeOption(random.NextUInt()); + + case DhcpOptionCode.OptionOverload: + return new DhcpOptionOverloadOption(random.NextEnum()); + + case DhcpOptionCode.TfptServerName: + return new DhcpTFtpServerNameOption(random.NextCString(1, byte.MaxValue - 1)); + + case DhcpOptionCode.BootfileName: + return new DhcpBootfileNameOption(random.NextCString(1, byte.MaxValue - 1)); + + case DhcpOptionCode.MessageType: + return new DhcpMessageTypeOption(random.NextEnum()); + + case DhcpOptionCode.ServerIdentifier: + return new DhcpServerIdentifierOption(random.NextIpV4Address()); + + case DhcpOptionCode.ParameterRequestList: + return new DhcpParameterRequestListOption(Enumerable.Range(0, random.NextByte(sizeof(DhcpOptionCode), byte.MaxValue) / sizeof(DhcpOptionCode)).Select(p => random.NextEnum()).ToList()); + + case DhcpOptionCode.Message: + return new DhcpMessageOption(random.NextCString(1, byte.MaxValue - 1)); + + case DhcpOptionCode.MaximumDhcpMessageSize: + return new DhcpMaximumDhcpMessageSizeOption(random.NextUShort()); + + case DhcpOptionCode.RenewalTimeValue: + return new DhcpRenewalTimeValueOption(random.NextUInt()); + + case DhcpOptionCode.RebindingTimeValue: + return new DhcpRebindingTimeValueOption(random.NextUInt()); + + case DhcpOptionCode.VendorClassidentifier: + return new DhcpVendorClassidentifierOption(random.NextDataSegment(random.NextByte(1, 254))); + + case DhcpOptionCode.ClientIdentifier: + return new DhcpClientIdentifierOption(random.NextByte(), random.NextDataSegment(random.NextByte(1, byte.MaxValue - 1))); + + #endregion 9.DHCP Extensions + + default: + throw new NotSupportedException(); + } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/DhcpDatagram.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/DhcpDatagram.cs new file mode 100644 index 00000000..92df8a48 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/DhcpDatagram.cs @@ -0,0 +1,384 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.Arp; +using PcapDotNet.Packets.Dhcp.Options; +using PcapDotNet.Packets.Ethernet; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp +{ + /// + /// RFC 2131. + /// The DHCP message structure is shown below: + ///
+    /// 0                   1                   2                   3
+    /// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+    /// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    /// |     op (1)    |   htype (1)   |   hlen (1)    |   hops (1)    |
+    /// +---------------+---------------+---------------+---------------+
+    /// |                            xid (4)                            |
+    /// +-------------------------------+-------------------------------+
+    /// |           secs (2)            |           flags (2)           |
+    /// +-------------------------------+-------------------------------+
+    /// |                          ciaddr  (4)                          |
+    /// +---------------------------------------------------------------+
+    /// |                          yiaddr  (4)                          |
+    /// +---------------------------------------------------------------+
+    /// |                          siaddr  (4)                          |
+    /// +---------------------------------------------------------------+
+    /// |                          giaddr  (4)                          |
+    /// +---------------------------------------------------------------+
+    /// |                                                               |
+    /// |                          chaddr  (16)                         |
+    /// |                                                               |
+    /// |                                                               |
+    /// +---------------------------------------------------------------+
+    /// |                                                               |
+    /// |                          sname   (64)                         |
+    /// +---------------------------------------------------------------+
+    /// |                                                               |
+    /// |                          file    (128)                        |
+    /// +---------------------------------------------------------------+
+    /// |                                                               |
+    /// |                          options (variable)                   |
+    /// +---------------------------------------------------------------+
+    /// 
+ ///
+ public class DhcpDatagram : Datagram + { + private static class Offset + { + public const int Op = 0; + public const int Htype = 1; + public const int Hlen = 2; + public const int Hops = 3; + public const int Xid = 4; + public const int Secs = 8; + public const int Flags = 10; + public const int CiAddr = 12; + public const int YiAddr = 16; + public const int SiAddr = 20; + public const int GiAddr = 24; + public const int ChAddr = 28; + public const int Sname = 44; + public const int File = 108; + public const int Options = 236; + public const int OptionsWithMagicCookie = 240; + } + + internal const uint DHCP_MAGIC_COOKIE = 0x63825363; + + /// + /// RFC 2131. + /// Message op code. + /// + public DhcpMessageOPCode MessageOPCode + { + get { return (DhcpMessageOPCode)this[Offset.Op]; } + } + + /// + /// RFC 2131. + /// Hardware address type. + /// + public ArpHardwareType HardwareType + { + get { return (ArpHardwareType)this[Offset.Htype]; } + } + + /// + /// RFC 2131. + /// Hardware address length. + /// + public byte HardwareAddressLength + { + get { return (byte)this[Offset.Hlen]; } + } + + /// + /// RFC 2131. + /// Client sets to zero, optionally used by relay agents when booting via a relay agent. + /// + public byte Hops + { + get { return (byte)this[Offset.Hops]; } + } + + /// + /// RFC 2131. + /// Transaction ID, a random number chosen by the client, used by the client and server to associate messages and responses between a client and a server. + /// + public uint TransactionId + { + get { return ReadUInt(Offset.Xid, Endianity.Big); } + } + + /// + /// RFC 2131. + /// Filled in by client, seconds elapsed since client began address acquisition or renewal process. + /// + public ushort SecondsElapsed + { + get { return ReadUShort(Offset.Secs, Endianity.Big); } + } + + /// + /// RFC 2131. + /// Flags. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms", MessageId = "Flags")] + public DhcpFlags Flags + { + get { return (DhcpFlags)ReadUShort(Offset.Flags, Endianity.Big); } + } + + /// + /// Whether the broadcast-flag is set. + /// + public bool Broadcast + { + get { return Flags.HasFlag(DhcpFlags.Broadcast); } + } + + /// + /// RFC 2131. + /// Client IP address; only filled in if client is in BOUND, RENEW or REBINDING state and can respond to ARP requests. + /// + public IpV4Address ClientIpAddress + { + get { return ReadIpV4Address(Offset.CiAddr, Endianity.Big); } + } + + /// + /// RFC 2131. + /// 'your' (client) IP address. + /// + public IpV4Address YourClientIpAddress + { + get { return ReadIpV4Address(Offset.YiAddr, Endianity.Big); } + } + + /// + /// RFC 2131. + /// IP address of next server to use in bootstrap; returned in DHCPOFFER, DHCPACK by server. + /// + public IpV4Address NextServerIpAddress + { + get { return ReadIpV4Address(Offset.SiAddr, Endianity.Big); } + } + + /// + /// RFC 2131. + /// Relay agent IP address, used in booting via a relay agent. + /// + public IpV4Address RelayAgentIpAddress + { + get { return ReadIpV4Address(Offset.GiAddr, Endianity.Big); } + } + + /// + /// RFC 2131. + /// Client hardware address. + /// + public DataSegment ClientHardwareAddress + { + get { return Subsegment(Offset.ChAddr, 16); } + } + + /// + /// Client MAC address. + /// + public MacAddress ClientMacAddress + { + get { return new MacAddress(ReadUInt48(Offset.ChAddr, Endianity.Big)); } + } + + /// + /// RFC 2131. + /// Optional server host name. + /// + public string ServerHostName + { + get + { + ParseServerHostName(); + return _serverHostName; + } + } + + /// + /// RFC 2131. + /// Boot file name; "generic" name or null in DHCPDISCOVER, fully qualified directory-path name in DHCPOFFER. + /// + public string BootFileName + { + get + { + ParseBootFileName(); + return _bootFileName; + } + } + + /// + /// RFC 2131. + /// Whether the magic dhcp-cookie is set. If set this datagram is a dhcp-datagram. Otherwise it's a bootp-datagram. + /// + public bool IsDhcp + { + get + { + if (Length >= Offset.Options + sizeof(uint)) + { + return ReadUInt(Offset.Options, Endianity.Big) == DHCP_MAGIC_COOKIE; + } + else + { + return false; + } + } + } + + /// + /// RFC 2131. + /// Optional parameters field. + /// + public IReadOnlyCollection Options + { + get + { + ParseOptions(); + return _options; + } + } + + /// + /// Creates a Layer that represents the datagram to be used with PacketBuilder. + /// + public override ILayer ExtractLayer() + { + return new DhcpLayer + { + MessageOPCode = MessageOPCode, + HardwareType = HardwareType, + HardwareAddressLength = HardwareAddressLength, + Hops = Hops, + TransactionId = TransactionId, + SecondsElapsed = SecondsElapsed, + DhcpFlags = Flags, + ClientIpAddress = ClientIpAddress, + YourClientIpAddress = YourClientIpAddress, + NextServerIpAddress = NextServerIpAddress, + RelayAgentIpAddress = RelayAgentIpAddress, + ClientHardwareAddress = ClientHardwareAddress, + ServerHostName = ServerHostName, + BootFileName = BootFileName, + IsDhcp = IsDhcp, + Options = Options.ToList() + }; + } + + + internal DhcpDatagram(byte[] buffer, int offset, int length) : base(buffer, offset, length) + { + } + + internal static int GetLength(bool isDhcp, IList options) + { + int length = isDhcp ? Offset.OptionsWithMagicCookie : Offset.Options; + + if (options != null) + { + length += options.Sum(option => sizeof(byte) + (!(option.OptionCode == DhcpOptionCode.Pad || option.OptionCode == DhcpOptionCode.End) ? sizeof(byte) : 0) + option.Length); // Type + Len? + Option + } + + return length; + } + + internal static void Write(byte[] buffer, int offset, DhcpMessageOPCode messageType, ArpHardwareType hardwareType, byte hardwareAddressLength, byte hops, uint transactionId, ushort secondsElapsed, DhcpFlags flags, IpV4Address clientIpAddress, IpV4Address yourClientIpAddress, IpV4Address nextServerIpAddress, IpV4Address relayAgentIpAddress, DataSegment clientHardwareAddress, string serverHostName, string bootFileName, bool isDhcp, IList options) + { + buffer.Write(offset + Offset.Op, (byte)messageType); + buffer.Write(offset + Offset.Htype, (byte)hardwareType); + buffer.Write(offset + Offset.Hlen, hardwareAddressLength); + buffer.Write(offset + Offset.Hops, hops); + buffer.Write(offset + Offset.Xid, transactionId, Endianity.Big); + buffer.Write(offset + Offset.Secs, secondsElapsed, Endianity.Big); + buffer.Write(offset + Offset.Flags, (ushort)flags, Endianity.Big); + buffer.Write(offset + Offset.CiAddr, clientIpAddress, Endianity.Big); + buffer.Write(offset + Offset.YiAddr, yourClientIpAddress, Endianity.Big); + buffer.Write(offset + Offset.SiAddr, nextServerIpAddress, Endianity.Big); + buffer.Write(offset + Offset.GiAddr, relayAgentIpAddress, Endianity.Big); + buffer.Write(offset + Offset.ChAddr, clientHardwareAddress); + + buffer.Write(offset + Offset.Sname, new DataSegment(new byte[Offset.File - Offset.Sname])); // ensure 0 + if (serverHostName != null) + { + buffer.Write(offset + Offset.Sname, new DataSegment(Encoding.ASCII.GetBytes(serverHostName))); + } + buffer.Write(offset + Offset.File, new DataSegment(new byte[Offset.Options - Offset.File])); // ensure 0 + if (bootFileName != null) + { + buffer.Write(offset + Offset.File, new DataSegment(Encoding.ASCII.GetBytes(bootFileName))); + } + + if (isDhcp) + { + buffer.Write(offset + Offset.Options, DHCP_MAGIC_COOKIE, Endianity.Big); + offset += Offset.OptionsWithMagicCookie; + } + else + { + offset += Offset.Options; + } + + if (options != null) + { + foreach (DhcpOption option in options) + { + option.Write(buffer, ref offset); + } + } + } + + private void ParseServerHostName() + { + if (_serverHostName == null) + { + //at the moment we only interpret server host name as sname and ignore options + byte[] byteServerHostName = ReadBytes(Offset.Sname, 64); + _serverHostName = Encoding.ASCII.GetString(byteServerHostName).TrimEnd('\0'); + } + } + + private void ParseBootFileName() + { + if (_bootFileName == null) + { + //at the moment we only interpret server host name as sname and ignore options + byte[] byteBootFileName = ReadBytes(Offset.File, 128); + _bootFileName = Encoding.ASCII.GetString(byteBootFileName).TrimEnd('\0'); + } + } + + private void ParseOptions() + { + if (_options == null) + { + List options = new List(); + int offset = IsDhcp ? Offset.OptionsWithMagicCookie : Offset.Options; + while (offset < Length) + { + options.Add(DhcpOptionFactory.CreateInstance(this, ref offset)); + } + _options = new ReadOnlyCollection(options); + } + } + + private string _serverHostName; + private string _bootFileName; + private IReadOnlyCollection _options; + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/DhcpFlags.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/DhcpFlags.cs new file mode 100644 index 00000000..f08f48ae --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/DhcpFlags.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp +{ + /// + /// RFC 2131. + ///
+    ///                     1 1 1 1 1 1
+    /// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+    /// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    /// |B|             MBZ             |
+    /// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    ///
+    /// B:  BROADCAST flag
+    /// MBZ:  MUST BE ZERO(reserved for future use)
+    /// 
+ ///
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms", MessageId = "Flags")] + public enum DhcpFlags : ushort + { + /// + /// RFC 2131. + /// Response as Unicast. + /// + Unicast = 0 << 15, + + /// + /// RFC 2131. + /// Response as Broadcast. + /// + Broadcast = 1 << 15 + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/DhcpLayer.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/DhcpLayer.cs new file mode 100644 index 00000000..8dedfd0a --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/DhcpLayer.cs @@ -0,0 +1,216 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Base; +using PcapDotNet.Packets.Arp; +using PcapDotNet.Packets.Dhcp.Options; +using PcapDotNet.Packets.Ethernet; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp +{ + /// + /// Represents a DHCP layer. + /// + /// + public sealed class DhcpLayer : SimpleLayer, IEquatable + { + /// + /// Message op code. + /// + public DhcpMessageOPCode MessageOPCode { get; set; } + + /// + /// Hardware address type. + /// + public ArpHardwareType HardwareType { get; set; } + + /// + /// Hardware address length. + /// + public byte HardwareAddressLength + { + get + { + return _hardwareAddressLength.GetValueOrDefault(); + } + set + { + _hardwareAddressLength = value; + } + } + + /// + /// Client sets to zero, optionally used by relay agents when booting via a relay agent. + /// + public byte Hops { get; set; } + + /// + /// Transaction ID, a random number chosen by the client, used by the client and server to associate messages and responses between a client and a server. + /// + public uint TransactionId { get; set; } + + /// + /// Filled in by client, seconds elapsed since client began address acquisition or renewal process. + /// + public ushort SecondsElapsed { get; set; } + + /// + /// Flags. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1726:UsePreferredTerms", MessageId = "Flags")] + public DhcpFlags DhcpFlags { get; set; } + + /// + /// Whether the broadcast-flag is set. + /// + public bool Broadcast + { + get + { + return DhcpFlags.HasFlag(DhcpFlags.Broadcast); + } + set + { + if (value) + { + DhcpFlags |= DhcpFlags.Broadcast; + } + else + { + DhcpFlags &= ~DhcpFlags.Broadcast; + } + } + } + + /// + /// Client IP address; only filled in if client is in BOUND, RENEW or REBINDING state and can respond to ARP requests. + /// + public IpV4Address ClientIpAddress { get; set; } + + /// + /// 'your' (client) IP address. + /// + public IpV4Address YourClientIpAddress { get; set; } + + /// + /// IP address of next server to use in bootstrap; returned in DHCPOFFER, DHCPACK by server. + /// + public IpV4Address NextServerIpAddress { get; set; } + + /// + /// Relay agent IP address, used in booting via a relay agent. + /// + public IpV4Address RelayAgentIpAddress { get; set; } + + /// + /// Client hardware address. + /// + public DataSegment ClientHardwareAddress { get; set; } + + /// + /// Client MAC address. + /// When setting this property and the HardwareAddressLength has not been set, the HardwareAddressLength will be automatically set according MacAddress.SizeOf (6). + /// + public MacAddress ClientMacAddress + { + get + { + if (ClientHardwareAddress == null) + return MacAddress.Zero; + return new MacAddress(ClientHardwareAddress.ReadUInt48(0, Endianity.Big)); + } + set + { + if (ClientHardwareAddress == null) + ClientHardwareAddress = new DataSegment(new byte[16]); + ClientHardwareAddress.Buffer.Write(0, value, Endianity.Big); + + if (!_hardwareAddressLength.HasValue) + { + HardwareAddressLength = MacAddress.SizeOf; + } + } + } + + /// + /// Optional server host name. + /// + public string ServerHostName { get; set; } + + /// + /// Boot file name; "generic" name or null in DHCPDISCOVER, fully qualified directory-path name in DHCPOFFER. + /// + public string BootFileName { get; set; } + + /// + /// Whether the magic dhcp-cookie is set. If set this datagram is a dhcp-datagram. Otherwise it's a bootp-datagram. + /// + public bool IsDhcp { get; set; } + + /// + /// Optional parameters field. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public IList Options { get; set; } + + /// + /// The number of bytes this layer will take. + /// + public override int Length + { + get + { + return DhcpDatagram.GetLength(IsDhcp, Options); + } + } + + /// + /// Writes the layer to the buffer. + /// + /// The buffer to write the layer to. + /// The offset in the buffer to start writing the layer at. + protected override void Write(byte[] buffer, int offset) + { + DhcpDatagram.Write(buffer, offset, + MessageOPCode, HardwareType, HardwareAddressLength, Hops, TransactionId, SecondsElapsed, DhcpFlags, ClientIpAddress, YourClientIpAddress, + NextServerIpAddress, RelayAgentIpAddress, ClientHardwareAddress, ServerHostName, BootFileName, IsDhcp, Options); + } + + /// + /// True if the two objects are equal Layers. + /// + public bool Equals(DhcpLayer other) + { + return other != null && + Equals(MessageOPCode, other.MessageOPCode) && + Equals(HardwareType, other.HardwareType) && + Equals(HardwareAddressLength, other.HardwareAddressLength) && + Equals(Hops, other.Hops) && + Equals(TransactionId, other.TransactionId) && + Equals(SecondsElapsed, other.SecondsElapsed) && + Equals(DhcpFlags, other.DhcpFlags) && + Equals(ClientIpAddress, other.ClientIpAddress) && + Equals(YourClientIpAddress, other.YourClientIpAddress) && + Equals(NextServerIpAddress, other.NextServerIpAddress) && + Equals(RelayAgentIpAddress, other.RelayAgentIpAddress) && + Equals(ClientHardwareAddress, ClientHardwareAddress) && + Equals(ServerHostName, other.ServerHostName) && + Equals(BootFileName, other.BootFileName) && + Equals(IsDhcp, other.IsDhcp) && + (Options.IsNullOrEmpty() && other.Options.IsNullOrEmpty() || Options.SequenceEqual(other.Options)); + } + + /// + /// True if the two objects are equal Layers. + /// + public override bool Equals(Layer other) + { + return Equals(other as DhcpLayer); + } + + private byte? _hardwareAddressLength; + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/DhcpMessageType.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/DhcpMessageType.cs new file mode 100644 index 00000000..6ca39216 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/DhcpMessageType.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp +{ + /// + /// RFC 2131. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue")] + public enum DhcpMessageOPCode : byte + { + /// + /// RFC 2131. + /// Indicates a Boot Request. + /// + BootRequest = 1, + + /// + /// RFC 2131. + /// Indicates a Boot Reply. + /// + BootReply = 2 + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/DhcpOptionFactory.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/DhcpOptionFactory.cs new file mode 100644 index 00000000..8ea067e3 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/DhcpOptionFactory.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.Dhcp.Options; + +namespace PcapDotNet.Packets.Dhcp +{ + internal static class DhcpOptionFactory + { + internal static DhcpOption CreateInstance(DataSegment data, ref int offset) + { + DhcpOptionCode optionCode = (DhcpOptionCode)data[offset++]; + + MethodInfo readMethod; + if (_optionReaders.TryGetValue(optionCode, out readMethod)) + { + object[] args = new object[] { data, offset }; + DhcpOption option = (DhcpOption)readMethod.Invoke(null, args); + offset = (int)args[1]; + return option; + } + else + { + return DhcpAnyOption.Read(data, ref offset); + } + } + + private static Dictionary InitializeComplexOptions() + { + Dictionary optionReaders = new Dictionary(); + foreach (MethodInfo readMethod in Assembly.GetExecutingAssembly().GetTypes(). + Where(type=> typeof(DhcpOption).IsAssignableFrom(type)) + .SelectMany(type => type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static))) + { + DhcpOptionReadRegistrationAttribute readRegistrationAttribute = readMethod.GetCustomAttribute(false); + if (readRegistrationAttribute == null) + continue; + + if (typeof(DataSegment).IsAssignableFrom(readMethod.GetParameters()[0].ParameterType) && + readMethod.GetParameters()[1].ParameterType == typeof(int).MakeByRefType() && + typeof(DhcpOption).IsAssignableFrom(readMethod.ReturnType)) + { + optionReaders.Add(readRegistrationAttribute.OptionCode, readMethod); + } + else + { + throw new NotSupportedException("Method " + readMethod + " has a DhcpOptionReadRegistrationAttribute but has no valid signature"); + } + } + return optionReaders; + } + + private static readonly Dictionary _optionReaders = InitializeComplexOptions(); + } +} diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/DhcpOptionReadRegistrationAttribute.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/DhcpOptionReadRegistrationAttribute.cs new file mode 100644 index 00000000..d0abfeae --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/DhcpOptionReadRegistrationAttribute.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.Dhcp.Options; + +namespace PcapDotNet.Packets.Dhcp +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] + internal sealed class DhcpOptionReadRegistrationAttribute : Attribute + { + public DhcpOptionReadRegistrationAttribute(DhcpOptionCode optionCode) + { + OptionCode = optionCode; + } + + public DhcpOptionCode OptionCode { get; private set; } + } +} diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpARPCacheTimeoutOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpARPCacheTimeoutOption.cs new file mode 100644 index 00000000..b38cf5d2 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpARPCacheTimeoutOption.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies the timeout in seconds for ARP cache entries. + ///
+    ///  Code   Len           Time
+    /// +-----+-----+-----+-----+-----+-----+
+    /// |  35 |  4  |  t1 |  t2 |  t3 |  t4 |
+    /// +-----+-----+-----+-----+-----+-----+
+    /// 
+ ///
+ public class DhcpArpCacheTimeoutOption : DhcpUIntOption + { + /// + /// create new ArpCacheTimeoutOption. + /// + /// Time + public DhcpArpCacheTimeoutOption(uint time) : base(time, DhcpOptionCode.ArpCacheTimeout) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.ArpCacheTimeout)] + internal static DhcpArpCacheTimeoutOption Read(DataSegment data, ref int offset) + { + return DhcpUIntOption.Read(data, ref offset, p => new DhcpArpCacheTimeoutOption(p)); + } + + /// + /// RFC 2132. + /// Time + /// timeout in seconds for ARP cache entries. + /// + public uint Time + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpAddressListOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpAddressListOption.cs new file mode 100644 index 00000000..3c82097b --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpAddressListOption.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// Abstract class for all Dhcp-Options with a list of Addresses. + /// + public abstract class DhcpAddressListOption : DhcpOption + { + internal const int MAX_ADDRESSES = byte.MaxValue / IpV4Address.SizeOf; + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] + internal DhcpAddressListOption(IList addresses, DhcpOptionCode code) : base(code) + { + if (addresses == null) + throw new ArgumentNullException(nameof(addresses)); + if (addresses.Count == 0 && !AllowEmptyAddresses) + throw new ArgumentOutOfRangeException(nameof(addresses), addresses.Count, "The minimum items in addresses is 1"); + if (addresses.Count > MAX_ADDRESSES) + throw new ArgumentOutOfRangeException(nameof(addresses), addresses.Count, "The maximum items in addresses is " + MAX_ADDRESSES); + Addresses = new ReadOnlyCollection(addresses); + } + + internal static T Read(DataSegment data, ref int offset, Func, T> ctor) where T : DhcpAddressListOption + { + return ctor(GetAddresses(data, ref offset)); + } + + internal static IList GetAddresses(DataSegment data, ref int offset) + { + byte length = data[offset++]; + return GetAddresses(data, length, ref offset); + } + + internal static IList GetAddresses(DataSegment data, byte length, ref int offset) + { + if (length % IpV4Address.SizeOf != 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "length has to be multiple of " + IpV4Address.SizeOf); + List addresses = new List(); + for (int i = 0; i < length; i += IpV4Address.SizeOf) + { + addresses.Add(data.ReadIpV4Address(offset + i, Endianity.Big)); + } + offset += length; + return addresses; + } + + internal override void Write(byte[] buffer, ref int offset) + { + base.Write(buffer, ref offset); + foreach (IpV4Address address in Addresses) + { + buffer.Write(ref offset, address, Endianity.Big); + } + } + + /// + /// true if Addresses-List is allowed to be empty (Default false). + /// + protected virtual bool AllowEmptyAddresses + { + get { return false; } + } + + /// + /// RFC 2132. + /// Value of Length-Field. + /// + public override byte Length + { + get + { + return (byte)(Addresses.Count * IpV4Address.SizeOf); + } + } + + /// + /// RFC 2132. + /// collection of all addresses of this option. + /// + public IReadOnlyCollection Addresses + { + get; + private set; + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpAllSubnetsAreLocalOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpAllSubnetsAreLocalOption.cs new file mode 100644 index 00000000..996a569c --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpAllSubnetsAreLocalOption.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies whether or not the client may assume that all + /// subnets of the IP network to which the client is connected use the + /// same MTU as the subnet of that network to which the client is + /// directly connected. + ///
+    ///  Code   Len  Value
+    /// +-----+-----+-----+
+    /// |  27 |  1  | 0/1 |
+    /// +-----+-----+-----+
+    /// 
+ ///
+ public class DhcpAllSubnetsAreLocalOption : DhcpBooleanOption + { + /// + /// create new AllSubnetsAreLocalOption. + /// + /// Value + public DhcpAllSubnetsAreLocalOption(bool value) : base(value, DhcpOptionCode.AllSubnetsAreLocal) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.AllSubnetsAreLocal)] + internal static DhcpAllSubnetsAreLocalOption Read(DataSegment data, ref int offset) + { + return DhcpBooleanOption.Read(data, ref offset, p => new DhcpAllSubnetsAreLocalOption(p)); + } + + /// + /// RFC 2132. + /// True indicates that all subnets share + /// the same MTU. False means that the client should assume that + /// some subnets of the directly connected network may have smaller MTUs. + /// + public bool Value + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpAnyOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpAnyOption.cs new file mode 100644 index 00000000..ad581cac --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpAnyOption.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// DHCP option for any options. + /// + public class DhcpAnyOption : DhcpOption + { + /// + /// create new Any-Option. + /// + /// data represented by the option + /// the OptionCode + public DhcpAnyOption(DataSegment data, DhcpOptionCode code) : base(code) + { + Data = data; + } + + /// + /// Length of the Dhcp-Option. + /// + public override byte Length + { + get + { + return (byte)Data.Length; + } + } + + internal static DhcpAnyOption Read(DataSegment data, ref int offset) + { + DhcpOptionCode code = (DhcpOptionCode)data[offset - 1]; + byte length = data[offset++]; + DhcpAnyOption option = new DhcpAnyOption(data.Subsegment(offset, length), code); + offset += length; + return option; + } + + internal override void Write(byte[] buffer, ref int offset) + { + if (Data.Length > byte.MaxValue) + throw new InvalidOperationException("Data.Length has to be less than 256 but is " + Data.Length); + base.Write(buffer, ref offset); + buffer.Write(ref offset, Data); + } + + /// + /// Data of the Option. + /// + public DataSegment Data + { + get { return _data; } + set + { + if (value == null) + throw new ArgumentNullException(nameof(value)); + if (value.Length > byte.MaxValue) + throw new ArgumentOutOfRangeException(nameof(value), value.Length, "Data.Length has to be less than 256"); + _data = value; + } + } + + private DataSegment _data; + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpBooleanOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpBooleanOption.cs new file mode 100644 index 00000000..d083e9d9 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpBooleanOption.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// Abstract class for all Dhcp-Options with a boolean value. + /// + public class DhcpBooleanOption : DhcpOption + { + internal DhcpBooleanOption(bool value, DhcpOptionCode code) : base(code) + { + InternalValue = value; + } + + internal static T Read(DataSegment data, ref int offset, Func ctor) where T : DhcpBooleanOption + { + if (ctor == null) + throw new ArgumentNullException(nameof(ctor)); + byte len = data[offset++]; + if (len != 1) + throw new ArgumentException("Length of a DHCP DhcpBooleanOption Option has to be 1"); + if (data[offset] != 0 && data[offset] != 1) + throw new ArgumentException("Value of a DHCP DhcpBooleanOption Option has to be 0 or 1"); + T option = ctor(data[offset++] == 1 ? true : false); + return option; + } + + internal override void Write(byte[] buffer, ref int offset) + { + base.Write(buffer, ref offset); + buffer.Write(ref offset, InternalValue ? (byte)1 : (byte)0); + } + + /// + /// RFC 2132. + /// Value of Length-Field. + /// + public override byte Length + { + get + { + return sizeof(bool); + } + } + + /// + /// The real value of the BooleanOption. + /// + protected bool InternalValue + { + get; + set; + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpBootFileSizeOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpBootFileSizeOption.cs new file mode 100644 index 00000000..16c37450 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpBootFileSizeOption.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies the length in 512-octet blocks of the default + /// boot image for the client. + ///
+    ///  Code   Len   File Size
+    /// +-----+-----+-----+-----+
+    /// |  13 |  2  |  l1 |  l2 |
+    /// +-----+-----+-----+-----+
+    /// 
+ ///
+ public class DhcpBootFileSizeOption : DhcpUShortOption + { + /// + /// create new DhcpBootFileSizeOption. + /// + /// File Size + public DhcpBootFileSizeOption(ushort fileSize) : base(fileSize, DhcpOptionCode.BootFileSize) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.BootFileSize)] + internal static DhcpBootFileSizeOption Read(DataSegment data, ref int offset) + { + return DhcpUShortOption.Read(data, ref offset, p => new DhcpBootFileSizeOption(p)); + } + + /// + /// File Size. + /// + public ushort FileSize + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpBootfileNameOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpBootfileNameOption.cs new file mode 100644 index 00000000..dcbdd87d --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpBootfileNameOption.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option is used to identify a bootfile when the 'file' field in + /// the DHCP header has been used for DHCP options. + ///
+    ///  Code  Len    Bootfile name
+    /// +-----+-----+-----+-----+-----+---
+    /// | 67  |  n  |  c1 |  c2 |  c3 | ...
+    /// +-----+-----+-----+-----+-----+---
+    /// 
+ ///
+ public class DhcpBootfileNameOption : DhcpStringOption + { + /// + /// create new DhcpBootfileNameOption. + /// + /// Bootfilename + public DhcpBootfileNameOption(string bootfileName) : base(bootfileName, DhcpOptionCode.BootfileName) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.BootfileName)] + internal static DhcpBootfileNameOption Read(DataSegment data, ref int offset) + { + return DhcpStringOption.Read(data, ref offset, p => new DhcpBootfileNameOption(p)); + } + + /// + /// Bootfilename. + /// + public string BootfileName + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpBroadcastAddressOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpBroadcastAddressOption.cs new file mode 100644 index 00000000..5056fbc3 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpBroadcastAddressOption.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies the broadcast address in use on the client's + /// subnet. + ///
+    ///  Code   Len     Broadcast Address
+    /// +-----+-----+-----+-----+-----+-----+
+    /// |  28 |  4  |  b1 |  b2 |  b3 |  b4 |
+    /// +-----+-----+-----+-----+-----+-----+
+    /// 
+ ///
+ public class DhcpBroadcastAddressOption : DhcpSingleAddressOption + { + /// + /// create new DhcpBroadcastAddressOption. + /// + /// Broadcast Address + public DhcpBroadcastAddressOption(IpV4Address broadcastAddress) : base(broadcastAddress, DhcpOptionCode.BroadcastAddress) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.BroadcastAddress)] + internal static DhcpBroadcastAddressOption Read(DataSegment data, ref int offset) + { + return DhcpSingleAddressOption.Read(data, ref offset, p => new DhcpBroadcastAddressOption(p)); + } + + /// + /// Broadcast Address + /// + public IpV4Address BroadcastAddress + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpByteOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpByteOption.cs new file mode 100644 index 00000000..7a8b07e1 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpByteOption.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// Abstract class for all Dhcp-Options with a byte value. + /// + public class DhcpByteOption : DhcpOption + { + internal DhcpByteOption(byte value, DhcpOptionCode code) : base(code) + { + InternalValue = value; + } + + internal static T Read(DataSegment data, ref int offset, Func ctor) where T : DhcpByteOption + { + if (ctor == null) + throw new ArgumentNullException(nameof(ctor)); + byte len = data[offset++]; + if (len != 1) + throw new ArgumentException("Length of a DHCP DhcpByteOption Option has to be 1"); + T option = ctor(data[offset++]); + return option; + } + + internal override void Write(byte[] buffer, ref int offset) + { + base.Write(buffer, ref offset); + buffer.Write(ref offset, InternalValue); + } + + /// + /// RFC 2132. + /// Value of Length-Field. + /// + public override byte Length + { + get + { + return sizeof(byte); + } + } + + /// + /// The real value of the ByteOption. + /// + protected byte InternalValue + { + get; + set; + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpClientIdentifierOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpClientIdentifierOption.cs new file mode 100644 index 00000000..c480ef23 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpClientIdentifierOption.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option is used by DHCP clients to specify their unique + /// identifier.DHCP servers use this value to index their database of + /// address bindings. This value is expected to be unique for all + /// clients in an administrative domain. + ///
+    ///  Code   Len   Type  Client-Identifier
+    /// +-----+-----+-----+-----+-----+---
+    /// |  61 |  n  |  t1 |  i1 |  i2 | ...
+    /// +-----+-----+-----+-----+-----+---
+    /// 
+ ///
+ public class DhcpClientIdentifierOption : DhcpOption + { + /// + /// create new DhcpClientIdentifierOption. + /// + /// Type + /// Client-Identifier + public DhcpClientIdentifierOption(byte type, DataSegment clientIdentifier) : base(DhcpOptionCode.ClientIdentifier) + { + ClientIdentifierType = type; + ClientIdentifier = clientIdentifier; + } + + [DhcpOptionReadRegistration(DhcpOptionCode.ClientIdentifier)] + internal static DhcpClientIdentifierOption Read(DataSegment data, ref int offset) + { + byte length = data[offset++]; + DhcpClientIdentifierOption option = new DhcpClientIdentifierOption(data[offset], data.Subsegment(offset + 1, length - 1)); + offset += option.Length; + return option; + } + + internal override void Write(byte[] buffer, ref int offset) + { + base.Write(buffer, ref offset); + buffer.Write(ref offset, ClientIdentifierType); + buffer.Write(ref offset, ClientIdentifier); + } + + /// + /// RFC 2132. + /// Value of Length-Field. + /// + public override byte Length + { + get + { + return (byte)(sizeof(byte) + ClientIdentifier.Length); + } + } + + /// + /// RFC 2132. + /// Type + /// + public byte ClientIdentifierType + { + get; + set; + } + + /// + /// RFC 2132. + /// Client-Identifier. + /// + public DataSegment ClientIdentifier + { + get { return _clientIdentifier; } + set + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + if (value.Length < 1) + { + throw new ArgumentOutOfRangeException(nameof(value), value.Length, "ClientIdentifier.Length has to be greater than 0"); + } + if (value.Length >= byte.MaxValue - 1) + { + throw new ArgumentOutOfRangeException(nameof(value), value.Length, "ClientIdentifier.Length has to be less than 254"); + } + _clientIdentifier = value; + } + } + + private DataSegment _clientIdentifier; + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpCookieServerOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpCookieServerOption.cs new file mode 100644 index 00000000..451e2aec --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpCookieServerOption.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// The cookie server option specifies a list of RFC 865 [9] cookie + /// servers available to the client.Servers SHOULD be listed in order + /// of preference. + ///
+    ///  Code   Len         Address 1               Address 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// |  8  |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |  ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// 
+ ///
+ public class DhcpCookieServerOption : DhcpAddressListOption + { + /// + /// create new DhcpCookieServerOption. + /// + /// Addresses + public DhcpCookieServerOption(IList addresses) : base(addresses, DhcpOptionCode.CookieServer) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.CookieServer)] + internal static DhcpCookieServerOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, (p) => new DhcpCookieServerOption(p)); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpDataSegmentOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpDataSegmentOption.cs new file mode 100644 index 00000000..7078c41b --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpDataSegmentOption.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// Abstract class for all Dhcp-Options with a DataSegment value. + /// + public class DhcpDataSegmentOption : DhcpOption + { + internal DhcpDataSegmentOption(DataSegment value, DhcpOptionCode code) : base(code) + { + InternalValue = value; + } + + internal static T Read(DataSegment data, ref int offset, Func ctor) where T : DhcpDataSegmentOption + { + if (ctor == null) + throw new ArgumentNullException(nameof(ctor)); + byte len = data[offset++]; + T option = ctor(data.Subsegment(offset, len)); + offset += option.Length; + return option; + } + + internal override void Write(byte[] buffer, ref int offset) + { + base.Write(buffer, ref offset); + buffer.Write(ref offset, InternalValue); + } + + /// + /// RFC 2132. + /// Value of Length-Field. + /// + public override byte Length + { + get + { + return (byte)InternalValue.Length; + } + } + + /// + /// The real value of the UIntOption. + /// + protected DataSegment InternalValue + { + get { return _internalValue; } + set + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + if (value.Length < 1) + { + throw new ArgumentOutOfRangeException(nameof(value), value.Length, "DataSegment.Length has to be greater than 0"); + } + if (value.Length > byte.MaxValue) + { + throw new ArgumentOutOfRangeException(nameof(value), value.Length, "DataSegment.Length has to be less than 256"); + } + _internalValue = value; + } + } + + private DataSegment _internalValue; + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpDefaultFingerServerOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpDefaultFingerServerOption.cs new file mode 100644 index 00000000..e9d5d3fe --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpDefaultFingerServerOption.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// The Finger server option specifies a list of Finger available to the + /// client.Servers SHOULD be listed in order of preference. + ///
+    ///  Code   Len         Address 1               Address 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// | 73  |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |  ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// 
+ ///
+ public class DhcpDefaultFingerServerOption : DhcpAddressListOption + { + /// + /// create new DhcpDefaultFingerServerOption. + /// + /// Addresses + public DhcpDefaultFingerServerOption(IList addresses) : base(addresses, DhcpOptionCode.DefaultFingerServer) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.DefaultFingerServer)] + internal static DhcpDefaultFingerServerOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, (p) => new DhcpDefaultFingerServerOption(p)); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpDefaultIPTimeToLiveOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpDefaultIPTimeToLiveOption.cs new file mode 100644 index 00000000..5b5f1735 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpDefaultIPTimeToLiveOption.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies the default time-to-live that the client should + /// use on outgoing datagrams. + ///
+    ///  Code   Len   TTL
+    /// +-----+-----+-----+
+    /// |  23 |  1  | ttl |
+    /// +-----+-----+-----+
+    /// 
+ ///
+ public class DhcpDefaultIPTimeToLiveOption : DhcpByteOption + { + /// + /// create new DhcpDefaultIPTimeToLiveOption. + /// + /// TTL + public DhcpDefaultIPTimeToLiveOption(byte ttl) : base(ttl, DhcpOptionCode.DefaultIpTimeToLive) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.DefaultIpTimeToLive)] + internal static DhcpDefaultIPTimeToLiveOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpDefaultIPTimeToLiveOption(p)); + } + + /// + /// RFC 2132. + /// TTL. + /// + public byte Ttl + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpDefaultInternetRelayChatServerOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpDefaultInternetRelayChatServerOption.cs new file mode 100644 index 00000000..16831bf4 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpDefaultInternetRelayChatServerOption.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// The IRC server option specifies a list of IRC available to the + /// client.Servers SHOULD be listed in order of preference. + ///
+    ///  Code   Len         Address 1               Address 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// | 74  |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |  ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// 
+ ///
+ public class DhcpDefaultInternetRelayChatServerOption : DhcpAddressListOption + { + /// + /// create new DhcpDefaultInternetRelayChatServerOption. + /// + /// Addresses + public DhcpDefaultInternetRelayChatServerOption(IList addresses) : base(addresses, DhcpOptionCode.DefaultInternetRelayChatServer) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.DefaultInternetRelayChatServer)] + internal static DhcpDefaultInternetRelayChatServerOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, (p) => new DhcpDefaultInternetRelayChatServerOption(p)); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpDefaultWorldWideWebServerOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpDefaultWorldWideWebServerOption.cs new file mode 100644 index 00000000..ee563aee --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpDefaultWorldWideWebServerOption.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// The WWW server option specifies a list of WWW available to the + /// client.Servers SHOULD be listed in order of preference. + ///
+    ///  Code   Len         Address 1               Address 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// | 72  |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |  ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// 
+ ///
+ public class DhcpDefaultWorldWideWebServerOption : DhcpAddressListOption + { + /// + /// create new DhcpDefaultWorldWideWebServerOption. + /// + /// Addresses + public DhcpDefaultWorldWideWebServerOption(IList addresses) : base(addresses, DhcpOptionCode.DefaultWorldWideWebServer) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.DefaultWorldWideWebServer)] + internal static DhcpDefaultWorldWideWebServerOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpDefaultWorldWideWebServerOption(p)); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpDomainNameOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpDomainNameOption.cs new file mode 100644 index 00000000..a40b2142 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpDomainNameOption.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies the domain name that client should use when + /// resolving hostnames via the Domain Name System. + ///
+    ///  Code   Len        Domain Name
+    /// +-----+-----+-----+-----+-----+-----+---
+    /// |  15 |  n  |  d1 |  d2 |  d3 |  d4 | ...
+    /// +-----+-----+-----+-----+-----+-----+---
+    /// 
+ ///
+ public class DhcpDomainNameOption : DhcpStringOption + { + /// + /// create new DhcpDomainNameOption. + /// + /// Domain Name + public DhcpDomainNameOption(string domainName) : base(domainName, DhcpOptionCode.DomainName) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.DomainName)] + internal static DhcpDomainNameOption Read(DataSegment data, ref int offset) + { + return DhcpStringOption.Read(data, ref offset, p => new DhcpDomainNameOption(p)); + } + + /// + /// RFC 2132. + /// Domain Name. + /// + public string DomainName + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpDomainNameServerOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpDomainNameServerOption.cs new file mode 100644 index 00000000..9d81d9b0 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpDomainNameServerOption.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// The domain name server option specifies a list of Domain Name System + /// (STD 13, RFC 1035 [8]) name servers available to the client. Servers + /// SHOULD be listed in order of preference. + ///
+    ///  Code   Len         Address 1               Address 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// |  6  |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |  ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// 
+ ///
+ public class DhcpDomainNameServerOption : DhcpAddressListOption + { + /// + /// create new DhcpDomainNameServerOption. + /// + /// Addresses + public DhcpDomainNameServerOption(IList addresses) : base(addresses, DhcpOptionCode.DomainNameServerServer) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.DomainNameServerServer)] + internal static DhcpDomainNameServerOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpDomainNameServerOption(p)); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpEndOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpEndOption.cs new file mode 100644 index 00000000..e84d408a --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpEndOption.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// The end option marks the end of valid information in the vendor field. + ///
+    ///  Code
+    /// +-----+
+    /// | 255 |
+    /// +-----+
+    /// 
+ ///
+ public class DhcpEndOption : DhcpOption + { + /// + /// create new EndOption. + /// + public DhcpEndOption() : base(DhcpOptionCode.End) + { + } + + /// + /// Length of the Dhcp-Option + /// + public override byte Length + { + get { return 0; } + } + + [DhcpOptionReadRegistration(DhcpOptionCode.End)] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "offset")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "data")] + internal static DhcpEndOption Read(DataSegment data, ref int offset) + { + return new Options.DhcpEndOption(); + } + + internal override void Write(byte[] buffer, ref int offset) + { + buffer.Write(offset++, (byte)OptionCode); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpEthernetEncapsulationOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpEthernetEncapsulationOption.cs new file mode 100644 index 00000000..fc84bcfd --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpEthernetEncapsulationOption.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies whether or not the client should use Ethernet + /// Version 2 (RFC 894 [15]) or IEEE 802.3 (RFC 1042 [16]) encapsulation + /// if the interface is an Ethernet. + ///
+    ///  Code   Len  Value
+    /// +-----+-----+-----+
+    /// |  36 |  1  | 0/1 |
+    /// +-----+-----+-----+
+    /// 
+ ///
+ public class DhcpEthernetEncapsulationOption : DhcpBooleanOption + { + /// + /// create new DhcpEthernetEncapsulationOption. + /// + /// Value + public DhcpEthernetEncapsulationOption(bool value) : base(value, DhcpOptionCode.EthernetEncapsulation) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.EthernetEncapsulation)] + internal static DhcpEthernetEncapsulationOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpEthernetEncapsulationOption(p)); + } + + /// + /// RFC 2132. + /// A value of false indicates that the + /// client should use RFC 894 encapsulation. A value of true means that the + /// client should use RFC 1042 encapsulation. + /// + public bool Value + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpExtensionsPathOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpExtensionsPathOption.cs new file mode 100644 index 00000000..cd41f3af --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpExtensionsPathOption.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// A string to specify a file, retrievable via TFTP, which contains + /// information which can be interpreted in the same way as the 64-octet + /// vendor-extension field within the BOOTP response, with the following + /// exceptions: + /// - the length of the file is unconstrained; + /// - all references to Tag 18 (i.e., instances of the BOOTP Extensions Path field) within the file are ignored. + ///
+    ///  Code   Len      Extensions Pathname
+    /// +-----+-----+-----+-----+-----+-----+---
+    /// |  18 |  n  |  n1 |  n2 |  n3 |  n4 | ...
+    /// +-----+-----+-----+-----+-----+-----+---
+    /// 
+ ///
+ public class DhcpExtensionsPathOption : DhcpStringOption + { + /// + /// create new DhcpExtensionsPathOption. + /// + /// Extensions Pathname + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "Pathname")] + public DhcpExtensionsPathOption(string extensionsPathname) : base(extensionsPathname, DhcpOptionCode.ExtensionsPath) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.ExtensionsPath)] + internal static DhcpExtensionsPathOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new Options.DhcpExtensionsPathOption(p)); + } + + /// + /// RFC 2132. + /// Extensions Pathname. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "Pathname")] + public string ExtensionsPathname + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpHostNameOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpHostNameOption.cs new file mode 100644 index 00000000..42baf093 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpHostNameOption.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies the name of the client. The name may or may + /// not be qualified with the local domain name(see section 3.17 for the + /// preferred way to retrieve the domain name). See RFC 1035 for + /// character set restrictions. + ///
+    ///  Code   Len                 Host Name
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// |  12 |  n  |  h1 |  h2 |  h3 |  h4 |  h5 |  h6 |  ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// 
+ ///
+ public class DhcpHostNameOption : DhcpStringOption + { + /// + /// create new DhcpHostNameOption. + /// + /// Host Name + public DhcpHostNameOption(string hostName) : base(hostName, DhcpOptionCode.HostName) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.HostName)] + internal static DhcpHostNameOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpHostNameOption(p)); + } + + /// + /// RFC 2132. + /// Host Name. + /// + public string HostName + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpIPAddressLeaseTimeOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpIPAddressLeaseTimeOption.cs new file mode 100644 index 00000000..f3f5330f --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpIPAddressLeaseTimeOption.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option is used in a client request (DHCPDISCOVER or DHCPREQUEST) + /// to allow the client to request a lease time for the IP address. In a + /// server reply(DHCPOFFER), a DHCP server uses this option to specify + /// the lease time it is willing to offer. + ///
+    ///  Code   Len         Lease Time
+    /// +-----+-----+-----+-----+-----+-----+
+    /// |  51 |  4  |  t1 |  t2 |  t3 |  t4 |
+    /// +-----+-----+-----+-----+-----+-----+
+    /// 
+ ///
+ public class DhcpIPAddressLeaseTimeOption : DhcpUIntOption + { + /// + /// create new DhcpIPAddressLeaseTimeOption. + /// + /// Lease Time + public DhcpIPAddressLeaseTimeOption(uint leaseTime) : base(leaseTime, DhcpOptionCode.IPAddressLeaseTime) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.IPAddressLeaseTime)] + internal static DhcpIPAddressLeaseTimeOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new Options.DhcpIPAddressLeaseTimeOption(p)); + } + + /// + /// RFC 2132. + /// Lease Time. + /// The time is in units of seconds. + /// + public uint LeaseTime + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpIPForwardingEnableOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpIPForwardingEnableOption.cs new file mode 100644 index 00000000..116d40f9 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpIPForwardingEnableOption.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies whether the client should configure its IP + /// layer for packet forwarding. + ///
+    ///  Code   Len  Value
+    /// +-----+-----+-----+
+    /// |  19 |  1  | 0/1 |
+    /// +-----+-----+-----+
+    /// 
+ ///
+ public class DhcpIPForwardingEnableOption : DhcpBooleanOption + { + /// + /// create new DhcpIPForwardingEnableOption. + /// + /// Value + public DhcpIPForwardingEnableOption(bool value) : base(value, DhcpOptionCode.IPForwardingEnable) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.IPForwardingEnable)] + internal static DhcpIPForwardingEnableOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpIPForwardingEnableOption(p)); + } + + /// + /// RFC 2132. + /// A value of false means disable IP forwarding, and a value of true means enable IP forwarding. + /// + public bool Value + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpImpressServerOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpImpressServerOption.cs new file mode 100644 index 00000000..71b7aaa3 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpImpressServerOption.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// The Impress server option specifies a list of Imagen Impress servers + /// available to the client.Servers SHOULD be listed in order of + /// preference. + ///
+    ///  Code   Len         Address 1               Address 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// |  10 |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |  ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// 
+ ///
+ public class DhcpImpressServerOption : DhcpAddressListOption + { + /// + /// create new DhcpImpressServerOption. + /// + /// Addresses + public DhcpImpressServerOption(IList addresses) : base(addresses, DhcpOptionCode.ImpressServer) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.ImpressServer)] + internal static DhcpImpressServerOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new Options.DhcpImpressServerOption(p)); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpIntOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpIntOption.cs new file mode 100644 index 00000000..95876ee6 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpIntOption.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// Abstract class for all Dhcp-Options with a int value. + /// + public class DhcpIntOption : DhcpOption + { + internal DhcpIntOption(int value, DhcpOptionCode code) : base(code) + { + InternalValue = value; + } + + internal static T Read(DataSegment data, ref int offset, Func ctor) where T : DhcpIntOption + { + if (ctor == null) + throw new ArgumentNullException(nameof(ctor)); + byte len = data[offset++]; + if (len != sizeof(int)) + throw new ArgumentException("Length of a DHCP UIntOption Option has to be 4"); + T option = ctor(data.ReadInt(offset, Endianity.Big)); + offset += sizeof(uint); + return option; + } + + internal override void Write(byte[] buffer, ref int offset) + { + base.Write(buffer, ref offset); + buffer.Write(ref offset, InternalValue, Endianity.Big); + } + + /// + /// RFC 2132. + /// Value of Length-Field. + /// + public override byte Length + { + get + { + return sizeof(int); + } + } + + /// + /// The real value of the IntOption. + /// + protected int InternalValue + { + get; + set; + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpInterfaceMtuOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpInterfaceMtuOption.cs new file mode 100644 index 00000000..a709d6e9 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpInterfaceMtuOption.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies the MTU to use on this interface. The MTU is + /// specified as a 16-bit unsigned integer. The minimum legal value for + /// the MTU is 68. + ///
+    ///  Code   Len      MTU
+    /// +-----+-----+-----+-----+
+    /// |  26 |  2  |  m1 |  m2 |
+    /// +-----+-----+-----+-----+
+    /// 
+ ///
+ public class DhcpInterfaceMtuOption : DhcpUShortOption + { + private const ushort MIN_MTU = 68; + + /// + /// create new DhcpInterfaceMTUOption. + /// + /// MTU + public DhcpInterfaceMtuOption(ushort mtu) : base(mtu, DhcpOptionCode.InterfaceMtu) + { + if (mtu < MIN_MTU) + throw new ArgumentOutOfRangeException(nameof(mtu), mtu, "Minimum value of MTU is " + MIN_MTU); + } + + [DhcpOptionReadRegistration(DhcpOptionCode.InterfaceMtu)] + internal static DhcpInterfaceMtuOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpInterfaceMtuOption(p)); + } + + /// + /// RFC 2132. + /// MTU. + /// + public ushort Mtu + { + get { return InternalValue; } + set + { + if (value < MIN_MTU) + throw new ArgumentOutOfRangeException(nameof(value), value, "Minimum value of MTU is " + MIN_MTU); + InternalValue = value; + } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpLogServerOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpLogServerOption.cs new file mode 100644 index 00000000..0393c3d9 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpLogServerOption.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// The log server option specifies a list of MIT-LCS UDP log servers + /// available to the client. Servers SHOULD be listed in order of + /// preference. + ///
+    ///  Code   Len         Address 1               Address 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// |  7  |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |  ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// 
+ ///
+ public class DhcpLogServerOption : DhcpAddressListOption + { + /// + /// create new DhcpLogServerOption. + /// + /// Addresses + public DhcpLogServerOption(IList addresses) : base(addresses, DhcpOptionCode.LogServer) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.LogServer)] + internal static DhcpLogServerOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpLogServerOption(p)); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpLprServerOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpLprServerOption.cs new file mode 100644 index 00000000..73cd11e4 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpLprServerOption.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// The LPR server option specifies a list of RFC 1179 [10] line printer + /// servers available to the client. Servers SHOULD be listed in order + /// of preference. + ///
+    ///  Code   Len         Address 1               Address 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// |  9  |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |  ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// 
+ ///
+ public class DhcpLprServerOption : DhcpAddressListOption + { + /// + /// create new DhcpLprServerOption. + /// + /// Addresses + public DhcpLprServerOption(IList addresses) : base(addresses, DhcpOptionCode.LprServer) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.LprServer)] + internal static DhcpLprServerOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpLprServerOption(p)); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpMaskSupplierOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpMaskSupplierOption.cs new file mode 100644 index 00000000..8be8ba82 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpMaskSupplierOption.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies whether or not the client should respond to + /// subnet mask requests using ICMP. + ///
+    ///  Code   Len  Value
+    /// +-----+-----+-----+
+    /// |  30 |  1  | 0/1 |
+    /// +-----+-----+-----+
+    /// 
+ ///
+ public class DhcpMaskSupplierOption : DhcpBooleanOption + { + /// + /// create new DhcpMaskSupplierOption. + /// + /// Value + public DhcpMaskSupplierOption(bool value) : base(value, DhcpOptionCode.MaskSupplier) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.MaskSupplier)] + internal static DhcpMaskSupplierOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new Options.DhcpMaskSupplierOption(p)); + } + + /// + /// RFC 2132. + /// A value of false indicates that the client + /// should not perform mask discovery. A value of true means that the + /// client should perform mask discovery. + /// + public bool Value + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpMaximumDatagramReassemblySizeOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpMaximumDatagramReassemblySizeOption.cs new file mode 100644 index 00000000..7e3d10ee --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpMaximumDatagramReassemblySizeOption.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies the maximum size datagram that the client + /// should be prepared to reassemble.unsigned integer. + ///
+    ///  Code   Len      Size
+    /// +-----+-----+-----+-----+
+    /// |  22 |  2  |  s1 |  s2 |
+    /// +-----+-----+-----+-----+
+    /// 
+ ///
+ public class DhcpMaximumDatagramReassemblySizeOption : DhcpUShortOption + { + private const ushort MIN_SIZE = 576; + + /// + /// create new DhcpMaximumDatagramReassemblySizeOption. + /// + /// Size + public DhcpMaximumDatagramReassemblySizeOption(ushort size) : base(size, DhcpOptionCode.MaximumDatagramReassemblySize) + { + if (size < MIN_SIZE) + throw new ArgumentOutOfRangeException(nameof(size), size, "Minimum value of Size is " + MIN_SIZE); + } + + [DhcpOptionReadRegistration(DhcpOptionCode.MaximumDatagramReassemblySize)] + internal static DhcpMaximumDatagramReassemblySizeOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpMaximumDatagramReassemblySizeOption(p)); + } + + /// + /// RFC 2132. + /// Size. + /// + public ushort Size + { + get { return InternalValue; } + set + { + if (value < MIN_SIZE) + throw new ArgumentOutOfRangeException(nameof(value), value, "Minimum value of Size is " + MIN_SIZE); + InternalValue = value; + } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpMaximumDhcpMessageSizeOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpMaximumDhcpMessageSizeOption.cs new file mode 100644 index 00000000..d592e060 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpMaximumDhcpMessageSizeOption.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies the maximum length DHCP message that it is + /// willing to accept. A client may use the maximum DHCP message size option in + /// DHCPDISCOVER or DHCPREQUEST messages, but should not use the option + /// in DHCPDECLINE messages. + ///
+    ///  Code   Len     Length
+    /// +-----+-----+-----+-----+
+    /// |  57 |  2  |  l1 |  l2 |
+    /// +-----+-----+-----+-----+
+    /// 
+ ///
+ public class DhcpMaximumDhcpMessageSizeOption : DhcpUShortOption + { + /// + /// create new DhcpMaximumDhcpMessageSizeOption. + /// + /// Length + public DhcpMaximumDhcpMessageSizeOption(ushort length) : base(length, DhcpOptionCode.MaximumDhcpMessageSize) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.MaximumDhcpMessageSize)] + internal static DhcpMaximumDhcpMessageSizeOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpMaximumDhcpMessageSizeOption(p)); + } + + /// + /// RFC 2132. + /// Length. + /// + public ushort MaxLength + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpMeritDumpFileOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpMeritDumpFileOption.cs new file mode 100644 index 00000000..3e0e90d6 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpMeritDumpFileOption.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies the path-name of a file to which the client's + /// core image should be dumped in the event the client crashes. + ///
+    ///  Code   Len      Dump File Pathname
+    /// +-----+-----+-----+-----+-----+-----+---
+    /// |  14 |  n  |  n1 |  n2 |  n3 |  n4 | ...
+    /// +-----+-----+-----+-----+-----+-----+---
+    /// 
+ ///
+ public class DhcpMeritDumpFileOption : DhcpStringOption + { + /// + /// create new DhcpMeritDumpFileOption. + /// + /// Dump File Pathname + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "Pathname")] + public DhcpMeritDumpFileOption(string dumpFilePathname) : base(dumpFilePathname, DhcpOptionCode.MeritDumpFile) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.MeritDumpFile)] + internal static DhcpMeritDumpFileOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpMeritDumpFileOption(p)); + } + + /// + /// RFC 2132. + /// Dump File Pathname. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "Pathname")] + public string DumpFilePathname + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpMessageOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpMessageOption.cs new file mode 100644 index 00000000..b2010917 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpMessageOption.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option is used by a DHCP server to provide an error message to a + /// DHCP client in a DHCPNAK message in the event of a failure. A client + /// may use this option in a DHCPDECLINE message to indicate the why the + /// client declined the offered parameters. + ///
+    ///  Code   Len     Text
+    /// +-----+-----+-----+-----+---
+    /// |  56 |  n  |  c1 |  c2 | ...
+    /// +-----+-----+-----+-----+---
+    /// 
+ ///
+ public class DhcpMessageOption : DhcpStringOption + { + /// + /// create new DhcpMessageOption. + /// + /// Text + public DhcpMessageOption(string text) : base(text, DhcpOptionCode.Message) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.Message)] + internal static DhcpMessageOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpMessageOption(p)); + } + + /// + /// RFC 2132. + /// Text. + /// + public string Text + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpMessageTypeOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpMessageTypeOption.cs new file mode 100644 index 00000000..26dd9f4d --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpMessageTypeOption.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option is used to convey the type of the DHCP message. + ///
+    ///  Code   Len  Type
+    /// +-----+-----+-----+
+    /// |  53 |  1  | 1-7 |
+    /// +-----+-----+-----+
+    /// 
+ ///
+ public class DhcpMessageTypeOption : DhcpOption + { + /// + /// create new DhcpMessageTypeOption. + /// + /// Type + public DhcpMessageTypeOption(MessageType type) : base(DhcpOptionCode.MessageType) + { + Type = type; + } + + [DhcpOptionReadRegistration(DhcpOptionCode.MessageType)] + internal static DhcpMessageTypeOption Read(DataSegment data, ref int offset) + { + byte len = data[offset++]; + if (len != 1) + throw new ArgumentException("Length of a DHCP MessageTypeOption has to be 1"); + DhcpMessageTypeOption option = new DhcpMessageTypeOption((MessageType)data[offset]); + offset += option.Length; + return option; + } + + internal override void Write(byte[] buffer, ref int offset) + { + base.Write(buffer, ref offset); + buffer.Write(ref offset, (byte)Type); + } + + /// + /// Length of the Dhcp-Option. + /// + public override byte Length + { + get + { + return sizeof(MessageType); + } + } + + /// + /// RFC 2132. + /// Message Type + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")] + public MessageType Type + { + get { return _type; } + set + { + if (!Enum.IsDefined(typeof(MessageType), value)) + throw new ArgumentOutOfRangeException(nameof(value), value, "Not a valid MessageType"); + _type = value; + } + } + + private MessageType _type; + + /// + /// RFC 2132. + /// Supported Message-Types. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue")] + public enum MessageType : byte + { + /// + /// RFC 2132. + /// DHCP Discover message + /// + Discover = 1, + + /// + /// RFC 2132. + /// DHCP Offer message + /// + Offer = 2, + + /// + /// RFC 2132. + /// DHCP Request message + /// + Request = 3, + + /// + /// RFC 2132. + /// DHCP Decline message + /// + Decline = 4, + + /// + /// RFC 2132. + /// DHCP Acknowledgment message + /// + Ack = 5, + + /// + /// RFC 2132. + /// DHCP Negative Acknowledgment message + /// + Nak = 6, + + /// + /// RFC 2132. + /// DHCP Release message + /// + Release = 7 + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpMobileIPHomeAgentOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpMobileIPHomeAgentOption.cs new file mode 100644 index 00000000..2b1051f2 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpMobileIPHomeAgentOption.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies a list of IP addresses indicating mobile IP + /// home agents available to the client. Agents SHOULD be listed in + /// order of preference. + ///
+    ///  Code Len    Home Agent Addresses (zero or more)
+    /// +-----+-----+-----+-----+-----+-----+--
+    /// | 68  |  n  | a1  | a2  | a3  | a4  | ...
+    /// +-----+-----+-----+-----+-----+-----+--
+    /// 
+ ///
+ public class DhcpMobileIPHomeAgentOption : DhcpAddressListOption + { + /// + /// create new DhcpMobileIPHomeAgentOption. + /// + /// Addresses + public DhcpMobileIPHomeAgentOption(IList addresses) : base(addresses, DhcpOptionCode.MobileIPHomeAgent) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.MobileIPHomeAgent)] + internal static DhcpMobileIPHomeAgentOption Read(DataSegment data, ref int offset) + { + byte length = data[offset++]; + return new DhcpMobileIPHomeAgentOption(GetAddresses(data, length, ref offset)); + } + + /// + /// true if Addresses-List is allowed to be empty. + /// + protected override bool AllowEmptyAddresses + { + get + { + return true; + } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNameServerOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNameServerOption.cs new file mode 100644 index 00000000..96d15ccd --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNameServerOption.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// The name server option specifies a list of IEN 116 [7] name servers + /// available to the client.Servers SHOULD be listed in order of preference. + ///
+    ///  Code Len         Address 1               Address 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// |  5  |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |  ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// 
+ ///
+ public class DhcpNameServerOption : DhcpAddressListOption + { + /// + /// create new DhcpNameServerOption. + /// + /// Addresses + public DhcpNameServerOption(IList addresses) : base(addresses, DhcpOptionCode.NameServer) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.NameServer)] + internal static DhcpNameServerOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpNameServerOption(p)); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetBiosOverTcpIpDatagramDistributionServerOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetBiosOverTcpIpDatagramDistributionServerOption.cs new file mode 100644 index 00000000..273a619b --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetBiosOverTcpIpDatagramDistributionServerOption.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// The NetBIOS datagram distribution server (NBDD) option specifies a + /// list of RFC 1001/1002 NBDD servers listed in order of preference. + ///
+    ///  Code   Len           Address 1              Address 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+----
+    /// |  45 |  n  |  a1 |  a2 |  a3 |  a4 |  b1 |  b2 |  b3 |  b4 | ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+----
+    /// 
+ ///
+ public class DhcpNetBiosOverTcpIpDatagramDistributionServerOption : DhcpAddressListOption + { + /// + /// create new DhcpNetBiosOverTcpIpDatagramDistributionServerOption. + /// + /// + public DhcpNetBiosOverTcpIpDatagramDistributionServerOption(IList addresses) : base(addresses, DhcpOptionCode.NetBiosOverTcpIpDatagramDistributionServer) + { + } + + + [DhcpOptionReadRegistration(DhcpOptionCode.NetBiosOverTcpIpDatagramDistributionServer)] + internal static DhcpNetBiosOverTcpIpDatagramDistributionServerOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpNetBiosOverTcpIpDatagramDistributionServerOption(p)); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetBiosOverTcpIpNameServerOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetBiosOverTcpIpNameServerOption.cs new file mode 100644 index 00000000..288920d3 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetBiosOverTcpIpNameServerOption.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// The NetBIOS name server (NBNS) option specifies a list of RFC 1001/1002 [19] [20] + /// NBNS name servers listed in order of preference. + ///
+    ///  Code   Len           Address 1              Address 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+----
+    /// |  44 |  n  |  a1 |  a2 |  a3 |  a4 |  b1 |  b2 |  b3 |  b4 | ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+----
+    /// 
+ ///
+ public class DhcpNetBiosOverTcpIpNameServerOption : DhcpAddressListOption + { + /// + /// create new DhcpNetBiosOverTcpIpNameServerOption. + /// + /// Addresses + public DhcpNetBiosOverTcpIpNameServerOption(IList addresses) : base(addresses, DhcpOptionCode.NetBiosOverTcpIpNameServer) + { + } + + + [DhcpOptionReadRegistration(DhcpOptionCode.NetBiosOverTcpIpNameServer)] + internal static DhcpNetBiosOverTcpIpNameServerOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpNetBiosOverTcpIpNameServerOption(p)); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetBiosOverTcpIpNodeTypeOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetBiosOverTcpIpNodeTypeOption.cs new file mode 100644 index 00000000..298ca560 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetBiosOverTcpIpNodeTypeOption.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// The NetBIOS node type option allows NetBIOS over TCP/IP clients which + /// are configurable to be configured as described in RFC 1001/1002. + ///
+    ///  Code   Len  Node Type
+    /// +-----+-----+-----------+
+    /// |  46 |  1  |   flags   |
+    /// +-----+-----+-----------+
+    /// 
+ ///
+ public class DhcpNetBiosOverTcpIpNodeTypeOption : DhcpOption + { + /// + /// create new DhcpNetBIOSOverTCPIPNodeTypeOption. + /// + /// Type + public DhcpNetBiosOverTcpIpNodeTypeOption(NodeType type) : base(DhcpOptionCode.NetBiosOverTcpIpNodeType) + { + Type = type; + } + + [DhcpOptionReadRegistration(DhcpOptionCode.NetBiosOverTcpIpNodeType)] + internal static DhcpNetBiosOverTcpIpNodeTypeOption Read(DataSegment data, ref int offset) + { + byte len = data[offset++]; + if (len != 1) + throw new ArgumentException("Length of a DHCP NetBIOSOverTCPIPNodeType Option has to be 1"); + DhcpNetBiosOverTcpIpNodeTypeOption option = new DhcpNetBiosOverTcpIpNodeTypeOption((NodeType)data[offset]); + offset += option.Length; + return option; + } + + internal override void Write(byte[] buffer, ref int offset) + { + base.Write(buffer, ref offset); + buffer.Write(ref offset, (byte)Type); + } + + /// + /// Length of the Dhcp-Option. + /// + public override byte Length + { + get + { + return sizeof(NodeType); + } + } + + /// + /// RFC 2132. + /// Node Type + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")] + public NodeType Type + { + get { return _type; } + set + { + bool flagSet = false; + foreach (NodeType type in Enum.GetValues(typeof(NodeType))) + { + if ((value & type) != 0) + { + flagSet = true; + break; + } + } + if (!flagSet) + throw new ArgumentOutOfRangeException(nameof(value), value, "Not a valid NodeType"); + _type = value; + } + } + + private NodeType _type; + + /// + /// RFC 2132. + /// Node Type + /// + [Flags] + public enum NodeType : byte + { + /// + /// RFC 2132. + /// B-node + /// + BNode = 0x1, + + /// + /// RFC 2132. + /// P-node + /// + PNode = 0x2, + + /// + /// RFC 2132. + /// M-node + /// + MNode = 0x4, + + /// + /// RFC 2132. + /// H-node + /// + HNode = 0x8, + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetBiosOverTcpIpScopeOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetBiosOverTcpIpScopeOption.cs new file mode 100644 index 00000000..0ecb7b7e --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetBiosOverTcpIpScopeOption.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// The NetBIOS scope option specifies the NetBIOS over TCP/IP scope + /// parameter for the client as specified in RFC 1001/1002. + ///
+    /// Code   Len       NetBIOS Scope
+    /// +-----+-----+-----+-----+-----+-----+----
+    /// |  47 |  n  |  s1 |  s2 |  s3 |  s4 | ...
+    /// +-----+-----+-----+-----+-----+-----+----
+    /// 
+ ///
+ public class DhcpNetBiosOverTcpIpScopeOption : DhcpOption + { + /// + /// create new DhcpNetBiosOverTcpIpScopeOption. + /// + /// NetBIOS Scope + public DhcpNetBiosOverTcpIpScopeOption(DataSegment netBiosScope) : base(DhcpOptionCode.NetBiosOverTcpIpScope) + { + NetBiosScope = netBiosScope; + } + + [DhcpOptionReadRegistration(DhcpOptionCode.NetBiosOverTcpIpScope)] + internal static DhcpNetBiosOverTcpIpScopeOption Read(DataSegment data, ref int offset) + { + byte length = data[offset++]; + DhcpNetBiosOverTcpIpScopeOption option = new DhcpNetBiosOverTcpIpScopeOption(data.Subsegment(offset, length)); + offset += length; + return option; + } + + internal override void Write(byte[] buffer, ref int offset) + { + base.Write(buffer, ref offset); + buffer.Write(ref offset, NetBiosScope); + } + + /// + /// Length of the Dhcp-Option. + /// + public override byte Length + { + get + { + return (byte)NetBiosScope.Length; + } + } + + /// + /// RFC 2132. + /// NetBIOS Scope. + /// + public DataSegment NetBiosScope + { + get { return _netBiosScope; } + set + { + if (value == null) + throw new ArgumentNullException(nameof(value)); + if (value.Length > byte.MaxValue) + throw new ArgumentOutOfRangeException(nameof(value), value.Length, "NetBiosScope.Length has to be less than 256"); + _netBiosScope = value; + } + } + + private DataSegment _netBiosScope; + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetworkInformationServersOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetworkInformationServersOption.cs new file mode 100644 index 00000000..e60f9595 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetworkInformationServersOption.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies a list of IP addresses indicating NIS servers + /// available to the client.Servers SHOULD be listed in order of + /// preference. + ///
+    ///  Code   Len         Address 1               Address 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// |  41 |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |  ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// 
+ ///
+ public class DhcpNetworkInformationServersOption : DhcpAddressListOption + { + /// + /// create new DhcpNetworkInformationServersOption. + /// + /// Addresses + public DhcpNetworkInformationServersOption(IList addresses) : base(addresses, DhcpOptionCode.NetworkInformationServers) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.NetworkInformationServers)] + internal static DhcpNetworkInformationServersOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new Options.DhcpNetworkInformationServersOption(p)); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetworkInformationServiceDomainOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetworkInformationServiceDomainOption.cs new file mode 100644 index 00000000..a073e8e9 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetworkInformationServiceDomainOption.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies the name of the client's NIS [17] domain. + ///
+    ///  Code   Len      NIS Domain Name
+    /// +-----+-----+-----+-----+-----+-----+---
+    /// |  40 |  n  |  n1 |  n2 |  n3 |  n4 | ...
+    /// +-----+-----+-----+-----+-----+-----+---
+    /// 
+ ///
+ public class DhcpNetworkInformationServiceDomainOption : DhcpStringOption + { + /// + /// create new DhcpNetworkInformationServiceDomainOption. + /// + /// NIS Domain Name + public DhcpNetworkInformationServiceDomainOption(string nisDomainName) : base(nisDomainName, DhcpOptionCode.NetworkInformationServiceDomain) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.NetworkInformationServiceDomain)] + internal static DhcpNetworkInformationServiceDomainOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpNetworkInformationServiceDomainOption(p)); + } + + /// + /// RFC 2132. + /// NIS Domain Name. + /// + public string NisDomainName + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetworkInformationServicePlusDomainOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetworkInformationServicePlusDomainOption.cs new file mode 100644 index 00000000..34408046 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetworkInformationServicePlusDomainOption.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies the name of the client's NIS+ [17] domain. + ///
+    ///  Code   Len      NIS Client Domain Name
+    /// +-----+-----+-----+-----+-----+-----+---
+    /// |  64 |  n  |  n1 |  n2 |  n3 |  n4 | ...
+    /// +-----+-----+-----+-----+-----+-----+---
+    /// 
+ ///
+ public class DhcpNetworkInformationServicePlusDomainOption : DhcpStringOption + { + /// + /// create new DhcpNetworkInformationServicePlusDomainOption. + /// + /// NIS Client Domain Name + public DhcpNetworkInformationServicePlusDomainOption(string nisClientDomainName) : base(nisClientDomainName, DhcpOptionCode.NetworkInformationServicePlusDomain) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.NetworkInformationServicePlusDomain)] + internal static DhcpNetworkInformationServicePlusDomainOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new Options.DhcpNetworkInformationServicePlusDomainOption(p)); + } + + /// + /// RFC 2132. + /// NIS Client Domain Name. + /// + public string NisClientDomainName + + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetworkInformationServicePlusServersOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetworkInformationServicePlusServersOption.cs new file mode 100644 index 00000000..26736f51 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetworkInformationServicePlusServersOption.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies a list of IP addresses indicating NIS+ servers + /// available to the client.Servers SHOULD be listed in order of + /// preference. + ///
+    ///  Code   Len         Address 1               Address 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// |  65 |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |  ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// 
+ ///
+ public class DhcpNetworkInformationServicePlusServersOption : DhcpAddressListOption + { + /// + /// create new DhcpNetworkInformationServicePlusServersOption. + /// + /// Addresses + public DhcpNetworkInformationServicePlusServersOption(IList addresses) : base(addresses, DhcpOptionCode.NetworkInformationServicePlusServers) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.NetworkInformationServicePlusServers)] + internal static DhcpNetworkInformationServicePlusServersOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpNetworkInformationServicePlusServersOption(p)); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetworkNewsTransportProtocolServerOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetworkNewsTransportProtocolServerOption.cs new file mode 100644 index 00000000..e08d7042 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetworkNewsTransportProtocolServerOption.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// The NNTP server option specifies a list of NNTP available to the + /// client.Servers SHOULD be listed in order of preference. + ///
+    ///  Code   Len         Address 1               Address 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// | 71  |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |  ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// 
+ ///
+ public class DhcpNetworkNewsTransportProtocolServerOption : DhcpAddressListOption + { + /// + /// create new DhcpNetworkNewsTransportProtocolServerOption. + /// + /// Addresses + public DhcpNetworkNewsTransportProtocolServerOption(IList addresses) : base(addresses, DhcpOptionCode.NetworkNewsTransportProtocolServer) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.NetworkNewsTransportProtocolServer)] + internal static DhcpNetworkNewsTransportProtocolServerOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new Options.DhcpNetworkNewsTransportProtocolServerOption(p)); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetworkTimeProtocolServersOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetworkTimeProtocolServersOption.cs new file mode 100644 index 00000000..97c1ff1a --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNetworkTimeProtocolServersOption.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies a list of IP addresses indicating NTP [18] + /// servers available to the client.Servers SHOULD be listed in order + /// of preference. + ///
+    ///  Code   Len         Address 1               Address 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// |  42 |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |  ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// 
+ ///
+ public class DhcpNetworkTimeProtocolServersOption : DhcpAddressListOption + { + /// + /// create new DhcpNetworkTimeProtocolServersOption. + /// + /// Addresses + public DhcpNetworkTimeProtocolServersOption(IList addresses) : base(addresses, DhcpOptionCode.NetworkTimeProtocolServers) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.NetworkTimeProtocolServers)] + internal static DhcpNetworkTimeProtocolServersOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new Options.DhcpNetworkTimeProtocolServersOption(p)); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNonLocalSourceRoutingEnableOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNonLocalSourceRoutingEnableOption.cs new file mode 100644 index 00000000..f3adc8d8 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpNonLocalSourceRoutingEnableOption.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies whether the client should configure its IP + /// layer to allow forwarding of datagrams with non-local source routes. + ///
+    ///  Code   Len  Value
+    /// +-----+-----+-----+
+    /// |  20 |  1  | 0/1 |
+    /// +-----+-----+-----+
+    /// 
+ ///
+ public class DhcpNonLocalSourceRoutingEnableOption : DhcpBooleanOption + { + /// + /// create new DhcpNonLocalSourceRoutingEnableOption. + /// + /// Value + public DhcpNonLocalSourceRoutingEnableOption(bool value) : base(value, DhcpOptionCode.NonLocalSourceRoutingEnable) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.NonLocalSourceRoutingEnable)] + internal static DhcpNonLocalSourceRoutingEnableOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpNonLocalSourceRoutingEnableOption(p)); + } + + /// + /// RFC 2132. + /// Value + /// A value of false means disallow forwarding of such datagrams, and a value of true + /// means allow forwarding. + /// + public bool Value + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpOption.cs new file mode 100644 index 00000000..c76aca0d --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpOption.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Base; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// Abstract class for all possible Dhcp-Options. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")] + public abstract class DhcpOption : IEquatable + { + /// + /// Option-Code according RFC 2132. + /// + public DhcpOptionCode OptionCode + { + get; + private set; + } + + /// + /// Length of the Dhcp-Option. + /// + public abstract byte Length + { + get; + } + + /// + /// create new Option. + /// + /// Option-Code + protected DhcpOption(DhcpOptionCode code) + { + OptionCode = code; + } + + internal virtual void Write(byte[] buffer, ref int offset) + { + buffer.Write(offset++, (byte)OptionCode); + buffer.Write(offset++, Length); + } + + /// + /// Two options objects are equal if they have the same parameters. + /// + public override bool Equals(object obj) + { + return Equals(obj as DhcpOption); + } + + /// + /// Two options objects are equal if they have the same parameters. + /// + public bool Equals(DhcpOption other) + { + if (other == null) + return false; + + if (OptionCode != other.OptionCode) + return false; + + if (Length != other.Length) + return false; + + //we compare the output of write + + byte[] selfData = new byte[2 + Length]; + byte[] otherData = new byte[2 + other.Length]; + int offset = 0; + Write(selfData, ref offset); + offset = 0; + other.Write(otherData, ref offset); + + return selfData.SequenceEqual(otherData); + } + + /// + /// calculate a hash of the option. + /// + /// a hash representing this instance + public override int GetHashCode() + { + byte[] selfData = new byte[2 + Length]; + int offset = 0; + Write(selfData, ref offset); + + return Sequence.GetHashCode(selfData.Cast().ToArray()); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpOptionCode.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpOptionCode.cs new file mode 100644 index 00000000..0dc56b6f --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpOptionCode.cs @@ -0,0 +1,631 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// + public enum DhcpOptionCode : byte + { + #region 3. RFC 1497 Vendor Extensions + + /// + /// RFC 2132. + /// The pad option can be used to cause subsequent fields to align on + /// word boundaries. + /// + Pad = 0, + + /// + /// RFC 2132. + /// The end option marks the end of valid information in the vendor field. + /// + End = 255, + + /// + /// RFC 2132. + /// The subnet mask option specifies the client's subnet mask as per RFC + /// 950 [5]. + /// If both the subnet mask and the router option are specified in a DHCP + /// reply, the subnet mask option MUST be first. + /// + SubnetMask = 1, + + /// + /// RFC 2132. + /// The time offset field specifies the offset of the client's subnet in + /// seconds from Coordinated Universal Time(UTC). + /// + TimeOffset = 2, + + /// + /// RFC 2132. + /// The router option specifies a list of IP addresses for routers on the + /// client's subnet. Routers SHOULD be listed in order of preference. + /// + Router = 3, + + /// + /// RFC 2132. + /// The time server option specifies a list of RFC 868 [6] time servers + /// available to the client.Servers SHOULD be listed in order of + /// preference. + /// + TimeServer = 4, + + /// + /// RFC 2132. + /// The name server option specifies a list of IEN 116 [7] name servers + /// available to the client.Servers SHOULD be listed in order of preference. + /// + NameServer = 5, + + /// + /// RFC 2132. + /// The domain name server option specifies a list of Domain Name System + /// (STD 13, RFC 1035 [8]) name servers available to the client. Servers + /// SHOULD be listed in order of preference. + /// + DomainNameServerServer = 6, + + /// + /// RFC 2132. + /// The log server option specifies a list of MIT-LCS UDP log servers + /// available to the client + /// + LogServer = 7, + + /// + /// RFC 2132. + /// The cookie server option specifies a list of RFC 865 [9] cookie + /// servers available to the client. Servers SHOULD be listed in order + /// of preference. + /// + CookieServer = 8, + + /// + /// RFC 2132. + /// The LPR server option specifies a list of RFC 1179 [10] line printer + /// servers available to the client. Servers SHOULD be listed in order + /// of preference. + /// + LprServer = 9, + + /// + /// RFC 2132. + /// The Impress server option specifies a list of Imagen Impress servers + /// available to the client.Servers SHOULD be listed in order of + /// preference. + /// + ImpressServer = 10, + + /// + /// RFC 2132. + /// This option specifies a list of RFC 887 [11] Resource Location + /// servers available to the client.Servers SHOULD be listed in order + /// of preference. + /// + ResourceLocationServer = 11, + + /// + /// RFC 2132. + /// This option specifies the name of the client. The name may or may + /// not be qualified with the local domain name(see section 3.17 for the + /// preferred way to retrieve the domain name). See RFC 1035 for + /// character set restrictions. + /// + HostName = 12, + + /// + /// RFC 2132. + /// This option specifies the length in 512-octet blocks of the default + /// boot image for the client. + /// + BootFileSize = 13, + + /// + /// RFC 2132. + /// This option specifies the path-name of a file to which the client's + /// core image should be dumped in the event the client crashes. + /// + MeritDumpFile = 14, + + /// + /// RFC 2132. + /// This option specifies the domain name that client should use when + /// resolving hostnames via the Domain Name System. + /// + DomainName = 15, + + /// + /// RFC 2132. + /// This specifies the IP address of the client's swap server. + /// + SwapServer = 16, + + /// + /// RFC 2132. + /// This option specifies the path-name that contains the client's root + /// disk. + /// + RootPath = 17, + + /// + /// RFC 2132. + /// A string to specify a file, retrievable via TFTP, which contains + /// information which can be interpreted in the same way as the 64-octet + /// vendor-extension field within the BOOTP response, with the following + /// exceptions: + /// - the length of the file is unconstrained; + /// - all references to Tag 18 (i.e., instances of the BOOTP Extensions Path field) within the file are ignored. + /// + ExtensionsPath = 18, + + #endregion 3. RFC 1497 Vendor Extensions + + #region 4. IP Layer Parameters per Host + + /// + /// RFC 2132. + /// This option specifies whether the client should configure its IP + /// layer for packet forwarding. + /// + IPForwardingEnable = 19, + + /// + /// RFC 2132. + /// This option specifies whether the client should configure its IP + /// layer to allow forwarding of datagrams with non-local source routes. + /// + NonLocalSourceRoutingEnable = 20, + + /// + /// RFC 2132. + /// This option specifies policy filters for non-local source routing. + /// The filters consist of a list of IP addresses and masks which specify + /// destination/mask pairs with which to filter incoming source routes. + /// Any source routed datagram whose next-hop address does not match one + /// of the filters should be discarded by the client. + /// + PolicyFilter = 21, + + /// + /// RFC 2132. + /// This option specifies the maximum size datagram that the client + /// should be prepared to reassemble.unsigned integer. + /// + MaximumDatagramReassemblySize = 22, + + /// + /// RFC 2132. + /// This option specifies the default time-to-live that the client should + /// use on outgoing datagrams. + /// + DefaultIpTimeToLive = 23, + + /// + /// RFC 2132. + /// This option specifies the timeout (in seconds) to use when aging Path + /// MTU values discovered by the mechanism defined in RFC 1191 [12]. + /// + PathMtuAgingTimeout = 24, + + /// + /// RFC 2132. + /// This option specifies a table of MTU sizes to use when performing + /// Path MTU Discovery as defined in RFC 1191. The table is formatted as + /// a list of 16-bit unsigned integers, ordered from smallest to largest. + /// + PathMtuPlateauTable = 25, + + #endregion 4. IP Layer Parameters per Host + + #region 5. IP Layer Parameters per Interface + + /// + /// RFC 2132. + /// This option specifies the MTU to use on this interface. + /// + InterfaceMtu = 26, + + /// + /// RFC 2132. + /// This option specifies whether or not the client may assume that all + /// subnets of the IP network to which the client is connected use the + /// same MTU as the subnet of that network to which the client is + /// directly connected. + /// + AllSubnetsAreLocal = 27, + + /// + /// RFC 2132. + /// This option specifies the broadcast address in use on the client's + /// subnet. + /// + BroadcastAddress = 28, + + /// + /// RFC 2132. + /// This option specifies whether or not the client should perform subnet + /// mask discovery using ICMP. + /// + PerformMaskDiscovery = 29, + + /// + /// RFC 2132. + /// This option specifies whether or not the client should respond to + /// subnet mask requests using ICMP. + /// + MaskSupplier = 30, + + /// + /// RFC 2132. + /// This option specifies whether or not the client should solicit + /// routers using the Router Discovery mechanism defined in RFC 1256. + /// + PerformRouterDiscovery = 31, + + /// + /// RFC 2132. + /// This option specifies the address to which the client should transmit + /// router solicitation requests. + /// + RouterSolicitationAddress = 32, + + /// + /// RFC 2132. + /// This option specifies a list of static routes that the client should + /// install in its routing cache.If multiple routes to the same + /// destination are specified, they are listed in descending order of + /// priority. + /// + StaticRoute = 33, + + #endregion 5. IP Layer Parameters per Interface + + #region 6. Link Layer Parameters per Interface + + /// + /// RFC 2132. + /// This option specifies whether or not the client should negotiate the + /// use of trailers(RFC 893 [14]) when using the ARP protocol. + /// + TrailerEncapsulation = 34, + + /// + /// RFC 2132. + /// This option specifies the timeout in seconds for ARP cache entries. + /// + ArpCacheTimeout = 35, + + /// + /// RFC 2132. + /// This option specifies whether or not the client should use Ethernet + /// Version 2 (RFC 894 [15]) or IEEE 802.3 (RFC 1042 [16]) encapsulation + /// if the interface is an Ethernet. + /// + EthernetEncapsulation = 36, + + #endregion 6. Link Layer Parameters per Interface + + #region 7. TCP Parameters + + /// + /// RFC 2132. + /// This option specifies the default TTL that the client should use when + /// sending TCP segments. + /// + TcpDefaultTtl = 37, + + /// + /// RFC 2132. + /// This option specifies the interval (in seconds) that the client TCP + /// should wait before sending a keepalive message on a TCP connection. + /// + TcpKeepaliveInterval = 38, + + /// + /// RFC 2132. + /// This option specifies the whether or not the client should send TCP + /// keepalive messages with a octet of garbage for compatibility with + /// older implementations. + /// + TcpKeepaliveGarbage = 39, + + #endregion 7. TCP Parameters + + #region 8. Application and Service Parameters + + /// + /// RFC 2132. + /// This option specifies the name of the client's NIS [17] domain. + /// + NetworkInformationServiceDomain = 40, + + /// + /// RFC 2132. + /// This option specifies a list of IP addresses indicating NIS servers + /// available to the client.Servers SHOULD be listed in order of + /// + NetworkInformationServers = 41, + + /// + /// RFC 2132. + /// This option specifies a list of IP addresses indicating NTP [18] + /// servers available to the client.Servers SHOULD be listed in order + /// of preference. + /// + NetworkTimeProtocolServers = 42, + + /// + /// RFC 2132. + /// This option is used by clients and servers to exchange vendor- + /// specific information. The information is an opaque object of n + /// octets, presumably interpreted by vendor-specific code on the clients + /// and servers. The definition of this information is vendor specific. + /// The vendor is indicated in the vendor class identifier option. + /// Servers not equipped to interpret the vendor-specific information + /// sent by a client MUST ignore it(although it may be reported). + /// Clients which do not receive desired vendor-specific information + /// SHOULD make an attempt to operate without it, although they may do so + /// (and announce they are doing so) in a degraded mode. + /// + VendorSpecificInformation = 43, + + /// + /// RFC 2132. + /// The NetBIOS name server (NBNS) option specifies a list of RFC 1001/1002 [19] [20] + /// NBNS name servers listed in order of preference. + /// + NetBiosOverTcpIpNameServer = 44, + + /// + /// RFC 2132. + /// The NetBIOS datagram distribution server (NBDD) option specifies a + /// list of RFC 1001/1002 NBDD servers listed in order of preference. + /// + NetBiosOverTcpIpDatagramDistributionServer = 45, + + /// + /// RFC 2132. + /// The NetBIOS node type option allows NetBIOS over TCP/IP clients which + /// are configurable to be configured as described in RFC 1001/1002. + /// + NetBiosOverTcpIpNodeType = 46, + + /// + /// RFC 2132. + /// The NetBIOS scope option specifies the NetBIOS over TCP/IP scope + /// parameter for the client as specified in RFC 1001/1002. + /// + NetBiosOverTcpIpScope = 47, + + /// + /// RFC 2132. + /// This option specifies a list of X Window System [21] Font servers + /// available to the client. Servers SHOULD be listed in order of + /// preference. + /// + XWindowSystemFontServer = 48, + + /// + /// RFC 2132. + /// This option specifies a list of IP addresses of systems that are + /// running the X Window System Display Manager and are available to the + /// client. + /// + XWindowSystemDisplayManager = 49, + + /// + /// RFC 2132. + /// This option specifies the name of the client's NIS+ [17] domain. + /// + NetworkInformationServicePlusDomain = 64, + + /// + /// RFC 2132. + /// This option specifies a list of IP addresses indicating NIS+ servers + /// available to the client.Servers SHOULD be listed in order of + /// preference. + /// + NetworkInformationServicePlusServers = 65, + + /// + /// RFC 2132. + /// This option specifies a list of IP addresses indicating mobile IP + /// home agents available to the client. Agents SHOULD be listed in + /// order of preference. + /// + MobileIPHomeAgent = 68, + + /// + /// RFC 2132. + /// The SMTP server option specifies a list of SMTP servers available to + /// the client. Servers SHOULD be listed in order of preference. + /// + SimpleMailTransportProtocolServer = 69, + + /// + /// RFC 2132. + /// The POP3 server option specifies a list of POP3 available to the + /// client.Servers SHOULD be listed in order of preference. + /// + PostOfficeProtocolServer = 70, + + /// + /// RFC 2132. + /// The NNTP server option specifies a list of NNTP available to the + /// client.Servers SHOULD be listed in order of preference. + /// + NetworkNewsTransportProtocolServer = 71, + + /// + /// RFC 2132. + /// The WWW server option specifies a list of WWW available to the + /// client.Servers SHOULD be listed in order of preference. + /// + DefaultWorldWideWebServer = 72, + + /// + /// RFC 2132. + /// The Finger server option specifies a list of Finger available to the + /// client.Servers SHOULD be listed in order of preference. + /// + DefaultFingerServer = 73, + + /// + /// RFC 2132. + /// The IRC server option specifies a list of IRC available to the + /// client.Servers SHOULD be listed in order of preference. + /// + DefaultInternetRelayChatServer = 74, + + /// + /// RFC 2132. + /// The StreetTalk server option specifies a list of StreetTalk servers + /// available to the client.Servers SHOULD be listed in order of + /// preference. + /// + StreetTalkServer = 75, + + /// + /// RFC 2132. + /// The StreetTalk Directory Assistance (STDA) server option specifies a + /// list of STDA servers available to the client.Servers SHOULD be + /// listed in order of preference. + /// + StreetTalkDirectoryAssistanceServer = 76, + + #endregion 8. Application and Service Parameters + + #region 9. DHCP Extensions + + /// + /// RFC 2132. + /// This option is used in a client request (DHCPDISCOVER) to allow the + /// client to request that a particular IP address be assigned. + /// + RequestedIPAddress = 50, + + /// + /// RFC 2132. + /// This option is used in a client request (DHCPDISCOVER or DHCPREQUEST) + /// to allow the client to request a lease time for the IP address. In a + /// server reply(DHCPOFFER), a DHCP server uses this option to specify + /// the lease time it is willing to offer. + /// + IPAddressLeaseTime = 51, + + /// + /// RFC 2132. + /// This option is used to indicate that the DHCP 'sname' or 'file' + /// fields are being overloaded by using them to carry DHCP options.A + /// DHCP server inserts this option if the returned parameters will + /// exceed the usual space allotted for options. + /// If this option is present, the client interprets the specified + /// additional fields after it concludes interpretation of the standard + /// option fields. + /// + OptionOverload = 52, + + /// + /// RFC 2132. + /// This option is used to identify a TFTP server when the 'sname' field + /// in the DHCP header has been used for DHCP options. + /// + TfptServerName = 66, + + /// + /// RFC 2132. + /// This option is used to identify a bootfile when the 'file' field in + /// the DHCP header has been used for DHCP options. + /// + BootfileName = 67, + + /// + /// RFC 2132. + /// This option is used to convey the type of the DHCP message. + /// + MessageType = 53, + + /// + /// RFC 2132. + /// This option is used in DHCPOFFER and DHCPREQUEST messages, and may + /// optionally be included in the DHCPACK and DHCPNAK messages.DHCP + /// servers include this option in the DHCPOFFER in order to allow the + /// client to distinguish between lease offers. DHCP clients use the + /// contents of the 'server identifier' field as the destination address + /// for any DHCP messages unicast to the DHCP server. DHCP clients also + /// indicate which of several lease offers is being accepted by including + /// this option in a DHCPREQUEST message. + /// + ServerIdentifier = 54, + + /// + /// RFC 2132. + /// This option is used by a DHCP client to request values for specified + /// configuration parameters.The list of requested parameters is + /// specified as n octets, where each octet is a valid DHCP option code + /// as defined in this document. + /// The client MAY list the options in order of preference.The DHCP + /// server is not required to return the options in the requested order, + /// but MUST try to insert the requested options in the order requested + /// by the client. + /// + ParameterRequestList = 55, + + /// + /// RFC 2132. + /// This option is used by a DHCP server to provide an error message to a + /// DHCP client in a DHCPNAK message in the event of a failure. A client + /// may use this option in a DHCPDECLINE message to indicate the why the + /// client declined the offered parameters. + /// + Message = 56, + + /// + /// RFC 2132. + /// This option specifies the maximum length DHCP message that it is + /// willing to accept. A client may use the maximum DHCP message size option in + /// DHCPDISCOVER or DHCPREQUEST messages, but should not use the option + /// in DHCPDECLINE messages. + /// + MaximumDhcpMessageSize = 57, + + /// + /// RFC 2132. + /// This option specifies the time interval from address assignment until + /// the client transitions to the RENEWING state. + /// + RenewalTimeValue = 58, + + /// + /// RFC 2132. + /// This option specifies the time interval from address assignment until + /// the client transitions to the REBINDING state. + /// + RebindingTimeValue = 59, + + /// + /// RFC 2132. + /// This option is used by DHCP clients to optionally identify the vendor + /// type and configuration of a DHCP client. + /// + VendorClassidentifier = 60, + + /// + /// RFC 2132. + /// This option is used by DHCP clients to specify their unique + /// identifier.DHCP servers use this value to index their database of + /// address bindings. This value is expected to be unique for all + /// clients in an administrative domain. + /// + ClientIdentifier = 61, + + #endregion 9. DHCP Extensions + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpOptionOverloadOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpOptionOverloadOption.cs new file mode 100644 index 00000000..57431850 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpOptionOverloadOption.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option is used to indicate that the DHCP 'sname' or 'file' + /// fields are being overloaded by using them to carry DHCP options.A + /// DHCP server inserts this option if the returned parameters will + /// exceed the usual space allotted for options. + /// If this option is present, the client interprets the specified + /// additional fields after it concludes interpretation of the standard + /// option fields. + ///
+    ///  Code   Len  Value
+    /// +-----+-----+-----+
+    /// |  52 |  1  |1/2/3|
+    /// +-----+-----+-----+
+    /// 
+ ///
+ public class DhcpOptionOverloadOption : DhcpOption + { + /// + /// create new DhcpOptionOverloadOption. + /// + /// Value + public DhcpOptionOverloadOption(OptionOverloadValue value) : base(DhcpOptionCode.OptionOverload) + { + Value = value; + } + + [DhcpOptionReadRegistration(DhcpOptionCode.OptionOverload)] + internal static DhcpOptionOverloadOption Read(DataSegment data, ref int offset) + { + byte len = data[offset++]; + if (len != 1) + throw new ArgumentException("Length of a DHCP OptionOverload Option has to be 1"); + DhcpOptionOverloadOption option = new DhcpOptionOverloadOption((OptionOverloadValue)data[offset]); + offset += option.Length; + return option; + } + + internal override void Write(byte[] buffer, ref int offset) + { + base.Write(buffer, ref offset); + buffer.Write(ref offset, (byte)Value); + } + + /// + /// Length of the Dhcp-Option. + /// + public override byte Length + { + get + { + return sizeof(OptionOverloadValue); + } + } + + /// + /// RFC 2132. + /// Value. + /// + public OptionOverloadValue Value + { + get { return _value; } + set + { + if (!Enum.IsDefined(typeof(OptionOverloadValue), value)) + throw new ArgumentOutOfRangeException(nameof(value), value, "Not a valid OptionOverloadValue"); + _value = value; + } + } + + private OptionOverloadValue _value; + + /// + /// RFC 2132. + /// Option Overload Value + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue")] + public enum OptionOverloadValue : byte + { + /// + /// RFC 2132. + /// the 'file' field is used to hold options + /// + File = 1, + + /// + /// RFC 2132. + /// the 'sname' field is used to hold options + /// + SName = 2, + + /// + /// RFC 2132. + /// both fields are used to hold options + /// + Both = 3 + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpPadOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpPadOption.cs new file mode 100644 index 00000000..b4ad3444 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpPadOption.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// The pad option can be used to cause subsequent fields to align on + /// word boundaries. + ///
+    ///  Code
+    /// +-----+
+    /// |  0  |
+    /// +-----+
+    /// 
+ ///
+ public class DhcpPadOption : DhcpOption + { + /// + /// create new PadOption. + /// + public DhcpPadOption() : base(DhcpOptionCode.Pad) + { + } + + /// + /// Length of the Dhcp-Option. + /// + public override byte Length + { + get { return 0; } + } + + [DhcpOptionReadRegistration(DhcpOptionCode.Pad)] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "data")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "offset")] + internal static DhcpPadOption Read(DataSegment data, ref int offset) + { + return new Options.DhcpPadOption(); + } + + internal override void Write(byte[] buffer, ref int offset) + { + buffer.Write(offset++, (byte)OptionCode); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpParameterRequestListOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpParameterRequestListOption.cs new file mode 100644 index 00000000..3acf9f69 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpParameterRequestListOption.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option is used by a DHCP client to request values for specified + /// configuration parameters.The list of requested parameters is + /// specified as n octets, where each octet is a valid DHCP option code + /// as defined in this document. + /// The client MAY list the options in order of preference.The DHCP + /// server is not required to return the options in the requested order, + /// but MUST try to insert the requested options in the order requested + /// by the client. + ///
+    /// Code   Len   Option Codes
+    /// +-----+-----+-----+-----+---
+    /// |  55 |  n  |  c1 |  c2 | ...
+    /// +-----+-----+-----+-----+---
+    /// 
+ ///
+ public class DhcpParameterRequestListOption : DhcpOption + { + /// + /// create new DhcpParameterRequestListOption. + /// + /// Option Codes + public DhcpParameterRequestListOption(IList optionCodes) : base(DhcpOptionCode.ParameterRequestList) + { + if (optionCodes == null) + throw new ArgumentNullException(nameof(optionCodes)); + if (optionCodes.Count < 1) + throw new ArgumentOutOfRangeException(nameof(optionCodes), optionCodes.Count, "The minimum items in optionCodes is 1"); + if (optionCodes.Count > byte.MaxValue) + throw new ArgumentOutOfRangeException(nameof(optionCodes), optionCodes.Count, "The maximum items in optionCodes is 255"); + OptionCodes = new ReadOnlyCollection(optionCodes); + } + + [DhcpOptionReadRegistration(DhcpOptionCode.ParameterRequestList)] + internal static DhcpParameterRequestListOption Read(DataSegment data, ref int offset) + { + byte length = data[offset++]; + List codes = new List(); + for (int i = 0; i < length; i++) + { + codes.Add((DhcpOptionCode)data[offset++]); + } + return new DhcpParameterRequestListOption(codes); + } + + internal override void Write(byte[] buffer, ref int offset) + { + base.Write(buffer, ref offset); + buffer.Write(ref offset, OptionCodes.Select(p => (byte)p)); + } + + /// + /// Length of the Dhcp-Option. + /// + public override byte Length + { + get + { + return (byte)(OptionCodes.Count * sizeof(DhcpOptionCode)); + } + } + + /// + /// RFC 2132. + /// Option Codes + /// + public IReadOnlyCollection OptionCodes + { + get; + private set; + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpPathMtuAgingTimeoutOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpPathMtuAgingTimeoutOption.cs new file mode 100644 index 00000000..adfb35b3 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpPathMtuAgingTimeoutOption.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies the timeout (in seconds) to use when aging Path + /// MTU values discovered by the mechanism defined in RFC 1191 [12]. + ///
+    ///  Code   Len           Timeout
+    /// +-----+-----+-----+-----+-----+-----+
+    /// |  24 |  4  |  t1 |  t2 |  t3 |  t4 |
+    /// +-----+-----+-----+-----+-----+-----+
+    /// 
+ ///
+ public class DhcpPathMtuAgingTimeoutOption : DhcpUIntOption + { + /// + /// create new DhcpPathMtuAgingTimeoutOption. + /// + /// Timeout + public DhcpPathMtuAgingTimeoutOption(uint timeout) : base(timeout, DhcpOptionCode.PathMtuAgingTimeout) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.PathMtuAgingTimeout)] + internal static DhcpPathMtuAgingTimeoutOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpPathMtuAgingTimeoutOption(p)); + } + + /// + /// RFC 2132. + /// Timeout. + /// + public uint Timeout + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpPathMtuPlateauTableOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpPathMtuPlateauTableOption.cs new file mode 100644 index 00000000..13bb38b4 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpPathMtuPlateauTableOption.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies a table of MTU sizes to use when performing + /// Path MTU Discovery as defined in RFC 1191. The table is formatted as + /// a list of 16-bit unsigned integers, ordered from smallest to largest. + ///
+    ///  Code   Len     Size 1      Size 2
+    /// +-----+-----+-----+-----+-----+-----+---
+    /// |  25 |  n  |  s1 |  s2 |  s1 |  s2 | ...
+    /// +-----+-----+-----+-----+-----+-----+---
+    /// 
+ ///
+ public class DhcpPathMtuPlateauTableOption : DhcpOption + { + internal const int MAX_SIZES = 255 / sizeof(ushort); + + /// + /// create new DhcpPathMtuPlateauTableOption. + /// + /// Sizes + public DhcpPathMtuPlateauTableOption(IList sizes) : base(DhcpOptionCode.PathMtuPlateauTable) + { + if (sizes == null) + throw new ArgumentNullException(nameof(sizes)); + if (sizes.Count < 1) + throw new ArgumentOutOfRangeException(nameof(sizes), sizes.Count, "The minimum items in sizes is 1"); + if (sizes.Count > MAX_SIZES) + throw new ArgumentOutOfRangeException(nameof(sizes), sizes.Count, "The maximum items in addresses is " + MAX_SIZES); + + Sizes = new ReadOnlyCollection(sizes); + } + + [DhcpOptionReadRegistration(DhcpOptionCode.PathMtuPlateauTable)] + internal static DhcpPathMtuPlateauTableOption Read(DataSegment data, ref int offset) + { + byte len = data[offset++]; + if (len % sizeof(ushort) != 0) + { + throw new ArgumentException("Length of a DHCP PathMTUPlateauTable Option has to be a multiple of 2"); + } + List sizes = new List(); + for (int i = 0; i < len; i += 2) + { + sizes.Add(data.ReadUShort(offset + i, Endianity.Big)); + } + DhcpPathMtuPlateauTableOption option = new DhcpPathMtuPlateauTableOption(sizes); + offset += option.Length; + return option; + } + + internal override void Write(byte[] buffer, ref int offset) + { + base.Write(buffer, ref offset); + foreach (ushort size in Sizes) + { + buffer.Write(ref offset, size, Endianity.Big); + } + } + + /// + /// Length of the Dhcp-Option. + /// + public override byte Length + { + get + { + return (byte)(Sizes.Count * sizeof(ushort)); + } + } + + /// + /// RFC 2132. + /// Sizes. + /// + public IReadOnlyCollection Sizes + { + get; + private set; + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpPerformMaskDiscoveryOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpPerformMaskDiscoveryOption.cs new file mode 100644 index 00000000..383c7d5e --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpPerformMaskDiscoveryOption.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies whether or not the client should perform subnet + /// mask discovery using ICMP. + ///
+    ///  Code   Len  Value
+    /// +-----+-----+-----+
+    /// |  29 |  1  | 0/1 |
+    /// +-----+-----+-----+
+    /// 
+ ///
+ public class DhcpPerformMaskDiscoveryOption : DhcpBooleanOption + { + /// + /// create new DhcpPerformMaskDiscoveryOption. + /// + /// Value + public DhcpPerformMaskDiscoveryOption(bool value) : base(value, DhcpOptionCode.PerformMaskDiscovery) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.PerformMaskDiscovery)] + internal static DhcpPerformMaskDiscoveryOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpPerformMaskDiscoveryOption(p)); + } + + /// + /// RFC 2132. + /// A value of false indicates that the client + /// should not perform mask discovery. A value of true means that the + /// client should perform mask discovery. + /// + public bool Value + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpPerformRouterDiscoveryOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpPerformRouterDiscoveryOption.cs new file mode 100644 index 00000000..8966df25 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpPerformRouterDiscoveryOption.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies whether or not the client should solicit + /// routers using the Router Discovery mechanism defined in RFC 1256. + ///
+    ///  Code   Len  Value
+    /// +-----+-----+-----+
+    /// |  31 |  1  | 0/1 |
+    /// +-----+-----+-----+
+    /// 
+ ///
+ public class DhcpPerformRouterDiscoveryOption : DhcpBooleanOption + { + /// + /// create new DhcpPerformRouterDiscoveryOption. + /// + /// Value + public DhcpPerformRouterDiscoveryOption(bool value) : base(value, DhcpOptionCode.PerformRouterDiscovery) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.PerformRouterDiscovery)] + internal static DhcpPerformRouterDiscoveryOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpPerformRouterDiscoveryOption(p)); + } + + /// + /// RFC 2132. + /// A value of false indicates that the client should not perform + /// router discovery. A value of true means that the client should perform + /// router discovery. + /// + public bool Value + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpPolicyFilterOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpPolicyFilterOption.cs new file mode 100644 index 00000000..6d63d857 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpPolicyFilterOption.cs @@ -0,0 +1,192 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies policy filters for non-local source routing. + /// The filters consist of a list of IP addresses and masks which specify + /// destination/mask pairs with which to filter incoming source routes. + /// Any source routed datagram whose next-hop address does not match one + /// of the filters should be discarded by the client. + ///
+    ///  Code   Len         Address 1                  Mask 1
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
+    /// |  21 |  n  |  a1 |  a2 |  a3 |  a4 |  m1 |  m2 |  m3 |  m4 |
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
+    ///         Address 2                  Mask 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+---
+    /// |  a1 |  a2 |  a3 |  a4 |  m1 |  m2 |  m3 |  m4 | ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+---
+    /// 
+ ///
+ public class DhcpPolicyFilterOption : DhcpOption + { + internal const int MAX_FILTERS = 255 / IpV4AddressWithMask.SizeOf; + + /// + /// create new DhcpPolicyFilterOption. + /// + /// Filters + public DhcpPolicyFilterOption(IList filters) : base(DhcpOptionCode.PolicyFilter) + { + if (filters == null) + throw new ArgumentNullException(nameof(filters)); + if (filters.Count < 1) + throw new ArgumentOutOfRangeException(nameof(filters), filters.Count, "The minimum items in filters is 1"); + if (filters.Count > MAX_FILTERS) + throw new ArgumentOutOfRangeException(nameof(filters), filters.Count, "The maximum items in filters is " + MAX_FILTERS); + + Filters = new ReadOnlyCollection(filters); + } + + [DhcpOptionReadRegistration(DhcpOptionCode.PolicyFilter)] + internal static DhcpPolicyFilterOption Read(DataSegment data, ref int offset) + { + byte length = data[offset++]; + if (length % 8 != 0) + throw new ArgumentException("length has to be a multiple of 8"); + IList addresses = DhcpAddressListOption.GetAddresses(data, length, ref offset); + + List filters = new List(); + for (int i = 0; i < addresses.Count; i += 2) + { + filters.Add(new IpV4AddressWithMask(addresses[i], addresses[i + 1])); + } + return new DhcpPolicyFilterOption(filters); + } + + internal override void Write(byte[] buffer, ref int offset) + { + base.Write(buffer, ref offset); + foreach (IpV4AddressWithMask filter in Filters) + { + buffer.Write(ref offset, filter.Address, Endianity.Big); + buffer.Write(ref offset, filter.Mask, Endianity.Big); + } + } + + /// + /// Length of the Dhcp-Option. + /// + public override byte Length + { + get + { + return (byte)(Filters.Count * IpV4AddressWithMask.SizeOf); + } + } + + /// + /// Filters. + /// + public IReadOnlyCollection Filters + { + get; + private set; + } + + /// + /// Represents and IpV4Address with Mask. + /// + public struct IpV4AddressWithMask : IEquatable + { + /// + /// The number of bytes the IpV4AddressWithMask take. + /// + public const int SizeOf = IpV4Address.SizeOf + IpV4Address.SizeOf; + + /// + /// Address + /// + public IpV4Address Address + + { + get; + private set; + } + + /// + /// Mask + /// + public IpV4Address Mask + { + get; + private set; + } + + /// + /// create new IpV4AddressWithMask. + /// + /// Address + /// Mask + public IpV4AddressWithMask(IpV4Address address, IpV4Address mask) + { + Address = address; + Mask = mask; + } + + /// + /// Determines whether the specified object is equal to the current object. + /// + /// The object to compare with the current object. + /// true if the specified object is equal to the current object; otherwise, false. + public override bool Equals(object obj) + { + if (obj is IpV4AddressWithMask) + { + return Equals((IpV4AddressWithMask)obj); + } + return false; + } + + /// + /// Determines whether the IpV4AddressWithMask is equal to the current IpV4AddressWithMask. + /// + /// The object to compare with the current object. + /// true if the specified object is equal to the current object; otherwise, false. + public bool Equals(IpV4AddressWithMask other) + { + return object.Equals(Address, other.Address) && + object.Equals(Mask, other.Mask); + } + + /// + /// Returns the hash code for this instance. + /// + /// A 32-bit signed integer hash code. + public override int GetHashCode() + { + return Address.GetHashCode() ^ Mask.GetHashCode(); + } + + /// + /// Determines whether the IpV4AddressWithMask is equal to the current IpV4AddressWithMask. + /// + /// left IpV4AddressWithMask + /// right IpV4AddressWithMask + /// + public static bool operator ==(IpV4AddressWithMask left, IpV4AddressWithMask right) + { + return Object.Equals(left, right); + } + + /// + /// Determines whether the IpV4AddressWithMask is not equal to the current IpV4AddressWithMask. + /// + /// left IpV4AddressWithMask + /// right IpV4AddressWithMask + /// + public static bool operator !=(IpV4AddressWithMask left, IpV4AddressWithMask right) + { + return !Object.Equals(left, right); + } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpPostOfficeProtocolServerOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpPostOfficeProtocolServerOption.cs new file mode 100644 index 00000000..9e6b6e12 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpPostOfficeProtocolServerOption.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// The POP3 server option specifies a list of POP3 available to the + /// client.Servers SHOULD be listed in order of preference. + ///
+    ///  Code   Len         Address 1               Address 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// | 70  |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |  ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// 
+ ///
+ public class DhcpPostOfficeProtocolServerOption : DhcpAddressListOption + { + /// + /// create new DhcpPostOfficeProtocolServerOption. + /// + /// + public DhcpPostOfficeProtocolServerOption(IList addresses) : base(addresses, DhcpOptionCode.PostOfficeProtocolServer) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.PostOfficeProtocolServer)] + internal static DhcpPostOfficeProtocolServerOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpPostOfficeProtocolServerOption(p)); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpRebindingTimeValueOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpRebindingTimeValueOption.cs new file mode 100644 index 00000000..80fe39b9 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpRebindingTimeValueOption.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies the time interval from address assignment until + /// the client transitions to the REBINDING state. + ///
+    ///  Code   Len         T2 Interval
+    /// +-----+-----+-----+-----+-----+-----+
+    /// |  59 |  4  |  t1 |  t2 |  t3 |  t4 |
+    /// +-----+-----+-----+-----+-----+-----+
+    /// 
+ ///
+ public class DhcpRebindingTimeValueOption : DhcpUIntOption + { + /// + /// create new DhcpRebindingTimeValueOption. + /// + /// T1 Interval + public DhcpRebindingTimeValueOption(uint t2Interval) : base(t2Interval, DhcpOptionCode.RebindingTimeValue) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.RebindingTimeValue)] + internal static DhcpRebindingTimeValueOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new Options.DhcpRebindingTimeValueOption(p)); + } + + /// + /// RFC 2132. + /// T2 Interval. + /// + public uint T2Interval + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpRenewalTimeValueOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpRenewalTimeValueOption.cs new file mode 100644 index 00000000..6cae7abe --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpRenewalTimeValueOption.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies the time interval from address assignment until + /// the client transitions to the RENEWING state. + ///
+    ///  Code   Len         T1 Interval
+    /// +-----+-----+-----+-----+-----+-----+
+    /// |  58 |  4  |  t1 |  t2 |  t3 |  t4 |
+    /// +-----+-----+-----+-----+-----+-----+
+    /// 
+ ///
+ public class DhcpRenewalTimeValueOption : DhcpUIntOption + { + /// + /// DhcpRenewalTimeValueOption. + /// + /// + public DhcpRenewalTimeValueOption(uint t1Interval) : base(t1Interval, DhcpOptionCode.RenewalTimeValue) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.RenewalTimeValue)] + internal static DhcpRenewalTimeValueOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpRenewalTimeValueOption(p)); + } + + /// + /// RFC 2132. + /// T1 Interval. + /// + public uint T1Interval + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpRequestedIPAddressOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpRequestedIPAddressOption.cs new file mode 100644 index 00000000..a200b6be --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpRequestedIPAddressOption.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option is used in a client request (DHCPDISCOVER) to allow the + /// client to request that a particular IP address be assigned. + ///
+    ///  Code   Len          Address
+    /// +-----+-----+-----+-----+-----+-----+
+    /// |  50 |  4  |  a1 |  a2 |  a3 |  a4 |
+    /// +-----+-----+-----+-----+-----+-----+
+    /// 
+ ///
+ public class DhcpRequestedIPAddressOption : DhcpSingleAddressOption + { + /// + /// create new DhcpRequestedIPAddressOption. + /// + /// Address + public DhcpRequestedIPAddressOption(IpV4Address address) : base(address, DhcpOptionCode.RequestedIPAddress) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.RequestedIPAddress)] + internal static DhcpRequestedIPAddressOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new Options.DhcpRequestedIPAddressOption(p)); + } + + /// + /// RFC 2132. + /// Address. + /// + public IpV4Address Address + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpResourceLocationServerOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpResourceLocationServerOption.cs new file mode 100644 index 00000000..6fddea15 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpResourceLocationServerOption.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies a list of RFC 887 [11] Resource Location + /// servers available to the client.Servers SHOULD be listed in order + /// of preference. + ///
+    ///  Code   Len         Address 1               Address 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// |  11 |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |  ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// 
+ ///
+ public class DhcpResourceLocationServerOption : DhcpAddressListOption + { + /// + /// create new DhcpResourceLocationServerOption. + /// + /// Addresses + public DhcpResourceLocationServerOption(IList addresses) : base(addresses, DhcpOptionCode.ResourceLocationServer) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.ResourceLocationServer)] + internal static DhcpResourceLocationServerOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new Options.DhcpResourceLocationServerOption(p)); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpRootPathOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpRootPathOption.cs new file mode 100644 index 00000000..0323a3fa --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpRootPathOption.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies the path-name that contains the client's root + /// disk. + ///
+    ///  Code   Len      Root Disk Pathname
+    /// +-----+-----+-----+-----+-----+-----+---
+    /// |  17 |  n  |  n1 |  n2 |  n3 |  n4 | ...
+    /// +-----+-----+-----+-----+-----+-----+---
+    /// 
+ ///
+ public class DhcpRootPathOption : DhcpStringOption + { + /// + /// create new DhcpRootPathOption. + /// + /// Root Disk Pathname + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "Pathname")] + public DhcpRootPathOption(string rootDiskPathname) : base(rootDiskPathname, DhcpOptionCode.RootPath) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.RootPath)] + internal static DhcpRootPathOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpRootPathOption(p)); + } + + /// + /// RFC 2132. + /// Root Disk Pathname. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "Pathname")] + public string RootDiskPathname + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpRouterOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpRouterOption.cs new file mode 100644 index 00000000..b2939760 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpRouterOption.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// The router option specifies a list of IP addresses for routers on the + /// client's subnet. Routers SHOULD be listed in order of preference. + ///
+    ///  Code   Len         Address 1               Address 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// |  3  |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |  ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// 
+ ///
+ public class DhcpRouterOption : DhcpAddressListOption + { + /// + /// create new DhcpRouterOption. + /// + /// Addresses + public DhcpRouterOption(IList addresses) : base(addresses, DhcpOptionCode.Router) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.Router)] + internal static DhcpRouterOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpRouterOption(p)); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpRouterSolicitationAddressOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpRouterSolicitationAddressOption.cs new file mode 100644 index 00000000..6f3c9775 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpRouterSolicitationAddressOption.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies the address to which the client should transmit + /// router solicitation requests. + ///
+    ///  Code   Len            Address
+    /// +-----+-----+-----+-----+-----+-----+
+    /// |  32 |  4  |  a1 |  a2 |  a3 |  a4 |
+    /// +-----+-----+-----+-----+-----+-----+
+    /// 
+ ///
+ public class DhcpRouterSolicitationAddressOption : DhcpSingleAddressOption + { + /// + /// create new DhcpRouterSolicitationAddressOption. + /// + /// Address + public DhcpRouterSolicitationAddressOption(IpV4Address address) : base(address, DhcpOptionCode.RouterSolicitationAddress) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.RouterSolicitationAddress)] + internal static DhcpRouterSolicitationAddressOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpRouterSolicitationAddressOption(p)); + } + + /// + /// RFC 2132. + /// Address. + /// + public IpV4Address Address + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpServerIdentifierOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpServerIdentifierOption.cs new file mode 100644 index 00000000..2bdb16b2 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpServerIdentifierOption.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option is used in DHCPOFFER and DHCPREQUEST messages, and may + /// optionally be included in the DHCPACK and DHCPNAK messages.DHCP + /// servers include this option in the DHCPOFFER in order to allow the + /// client to distinguish between lease offers. DHCP clients use the + /// contents of the 'server identifier' field as the destination address + /// for any DHCP messages unicast to the DHCP server. DHCP clients also + /// indicate which of several lease offers is being accepted by including + /// this option in a DHCPREQUEST message. + /// The identifier is the IP address of the selected server. + ///
+    ///  Code   Len             Address
+    /// +-----+-----+-----+-----+-----+-----+
+    /// |  54 |  4  |  a1 |  a2 |  a3 |  a4 |
+    /// +-----+-----+-----+-----+-----+-----+
+    /// 
+ ///
+ public class DhcpServerIdentifierOption : DhcpSingleAddressOption + { + /// + /// create new DhcpServerIdentifierOption. + /// + /// Address + public DhcpServerIdentifierOption(IpV4Address address) : base(address, DhcpOptionCode.ServerIdentifier) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.ServerIdentifier)] + internal static DhcpServerIdentifierOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpServerIdentifierOption(p)); + } + + /// + /// RFC 2132. + /// Address. + /// + public IpV4Address Address + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpSimpleMailTransportProtocolServerOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpSimpleMailTransportProtocolServerOption.cs new file mode 100644 index 00000000..c4045c4e --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpSimpleMailTransportProtocolServerOption.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// The SMTP server option specifies a list of SMTP servers available to + /// the client. Servers SHOULD be listed in order of preference. + ///
+    ///  Code   Len         Address 1               Address 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// | 69  |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |  ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// 
+ ///
+ public class DhcpSimpleMailTransportProtocolServerOption : DhcpAddressListOption + { + /// + /// create new DhcpSimpleMailTransportProtocolServerOption. + /// + /// Addresses + public DhcpSimpleMailTransportProtocolServerOption(IList addresses) : base(addresses, DhcpOptionCode.SimpleMailTransportProtocolServer) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.SimpleMailTransportProtocolServer)] + internal static DhcpSimpleMailTransportProtocolServerOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpSimpleMailTransportProtocolServerOption(p)); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpSingleAddressOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpSingleAddressOption.cs new file mode 100644 index 00000000..82308b1c --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpSingleAddressOption.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// Abstract class for all Dhcp-Options with a single Addresses. + /// + public abstract class DhcpSingleAddressOption : DhcpOption + { + internal DhcpSingleAddressOption(IpV4Address address, DhcpOptionCode code) : base(code) + { + InternalValue = address; + } + + internal static T Read(DataSegment data, ref int offset, Func ctor) where T : DhcpSingleAddressOption + { + if (ctor == null) + throw new ArgumentNullException(nameof(ctor)); + byte len = data[offset++]; + if (len != IpV4Address.SizeOf) + throw new ArgumentException("Length of a DHCP SingleAddress Option has to be 4"); + T option = ctor(data.ReadIpV4Address(offset, Endianity.Big)); + offset += IpV4Address.SizeOf; + return option; + } + + internal override void Write(byte[] buffer, ref int offset) + { + base.Write(buffer, ref offset); + buffer.Write(ref offset, InternalValue, Endianity.Big); + } + + /// + /// RFC 2132. + /// Value of Length-Field. + /// + public override byte Length + { + get { return IpV4Address.SizeOf; } + } + + /// + /// The real value of the SingleAddressOption. + /// + protected IpV4Address InternalValue + { + get; + set; + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpStaticRouteOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpStaticRouteOption.cs new file mode 100644 index 00000000..d7706691 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpStaticRouteOption.cs @@ -0,0 +1,191 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies a list of static routes that the client should + /// install in its routing cache.If multiple routes to the same + /// destination are specified, they are listed in descending order of + /// priority. + ///
+    ///  Code   Len         Destination 1           Router 1
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
+    /// |  33 |  n  |  d1 |  d2 |  d3 |  d4 |  r1 |  r2 |  r3 |  r4 |
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
+    ///         Destination 2           Router 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+---
+    /// |  d1 |  d2 |  d3 |  d4 |  r1 |  r2 |  r3 |  r4 | ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+---
+    /// 
+ ///
+ public class DhcpStaticRouteOption : DhcpOption + { + internal const int MAX_ROUTES = 255 / 8; + + /// + /// create new DhcpStaticRouteOption. + /// + /// Routes + public DhcpStaticRouteOption(IList routes) : base(DhcpOptionCode.StaticRoute) + { + if (routes == null) + throw new ArgumentNullException(nameof(routes)); + if (routes.Count < 1) + throw new ArgumentOutOfRangeException(nameof(routes), routes.Count, "The minimum items in routes is 1"); + if (routes.Count > MAX_ROUTES) + throw new ArgumentOutOfRangeException(nameof(routes), routes.Count, "The maximum items in routes is " + MAX_ROUTES); + + Routes = new ReadOnlyCollection(routes); + } + + [DhcpOptionReadRegistration(DhcpOptionCode.StaticRoute)] + internal static DhcpStaticRouteOption Read(DataSegment data, ref int offset) + { + byte length = data[offset++]; + if (length % 8 != 0) + throw new ArgumentException("length has to be a multiple of 8"); + IList addresses = DhcpAddressListOption.GetAddresses(data, length, ref offset); + + List routes = new List(); + for (int i = 0; i < addresses.Count; i += 2) + { + routes.Add(new IpV4AddressRoute(addresses[i], addresses[i + 1])); + } + return new DhcpStaticRouteOption(routes); + } + + internal override void Write(byte[] buffer, ref int offset) + { + base.Write(buffer, ref offset); + foreach (IpV4AddressRoute route in Routes) + { + buffer.Write(ref offset, route.Destination, Endianity.Big); + buffer.Write(ref offset, route.Router, Endianity.Big); + } + } + + /// + /// Length of the Dhcp-Option. + /// + public override byte Length + { + get + { + return (byte)(Routes.Count * 8); + } + } + + /// + /// Routes. + /// + public IReadOnlyCollection Routes + { + get; + private set; + } + + /// + /// Mapping between Ipv$Address and Route Address. + /// + public struct IpV4AddressRoute : IEquatable + { + /// + /// The number of bytes the IpV4AddressRoute take. + /// + public const int SizeOf = IpV4Address.SizeOf + IpV4Address.SizeOf; + + /// + /// Destination Address. + /// + public IpV4Address Destination + + { + get; + private set; + } + + /// + /// Router-IP. + /// + public IpV4Address Router + { + get; + private set; + } + + /// + /// create new IpV4AddressRoute. + /// + /// Destination IP + /// Router IP + public IpV4AddressRoute(IpV4Address destination, IpV4Address router) + { + Destination = destination; + Router = router; + } + + /// + /// Determines whether the specified object is equal to the current object. + /// + /// The object to compare with the current object. + /// true if the specified object is equal to the current object; otherwise, false. + public override bool Equals(object obj) + { + if (obj is IpV4AddressRoute) + { + return Equals((IpV4AddressRoute)obj); + } + return false; + } + + /// + /// Determines whether the IpV4AddressWithMask is equal to the current IpV4AddressWithMask. + /// + /// The object to compare with the current object. + /// true if the specified object is equal to the current object; otherwise, false. + public bool Equals(IpV4AddressRoute other) + { + return object.Equals(Destination, other.Destination) && + object.Equals(Router, other.Router); + } + + /// + /// Returns the hash code for this instance. + /// + /// A 32-bit signed integer hash code. + public override int GetHashCode() + { + return Destination.GetHashCode() ^ Router.GetHashCode(); + } + + /// + /// Determines whether the IpV4AddressWithMask is equal to the current IpV4AddressWithMask. + /// + /// left IpV4AddressWithMask + /// right IpV4AddressWithMask + /// + public static bool operator ==(IpV4AddressRoute left, IpV4AddressRoute right) + { + return Object.Equals(left, right); + } + + /// + /// Determines whether the IpV4AddressWithMask is not equal to the current IpV4AddressWithMask. + /// + /// left IpV4AddressWithMask + /// right IpV4AddressWithMask + /// + public static bool operator !=(IpV4AddressRoute left, IpV4AddressRoute right) + { + return !Object.Equals(left, right); + } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpStreetTalkDirectoryAssistanceServerOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpStreetTalkDirectoryAssistanceServerOption.cs new file mode 100644 index 00000000..7a0238ed --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpStreetTalkDirectoryAssistanceServerOption.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// The StreetTalk Directory Assistance (STDA) server option specifies a + /// list of STDA servers available to the client.Servers SHOULD be + /// listed in order of preference. + ///
+    ///  Code   Len         Address 1               Address 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// | 76  |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |  ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// 
+ ///
+ public class DhcpStreetTalkDirectoryAssistanceServerOption : DhcpAddressListOption + { + /// + /// create new DhcpStreetTalkDirectoryAssistanceServerOption. + /// + /// Addresses + public DhcpStreetTalkDirectoryAssistanceServerOption(IList addresses) : base(addresses, DhcpOptionCode.StreetTalkDirectoryAssistanceServer) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.StreetTalkDirectoryAssistanceServer)] + internal static DhcpStreetTalkDirectoryAssistanceServerOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new Options.DhcpStreetTalkDirectoryAssistanceServerOption(p)); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpStreetTalkServerOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpStreetTalkServerOption.cs new file mode 100644 index 00000000..4c1e73cf --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpStreetTalkServerOption.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// The StreetTalk server option specifies a list of StreetTalk servers + /// available to the client.Servers SHOULD be listed in order of + /// preference. + ///
+    ///  Code   Len         Address 1               Address 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// | 75  |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |  ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// 
+ ///
+ public class DhcpStreetTalkServerOption : DhcpAddressListOption + { + /// + /// create new DhcpStreetTalkServerOption. + /// + /// Addresses + public DhcpStreetTalkServerOption(IList addresses) : base(addresses, DhcpOptionCode.StreetTalkServer) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.StreetTalkServer)] + internal static DhcpStreetTalkServerOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpStreetTalkServerOption(p)); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpStringOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpStringOption.cs new file mode 100644 index 00000000..25909a0e --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpStringOption.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// Abstract class for all Dhcp-Options with a string property + /// + public abstract class DhcpStringOption : DhcpOption + { + internal DhcpStringOption(string value, DhcpOptionCode code) : base(code) + { + InternalValue = value; + } + + internal static T Read(DataSegment data, ref int offset, Func ctor) where T : DhcpStringOption + { + byte len = data[offset++]; + T option = ctor(Encoding.ASCII.GetString(data.ReadBytes(offset, len))); + offset += option.Length; + return option; + } + + internal override void Write(byte[] buffer, ref int offset) + { + base.Write(buffer, ref offset); + buffer.Write(ref offset, Encoding.ASCII.GetBytes(InternalValue)); + } + + /// + /// RFC 2132. + /// Value of Length-Field. + /// + public override byte Length + { + get + { + return (byte)Encoding.ASCII.GetByteCount(InternalValue); + } + } + + /// + /// The real value of the StringOption. + /// + protected string InternalValue + { + get { return _value; } + + set + { + if (value == null) + throw new ArgumentNullException(nameof(value)); + if (value.Length < 1) + throw new ArgumentOutOfRangeException(nameof(value), value.Length, "Value has to be at least 1 characters long"); + if (value.Length >= byte.MaxValue) + throw new ArgumentOutOfRangeException(nameof(value), value.Length, "Value has to be less than 255 characters long"); + + _value = value; + } + } + + private string _value; + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpSubnetMaskOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpSubnetMaskOption.cs new file mode 100644 index 00000000..09e117c8 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpSubnetMaskOption.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// The subnet mask option specifies the client's subnet mask as per RFC + /// 950 [5]. + /// If both the subnet mask and the router option are specified in a DHCP + /// reply, the subnet mask option MUST be first. + ///
+    ///  Code   Len        Subnet Mask
+    /// +-----+-----+-----+-----+-----+-----+
+    /// |  1  |  4  |  m1 |  m2 |  m3 |  m4 |
+    /// +-----+-----+-----+-----+-----+-----+
+    /// 
+ ///
+ public class DhcpSubnetMaskOption : DhcpSingleAddressOption + { + /// + /// create new DhcpSubnetMaskOption. + /// + /// Subnet Mask> + public DhcpSubnetMaskOption(IpV4Address subnetMask) : base(subnetMask, DhcpOptionCode.SubnetMask) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.SubnetMask)] + internal static DhcpSubnetMaskOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new Options.DhcpSubnetMaskOption(p)); + } + + /// + /// RFC 2132. + /// Subnet Mask. + /// + public IpV4Address SubnetMask + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpSwapServerOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpSwapServerOption.cs new file mode 100644 index 00000000..275723c7 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpSwapServerOption.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This specifies the IP address of the client's swap server. + ///
+    ///  Code   Len    Swap Server Address
+    /// +-----+-----+-----+-----+-----+-----+
+    /// |  16 |  4  |  a1 |  a2 |  a3 |  a4 |
+    /// +-----+-----+-----+-----+-----+-----+
+    /// 
+ ///
+ public class DhcpSwapServerOption : DhcpSingleAddressOption + { + /// + /// create new DhcpSwapServerOption. + /// + /// Swap Server Address + public DhcpSwapServerOption(IpV4Address swapServerAddress) : base(swapServerAddress, DhcpOptionCode.SwapServer) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.SwapServer)] + internal static DhcpSwapServerOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpSwapServerOption(p)); + } + + /// + /// RFC 2132. + /// Swap Server Address. + /// + public IpV4Address SwapServerAddress + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpTFtpServerNameOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpTFtpServerNameOption.cs new file mode 100644 index 00000000..3c05920e --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpTFtpServerNameOption.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option is used to identify a TFTP server when the 'sname' field + /// in the DHCP header has been used for DHCP options. + ///
+    ///  Code Len    TFTP server
+    /// +-----+-----+-----+-----+-----+---
+    /// | 66  |  n  |  c1 |  c2 |  c3 | ...
+    /// +-----+-----+-----+-----+-----+---
+    /// 
+ ///
+ public class DhcpTFtpServerNameOption : DhcpStringOption + { + /// + /// create new DhcpTFtpServerNameOption. + /// + /// TFTP server + public DhcpTFtpServerNameOption(string tfptServer) : base(tfptServer, DhcpOptionCode.TfptServerName) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.TfptServerName)] + internal static DhcpTFtpServerNameOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpTFtpServerNameOption(p)); + } + + /// + /// RFC 2132. + /// TFTP server. + /// + public string TFtpServer + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpTcpDefaultTtlOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpTcpDefaultTtlOption.cs new file mode 100644 index 00000000..1d1f301f --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpTcpDefaultTtlOption.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies the default TTL that the client should use when + /// sending TCP segments. + ///
+    ///  Code   Len   TTL
+    /// +-----+-----+-----+
+    /// |  37 |  1  |  n  |
+    /// +-----+-----+-----+
+    /// 
+ ///
+ public class DhcpTcpDefaultTtlOption : DhcpByteOption + { + /// + /// create new DhcpTcpDefaultTtlOption. + /// + /// TTL + public DhcpTcpDefaultTtlOption(byte ttl) : base(ttl, DhcpOptionCode.TcpDefaultTtl) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.TcpDefaultTtl)] + internal static DhcpTcpDefaultTtlOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpTcpDefaultTtlOption(p)); + } + + /// + /// RFC 2132. + /// TTL. + /// + public byte Ttl + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpTcpKeepaliveGarbageOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpTcpKeepaliveGarbageOption.cs new file mode 100644 index 00000000..7778282e --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpTcpKeepaliveGarbageOption.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies the whether or not the client should send TCP + /// keepalive messages with a octet of garbage for compatibility with + /// older implementations. + ///
+    ///  Code   Len  Value
+    /// +-----+-----+-----+
+    /// |  39 |  1  | 0/1 |
+    /// +-----+-----+-----+
+    /// 
+ ///
+ public class DhcpTcpKeepaliveGarbageOption : DhcpBooleanOption + { + /// + /// create new DhcpTcpKeepaliveGarbageOption. + /// + /// Value + public DhcpTcpKeepaliveGarbageOption(bool value) : base(value, DhcpOptionCode.TcpKeepaliveGarbage) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.TcpKeepaliveGarbage)] + internal static DhcpTcpKeepaliveGarbageOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpTcpKeepaliveGarbageOption(p)); + } + + /// + /// RFC 2132. + /// Value + /// A value of false indicates that a garbage octet + /// should not be sent. A value of true indicates that a garbage octet + /// should be sent. + /// + public bool Value + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpTcpKeepaliveIntervalOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpTcpKeepaliveIntervalOption.cs new file mode 100644 index 00000000..bb5a8c30 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpTcpKeepaliveIntervalOption.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies the interval (in seconds) that the client TCP + /// should wait before sending a keepalive message on a TCP connection. + ///
+    ///  Code   Len           Time
+    /// +-----+-----+-----+-----+-----+-----+
+    /// |  38 |  4  |  t1 |  t2 |  t3 |  t4 |
+    /// +-----+-----+-----+-----+-----+-----+
+    /// 
+ ///
+ public class DhcpTcpKeepaliveIntervalOption : DhcpUIntOption + { + /// + /// create new DhcpTcpKeepaliveIntervalOption. + /// + /// Time + public DhcpTcpKeepaliveIntervalOption(uint time) : base(time, DhcpOptionCode.TcpKeepaliveInterval) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.TcpKeepaliveInterval)] + internal static DhcpTcpKeepaliveIntervalOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpTcpKeepaliveIntervalOption(p)); + } + + /// + /// RFC 2132. + /// Time. + /// A value of zero + /// indicates that the client should not generate keepalive messages on + /// connections unless specifically requested by an application. + /// + public uint Time + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpTimeOffsetOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpTimeOffsetOption.cs new file mode 100644 index 00000000..6f098bab --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpTimeOffsetOption.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// The time offset field specifies the offset of the client's subnet in + /// seconds from Coordinated Universal Time(UTC). + ///
+    ///  Code   Len        Time Offset
+    /// +-----+-----+-----+-----+-----+-----+
+    /// |  2  |  4  |  n1 |  n2 |  n3 |  n4 |
+    /// +-----+-----+-----+-----+-----+-----+
+    /// 
+ ///
+ public class DhcpTimeOffsetOption : DhcpIntOption + { + /// + /// create new DhcpTimeOffsetOption. + /// + /// Time Offset + public DhcpTimeOffsetOption(int timeOffset) : base(timeOffset, DhcpOptionCode.TimeOffset) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.TimeOffset)] + internal static DhcpTimeOffsetOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpTimeOffsetOption(p)); + } + + /// + /// RFC 2132. + /// Time Offset. + /// The offset is + /// expressed as a two's complement 32-bit integer. A positive offset + /// indicates a location east of the zero meridian and a negative offset + /// indicates a location west of the zero meridian. + /// + public int TimeOffset + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpTimeServerOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpTimeServerOption.cs new file mode 100644 index 00000000..7ff087c7 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpTimeServerOption.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// The time server option specifies a list of RFC 868 [6] time servers + /// available to the client.Servers SHOULD be listed in order of + /// preference. + ///
+    ///  Code   Len         Address 1               Address 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// |  4  |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |  ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+--
+    /// 
+ ///
+ public class DhcpTimeServerOption : DhcpAddressListOption + { + /// + /// create new DhcpTimeServerOption. + /// + /// Addresses + public DhcpTimeServerOption(IList addresses) : base(addresses, DhcpOptionCode.TimeServer) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.TimeServer)] + internal static DhcpTimeServerOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new Options.DhcpTimeServerOption(p)); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpTrailerEncapsulationOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpTrailerEncapsulationOption.cs new file mode 100644 index 00000000..15391a11 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpTrailerEncapsulationOption.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies whether or not the client should negotiate the + /// use of trailers (RFC 893 [14]) when using the ARP protocol. + ///
+    ///  Code   Len  Value
+    /// +-----+-----+-----+
+    /// |  34 |  1  | 0/1 |
+    /// +-----+-----+-----+
+    /// 
+ ///
+ public class DhcpTrailerEncapsulationOption : DhcpBooleanOption + { + /// + /// create new DhcpTrailerEncapsulationOption. + /// + /// Value + public DhcpTrailerEncapsulationOption(bool value) : base(value, DhcpOptionCode.TrailerEncapsulation) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.TrailerEncapsulation)] + internal static DhcpTrailerEncapsulationOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpTrailerEncapsulationOption(p)); + } + + /// + /// RFC 2132. + /// Value. + /// A value of false indicates that the client should not attempt to use trailers. A + /// value of true means that the client should attempt to use trailers. + /// + public bool Value + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpUIntOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpUIntOption.cs new file mode 100644 index 00000000..16ff324b --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpUIntOption.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// Abstract class for all Dhcp-Options with a uint value. + /// + public class DhcpUIntOption : DhcpOption + { + internal DhcpUIntOption(uint value, DhcpOptionCode code) : base(code) + { + InternalValue = value; + } + + internal static T Read(DataSegment data, ref int offset, Func ctor) where T : DhcpUIntOption + { + if (ctor == null) + throw new ArgumentNullException(nameof(ctor)); + byte len = data[offset++]; + if (len != sizeof(uint)) + throw new ArgumentException("Length of a DHCP UIntOption Option has to be 4"); + T option = ctor(data.ReadUInt(offset, Endianity.Big)); + offset += option.Length; + return option; + } + + internal override void Write(byte[] buffer, ref int offset) + { + base.Write(buffer, ref offset); + buffer.Write(ref offset, InternalValue, Endianity.Big); + } + + /// + /// RFC 2132. + /// Value of Length-Field. + /// + public override byte Length + { + get + { + return sizeof(uint); + } + } + + /// + /// The real value of the UIntOption. + /// + protected uint InternalValue + { + get; + set; + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpUShortOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpUShortOption.cs new file mode 100644 index 00000000..3dad87e5 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpUShortOption.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// Abstract class for all Dhcp-Options with a ushort value. + /// + public class DhcpUShortOption : DhcpOption + { + internal DhcpUShortOption(ushort value, DhcpOptionCode code) : base(code) + { + InternalValue = value; + } + + internal static T Read(DataSegment data, ref int offset, Func ctor) where T : DhcpUShortOption + { + if (ctor == null) + throw new ArgumentNullException(nameof(ctor)); + byte len = data[offset++]; + if (len != sizeof(ushort)) + throw new ArgumentException("Length of a DHCP UShortOption Option has to be 2"); + T option = ctor(data.ReadUShort(offset, Endianity.Big)); + offset += option.Length; + return option; + } + + internal override void Write(byte[] buffer, ref int offset) + { + base.Write(buffer, ref offset); + buffer.Write(ref offset, InternalValue, Endianity.Big); + } + + /// + /// RFC 2132. + /// Value of Length-Field. + /// + public override byte Length + { + get + { + return sizeof(ushort); + } + } + + /// + /// The real value of the UIntOption. + /// + protected ushort InternalValue + { + get; + set; + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpVendorClassidentifierOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpVendorClassidentifierOption.cs new file mode 100644 index 00000000..d6974729 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpVendorClassidentifierOption.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option is used by DHCP clients to optionally identify the vendor + /// type and configuration of a DHCP client. The information is a string + /// of n octets, interpreted by servers. Vendors may choose to define + /// specific vendor class identifiers to convey particular configuration + /// or other identification information about a client. For example, the + /// identifier may encode the client's hardware configuration. Servers + /// not equipped to interpret the class-specific information sent by a + /// client MUST ignore it(although it may be reported). Servers that + /// respond SHOULD only use option 43 to return the vendor-specific + /// information to the client. + ///
+    ///  Code   Len   Vendor class Identifier
+    /// +-----+-----+-----+-----+---
+    /// |  60 |  n  |  i1 |  i2 | ...
+    /// +-----+-----+-----+-----+---
+    /// 
+ ///
+ public class DhcpVendorClassidentifierOption : DhcpDataSegmentOption + { + /// + /// create new DhcpVendorClassidentifierOption. + /// + /// Vendor class Identifier + public DhcpVendorClassidentifierOption(DataSegment vendorClassIdentifier) : base(vendorClassIdentifier, DhcpOptionCode.VendorClassidentifier) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.VendorClassidentifier)] + internal static DhcpVendorClassidentifierOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpVendorClassidentifierOption(p)); + } + + /// + /// RFC 2132. + /// Vendor class Identifier. + /// + public DataSegment VendorClassIdentifier + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpVendorSpecificInformationOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpVendorSpecificInformationOption.cs new file mode 100644 index 00000000..ad4e28ac --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpVendorSpecificInformationOption.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option is used by clients and servers to exchange vendor- + /// specific information. The information is an opaque object of n + /// octets, presumably interpreted by vendor-specific code on the clients + /// and servers. The definition of this information is vendor specific. + /// The vendor is indicated in the vendor class identifier option. + /// Servers not equipped to interpret the vendor-specific information + /// sent by a client MUST ignore it(although it may be reported). + /// Clients which do not receive desired vendor-specific information + /// SHOULD make an attempt to operate without it, although they may do so + /// (and announce they are doing so) in a degraded mode. + ///
+    /// Code   Len   Vendor-specific information
+    /// +-----+-----+-----+-----+---
+    /// |  43 |  n  |  i1 |  i2 | ...
+    /// +-----+-----+-----+-----+---
+    /// 
+ ///
+ public class DhcpVendorSpecificInformationOption : DhcpDataSegmentOption + { + /// + /// create new DhcpVendorSpecificInformationOption. + /// + /// Vendor-specific information + public DhcpVendorSpecificInformationOption(DataSegment vendorSpecificInformation) : base(vendorSpecificInformation, DhcpOptionCode.VendorSpecificInformation) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.VendorSpecificInformation)] + internal static DhcpVendorSpecificInformationOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpVendorSpecificInformationOption(p)); + } + + /// + /// RFC 2132 + /// Vendor-specific information. + /// + public DataSegment VendorSpecificInformation + { + get { return InternalValue; } + set { InternalValue = value; } + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpXWindowSystemDisplayManagerOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpXWindowSystemDisplayManagerOption.cs new file mode 100644 index 00000000..aed63282 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpXWindowSystemDisplayManagerOption.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies a list of IP addresses of systems that are + /// running the X Window System Display Manager and are available to the + /// client. + /// Addresses SHOULD be listed in order of preference. + ///
+    ///  Code   Len         Address 1               Address 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+---
+    /// |  49 |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |   ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+---
+    /// 
+ ///
+ public class DhcpXWindowSystemDisplayManagerOption : DhcpAddressListOption + { + /// + /// create new DhcpXWindowSystemDisplayManagerOption. + /// + /// Addresses + public DhcpXWindowSystemDisplayManagerOption(IList addresses) : base(addresses, DhcpOptionCode.XWindowSystemDisplayManager) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.XWindowSystemDisplayManager)] + internal static DhcpXWindowSystemDisplayManagerOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new Options.DhcpXWindowSystemDisplayManagerOption(p)); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpXWindowSystemFontServerOption.cs b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpXWindowSystemFontServerOption.cs new file mode 100644 index 00000000..47b35309 --- /dev/null +++ b/PcapDotNet/src/PcapDotNet.Packets/Dhcp/Options/DhcpXWindowSystemFontServerOption.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using PcapDotNet.Packets.IpV4; + +namespace PcapDotNet.Packets.Dhcp.Options +{ + /// + /// RFC 2132. + /// This option specifies a list of X Window System [21] Font servers + /// available to the client. Servers SHOULD be listed in order of + /// preference. + ///
+    ///  Code   Len         Address 1               Address 2
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+---
+    /// |  48 |  n  |  a1 |  a2 |  a3 |  a4 |  a1 |  a2 |   ...
+    /// +-----+-----+-----+-----+-----+-----+-----+-----+---
+    /// 
+ ///
+ public class DhcpXWindowSystemFontServerOption : DhcpAddressListOption + { + /// + /// create new DhcpXWindowSystemFontServerOption. + /// + /// Addresses + public DhcpXWindowSystemFontServerOption(IList addresses) : base(addresses, DhcpOptionCode.XWindowSystemFontServer) + { + } + + [DhcpOptionReadRegistration(DhcpOptionCode.XWindowSystemFontServer)] + internal static DhcpXWindowSystemFontServerOption Read(DataSegment data, ref int offset) + { + return Read(data, ref offset, p => new DhcpXWindowSystemFontServerOption(p)); + } + } +} \ No newline at end of file diff --git a/PcapDotNet/src/PcapDotNet.Packets/PcapDotNet.Packets.csproj b/PcapDotNet/src/PcapDotNet.Packets/PcapDotNet.Packets.csproj index ff5a9534..e1e7f938 100644 --- a/PcapDotNet/src/PcapDotNet.Packets/PcapDotNet.Packets.csproj +++ b/PcapDotNet/src/PcapDotNet.Packets/PcapDotNet.Packets.csproj @@ -95,6 +95,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/PcapDotNet/src/PcapDotNet.Packets/Transport/UdpDatagram.cs b/PcapDotNet/src/PcapDotNet.Packets/Transport/UdpDatagram.cs index 16490d6a..0b55d652 100644 --- a/PcapDotNet/src/PcapDotNet.Packets/Transport/UdpDatagram.cs +++ b/PcapDotNet/src/PcapDotNet.Packets/Transport/UdpDatagram.cs @@ -1,20 +1,21 @@ +using PcapDotNet.Packets.Dhcp; using PcapDotNet.Packets.Dns; namespace PcapDotNet.Packets.Transport { /// /// RFC 768. - /// This User Datagram Protocol (UDP) is defined to make available a datagram mode of packet-switched computer communication - /// in the environment of an interconnected set of computer networks. + /// This User Datagram Protocol (UDP) is defined to make available a datagram mode of packet-switched computer communication + /// in the environment of an interconnected set of computer networks. /// This protocol assumes that the Internet Protocol (IP) is used as the underlying protocol. - /// + /// /// - /// This protocol provides a procedure for application programs to send messages to other programs - /// with a minimum of protocol mechanism. - /// The protocol is transaction oriented, and delivery and duplicate protection are not guaranteed. + /// This protocol provides a procedure for application programs to send messages to other programs + /// with a minimum of protocol mechanism. + /// The protocol is transaction oriented, and delivery and duplicate protection are not guaranteed. /// Applications requiring ordered reliable delivery of streams of data should use the Transmission Control Protocol (TCP). /// - /// + /// /// /// Format ///
@@ -41,14 +42,15 @@ public sealed class UdpDatagram : TransportDatagram
 
         internal static class Offset
         {
-//            public const int SourcePort = 0;
-//            public const int DestinationPort = 2;
+            //            public const int SourcePort = 0;
+            //            public const int DestinationPort = 2;
             public const int TotalLength = 4;
+
             public const int Checksum = 6;
         }
 
         /// 
-        /// The length in octets of this user datagram including this header and the data.   
+        /// The length in octets of this user datagram including this header and the data.
         /// (This  means  the minimum value of the length is eight.)
         /// 
         public ushort TotalLength
@@ -57,7 +59,7 @@ public ushort TotalLength
         }
 
         /// 
-        /// Checksum is the 16-bit one's complement of the one's complement sum of a pseudo header of information from the IP header, 
+        /// Checksum is the 16-bit one's complement of the one's complement sum of a pseudo header of information from the IP header,
         /// the UDP header, and the data, padded  with zero octets at the end (if  necessary) to  make  a multiple of two octets.
         /// 
         public override ushort Checksum
@@ -79,12 +81,12 @@ public override bool IsChecksumOptional
         public override ILayer ExtractLayer()
         {
             return new UdpLayer
-                       {
-                           Checksum = Checksum,
-                           SourcePort = SourcePort,
-                           DestinationPort = DestinationPort,
-                           CalculateChecksumValue = (Checksum != 0)
-                       };
+            {
+                Checksum = Checksum,
+                SourcePort = SourcePort,
+                DestinationPort = DestinationPort,
+                CalculateChecksumValue = (Checksum != 0)
+            };
         }
 
         /// 
@@ -109,6 +111,20 @@ public DnsDatagram Dns
             }
         }
 
+        /// 
+        /// The payload of the datagram as a DHCP datagram.
+        /// 
+        public DhcpDatagram Dhcp
+        {
+            get
+            {
+                if (_dhcp == null && Length >= HeaderLength)
+                    _dhcp = new DhcpDatagram(Buffer, StartOffset + HeaderLength, Length - HeaderLength);
+
+                return _dhcp;
+            }
+        }
+
         internal override int ChecksumOffset
         {
             get { return Offset.Checksum; }
@@ -134,5 +150,6 @@ protected override bool CalculateIsValid()
         }
 
         private DnsDatagram _dns;
+        private DhcpDatagram _dhcp;
     }
 }
\ No newline at end of file
diff --git a/PcapDotNet/src/PcapDotNet.TestUtils/RandomExtensions.cs b/PcapDotNet/src/PcapDotNet.TestUtils/RandomExtensions.cs
index 4f2233d9..e13739bf 100644
--- a/PcapDotNet/src/PcapDotNet.TestUtils/RandomExtensions.cs
+++ b/PcapDotNet/src/PcapDotNet.TestUtils/RandomExtensions.cs
@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using System.Diagnostics.CodeAnalysis;
 using System.Linq;
+using System.Text;
 using PcapDotNet.Base;
 
 namespace PcapDotNet.TestUtils
@@ -207,5 +208,28 @@ public static T NextFlags(this Random random)
             T resultEnum = (T)Convert.ChangeType(resultValue, underlyingType);
             return resultEnum;
         }
+
+        public static string NextCString(this Random random, int minLength, int maxLength)
+        {
+            if (minLength < 0)
+                throw new ArgumentOutOfRangeException(nameof(minLength), minLength, $"{nameof(minLength)} has to be greater than {nameof(maxLength)}");
+            if (minLength > maxLength)
+                throw new ArgumentOutOfRangeException(nameof(minLength), minLength, $"{nameof(minLength)} has to be greater or equal than {nameof(maxLength)}");
+
+            return random.NextCString(random.NextInt(minLength, maxLength));
+        }
+
+        public static string NextCString(this Random random, int length)
+        {
+            if (length < 0)
+                throw new ArgumentOutOfRangeException(nameof(length), length, $"{nameof(length)} has to be greater than 0");
+
+            StringBuilder builder = new StringBuilder();
+            for (int i = 0; i < length; i++)
+            {
+                builder.Append(random.NextChar((char)1, (char)127));
+            }
+            return builder.ToString();
+        }
     }
-}
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index 3e47ea61..f7f5c227 100644
--- a/README.md
+++ b/README.md
@@ -35,6 +35,7 @@ Not including:
 * UDP
 * TCP
 * DNS
+* DHCP
 * HTTP
 
 [![Follow Pcap.Net on Google+](https://ssl.gstatic.com/images/icons/gplus-32.png)](https://plus.google.com/111766834267147414574) [Follow Pcap.Net on Google+](https://plus.google.com/111766834267147414574)