diff --git a/DnsServerCore/Dhcp/ClientIdentifierOption.cs b/DnsServerCore/Dhcp/ClientIdentifierOption.cs
deleted file mode 100644
index d7210527..00000000
--- a/DnsServerCore/Dhcp/ClientIdentifierOption.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
-Technitium DNS Server
-Copyright (C) 2019 Shreyas Zare (shreyas@technitium.com)
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-
-*/
-
-using System;
-using System.IO;
-using TechnitiumLibrary.IO;
-
-namespace DnsServerCore.Dhcp
-{
- class ClientIdentifierOption : DhcpOption
- {
- #region variables
-
- readonly byte _type;
- readonly byte[] _identifier;
-
- #endregion
-
- #region constructor
-
- public ClientIdentifierOption(Stream s)
- : base(DhcpOptionCode.ClientIdentifier)
- {
- int len = s.ReadByte();
- if (len < 0)
- throw new EndOfStreamException();
-
- if (len < 2)
- throw new InvalidDataException();
-
- int type = s.ReadByte();
- if (type < 0)
- throw new EndOfStreamException();
-
- _type = (byte)type;
- _identifier = s.ReadBytes(len - 1);
- }
-
- #endregion
-
- #region protected
-
- protected override void WriteOptionTo(Stream s)
- {
- s.WriteByte(Convert.ToByte(_identifier.Length + 1));
- s.WriteByte(_type);
- s.Write(_identifier);
- }
-
- #endregion
-
- #region properties
-
- public byte Type
- { get { return _type; } }
-
- public byte[] Identifier
- { get { return _identifier; } }
-
- #endregion
- }
-}
diff --git a/DnsServerCore/Dhcp/DhcpMessage.cs b/DnsServerCore/Dhcp/DhcpMessage.cs
index 9ed83928..18cf8ead 100644
--- a/DnsServerCore/Dhcp/DhcpMessage.cs
+++ b/DnsServerCore/Dhcp/DhcpMessage.cs
@@ -17,6 +17,7 @@ along with this program. If not, see .
*/
+using DnsServerCore.Dhcp.Options;
using System;
using System.Collections.Generic;
using System.IO;
@@ -39,6 +40,7 @@ namespace DnsServerCore.Dhcp
enum DhcpMessageFlags : ushort
{
+ None = 0,
Broadcast = 0x8000
}
@@ -46,16 +48,16 @@ namespace DnsServerCore.Dhcp
{
#region variables
- const uint MAGIC_COOKIE = 0x63825363;
+ const uint MAGIC_COOKIE = 0x63538263; //in reverse format
readonly DhcpMessageOpCode _op;
readonly DhcpMessageHardwareAddressType _htype;
readonly byte _hlen;
readonly byte _hops;
- readonly uint _xid;
+ readonly byte[] _xid;
- readonly ushort _secs;
+ readonly byte[] _secs;
readonly DhcpMessageFlags _flags;
readonly IPAddress _ciaddr;
@@ -67,13 +69,26 @@ namespace DnsServerCore.Dhcp
readonly byte[] _sname;
readonly byte[] _file;
- readonly List _options;
+ readonly IReadOnlyCollection _options;
+
+ readonly byte[] _clientHardwareAddress;
+
+ OptionOverloadOption _optionOverload;
+
+ DhcpMessageTypeOption _dhcpMessageType;
+ ClientIdentifierOption _clientIdentifier;
+ HostNameOption _hostName;
+ ClientFullyQualifiedDomainNameOption _clientFullyQualifiedDomainName;
+ ParameterRequestListOption _parameterRequestList;
+ MaximumDhcpMessageSizeOption _maximumDhcpMessageSize;
+ ServerIdentifierOption _serverIdentifier;
+ RequestedIpAddressOption _requestedIpAddress;
#endregion
#region constructor
- public DhcpMessage(DhcpMessageOpCode op, uint xid, ushort secs, DhcpMessageFlags flags, IPAddress ciaddr, IPAddress yiaddr, IPAddress siaddr, IPAddress giaddr, byte[] chaddr, List options)
+ public DhcpMessage(DhcpMessageOpCode op, byte[] xid, byte[] secs, DhcpMessageFlags flags, IPAddress ciaddr, IPAddress yiaddr, IPAddress siaddr, IPAddress giaddr, byte[] clientHardwareAddress, IReadOnlyCollection options)
{
if (ciaddr.AddressFamily != AddressFamily.InterNetwork)
throw new ArgumentException("Address family not supported.", "ciaddr");
@@ -87,22 +102,14 @@ namespace DnsServerCore.Dhcp
if (giaddr.AddressFamily != AddressFamily.InterNetwork)
throw new ArgumentException("Address family not supported.", "giaddr");
- if (chaddr == null)
- {
- chaddr = new byte[16];
- }
- else
- {
- if (chaddr.Length > 16)
- throw new ArgumentException("Value cannot be greater that 16 bytes.", "chaddr");
+ if ((clientHardwareAddress != null) && (clientHardwareAddress.Length != 6))
+ throw new ArgumentException("Value must be 6 bytes long for a valid Ethernet hardware address.", "chaddr");
- if (chaddr.Length < 16)
- {
- byte[] newchaddr = new byte[16];
- Buffer.BlockCopy(chaddr, 0, newchaddr, 0, chaddr.Length);
- chaddr = newchaddr;
- }
- }
+ if (xid.Length != 4)
+ throw new ArgumentException("Transaction ID must be 4 bytes.", "xid");
+
+ if (secs.Length != 2)
+ throw new ArgumentException("Seconds elapsed must be 2 bytes.", "secs");
_op = op;
_htype = DhcpMessageHardwareAddressType.Ethernet;
@@ -119,13 +126,20 @@ namespace DnsServerCore.Dhcp
_siaddr = siaddr;
_giaddr = giaddr;
- _chaddr = chaddr;
+ _clientHardwareAddress = clientHardwareAddress;
+ _chaddr = new byte[16];
+ Buffer.BlockCopy(_clientHardwareAddress, 0, _chaddr, 0, 6);
+
_sname = new byte[64];
_file = new byte[128];
_options = options;
}
+ public DhcpMessage(DhcpMessage request, IPAddress yiaddr, IPAddress siaddr, IReadOnlyCollection options)
+ : this(DhcpMessageOpCode.BootReply, request.TransactionId, request.SecondsElapsed, request.Flags, request.ClientIpAddress, yiaddr, siaddr, request.RelayAgentIpAddress, request.ClientHardwareAddress, options)
+ { }
+
public DhcpMessage(Stream s)
{
byte[] buffer = new byte[4];
@@ -136,12 +150,13 @@ namespace DnsServerCore.Dhcp
_hlen = buffer[2];
_hops = buffer[3];
- s.ReadBytes(buffer, 0, 4);
- _xid = BitConverter.ToUInt32(buffer, 0);
+ _xid = s.ReadBytes(4);
s.ReadBytes(buffer, 0, 4);
- _secs = BitConverter.ToUInt16(buffer, 0);
- _flags = (DhcpMessageFlags)BitConverter.ToUInt16(buffer, 2);
+ _secs = new byte[2];
+ Buffer.BlockCopy(buffer, 0, _secs, 0, 2);
+ Array.Reverse(buffer);
+ _flags = (DhcpMessageFlags)BitConverter.ToUInt16(buffer, 0);
s.ReadBytes(buffer, 0, 4);
_ciaddr = new IPAddress(buffer);
@@ -156,25 +171,125 @@ namespace DnsServerCore.Dhcp
_giaddr = new IPAddress(buffer);
_chaddr = s.ReadBytes(16);
+ _clientHardwareAddress = new byte[_hlen];
+ Buffer.BlockCopy(_chaddr, 0, _clientHardwareAddress, 0, _hlen);
+
_sname = s.ReadBytes(64);
_file = s.ReadBytes(128);
//read options
- _options = new List();
+ List options = new List();
+ _options = options;
s.ReadBytes(buffer, 0, 4);
- Array.Reverse(buffer);
uint magicCookie = BitConverter.ToUInt32(buffer, 0);
if (magicCookie == MAGIC_COOKIE)
{
- while (true)
+ ParseOptions(s, options);
+
+ if (_optionOverload != null)
{
- DhcpOption option = DhcpOption.Parse(s);
- if (option.Code == DhcpOptionCode.End)
+ if (_optionOverload.Value.HasFlag(OptionOverloadValue.FileFieldUsed))
+ {
+ using (MemoryStream mS = new MemoryStream(_file))
+ {
+ ParseOptions(mS, options);
+ }
+ }
+
+ if (_optionOverload.Value.HasFlag(OptionOverloadValue.SnameFieldUsed))
+ {
+ using (MemoryStream mS = new MemoryStream(_sname))
+ {
+ ParseOptions(mS, options);
+ }
+ }
+ }
+
+ //parse all option values
+ foreach (DhcpOption option in options)
+ option.ParseOptionValue();
+ }
+
+ if (_clientIdentifier == null)
+ _clientIdentifier = new ClientIdentifierOption((byte)_htype, _clientHardwareAddress);
+
+ if (_maximumDhcpMessageSize != null)
+ _maximumDhcpMessageSize = new MaximumDhcpMessageSizeOption(576);
+ }
+
+ #endregion
+
+ #region private
+
+ private void ParseOptions(Stream s, List options)
+ {
+ while (true)
+ {
+ DhcpOption option = DhcpOption.Parse(s);
+ if (option.Code == DhcpOptionCode.End)
+ break;
+
+ if (option.Code == DhcpOptionCode.Pad)
+ continue;
+
+ bool optionExists = false;
+
+ foreach (DhcpOption existingOption in options)
+ {
+ if (existingOption.Code == option.Code)
+ {
+ //option already exists so append current option value into existing option
+ existingOption.AppendOptionValue(option);
+ optionExists = true;
+ break;
+ }
+ }
+
+ if (optionExists)
+ continue;
+
+ //add option to list
+ options.Add(option);
+
+ switch (option.Code)
+ {
+ case DhcpOptionCode.DhcpMessageType:
+ _dhcpMessageType = option as DhcpMessageTypeOption;
break;
- _options.Add(option);
+ case DhcpOptionCode.ClientIdentifier:
+ _clientIdentifier = option as ClientIdentifierOption;
+ break;
+
+ case DhcpOptionCode.HostName:
+ _hostName = option as HostNameOption;
+ break;
+
+ case DhcpOptionCode.ClientFullyQualifiedDomainName:
+ _clientFullyQualifiedDomainName = option as ClientFullyQualifiedDomainNameOption;
+ break;
+
+ case DhcpOptionCode.ParameterRequestList:
+ _parameterRequestList = option as ParameterRequestListOption;
+ break;
+
+ case DhcpOptionCode.MaximumDhcpMessageSize:
+ _maximumDhcpMessageSize = option as MaximumDhcpMessageSizeOption;
+ break;
+
+ case DhcpOptionCode.ServerIdentifier:
+ _serverIdentifier = option as ServerIdentifierOption;
+ break;
+
+ case DhcpOptionCode.RequestedIpAddress:
+ _requestedIpAddress = option as RequestedIpAddressOption;
+ break;
+
+ case DhcpOptionCode.OptionOverload:
+ _optionOverload = option as OptionOverloadOption;
+ break;
}
}
}
@@ -190,10 +305,12 @@ namespace DnsServerCore.Dhcp
s.WriteByte(_hlen);
s.WriteByte(_hops);
- s.Write(BitConverter.GetBytes(_xid));
+ s.Write(_xid);
- s.Write(BitConverter.GetBytes(_secs));
- s.Write(BitConverter.GetBytes((ushort)_flags));
+ s.Write(_secs);
+ byte[] buffer = BitConverter.GetBytes((ushort)_flags);
+ Array.Reverse(buffer);
+ s.Write(buffer);
s.Write(_ciaddr.GetAddressBytes());
s.Write(_yiaddr.GetAddressBytes());
@@ -227,10 +344,10 @@ namespace DnsServerCore.Dhcp
public byte Hops
{ get { return _hops; } }
- public uint TransactionId
+ public byte[] TransactionId
{ get { return _xid; } }
- public ushort SecondsElapsed
+ public byte[] SecondsElapsed
{ get { return _secs; } }
public DhcpMessageFlags Flags
@@ -249,7 +366,7 @@ namespace DnsServerCore.Dhcp
{ get { return _giaddr; } }
public byte[] ClientHardwareAddress
- { get { return _chaddr; } }
+ { get { return _clientHardwareAddress; } }
public byte[] ServerHostName
{ get { return _sname; } }
@@ -257,9 +374,33 @@ namespace DnsServerCore.Dhcp
public byte[] BootFileName
{ get { return _file; } }
- public IReadOnlyList Options
+ public IReadOnlyCollection Options
{ get { return _options; } }
+ public DhcpMessageTypeOption DhcpMessageType
+ { get { return _dhcpMessageType; } }
+
+ public ClientIdentifierOption ClientIdentifier
+ { get { return _clientIdentifier; } }
+
+ public HostNameOption HostName
+ { get { return _hostName; } }
+
+ public ClientFullyQualifiedDomainNameOption ClientFullyQualifiedDomainName
+ { get { return _clientFullyQualifiedDomainName; } }
+
+ public ParameterRequestListOption ParameterRequestList
+ { get { return _parameterRequestList; } }
+
+ public MaximumDhcpMessageSizeOption MaximumDhcpMessageSize
+ { get { return _maximumDhcpMessageSize; } }
+
+ public ServerIdentifierOption ServerIdentifier
+ { get { return _serverIdentifier; } }
+
+ public RequestedIpAddressOption RequestedIpAddress
+ { get { return _requestedIpAddress; } }
+
#endregion
}
}
diff --git a/DnsServerCore/Dhcp/DhcpOption.cs b/DnsServerCore/Dhcp/DhcpOption.cs
index a44691f8..3b3840e6 100644
--- a/DnsServerCore/Dhcp/DhcpOption.cs
+++ b/DnsServerCore/Dhcp/DhcpOption.cs
@@ -17,6 +17,7 @@ along with this program. If not, see .
*/
+using DnsServerCore.Dhcp.Options;
using System;
using System.IO;
using TechnitiumLibrary.IO;
@@ -100,6 +101,8 @@ namespace DnsServerCore.Dhcp
DefaultIrc = 74,
StreetTalkServer = 75,
StreetTalkDirectoryAssistance = 76,
+ ClientFullyQualifiedDomainName = 81,
+ ClasslessStaticRoute = 121,
End = 255
}
@@ -108,21 +111,26 @@ namespace DnsServerCore.Dhcp
#region variables
readonly DhcpOptionCode _code;
- readonly byte[] _value;
+ byte[] _value;
#endregion
#region constructor
- protected DhcpOption(DhcpOptionCode type)
+ protected DhcpOption(DhcpOptionCode code, Stream s)
{
- _code = type;
+ _code = code;
+
+ int len = s.ReadByte();
+ if (len < 0)
+ throw new EndOfStreamException();
+
+ _value = s.ReadBytes(len);
}
- private DhcpOption(DhcpOptionCode type, byte[] value)
+ protected DhcpOption(DhcpOptionCode code)
{
- _code = type;
- _value = value;
+ _code = code;
}
#endregion
@@ -162,9 +170,6 @@ namespace DnsServerCore.Dhcp
case DhcpOptionCode.BroadcastAddress:
return new BroadcastAddressOption(s);
- case DhcpOptionCode.StaticRoute:
- return new StaticRouteOption(s);
-
case DhcpOptionCode.NetBiosOverTcpIpNameServer:
return new NetBiosNameServerOption(s);
@@ -201,17 +206,44 @@ namespace DnsServerCore.Dhcp
case DhcpOptionCode.ClientIdentifier:
return new ClientIdentifierOption(s);
+ case DhcpOptionCode.ClientFullyQualifiedDomainName:
+ return new ClientFullyQualifiedDomainNameOption(s);
+
+ case DhcpOptionCode.ClasslessStaticRoute:
+ return new ClasslessStaticRouteOption(s);
+
case DhcpOptionCode.Pad:
case DhcpOptionCode.End:
- return new DhcpOption(optionCode, null);
+ return new DhcpOption(optionCode);
default:
//unknown option
- int len = s.ReadByte();
- if (len < 0)
- throw new EndOfStreamException();
+ return new DhcpOption(optionCode, s);
+ }
+ }
- return new DhcpOption(optionCode, s.ReadBytes(len));
+ #endregion
+
+ #region internal
+
+ internal void AppendOptionValue(DhcpOption option)
+ {
+ byte[] value = new byte[_value.Length + option._value.Length];
+
+ Buffer.BlockCopy(_value, 0, value, 0, _value.Length);
+ Buffer.BlockCopy(option._value, 0, value, _value.Length, option._value.Length);
+
+ _value = value;
+ }
+
+ internal void ParseOptionValue()
+ {
+ if (_value != null)
+ {
+ using (MemoryStream mS = new MemoryStream(_value))
+ {
+ ParseOptionValue(mS);
+ }
}
}
@@ -219,12 +251,14 @@ namespace DnsServerCore.Dhcp
#region protected
- protected virtual void WriteOptionTo(Stream s)
+ protected virtual void ParseOptionValue(Stream s)
+ { }
+
+ protected virtual void WriteOptionValue(Stream s)
{
if (_value == null)
throw new NotImplementedException();
- s.WriteByte(Convert.ToByte(_value.Length));
s.Write(_value);
}
@@ -234,16 +268,37 @@ namespace DnsServerCore.Dhcp
public void WriteTo(Stream s)
{
- s.WriteByte((byte)_code);
-
switch (_code)
{
case DhcpOptionCode.Pad:
case DhcpOptionCode.End:
+ s.WriteByte((byte)_code);
break;
default:
- WriteOptionTo(s);
+ using (MemoryStream mS = new MemoryStream())
+ {
+ WriteOptionValue(mS);
+
+ int len = 255;
+ int valueLen = Convert.ToInt32(mS.Position);
+ mS.Position = 0;
+
+ do
+ {
+ if (valueLen < len)
+ len = valueLen;
+
+ //write option
+ s.WriteByte((byte)_code); //code
+ s.WriteByte((byte)len); //len
+ mS.CopyTo(s, len, len); //value
+
+ valueLen -= len;
+ }
+ while (valueLen > 0);
+ }
+
break;
}
}
diff --git a/DnsServerCore/Dhcp/BroadcastAddressOption.cs b/DnsServerCore/Dhcp/Options/BroadcastAddressOption.cs
similarity index 76%
rename from DnsServerCore/Dhcp/BroadcastAddressOption.cs
rename to DnsServerCore/Dhcp/Options/BroadcastAddressOption.cs
index 9cfa9fb9..e13dbcf2 100644
--- a/DnsServerCore/Dhcp/BroadcastAddressOption.cs
+++ b/DnsServerCore/Dhcp/Options/BroadcastAddressOption.cs
@@ -21,38 +21,43 @@ using System.IO;
using System.Net;
using TechnitiumLibrary.IO;
-namespace DnsServerCore.Dhcp
+namespace DnsServerCore.Dhcp.Options
{
class BroadcastAddressOption : DhcpOption
{
#region variables
- readonly IPAddress _broadcastAddress;
+ IPAddress _broadcastAddress;
#endregion
#region constructor
- public BroadcastAddressOption(Stream s)
+ public BroadcastAddressOption(IPAddress broadcastAddress)
: base(DhcpOptionCode.BroadcastAddress)
{
- int len = s.ReadByte();
- if (len < 0)
- throw new EndOfStreamException();
-
- if (len != 4)
- throw new InvalidDataException();
-
- _broadcastAddress = new IPAddress(s.ReadBytes(4));
+ _broadcastAddress = broadcastAddress;
}
+ public BroadcastAddressOption(Stream s)
+ : base(DhcpOptionCode.BroadcastAddress, s)
+ { }
+
#endregion
#region protected
- protected override void WriteOptionTo(Stream s)
+ protected override void ParseOptionValue(Stream s)
+ {
+ if (s.Length != 4)
+ throw new InvalidDataException();
+
+ _broadcastAddress = new IPAddress(s.ReadBytes(4));
+
+ }
+
+ protected override void WriteOptionValue(Stream s)
{
- s.WriteByte(4);
s.Write(_broadcastAddress.GetAddressBytes());
}
diff --git a/DnsServerCore/Dhcp/Options/ClasslessStaticRouteOption.cs b/DnsServerCore/Dhcp/Options/ClasslessStaticRouteOption.cs
new file mode 100644
index 00000000..021e952a
--- /dev/null
+++ b/DnsServerCore/Dhcp/Options/ClasslessStaticRouteOption.cs
@@ -0,0 +1,153 @@
+/*
+Technitium DNS Server
+Copyright (C) 2019 Shreyas Zare (shreyas@technitium.com)
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+*/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using TechnitiumLibrary.IO;
+
+namespace DnsServerCore.Dhcp.Options
+{
+ class ClasslessStaticRouteOption : DhcpOption
+ {
+ #region variables
+
+ ICollection _routes;
+
+ #endregion
+
+ #region constructor
+
+ public ClasslessStaticRouteOption(ICollection routes)
+ : base(DhcpOptionCode.ClasslessStaticRoute)
+ {
+ _routes = routes;
+ }
+
+ public ClasslessStaticRouteOption(Stream s)
+ : base(DhcpOptionCode.ClasslessStaticRoute, s)
+ { }
+
+ #endregion
+
+ #region protected
+
+ protected override void ParseOptionValue(Stream s)
+ {
+ if (s.Length < 5)
+ throw new InvalidDataException();
+
+ _routes = new List();
+
+ while (s.Position < s.Length)
+ {
+ _routes.Add(new Route(s));
+ }
+ }
+
+ protected override void WriteOptionValue(Stream s)
+ {
+ foreach (Route route in _routes)
+ route.WriteTo(s);
+ }
+
+ #endregion
+
+ #region properties
+
+ public ICollection Routes
+ { get { return _routes; } }
+
+ #endregion
+
+ public class Route
+ {
+ #region private
+
+ readonly IPAddress _destination;
+ readonly IPAddress _subnetMask;
+ readonly IPAddress _router;
+
+ #endregion
+
+ #region constructor
+
+ public Route(IPAddress destination, IPAddress subnetMask, IPAddress router)
+ {
+ _destination = destination;
+ _subnetMask = subnetMask;
+ _router = router;
+ }
+
+ public Route(Stream s)
+ {
+ int subnetMaskWidth = s.ReadByte();
+ if (subnetMaskWidth < 0)
+ throw new EndOfStreamException();
+
+ _destination = new IPAddress(s.ReadBytes(Convert.ToInt32(Math.Ceiling(Convert.ToDecimal(subnetMaskWidth) / 8))));
+
+ byte[] subnetMaskBuffer = BitConverter.GetBytes(0xFFFFFFFFu << (32 - subnetMaskWidth));
+ Array.Reverse(subnetMaskBuffer);
+ _subnetMask = new IPAddress(subnetMaskBuffer);
+
+ _router = new IPAddress(s.ReadBytes(4));
+ }
+
+ #endregion
+
+ #region public
+
+ public void WriteTo(Stream s)
+ {
+ byte[] subnetMaskBuffer = _subnetMask.GetAddressBytes();
+ Array.Reverse(subnetMaskBuffer);
+ uint subnetMaskNumber = BitConverter.ToUInt32(subnetMaskBuffer, 0);
+
+ byte subnetMaskWidth = 0;
+
+ while (subnetMaskNumber > 0u)
+ {
+ subnetMaskNumber <<= 1;
+ subnetMaskWidth++;
+ }
+
+ s.WriteByte(subnetMaskWidth);
+ s.Write(_destination.GetAddressBytes(), 0, Convert.ToInt32(Math.Ceiling(Convert.ToDecimal(subnetMaskWidth) / 8)));
+ s.Write(_router.GetAddressBytes());
+ }
+
+ #endregion
+
+ #region properties
+
+ public IPAddress Destination
+ { get { return _destination; } }
+
+ public IPAddress SubnetMask
+ { get { return _subnetMask; } }
+
+ public IPAddress Router
+ { get { return _router; } }
+
+ #endregion
+ }
+ }
+}
diff --git a/DnsServerCore/Dhcp/Options/ClientFullyQualifiedDomainNameOption.cs b/DnsServerCore/Dhcp/Options/ClientFullyQualifiedDomainNameOption.cs
new file mode 100644
index 00000000..05e33760
--- /dev/null
+++ b/DnsServerCore/Dhcp/Options/ClientFullyQualifiedDomainNameOption.cs
@@ -0,0 +1,127 @@
+/*
+Technitium DNS Server
+Copyright (C) 2019 Shreyas Zare (shreyas@technitium.com)
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+*/
+
+using System.IO;
+using System.Text;
+using TechnitiumLibrary.IO;
+using TechnitiumLibrary.Net.Dns;
+
+namespace DnsServerCore.Dhcp.Options
+{
+ enum ClientFullyQualifiedDomainNameFlags : byte
+ {
+ None = 0,
+ ShouldUpdateDns = 1,
+ OverrideByServer = 2,
+ EncodeUsingCanonicalWireFormat = 4,
+ NoDnsUpdate = 8,
+ }
+
+ class ClientFullyQualifiedDomainNameOption : DhcpOption
+ {
+ #region variables
+
+ ClientFullyQualifiedDomainNameFlags _flags;
+ byte _rcode1;
+ byte _rcode2;
+ string _domainName;
+
+ #endregion
+
+ #region constructor
+
+ public ClientFullyQualifiedDomainNameOption(ClientFullyQualifiedDomainNameFlags flags, byte rcode1, byte rcode2, string domainName)
+ : base(DhcpOptionCode.ClientFullyQualifiedDomainName)
+ {
+ _flags = flags;
+ _rcode1 = rcode1;
+ _rcode2 = rcode2;
+ _domainName = domainName;
+ }
+
+ public ClientFullyQualifiedDomainNameOption(Stream s)
+ : base(DhcpOptionCode.ClientFullyQualifiedDomainName, s)
+ { }
+
+ #endregion
+
+ #region protected
+
+ protected override void ParseOptionValue(Stream s)
+ {
+ if (s.Length < 3)
+ throw new InvalidDataException();
+
+ int flags = s.ReadByte();
+ if (flags < 0)
+ throw new EndOfStreamException();
+
+ _flags = (ClientFullyQualifiedDomainNameFlags)flags;
+
+ int rcode;
+
+ rcode = s.ReadByte();
+ if (rcode < 0)
+ throw new EndOfStreamException();
+
+ _rcode1 = (byte)rcode;
+
+ rcode = s.ReadByte();
+ if (rcode < 0)
+ throw new EndOfStreamException();
+
+ _rcode2 = (byte)rcode;
+
+ if (_flags.HasFlag(ClientFullyQualifiedDomainNameFlags.EncodeUsingCanonicalWireFormat))
+ _domainName = DnsDatagram.DeserializeDomainName(s);
+ else
+ _domainName = Encoding.ASCII.GetString(s.ReadBytes((int)s.Length - 3));
+ }
+
+ protected override void WriteOptionValue(Stream s)
+ {
+ s.WriteByte((byte)_flags);
+ s.WriteByte(_rcode1);
+ s.WriteByte(_rcode2);
+
+ if (_flags.HasFlag(ClientFullyQualifiedDomainNameFlags.EncodeUsingCanonicalWireFormat))
+ DnsDatagram.SerializeDomainName(_domainName, s);
+ else
+ s.Write(Encoding.ASCII.GetBytes(_domainName));
+ }
+
+ #endregion
+
+ #region properties
+
+ public ClientFullyQualifiedDomainNameFlags Flags
+ { get { return _flags; } }
+
+ public byte RCODE1
+ { get { return _rcode1; } }
+
+ public byte RCODE2
+ { get { return _rcode2; } }
+
+ public string DomainName
+ { get { return _domainName; } }
+
+ #endregion
+ }
+}
diff --git a/DnsServerCore/Dhcp/Options/ClientIdentifierOption.cs b/DnsServerCore/Dhcp/Options/ClientIdentifierOption.cs
new file mode 100644
index 00000000..34184b9f
--- /dev/null
+++ b/DnsServerCore/Dhcp/Options/ClientIdentifierOption.cs
@@ -0,0 +1,126 @@
+/*
+Technitium DNS Server
+Copyright (C) 2019 Shreyas Zare (shreyas@technitium.com)
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+*/
+
+using System;
+using System.IO;
+using TechnitiumLibrary.IO;
+
+namespace DnsServerCore.Dhcp.Options
+{
+ class ClientIdentifierOption : DhcpOption, IEquatable
+ {
+ #region variables
+
+ byte _type;
+ byte[] _identifier;
+
+ #endregion
+
+ #region constructor
+
+ public ClientIdentifierOption(byte type, byte[] identifier)
+ : base(DhcpOptionCode.ClientIdentifier)
+ {
+ _type = type;
+ _identifier = identifier;
+ }
+
+ public ClientIdentifierOption(Stream s)
+ : base(DhcpOptionCode.ClientIdentifier, s)
+ { }
+
+ #endregion
+
+ #region protected
+
+ protected override void ParseOptionValue(Stream s)
+ {
+ if (s.Length < 2)
+ throw new InvalidDataException();
+
+ int type = s.ReadByte();
+ if (type < 0)
+ throw new EndOfStreamException();
+
+ _type = (byte)type;
+ _identifier = s.ReadBytes((int)s.Length - 1);
+ }
+
+ protected override void WriteOptionValue(Stream s)
+ {
+ s.WriteByte(_type);
+ s.Write(_identifier);
+ }
+
+ #endregion
+
+ #region public
+
+ public override bool Equals(object obj)
+ {
+ if (obj is null)
+ return false;
+
+ if (ReferenceEquals(this, obj))
+ return true;
+
+ return Equals(obj as ClientIdentifierOption);
+ }
+
+ public bool Equals(ClientIdentifierOption other)
+ {
+ if (other is null)
+ return false;
+
+ if (this._type != other._type)
+ return false;
+
+ if (this._identifier.Length != other._identifier.Length)
+ return false;
+
+ for (int i = 0; i < this._identifier.Length; i++)
+ {
+ if (this._identifier[i] != other._identifier[i])
+ return false;
+ }
+
+ return true;
+ }
+
+ public override int GetHashCode()
+ {
+ int hashCode = 937899003;
+ hashCode = hashCode * -1521134295 + _type.GetHashCode();
+ hashCode = hashCode * -1521134295 + BitConverter.ToInt32(_identifier, 0);
+ return hashCode;
+ }
+
+ #endregion
+
+ #region properties
+
+ public byte Type
+ { get { return _type; } }
+
+ public byte[] Identifier
+ { get { return _identifier; } }
+
+ #endregion
+ }
+}
diff --git a/DnsServerCore/Dhcp/DhcpMessageTypeOption.cs b/DnsServerCore/Dhcp/Options/DhcpMessageTypeOption.cs
similarity index 67%
rename from DnsServerCore/Dhcp/DhcpMessageTypeOption.cs
rename to DnsServerCore/Dhcp/Options/DhcpMessageTypeOption.cs
index bf38e3a7..781cedbd 100644
--- a/DnsServerCore/Dhcp/DhcpMessageTypeOption.cs
+++ b/DnsServerCore/Dhcp/Options/DhcpMessageTypeOption.cs
@@ -19,10 +19,11 @@ along with this program. If not, see .
using System.IO;
-namespace DnsServerCore.Dhcp
+namespace DnsServerCore.Dhcp.Options
{
enum DhcpMessageType : byte
{
+ Unknown = 0,
Discover = 1,
Offer = 2,
Request = 3,
@@ -37,45 +38,58 @@ namespace DnsServerCore.Dhcp
{
#region variables
- readonly DhcpMessageType _messageType;
+ DhcpMessageType _type;
#endregion
#region constructor
- public DhcpMessageTypeOption(Stream s)
+ public DhcpMessageTypeOption(DhcpMessageType type)
: base(DhcpOptionCode.DhcpMessageType)
{
- int len = s.ReadByte();
- if (len < 0)
- throw new EndOfStreamException();
+ _type = type;
+ }
- if (len != 1)
+ public DhcpMessageTypeOption(Stream s)
+ : base(DhcpOptionCode.DhcpMessageType, s)
+ { }
+
+ #endregion
+
+ #region protected
+
+ protected override void ParseOptionValue(Stream s)
+ {
+ if (s.Length != 1)
throw new InvalidDataException();
int type = s.ReadByte();
if (type < 0)
throw new EndOfStreamException();
- _messageType = (DhcpMessageType)type;
+ _type = (DhcpMessageType)type;
+ }
+
+ protected override void WriteOptionValue(Stream s)
+ {
+ s.WriteByte((byte)_type);
}
#endregion
- #region protected
+ #region string
- protected override void WriteOptionTo(Stream s)
+ public override string ToString()
{
- s.WriteByte(1);
- s.WriteByte((byte)_messageType);
+ return _type.ToString();
}
#endregion
#region properties
- public DhcpMessageType MessageType
- { get { return _messageType; } }
+ public DhcpMessageType Type
+ { get { return _type; } }
#endregion
}
diff --git a/DnsServerCore/Dhcp/DomainNameOption.cs b/DnsServerCore/Dhcp/Options/DomainNameOption.cs
similarity index 74%
rename from DnsServerCore/Dhcp/DomainNameOption.cs
rename to DnsServerCore/Dhcp/Options/DomainNameOption.cs
index 5904bcf2..a9cdcde1 100644
--- a/DnsServerCore/Dhcp/DomainNameOption.cs
+++ b/DnsServerCore/Dhcp/Options/DomainNameOption.cs
@@ -17,43 +17,46 @@ along with this program. If not, see .
*/
-using System;
using System.IO;
using System.Text;
using TechnitiumLibrary.IO;
-namespace DnsServerCore.Dhcp
+namespace DnsServerCore.Dhcp.Options
{
class DomainNameOption : DhcpOption
{
#region variables
- readonly string _domainName;
+ string _domainName;
#endregion
#region constructor
- public DomainNameOption(Stream s)
+ public DomainNameOption(string domainName)
: base(DhcpOptionCode.DomainName)
{
- int len = s.ReadByte();
- if (len < 0)
- throw new EndOfStreamException();
-
- if (len < 1)
- throw new InvalidDataException();
-
- _domainName = Encoding.ASCII.GetString(s.ReadBytes(len));
+ _domainName = domainName;
}
+ public DomainNameOption(Stream s)
+ : base(DhcpOptionCode.DomainName, s)
+ { }
+
#endregion
#region protected
- protected override void WriteOptionTo(Stream s)
+ protected override void ParseOptionValue(Stream s)
+ {
+ if (s.Length < 1)
+ throw new InvalidDataException();
+
+ _domainName = Encoding.ASCII.GetString(s.ReadBytes((int)s.Length));
+ }
+
+ protected override void WriteOptionValue(Stream s)
{
- s.WriteByte(Convert.ToByte(_domainName.Length));
s.Write(Encoding.ASCII.GetBytes(_domainName));
}
diff --git a/DnsServerCore/Dhcp/DomainNameServerOption.cs b/DnsServerCore/Dhcp/Options/DomainNameServerOption.cs
similarity index 75%
rename from DnsServerCore/Dhcp/DomainNameServerOption.cs
rename to DnsServerCore/Dhcp/Options/DomainNameServerOption.cs
index 7b5f94b5..34ef27f6 100644
--- a/DnsServerCore/Dhcp/DomainNameServerOption.cs
+++ b/DnsServerCore/Dhcp/Options/DomainNameServerOption.cs
@@ -17,47 +17,49 @@ along with this program. If not, see .
*/
-using System;
using System.IO;
using System.Net;
using TechnitiumLibrary.IO;
-namespace DnsServerCore.Dhcp
+namespace DnsServerCore.Dhcp.Options
{
class DomainNameServerOption : DhcpOption
{
#region variables
- readonly IPAddress[] _addresses;
+ IPAddress[] _addresses;
#endregion
#region constructor
- public DomainNameServerOption(Stream s)
+ public DomainNameServerOption(IPAddress[] addresses)
: base(DhcpOptionCode.DomainNameServer)
{
- int len = s.ReadByte();
- if (len < 0)
- throw new EndOfStreamException();
-
- if ((len % 4 != 0) || (len < 4))
- throw new InvalidDataException();
-
- _addresses = new IPAddress[len / 4];
-
- for (int i = 0; i < _addresses.Length; i++)
- _addresses[i] = new IPAddress(s.ReadBytes(4));
+ _addresses = addresses;
}
+ public DomainNameServerOption(Stream s)
+ : base(DhcpOptionCode.DomainNameServer, s)
+ { }
+
#endregion
#region protected
- protected override void WriteOptionTo(Stream s)
+ protected override void ParseOptionValue(Stream s)
{
- s.WriteByte(Convert.ToByte(_addresses.Length * 4));
+ if ((s.Length % 4 != 0) || (s.Length < 4))
+ throw new InvalidDataException();
+ _addresses = new IPAddress[s.Length / 4];
+
+ for (int i = 0; i < _addresses.Length; i++)
+ _addresses[i] = new IPAddress(s.ReadBytes(4));
+ }
+
+ protected override void WriteOptionValue(Stream s)
+ {
foreach (IPAddress address in _addresses)
s.Write(address.GetAddressBytes());
}
diff --git a/DnsServerCore/Dhcp/HostNameOption.cs b/DnsServerCore/Dhcp/Options/HostNameOption.cs
similarity index 74%
rename from DnsServerCore/Dhcp/HostNameOption.cs
rename to DnsServerCore/Dhcp/Options/HostNameOption.cs
index d2e9f865..96830cfd 100644
--- a/DnsServerCore/Dhcp/HostNameOption.cs
+++ b/DnsServerCore/Dhcp/Options/HostNameOption.cs
@@ -17,43 +17,46 @@ along with this program. If not, see .
*/
-using System;
using System.IO;
using System.Text;
using TechnitiumLibrary.IO;
-namespace DnsServerCore.Dhcp
+namespace DnsServerCore.Dhcp.Options
{
class HostNameOption : DhcpOption
{
#region variables
- readonly string _hostName;
+ string _hostName;
#endregion
#region constructor
- public HostNameOption(Stream s)
+ public HostNameOption(string hostName)
: base(DhcpOptionCode.HostName)
{
- int len = s.ReadByte();
- if (len < 0)
- throw new EndOfStreamException();
-
- if (len < 1)
- throw new InvalidDataException();
-
- _hostName = Encoding.ASCII.GetString(s.ReadBytes(len));
+ _hostName = hostName;
}
+ public HostNameOption(Stream s)
+ : base(DhcpOptionCode.HostName, s)
+ { }
+
#endregion
#region protected
- protected override void WriteOptionTo(Stream s)
+ protected override void ParseOptionValue(Stream s)
+ {
+ if (s.Length < 1)
+ throw new InvalidDataException();
+
+ _hostName = Encoding.ASCII.GetString(s.ReadBytes((int)s.Length));
+ }
+
+ protected override void WriteOptionValue(Stream s)
{
- s.WriteByte(Convert.ToByte(_hostName.Length));
s.Write(Encoding.ASCII.GetBytes(_hostName));
}
diff --git a/DnsServerCore/Dhcp/IpAddressLeaseTimeOption.cs b/DnsServerCore/Dhcp/Options/IpAddressLeaseTimeOption.cs
similarity index 66%
rename from DnsServerCore/Dhcp/IpAddressLeaseTimeOption.cs
rename to DnsServerCore/Dhcp/Options/IpAddressLeaseTimeOption.cs
index 7a2e69c8..088940e9 100644
--- a/DnsServerCore/Dhcp/IpAddressLeaseTimeOption.cs
+++ b/DnsServerCore/Dhcp/Options/IpAddressLeaseTimeOption.cs
@@ -21,39 +21,47 @@ using System;
using System.IO;
using TechnitiumLibrary.IO;
-namespace DnsServerCore.Dhcp
+namespace DnsServerCore.Dhcp.Options
{
class IpAddressLeaseTimeOption : DhcpOption
{
#region variables
- readonly uint _leaseTime;
+ uint _leaseTime;
#endregion
#region constructor
- public IpAddressLeaseTimeOption(Stream s)
+ public IpAddressLeaseTimeOption(uint leaseTime)
: base(DhcpOptionCode.IpAddressLeaseTime)
{
- int len = s.ReadByte();
- if (len < 0)
- throw new EndOfStreamException();
-
- if (len != 4)
- throw new InvalidDataException();
-
- _leaseTime = BitConverter.ToUInt32(s.ReadBytes(4), 0);
+ _leaseTime = leaseTime;
}
+ public IpAddressLeaseTimeOption(Stream s)
+ : base(DhcpOptionCode.IpAddressLeaseTime, s)
+ { }
+
#endregion
#region protected
- protected override void WriteOptionTo(Stream s)
+ protected override void ParseOptionValue(Stream s)
{
- s.WriteByte(4);
- s.Write(BitConverter.GetBytes(_leaseTime));
+ if (s.Length != 4)
+ throw new InvalidDataException();
+
+ byte[] buffer = s.ReadBytes(4);
+ Array.Reverse(buffer);
+ _leaseTime = BitConverter.ToUInt32(buffer, 0);
+ }
+
+ protected override void WriteOptionValue(Stream s)
+ {
+ byte[] buffer = BitConverter.GetBytes(_leaseTime);
+ Array.Reverse(buffer);
+ s.Write(buffer);
}
#endregion
diff --git a/DnsServerCore/Dhcp/MaximumDhcpMessageSizeOption.cs b/DnsServerCore/Dhcp/Options/MaximumDhcpMessageSizeOption.cs
similarity index 60%
rename from DnsServerCore/Dhcp/MaximumDhcpMessageSizeOption.cs
rename to DnsServerCore/Dhcp/Options/MaximumDhcpMessageSizeOption.cs
index 51012570..7152dd69 100644
--- a/DnsServerCore/Dhcp/MaximumDhcpMessageSizeOption.cs
+++ b/DnsServerCore/Dhcp/Options/MaximumDhcpMessageSizeOption.cs
@@ -21,39 +21,53 @@ using System;
using System.IO;
using TechnitiumLibrary.IO;
-namespace DnsServerCore.Dhcp
+namespace DnsServerCore.Dhcp.Options
{
class MaximumDhcpMessageSizeOption : DhcpOption
{
#region variables
- readonly ushort _length;
+ ushort _length;
#endregion
#region constructor
- public MaximumDhcpMessageSizeOption(Stream s)
+ public MaximumDhcpMessageSizeOption(ushort length)
: base(DhcpOptionCode.MaximumDhcpMessageSize)
{
- int len = s.ReadByte();
- if (len < 0)
- throw new EndOfStreamException();
+ if (length < 576)
+ throw new ArgumentOutOfRangeException("length", "Length must be 576 bytes or more.");
- if (len != 2)
- throw new InvalidDataException();
-
- _length = BitConverter.ToUInt16(s.ReadBytes(2), 0);
+ _length = length;
}
+ public MaximumDhcpMessageSizeOption(Stream s)
+ : base(DhcpOptionCode.MaximumDhcpMessageSize, s)
+ { }
+
#endregion
#region protected
- protected override void WriteOptionTo(Stream s)
+ protected override void ParseOptionValue(Stream s)
{
- s.WriteByte(2);
- s.Write(BitConverter.GetBytes(_length));
+ if (s.Length != 2)
+ throw new InvalidDataException();
+
+ byte[] buffer = s.ReadBytes(2);
+ Array.Reverse(buffer);
+ _length = BitConverter.ToUInt16(buffer, 0);
+
+ if (_length < 576)
+ _length = 576;
+ }
+
+ protected override void WriteOptionValue(Stream s)
+ {
+ byte[] buffer = BitConverter.GetBytes(_length);
+ Array.Reverse(buffer);
+ s.Write(buffer);
}
#endregion
diff --git a/DnsServerCore/Dhcp/MessageOption.cs b/DnsServerCore/Dhcp/Options/MessageOption.cs
similarity index 76%
rename from DnsServerCore/Dhcp/MessageOption.cs
rename to DnsServerCore/Dhcp/Options/MessageOption.cs
index 17d9cbe1..7e039a1a 100644
--- a/DnsServerCore/Dhcp/MessageOption.cs
+++ b/DnsServerCore/Dhcp/Options/MessageOption.cs
@@ -17,43 +17,51 @@ along with this program. If not, see .
*/
-using System;
using System.IO;
using System.Text;
using TechnitiumLibrary.IO;
-namespace DnsServerCore.Dhcp
+namespace DnsServerCore.Dhcp.Options
{
class MessageOption : DhcpOption
{
#region variables
- readonly string _text;
+ string _text;
#endregion
#region constructor
- public MessageOption(Stream s)
+ public MessageOption(string text)
: base(DhcpOptionCode.Message)
+ {
+ _text = text;
+ }
+
+ public MessageOption(Stream s)
+ : base(DhcpOptionCode.Message, s)
{
int len = s.ReadByte();
if (len < 0)
throw new EndOfStreamException();
- if (len < 1)
- throw new InvalidDataException();
-
- _text = Encoding.ASCII.GetString(s.ReadBytes(len));
}
#endregion
#region protected
- protected override void WriteOptionTo(Stream s)
+ protected override void ParseOptionValue(Stream s)
+ {
+ if (s.Length < 1)
+ throw new InvalidDataException();
+
+ _text = Encoding.ASCII.GetString(s.ReadBytes((int)s.Length));
+ }
+
+ protected override void WriteOptionValue(Stream s)
{
- s.WriteByte(Convert.ToByte(_text.Length));
s.Write(Encoding.ASCII.GetBytes(_text));
}
diff --git a/DnsServerCore/Dhcp/NetBiosNameServerOption.cs b/DnsServerCore/Dhcp/Options/NetBiosNameServerOption.cs
similarity index 75%
rename from DnsServerCore/Dhcp/NetBiosNameServerOption.cs
rename to DnsServerCore/Dhcp/Options/NetBiosNameServerOption.cs
index f32158a4..dba24824 100644
--- a/DnsServerCore/Dhcp/NetBiosNameServerOption.cs
+++ b/DnsServerCore/Dhcp/Options/NetBiosNameServerOption.cs
@@ -17,47 +17,49 @@ along with this program. If not, see .
*/
-using System;
using System.IO;
using System.Net;
using TechnitiumLibrary.IO;
-namespace DnsServerCore.Dhcp
+namespace DnsServerCore.Dhcp.Options
{
class NetBiosNameServerOption : DhcpOption
{
#region variables
- readonly IPAddress[] _addresses;
+ IPAddress[] _addresses;
#endregion
#region constructor
- public NetBiosNameServerOption(Stream s)
+ public NetBiosNameServerOption(IPAddress[] addresses)
: base(DhcpOptionCode.NetBiosOverTcpIpNameServer)
{
- int len = s.ReadByte();
- if (len < 0)
- throw new EndOfStreamException();
-
- if ((len % 4 != 0) || (len < 4))
- throw new InvalidDataException();
-
- _addresses = new IPAddress[len / 4];
-
- for (int i = 0; i < _addresses.Length; i++)
- _addresses[i] = new IPAddress(s.ReadBytes(4));
+ _addresses = addresses;
}
+ public NetBiosNameServerOption(Stream s)
+ : base(DhcpOptionCode.NetBiosOverTcpIpNameServer, s)
+ { }
+
#endregion
#region protected
- protected override void WriteOptionTo(Stream s)
+ protected override void ParseOptionValue(Stream s)
{
- s.WriteByte(Convert.ToByte(_addresses.Length * 4));
+ if ((s.Length % 4 != 0) || (s.Length < 4))
+ throw new InvalidDataException();
+ _addresses = new IPAddress[s.Length / 4];
+
+ for (int i = 0; i < _addresses.Length; i++)
+ _addresses[i] = new IPAddress(s.ReadBytes(4));
+ }
+
+ protected override void WriteOptionValue(Stream s)
+ {
foreach (IPAddress address in _addresses)
s.Write(address.GetAddressBytes());
}
diff --git a/DnsServerCore/Dhcp/NetworkTimeProtocolServersOption.cs b/DnsServerCore/Dhcp/Options/NetworkTimeProtocolServersOption.cs
similarity index 75%
rename from DnsServerCore/Dhcp/NetworkTimeProtocolServersOption.cs
rename to DnsServerCore/Dhcp/Options/NetworkTimeProtocolServersOption.cs
index b7d6d3af..65e16abb 100644
--- a/DnsServerCore/Dhcp/NetworkTimeProtocolServersOption.cs
+++ b/DnsServerCore/Dhcp/Options/NetworkTimeProtocolServersOption.cs
@@ -17,47 +17,49 @@ along with this program. If not, see .
*/
-using System;
using System.IO;
using System.Net;
using TechnitiumLibrary.IO;
-namespace DnsServerCore.Dhcp
+namespace DnsServerCore.Dhcp.Options
{
class NetworkTimeProtocolServersOption : DhcpOption
{
#region variables
- readonly IPAddress[] _addresses;
+ IPAddress[] _addresses;
#endregion
#region constructor
- public NetworkTimeProtocolServersOption(Stream s)
+ public NetworkTimeProtocolServersOption(IPAddress[] addresses)
: base(DhcpOptionCode.NetworkTimeProtocolServers)
{
- int len = s.ReadByte();
- if (len < 0)
- throw new EndOfStreamException();
-
- if ((len % 4 != 0) || (len < 4))
- throw new InvalidDataException();
-
- _addresses = new IPAddress[len / 4];
-
- for (int i = 0; i < _addresses.Length; i++)
- _addresses[i] = new IPAddress(s.ReadBytes(4));
+ _addresses = addresses;
}
+ public NetworkTimeProtocolServersOption(Stream s)
+ : base(DhcpOptionCode.NetworkTimeProtocolServers, s)
+ { }
+
#endregion
#region protected
- protected override void WriteOptionTo(Stream s)
+ protected override void ParseOptionValue(Stream s)
{
- s.WriteByte(Convert.ToByte(_addresses.Length * 4));
+ if ((s.Length % 4 != 0) || (s.Length < 4))
+ throw new InvalidDataException();
+ _addresses = new IPAddress[s.Length / 4];
+
+ for (int i = 0; i < _addresses.Length; i++)
+ _addresses[i] = new IPAddress(s.ReadBytes(4));
+ }
+
+ protected override void WriteOptionValue(Stream s)
+ {
foreach (IPAddress address in _addresses)
s.Write(address.GetAddressBytes());
}
diff --git a/DnsServerCore/Dhcp/OptionOverloadOption.cs b/DnsServerCore/Dhcp/Options/OptionOverloadOption.cs
similarity index 79%
rename from DnsServerCore/Dhcp/OptionOverloadOption.cs
rename to DnsServerCore/Dhcp/Options/OptionOverloadOption.cs
index 39b57350..2f075138 100644
--- a/DnsServerCore/Dhcp/OptionOverloadOption.cs
+++ b/DnsServerCore/Dhcp/Options/OptionOverloadOption.cs
@@ -19,7 +19,7 @@ along with this program. If not, see .
using System.IO;
-namespace DnsServerCore.Dhcp
+namespace DnsServerCore.Dhcp.Options
{
enum OptionOverloadValue : byte
{
@@ -32,20 +32,29 @@ namespace DnsServerCore.Dhcp
{
#region variables
- readonly OptionOverloadValue _value;
+ OptionOverloadValue _value;
#endregion
#region constructor
- public OptionOverloadOption(Stream s)
+ public OptionOverloadOption(OptionOverloadValue value)
: base(DhcpOptionCode.OptionOverload)
{
- int len = s.ReadByte();
- if (len < 0)
- throw new EndOfStreamException();
+ _value = value;
+ }
- if (len != 1)
+ public OptionOverloadOption(Stream s)
+ : base(DhcpOptionCode.OptionOverload, s)
+ { }
+
+ #endregion
+
+ #region protected
+
+ protected override void ParseOptionValue(Stream s)
+ {
+ if (s.Length != 1)
throw new InvalidDataException();
int value = s.ReadByte();
@@ -55,13 +64,8 @@ namespace DnsServerCore.Dhcp
_value = (OptionOverloadValue)value;
}
- #endregion
-
- #region protected
-
- protected override void WriteOptionTo(Stream s)
+ protected override void WriteOptionValue(Stream s)
{
- s.WriteByte(4);
s.WriteByte((byte)_value);
}
diff --git a/DnsServerCore/Dhcp/ParameterRequestListOption.cs b/DnsServerCore/Dhcp/Options/ParameterRequestListOption.cs
similarity index 77%
rename from DnsServerCore/Dhcp/ParameterRequestListOption.cs
rename to DnsServerCore/Dhcp/Options/ParameterRequestListOption.cs
index 159776dc..2951dede 100644
--- a/DnsServerCore/Dhcp/ParameterRequestListOption.cs
+++ b/DnsServerCore/Dhcp/Options/ParameterRequestListOption.cs
@@ -17,32 +17,40 @@ along with this program. If not, see .
*/
-using System;
using System.IO;
-namespace DnsServerCore.Dhcp
+namespace DnsServerCore.Dhcp.Options
{
class ParameterRequestListOption : DhcpOption
{
#region variables
- readonly DhcpOptionCode[] _optionCodes;
+ DhcpOptionCode[] _optionCodes;
#endregion
#region constructor
- public ParameterRequestListOption(Stream s)
+ public ParameterRequestListOption(DhcpOptionCode[] optionCodes)
: base(DhcpOptionCode.ParameterRequestList)
{
- int len = s.ReadByte();
- if (len < 0)
- throw new EndOfStreamException();
+ _optionCodes = optionCodes;
+ }
- if (len < 1)
+ public ParameterRequestListOption(Stream s)
+ : base(DhcpOptionCode.ParameterRequestList, s)
+ { }
+
+ #endregion
+
+ #region protected
+
+ protected override void ParseOptionValue(Stream s)
+ {
+ if (s.Length < 1)
throw new InvalidDataException();
- _optionCodes = new DhcpOptionCode[len];
+ _optionCodes = new DhcpOptionCode[s.Length];
int optionCode;
for (int i = 0; i < _optionCodes.Length; i++)
@@ -55,14 +63,8 @@ namespace DnsServerCore.Dhcp
}
}
- #endregion
-
- #region protected
-
- protected override void WriteOptionTo(Stream s)
+ protected override void WriteOptionValue(Stream s)
{
- s.WriteByte(Convert.ToByte(_optionCodes.Length));
-
foreach (DhcpOptionCode optionCode in _optionCodes)
s.WriteByte((byte)optionCode);
}
diff --git a/DnsServerCore/Dhcp/RebindingTimeValueOption.cs b/DnsServerCore/Dhcp/Options/RebindingTimeValueOption.cs
similarity index 66%
rename from DnsServerCore/Dhcp/RebindingTimeValueOption.cs
rename to DnsServerCore/Dhcp/Options/RebindingTimeValueOption.cs
index f25270b7..1416d4e3 100644
--- a/DnsServerCore/Dhcp/RebindingTimeValueOption.cs
+++ b/DnsServerCore/Dhcp/Options/RebindingTimeValueOption.cs
@@ -21,39 +21,47 @@ using System;
using System.IO;
using TechnitiumLibrary.IO;
-namespace DnsServerCore.Dhcp
+namespace DnsServerCore.Dhcp.Options
{
class RebindingTimeValueOption : DhcpOption
{
#region variables
- readonly uint _t2Interval;
+ uint _t2Interval;
#endregion
#region constructor
- public RebindingTimeValueOption(Stream s)
+ public RebindingTimeValueOption(uint t2Interval)
: base(DhcpOptionCode.RebindingTimeValue)
{
- int len = s.ReadByte();
- if (len < 0)
- throw new EndOfStreamException();
-
- if (len != 4)
- throw new InvalidDataException();
-
- _t2Interval = BitConverter.ToUInt32(s.ReadBytes(4), 0);
+ _t2Interval = t2Interval;
}
+ public RebindingTimeValueOption(Stream s)
+ : base(DhcpOptionCode.RebindingTimeValue, s)
+ { }
+
#endregion
#region protected
- protected override void WriteOptionTo(Stream s)
+ protected override void ParseOptionValue(Stream s)
{
- s.WriteByte(4);
- s.Write(BitConverter.GetBytes(_t2Interval));
+ if (s.Length != 4)
+ throw new InvalidDataException();
+
+ byte[] buffer = s.ReadBytes(4);
+ Array.Reverse(buffer);
+ _t2Interval = BitConverter.ToUInt32(buffer, 0);
+ }
+
+ protected override void WriteOptionValue(Stream s)
+ {
+ byte[] buffer = BitConverter.GetBytes(_t2Interval);
+ Array.Reverse(buffer);
+ s.Write(buffer);
}
#endregion
diff --git a/DnsServerCore/Dhcp/RenewalTimeValueOption.cs b/DnsServerCore/Dhcp/Options/RenewalTimeValueOption.cs
similarity index 66%
rename from DnsServerCore/Dhcp/RenewalTimeValueOption.cs
rename to DnsServerCore/Dhcp/Options/RenewalTimeValueOption.cs
index b3817659..64808844 100644
--- a/DnsServerCore/Dhcp/RenewalTimeValueOption.cs
+++ b/DnsServerCore/Dhcp/Options/RenewalTimeValueOption.cs
@@ -21,39 +21,47 @@ using System;
using System.IO;
using TechnitiumLibrary.IO;
-namespace DnsServerCore.Dhcp
+namespace DnsServerCore.Dhcp.Options
{
class RenewalTimeValueOption : DhcpOption
{
#region variables
- readonly uint _t1Interval;
+ uint _t1Interval;
#endregion
#region constructor
- public RenewalTimeValueOption(Stream s)
+ public RenewalTimeValueOption(uint t1Interval)
: base(DhcpOptionCode.RenewalTimeValue)
{
- int len = s.ReadByte();
- if (len < 0)
- throw new EndOfStreamException();
-
- if (len != 4)
- throw new InvalidDataException();
-
- _t1Interval = BitConverter.ToUInt32(s.ReadBytes(4), 0);
+ _t1Interval = t1Interval;
}
+ public RenewalTimeValueOption(Stream s)
+ : base(DhcpOptionCode.RenewalTimeValue, s)
+ { }
+
#endregion
#region protected
- protected override void WriteOptionTo(Stream s)
+ protected override void ParseOptionValue(Stream s)
{
- s.WriteByte(4);
- s.Write(BitConverter.GetBytes(_t1Interval));
+ if (s.Length != 4)
+ throw new InvalidDataException();
+
+ byte[] buffer = s.ReadBytes(4);
+ Array.Reverse(buffer);
+ _t1Interval = BitConverter.ToUInt32(buffer, 0);
+ }
+
+ protected override void WriteOptionValue(Stream s)
+ {
+ byte[] buffer = BitConverter.GetBytes(_t1Interval);
+ Array.Reverse(buffer);
+ s.Write(buffer);
}
#endregion
diff --git a/DnsServerCore/Dhcp/RequestedIpAddressOption.cs b/DnsServerCore/Dhcp/Options/RequestedIpAddressOption.cs
similarity index 77%
rename from DnsServerCore/Dhcp/RequestedIpAddressOption.cs
rename to DnsServerCore/Dhcp/Options/RequestedIpAddressOption.cs
index a25bef35..1c8fd438 100644
--- a/DnsServerCore/Dhcp/RequestedIpAddressOption.cs
+++ b/DnsServerCore/Dhcp/Options/RequestedIpAddressOption.cs
@@ -21,38 +21,42 @@ using System.IO;
using System.Net;
using TechnitiumLibrary.IO;
-namespace DnsServerCore.Dhcp
+namespace DnsServerCore.Dhcp.Options
{
class RequestedIpAddressOption : DhcpOption
{
#region variables
- readonly IPAddress _address;
+ IPAddress _address;
#endregion
#region constructor
- public RequestedIpAddressOption(Stream s)
+ public RequestedIpAddressOption(IPAddress address)
: base(DhcpOptionCode.RequestedIpAddress)
{
- int len = s.ReadByte();
- if (len < 0)
- throw new EndOfStreamException();
-
- if (len != 4)
- throw new InvalidDataException();
-
- _address = new IPAddress(s.ReadBytes(4));
+ _address = address;
}
+ public RequestedIpAddressOption(Stream s)
+ : base(DhcpOptionCode.RequestedIpAddress, s)
+ { }
+
#endregion
#region protected
- protected override void WriteOptionTo(Stream s)
+ protected override void ParseOptionValue(Stream s)
+ {
+ if (s.Length != 4)
+ throw new InvalidDataException();
+
+ _address = new IPAddress(s.ReadBytes(4));
+ }
+
+ protected override void WriteOptionValue(Stream s)
{
- s.WriteByte(4);
s.Write(_address.GetAddressBytes());
}
diff --git a/DnsServerCore/Dhcp/RouterOption.cs b/DnsServerCore/Dhcp/Options/RouterOption.cs
similarity index 76%
rename from DnsServerCore/Dhcp/RouterOption.cs
rename to DnsServerCore/Dhcp/Options/RouterOption.cs
index ae0a6e31..74b464f5 100644
--- a/DnsServerCore/Dhcp/RouterOption.cs
+++ b/DnsServerCore/Dhcp/Options/RouterOption.cs
@@ -17,47 +17,49 @@ along with this program. If not, see .
*/
-using System;
using System.IO;
using System.Net;
using TechnitiumLibrary.IO;
-namespace DnsServerCore.Dhcp
+namespace DnsServerCore.Dhcp.Options
{
class RouterOption : DhcpOption
{
#region variables
- readonly IPAddress[] _addresses;
+ IPAddress[] _addresses;
#endregion
#region constructor
- public RouterOption(Stream s)
+ public RouterOption(IPAddress[] addresses)
: base(DhcpOptionCode.Router)
{
- int len = s.ReadByte();
- if (len < 0)
- throw new EndOfStreamException();
-
- if ((len % 4 != 0) || (len < 4))
- throw new InvalidDataException();
-
- _addresses = new IPAddress[len / 4];
-
- for (int i = 0; i < _addresses.Length; i++)
- _addresses[i] = new IPAddress(s.ReadBytes(4));
+ _addresses = addresses;
}
+ public RouterOption(Stream s)
+ : base(DhcpOptionCode.Router, s)
+ { }
+
#endregion
#region protected
- protected override void WriteOptionTo(Stream s)
+ protected override void ParseOptionValue(Stream s)
{
- s.WriteByte(Convert.ToByte(_addresses.Length * 4));
+ if ((s.Length % 4 != 0) || (s.Length < 4))
+ throw new InvalidDataException();
+ _addresses = new IPAddress[s.Length / 4];
+
+ for (int i = 0; i < _addresses.Length; i++)
+ _addresses[i] = new IPAddress(s.ReadBytes(4));
+ }
+
+ protected override void WriteOptionValue(Stream s)
+ {
foreach (IPAddress address in _addresses)
s.Write(address.GetAddressBytes());
}
diff --git a/DnsServerCore/Dhcp/ServerIdentifierOption.cs b/DnsServerCore/Dhcp/Options/ServerIdentifierOption.cs
similarity index 78%
rename from DnsServerCore/Dhcp/ServerIdentifierOption.cs
rename to DnsServerCore/Dhcp/Options/ServerIdentifierOption.cs
index dfd84be6..c0889409 100644
--- a/DnsServerCore/Dhcp/ServerIdentifierOption.cs
+++ b/DnsServerCore/Dhcp/Options/ServerIdentifierOption.cs
@@ -21,38 +21,42 @@ using System.IO;
using System.Net;
using TechnitiumLibrary.IO;
-namespace DnsServerCore.Dhcp
+namespace DnsServerCore.Dhcp.Options
{
class ServerIdentifierOption : DhcpOption
{
#region variables
- readonly IPAddress _address;
+ IPAddress _address;
#endregion
#region constructor
- public ServerIdentifierOption(Stream s)
+ public ServerIdentifierOption(IPAddress address)
: base(DhcpOptionCode.ServerIdentifier)
{
- int len = s.ReadByte();
- if (len < 0)
- throw new EndOfStreamException();
-
- if (len != 4)
- throw new InvalidDataException();
-
- _address = new IPAddress(s.ReadBytes(4));
+ _address = address;
}
+ public ServerIdentifierOption(Stream s)
+ : base(DhcpOptionCode.ServerIdentifier, s)
+ { }
+
#endregion
#region protected
- protected override void WriteOptionTo(Stream s)
+ protected override void ParseOptionValue(Stream s)
+ {
+ if (s.Length != 4)
+ throw new InvalidDataException();
+
+ _address = new IPAddress(s.ReadBytes(4));
+ }
+
+ protected override void WriteOptionValue(Stream s)
{
- s.WriteByte(4);
s.Write(_address.GetAddressBytes());
}
diff --git a/DnsServerCore/Dhcp/SubnetMaskOption.cs b/DnsServerCore/Dhcp/Options/SubnetMaskOption.cs
similarity index 77%
rename from DnsServerCore/Dhcp/SubnetMaskOption.cs
rename to DnsServerCore/Dhcp/Options/SubnetMaskOption.cs
index e40ef789..2bb87acf 100644
--- a/DnsServerCore/Dhcp/SubnetMaskOption.cs
+++ b/DnsServerCore/Dhcp/Options/SubnetMaskOption.cs
@@ -21,38 +21,42 @@ using System.IO;
using System.Net;
using TechnitiumLibrary.IO;
-namespace DnsServerCore.Dhcp
+namespace DnsServerCore.Dhcp.Options
{
class SubnetMaskOption : DhcpOption
{
#region variables
- readonly IPAddress _subnetMask;
+ IPAddress _subnetMask;
#endregion
#region constructor
- public SubnetMaskOption(Stream s)
+ public SubnetMaskOption(IPAddress subnetMask)
: base(DhcpOptionCode.SubnetMask)
{
- int len = s.ReadByte();
- if (len < 0)
- throw new EndOfStreamException();
-
- if (len != 4)
- throw new InvalidDataException();
-
- _subnetMask = new IPAddress(s.ReadBytes(4));
+ _subnetMask = subnetMask;
}
+ public SubnetMaskOption(Stream s)
+ : base(DhcpOptionCode.SubnetMask, s)
+ { }
+
#endregion
#region protected
- protected override void WriteOptionTo(Stream s)
+ protected override void ParseOptionValue(Stream s)
+ {
+ if (s.Length != 4)
+ throw new InvalidDataException();
+
+ _subnetMask = new IPAddress(s.ReadBytes(4));
+ }
+
+ protected override void WriteOptionValue(Stream s)
{
- s.WriteByte(4);
s.Write(_subnetMask.GetAddressBytes());
}
diff --git a/DnsServerCore/Dhcp/StaticRouteOption.cs b/DnsServerCore/Dhcp/StaticRouteOption.cs
deleted file mode 100644
index 59a3cea3..00000000
--- a/DnsServerCore/Dhcp/StaticRouteOption.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-Technitium DNS Server
-Copyright (C) 2019 Shreyas Zare (shreyas@technitium.com)
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-
-*/
-
-using System;
-using System.IO;
-using System.Net;
-using TechnitiumLibrary.IO;
-
-namespace DnsServerCore.Dhcp
-{
- class StaticRouteOption : DhcpOption
- {
- #region variables
-
- readonly Tuple[] _routes;
-
- #endregion
-
- #region constructor
-
- public StaticRouteOption(Stream s)
- : base(DhcpOptionCode.StaticRoute)
- {
- int len = s.ReadByte();
- if (len < 0)
- throw new EndOfStreamException();
-
- if ((len % 8 != 0) || (len < 8))
- throw new InvalidDataException();
-
- _routes = new Tuple[len / 8];
-
- for (int i = 0; i < _routes.Length; i++)
- _routes[i] = new Tuple(new IPAddress(s.ReadBytes(4)), new IPAddress(s.ReadBytes(4)));
- }
-
- #endregion
-
- #region protected
-
- protected override void WriteOptionTo(Stream s)
- {
- s.WriteByte(Convert.ToByte(_routes.Length * 4));
-
- foreach (Tuple route in _routes)
- {
- s.Write(route.Item1.GetAddressBytes());
- s.Write(route.Item2.GetAddressBytes());
- }
- }
-
- #endregion
-
- #region properties
-
- public Tuple[] Routes
- { get { return _routes; } }
-
- #endregion
- }
-}