Scope: implemented domain search and CAPWAPAP option support. Added option to disable dns updates. Added feature to support using domain names for NTP option. Added missing validation checks in properties.

This commit is contained in:
Shreyas Zare
2022-11-12 14:57:08 +05:30
parent f092bf266b
commit 6f89326acd

View File

@@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using DnsServerCore.Dhcp.Options;
using DnsServerCore.Dns;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -33,6 +34,7 @@ using TechnitiumLibrary;
using TechnitiumLibrary.IO;
using TechnitiumLibrary.Net;
using TechnitiumLibrary.Net.Dns;
using TechnitiumLibrary.Net.Dns.ResourceRecords;
namespace DnsServerCore.Dhcp
{
@@ -59,6 +61,8 @@ namespace DnsServerCore.Dhcp
//dhcp options
string _domainName;
IReadOnlyCollection<string> _domainSearchList;
bool _dnsUpdates = true;
uint _dnsTtl = 900;
IPAddress _serverAddress;
string _serverHostName;
@@ -68,8 +72,10 @@ namespace DnsServerCore.Dhcp
IReadOnlyCollection<IPAddress> _dnsServers;
IReadOnlyCollection<IPAddress> _winsServers;
IReadOnlyCollection<IPAddress> _ntpServers;
IReadOnlyCollection<string> _ntpServerDomainNames;
IReadOnlyCollection<ClasslessStaticRouteOption.Route> _staticRoutes;
IReadOnlyDictionary<string, VendorSpecificInformationOption> _vendorInfo;
IReadOnlyCollection<IPAddress> _capwapAcIpAddresses;
//advanced options
IReadOnlyCollection<Exclusion> _exclusions;
@@ -123,6 +129,7 @@ namespace DnsServerCore.Dhcp
case 4:
case 5:
case 6:
case 7:
_name = bR.ReadShortString();
_enabled = bR.ReadBoolean();
@@ -145,6 +152,22 @@ namespace DnsServerCore.Dhcp
if (string.IsNullOrWhiteSpace(_domainName))
_domainName = null;
if (version >= 7)
{
int count = bR.ReadByte();
if (count > 0)
{
string[] domainSearchStrings = new string[count];
for (int i = 0; i < count; i++)
domainSearchStrings[i] = bR.ReadShortString();
_domainSearchList = domainSearchStrings;
}
_dnsUpdates = bR.ReadBoolean();
}
_dnsTtl = bR.ReadUInt32();
if (version >= 2)
@@ -216,6 +239,20 @@ namespace DnsServerCore.Dhcp
}
}
if (version >= 7)
{
int count = bR.ReadByte();
if (count > 0)
{
string[] ntpServerDomainNames = new string[count];
for (int i = 0; i < count; i++)
ntpServerDomainNames[i] = bR.ReadShortString();
_ntpServerDomainNames = ntpServerDomainNames;
}
}
{
int count = bR.ReadByte();
if (count > 0)
@@ -248,6 +285,20 @@ namespace DnsServerCore.Dhcp
}
}
if (version >= 7)
{
int count = bR.ReadByte();
if (count > 0)
{
IPAddress[] capwapAcIpAddresses = new IPAddress[count];
for (int i = 0; i < count; i++)
capwapAcIpAddresses[i] = IPAddressExtension.ReadFrom(bR);
_capwapAcIpAddresses = capwapAcIpAddresses;
}
}
{
int count = bR.ReadByte();
if (count > 0)
@@ -323,7 +374,7 @@ namespace DnsServerCore.Dhcp
#region static
public static void ValidateScopeName(string name)
internal static void ValidateScopeName(string name)
{
foreach (char invalidChar in Path.GetInvalidFileNameChars())
{
@@ -332,7 +383,7 @@ namespace DnsServerCore.Dhcp
}
}
public static bool IsAddressInRange(IPAddress address, IPAddress startingAddress, IPAddress endingAddress)
private static bool IsAddressInRange(IPAddress address, IPAddress startingAddress, IPAddress endingAddress)
{
uint addressNumber = address.ConvertIpToNumber();
uint startingAddressNumber = startingAddress.ConvertIpToNumber();
@@ -341,6 +392,24 @@ namespace DnsServerCore.Dhcp
return (startingAddressNumber <= addressNumber) && (addressNumber <= endingAddressNumber);
}
private static void ValidateIpv4(IReadOnlyCollection<IPAddress> value, string paramName)
{
if (value is not null)
{
foreach (IPAddress ip in value)
{
if (ip.AddressFamily != AddressFamily.InterNetwork)
throw new ArgumentException("The address must be an IPv4 address: " + ip.ToString(), paramName);
}
}
}
private static void ValidateIpv4(IPAddress value, string paramName)
{
if ((value is not null) && (value.AddressFamily != AddressFamily.InterNetwork))
throw new ArgumentException("The address must be an IPv4 address: " + value.ToString(), paramName);
}
#endregion
#region private
@@ -463,7 +532,7 @@ namespace DnsServerCore.Dhcp
else if (string.IsNullOrWhiteSpace(request.ClientFullyQualifiedDomainName.DomainName))
{
//client domain empty and expects server for a fqdn domain name
if (request.HostName == null)
if (request.HostName is null)
return null; //server unable to decide a name for client
clientDomainName = request.HostName.HostName + "." + _domainName;
@@ -856,7 +925,7 @@ namespace DnsServerCore.Dhcp
}
}
if (offerAddress == null)
if (offerAddress is null)
{
await _lastAddressOfferedLock.WaitAsync();
try
@@ -919,7 +988,7 @@ namespace DnsServerCore.Dhcp
return null;
}
internal List<DhcpOption> GetOptions(DhcpMessage request, IPAddress serverIdentifierAddress, string overrideClientDomainName)
internal async Task<List<DhcpOption>> GetOptionsAsync(DhcpMessage request, IPAddress serverIdentifierAddress, string overrideClientDomainName, DnsServer dnsServer)
{
List<DhcpOption> options = new List<DhcpOption>();
@@ -952,7 +1021,7 @@ namespace DnsServerCore.Dhcp
break;
}
if (request.ParameterRequestList == null)
if (request.ParameterRequestList is null)
{
options.Add(new SubnetMaskOption(_subnetMask));
options.Add(new BroadcastAddressOption(_broadcastAddress));
@@ -965,19 +1034,22 @@ namespace DnsServerCore.Dhcp
options.Add(GetClientFullyQualifiedDomainNameOption(request, overrideClientDomainName));
}
if (_routerAddress != null)
if (_domainSearchList is not null)
options.Add(new DomainSearchOption(_domainSearchList));
if (_routerAddress is not null)
options.Add(new RouterOption(new IPAddress[] { _routerAddress }));
if (_dnsServers != null)
if (_dnsServers is not null)
options.Add(new DomainNameServerOption(_dnsServers));
if (_winsServers != null)
if (_winsServers is not null)
options.Add(new NetBiosNameServerOption(_winsServers));
if (_ntpServers != null)
options.Add(new NetworkTimeProtocolServersOption(_ntpServers));
if ((_ntpServers is not null) || (_ntpServerDomainNames is not null))
options.Add(await GetNetworkTimeProtocolServersOptionAsync(dnsServer));
if (_staticRoutes != null)
if (_staticRoutes is not null)
options.Add(new ClasslessStaticRouteOption(_staticRoutes));
}
else
@@ -1002,40 +1074,52 @@ namespace DnsServerCore.Dhcp
break;
case DhcpOptionCode.DomainSearch:
if (_domainSearchList is not null)
options.Add(new DomainSearchOption(_domainSearchList));
break;
case DhcpOptionCode.Router:
if (_routerAddress != null)
if (_routerAddress is not null)
options.Add(new RouterOption(new IPAddress[] { _routerAddress }));
break;
case DhcpOptionCode.DomainNameServer:
if (_dnsServers != null)
if (_dnsServers is not null)
options.Add(new DomainNameServerOption(_dnsServers));
break;
case DhcpOptionCode.NetBiosOverTcpIpNameServer:
if (_winsServers != null)
if (_winsServers is not null)
options.Add(new NetBiosNameServerOption(_winsServers));
break;
case DhcpOptionCode.NetworkTimeProtocolServers:
if (_ntpServers != null)
options.Add(new NetworkTimeProtocolServersOption(_ntpServers));
if ((_ntpServers is not null) || (_ntpServerDomainNames is not null))
options.Add(await GetNetworkTimeProtocolServersOptionAsync(dnsServer));
break;
case DhcpOptionCode.ClasslessStaticRoute:
if (_staticRoutes != null)
if (_staticRoutes is not null)
options.Add(new ClasslessStaticRouteOption(_staticRoutes));
break;
case DhcpOptionCode.CAPWAPAccessControllerAddresses:
if (_capwapAcIpAddresses is not null)
options.Add(new CAPWAPAccessControllerOption(_capwapAcIpAddresses));
break;
}
}
}
if ((_vendorInfo != null) && (request.VendorClassIdentifier != null))
if ((_vendorInfo is not null) && (request.VendorClassIdentifier is not null))
{
if (_vendorInfo.TryGetValue(request.VendorClassIdentifier.Identifier, out VendorSpecificInformationOption vendorSpecificInformationOption) || _vendorInfo.TryGetValue("", out vendorSpecificInformationOption))
{
@@ -1092,6 +1176,39 @@ namespace DnsServerCore.Dhcp
return options;
}
private async Task<NetworkTimeProtocolServersOption> GetNetworkTimeProtocolServersOptionAsync(DnsServer dnsServer)
{
if (_ntpServerDomainNames is not null)
{
Task<DnsDatagram>[] tasks = new Task<DnsDatagram>[_ntpServerDomainNames.Count];
int i = 0;
foreach (string ntpServerDomainName in _ntpServerDomainNames)
tasks[i++] = dnsServer.DirectQueryAsync(new DnsQuestionRecord(ntpServerDomainName, DnsResourceRecordType.A, DnsClass.IN), 1000);
List<IPAddress> ntpServers = new List<IPAddress>(_ntpServerDomainNames.Count + (_ntpServers is null ? 0 : _ntpServers.Count));
if (_ntpServers is not null)
ntpServers.AddRange(_ntpServers);
foreach (Task<DnsDatagram> task in tasks)
{
try
{
ntpServers.AddRange(DnsClient.ParseResponseA(await task));
}
catch
{ }
}
return new NetworkTimeProtocolServersOption(ntpServers);
}
else
{
return new NetworkTimeProtocolServersOption(_ntpServers);
}
}
internal void CommitLease(Lease lease)
{
lease.ExtendLease(GetLeaseTime());
@@ -1162,13 +1279,13 @@ namespace DnsServerCore.Dhcp
public void ChangeNetwork(IPAddress startingAddress, IPAddress endingAddress, IPAddress subnetMask)
{
if (startingAddress.AddressFamily != AddressFamily.InterNetwork)
throw new ArgumentException("Address family not supported.", nameof(startingAddress));
throw new ArgumentException("The address must be an IPv4 address: " + startingAddress.ToString(), nameof(startingAddress));
if (endingAddress.AddressFamily != AddressFamily.InterNetwork)
throw new ArgumentException("Address family not supported.", nameof(endingAddress));
throw new ArgumentException("The address must be an IPv4 address: " + endingAddress.ToString(), nameof(endingAddress));
if (subnetMask.AddressFamily != AddressFamily.InterNetwork)
throw new ArgumentException("Address family not supported.", nameof(subnetMask));
throw new ArgumentException("The address must be an IPv4 address: " + subnetMask.ToString(), nameof(subnetMask));
uint startingAddressNumber = startingAddress.ConvertIpToNumber();
uint endingAddressNumber = endingAddress.ConvertIpToNumber();
@@ -1306,7 +1423,7 @@ namespace DnsServerCore.Dhcp
public void WriteTo(BinaryWriter bW)
{
bW.Write(Encoding.ASCII.GetBytes("SC"));
bW.Write((byte)6); //version
bW.Write((byte)7); //version
bW.WriteShortString(_name);
bW.Write(_enabled);
@@ -1327,9 +1444,22 @@ namespace DnsServerCore.Dhcp
else
bW.WriteShortString(_domainName);
if (_domainSearchList is null)
{
bW.Write((byte)0);
}
else
{
bW.Write(Convert.ToByte(_domainSearchList.Count));
foreach (string domainSearchString in _domainSearchList)
bW.WriteShortString(domainSearchString);
}
bW.Write(_dnsUpdates);
bW.Write(_dnsTtl);
if (_serverAddress == null)
if (_serverAddress is null)
IPAddress.Any.WriteTo(bW);
else
_serverAddress.WriteTo(bW);
@@ -1344,7 +1474,7 @@ namespace DnsServerCore.Dhcp
else
bW.WriteShortString(_bootFileName);
if (_routerAddress == null)
if (_routerAddress is null)
IPAddress.Any.WriteTo(bW);
else
_routerAddress.WriteTo(bW);
@@ -1353,7 +1483,7 @@ namespace DnsServerCore.Dhcp
{
bW.Write((byte)255);
}
else if (_dnsServers == null)
else if (_dnsServers is null)
{
bW.Write((byte)0);
}
@@ -1365,7 +1495,7 @@ namespace DnsServerCore.Dhcp
dnsServer.WriteTo(bW);
}
if (_winsServers == null)
if (_winsServers is null)
{
bW.Write((byte)0);
}
@@ -1377,7 +1507,7 @@ namespace DnsServerCore.Dhcp
winsServer.WriteTo(bW);
}
if (_ntpServers == null)
if (_ntpServers is null)
{
bW.Write((byte)0);
}
@@ -1389,7 +1519,19 @@ namespace DnsServerCore.Dhcp
ntpServer.WriteTo(bW);
}
if (_staticRoutes == null)
if (_ntpServerDomainNames is null)
{
bW.Write((byte)0);
}
else
{
bW.Write(Convert.ToByte(_ntpServerDomainNames.Count));
foreach (string ntpServerDomainName in _ntpServerDomainNames)
bW.WriteShortString(ntpServerDomainName);
}
if (_staticRoutes is null)
{
bW.Write((byte)0);
}
@@ -1401,7 +1543,7 @@ namespace DnsServerCore.Dhcp
route.WriteTo(bW.BaseStream);
}
if (_vendorInfo == null)
if (_vendorInfo is null)
{
bW.Write((byte)0);
}
@@ -1416,7 +1558,19 @@ namespace DnsServerCore.Dhcp
}
}
if (_exclusions == null)
if (_capwapAcIpAddresses is null)
{
bW.Write((byte)0);
}
else
{
bW.Write(Convert.ToByte(_capwapAcIpAddresses.Count));
foreach (IPAddress capwapAcIpAddress in _capwapAcIpAddresses)
capwapAcIpAddress.WriteTo(bW);
}
if (_exclusions is null)
{
bW.Write((byte)0);
}
@@ -1585,6 +1739,27 @@ namespace DnsServerCore.Dhcp
}
}
public IReadOnlyCollection<string> DomainSearchList
{
get { return _domainSearchList; }
set
{
if (value is not null)
{
foreach (string domainSearchString in value)
DnsClient.IsDomainNameValid(domainSearchString, true);
}
_domainSearchList = value;
}
}
public bool DnsUpdates
{
get { return _dnsUpdates; }
set { _dnsUpdates = value; }
}
public uint DnsTtl
{
get { return _dnsTtl; }
@@ -1594,7 +1769,11 @@ namespace DnsServerCore.Dhcp
public IPAddress ServerAddress
{
get { return _serverAddress; }
set { _serverAddress = value; }
set
{
ValidateIpv4(value, nameof(ServerAddress));
_serverAddress = value;
}
}
public string ServerHostName
@@ -1624,7 +1803,11 @@ namespace DnsServerCore.Dhcp
public IPAddress RouterAddress
{
get { return _routerAddress; }
set { _routerAddress = value; }
set
{
ValidateIpv4(value, nameof(RouterAddress));
_routerAddress = value;
}
}
public bool UseThisDnsServer
@@ -1644,6 +1827,7 @@ namespace DnsServerCore.Dhcp
get { return _dnsServers; }
set
{
ValidateIpv4(value, nameof(DnsServers));
_dnsServers = value;
if ((_dnsServers != null) && _dnsServers.Count > 0)
@@ -1654,13 +1838,36 @@ namespace DnsServerCore.Dhcp
public IReadOnlyCollection<IPAddress> WinsServers
{
get { return _winsServers; }
set { _winsServers = value; }
set
{
ValidateIpv4(value, nameof(WinsServers));
_winsServers = value;
}
}
public IReadOnlyCollection<IPAddress> NtpServers
{
get { return _ntpServers; }
set { _ntpServers = value; }
set
{
ValidateIpv4(value, nameof(NtpServers));
_ntpServers = value;
}
}
public IReadOnlyCollection<string> NtpServerDomainNames
{
get { return _ntpServerDomainNames; }
set
{
if (value is not null)
{
foreach (string ntpServerDomainName in value)
DnsClient.IsDomainNameValid(ntpServerDomainName, true);
}
_ntpServerDomainNames = value;
}
}
public IReadOnlyCollection<ClasslessStaticRouteOption.Route> StaticRoutes
@@ -1675,12 +1882,22 @@ namespace DnsServerCore.Dhcp
set { _vendorInfo = value; }
}
public IReadOnlyCollection<IPAddress> CAPWAPAcIpAddresses
{
get { return _capwapAcIpAddresses; }
set
{
ValidateIpv4(value, nameof(CAPWAPAcIpAddresses));
_capwapAcIpAddresses = value;
}
}
public IReadOnlyCollection<Exclusion> Exclusions
{
get { return _exclusions; }
set
{
if (value == null)
if (value is null)
{
_exclusions = null;
}
@@ -1714,7 +1931,7 @@ namespace DnsServerCore.Dhcp
}
set
{
if (value == null)
if (value is null)
{
_reservedLeases.Clear();
}