dhcp: implemented dhcp message parsing changes. implemented all required options with parsing tests. implemented option fragmentation parsing using option overload.

This commit is contained in:
Shreyas Zare
2019-06-09 17:32:28 +05:30
parent ebcf49f315
commit 0f5cbfb9af
25 changed files with 1012 additions and 468 deletions

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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
}
}

View File

@@ -17,6 +17,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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<DhcpOption> _options;
readonly IReadOnlyCollection<DhcpOption> _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<DhcpOption> options)
public DhcpMessage(DhcpMessageOpCode op, byte[] xid, byte[] secs, DhcpMessageFlags flags, IPAddress ciaddr, IPAddress yiaddr, IPAddress siaddr, IPAddress giaddr, byte[] clientHardwareAddress, IReadOnlyCollection<DhcpOption> 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<DhcpOption> 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<DhcpOption>();
List<DhcpOption> options = new List<DhcpOption>();
_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<DhcpOption> 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<DhcpOption> Options
public IReadOnlyCollection<DhcpOption> 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
}
}

View File

@@ -17,6 +17,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@@ -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());
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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<Route> _routes;
#endregion
#region constructor
public ClasslessStaticRouteOption(ICollection<Route> 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<Route>();
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<Route> 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
}
}
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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
}
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
using System;
using System.IO;
using TechnitiumLibrary.IO;
namespace DnsServerCore.Dhcp.Options
{
class ClientIdentifierOption : DhcpOption, IEquatable<ClientIdentifierOption>
{
#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
}
}

View File

@@ -19,10 +19,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
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
}

View File

@@ -17,43 +17,46 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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));
}

View File

@@ -17,47 +17,49 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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());
}

View File

@@ -17,43 +17,46 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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));
}

View File

@@ -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

View File

@@ -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

View File

@@ -17,43 +17,51 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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));
}

View File

@@ -17,47 +17,49 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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());
}

View File

@@ -17,47 +17,49 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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());
}

View File

@@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
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);
}

View File

@@ -17,32 +17,40 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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);
}

View File

@@ -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

View File

@@ -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

View File

@@ -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());
}

View File

@@ -17,47 +17,49 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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());
}

View File

@@ -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());
}

View File

@@ -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());
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
using System;
using System.IO;
using System.Net;
using TechnitiumLibrary.IO;
namespace DnsServerCore.Dhcp
{
class StaticRouteOption : DhcpOption
{
#region variables
readonly Tuple<IPAddress, IPAddress>[] _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<IPAddress, IPAddress>[len / 8];
for (int i = 0; i < _routes.Length; i++)
_routes[i] = new Tuple<IPAddress, IPAddress>(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<IPAddress, IPAddress> route in _routes)
{
s.Write(route.Item1.GetAddressBytes());
s.Write(route.Item2.GetAddressBytes());
}
}
#endregion
#region properties
public Tuple<IPAddress, IPAddress>[] Routes
{ get { return _routes; } }
#endregion
}
}