diff --git a/DnsServerCore/Dhcp/Scope.cs b/DnsServerCore/Dhcp/Scope.cs index 55ae6c37..3e942482 100644 --- a/DnsServerCore/Dhcp/Scope.cs +++ b/DnsServerCore/Dhcp/Scope.cs @@ -1,6 +1,6 @@ /* Technitium DNS Server -Copyright (C) 2020 Shreyas Zare (shreyas@technitium.com) +Copyright (C) 2021 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 @@ -22,6 +22,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; @@ -55,14 +56,14 @@ namespace DnsServerCore.Dhcp string _bootFileName; IPAddress _routerAddress; bool _useThisDnsServer; - ICollection _dnsServers; - ICollection _winsServers; - ICollection _ntpServers; - ICollection _staticRoutes; + IReadOnlyCollection _dnsServers; + IReadOnlyCollection _winsServers; + IReadOnlyCollection _ntpServers; + IReadOnlyCollection _staticRoutes; IReadOnlyDictionary _vendorInfo; //advanced options - ICollection _exclusions; + IReadOnlyCollection _exclusions; readonly ConcurrentDictionary _reservedLeases = new ConcurrentDictionary(); bool _allowOnlyReservedLeases; @@ -357,7 +358,7 @@ namespace DnsServerCore.Dhcp return false; } - private ClientFullyQualifiedDomainNameOption GetClientFullyQualifiedDomainNameOption(DhcpMessage request) + private ClientFullyQualifiedDomainNameOption GetClientFullyQualifiedDomainNameOption(DhcpMessage request, string overrideClientDomainName) { ClientFullyQualifiedDomainNameFlags responseFlags = ClientFullyQualifiedDomainNameFlags.None; @@ -381,7 +382,12 @@ namespace DnsServerCore.Dhcp string clientDomainName; - if (string.IsNullOrWhiteSpace(request.ClientFullyQualifiedDomainName.DomainName)) + if (!string.IsNullOrWhiteSpace(overrideClientDomainName)) + { + //domain name override by server + clientDomainName = overrideClientDomainName; + } + else if (string.IsNullOrWhiteSpace(request.ClientFullyQualifiedDomainName.DomainName)) { //client domain empty and expects server for a fqdn domain name if (request.HostName == null) @@ -625,7 +631,7 @@ namespace DnsServerCore.Dhcp Lease reservedLease = GetReservedLease(request); if (reservedLease != null) { - Lease reservedOffer = new Lease(LeaseType.Reserved, request.ClientIdentifier, request.HostName?.HostName, request.ClientHardwareAddress, reservedLease.Address, null, GetLeaseTime()); + Lease reservedOffer = new Lease(LeaseType.Reserved, request.ClientIdentifier, null, request.ClientHardwareAddress, reservedLease.Address, null, GetLeaseTime()); _offers[request.ClientIdentifier] = reservedOffer; return reservedOffer; } @@ -692,7 +698,7 @@ namespace DnsServerCore.Dhcp } } - Lease offerLease = new Lease(LeaseType.Dynamic, request.ClientIdentifier, request.HostName?.HostName, request.ClientHardwareAddress, offerAddress, null, GetLeaseTime()); + Lease offerLease = new Lease(LeaseType.Dynamic, request.ClientIdentifier, null, request.ClientHardwareAddress, offerAddress, null, GetLeaseTime()); return _offers[request.ClientIdentifier] = offerLease; } @@ -707,7 +713,7 @@ namespace DnsServerCore.Dhcp return null; } - internal List GetOptions(DhcpMessage request, IPAddress serverIdentifierAddress) + internal List GetOptions(DhcpMessage request, IPAddress serverIdentifierAddress, string overrideClientDomainName) { List options = new List(); @@ -750,7 +756,7 @@ namespace DnsServerCore.Dhcp options.Add(new DomainNameOption(_domainName)); if (request.ClientFullyQualifiedDomainName != null) - options.Add(GetClientFullyQualifiedDomainNameOption(request)); + options.Add(GetClientFullyQualifiedDomainNameOption(request, overrideClientDomainName)); } if (_routerAddress != null) @@ -785,7 +791,7 @@ namespace DnsServerCore.Dhcp options.Add(new DomainNameOption(_domainName)); if (request.ClientFullyQualifiedDomainName != null) - options.Add(GetClientFullyQualifiedDomainNameOption(request)); + options.Add(GetClientFullyQualifiedDomainNameOption(request, overrideClientDomainName)); } break; @@ -998,6 +1004,90 @@ namespace DnsServerCore.Dhcp } } + public void ConvertToReservedLease(string hardwareAddress) + { + byte[] hardwareAddressBytes = Lease.ParseHardwareAddress(hardwareAddress); + + foreach (Lease lease in _leases.Values) + { + if ((lease.Type == LeaseType.Dynamic) && BinaryNumber.Equals(lease.HardwareAddress, hardwareAddressBytes)) + { + //convert dynamic to reserved lease + lease.ConvertToReserved(); + + //add reserved lease + Lease reservedLease = new Lease(LeaseType.Reserved, null, DhcpMessageHardwareAddressType.Ethernet, lease.HardwareAddress, lease.Address, null); + _reservedLeases[reservedLease.ClientIdentifier] = reservedLease; + + //add exclusion if required + if (!IsAddressExcluded(lease.Address)) + { + List exclusions = new List(); + + if (_exclusions != null) + exclusions.AddRange(_exclusions); + + exclusions.Add(new Exclusion(lease.Address, lease.Address)); + _exclusions = exclusions; + } + + return; + } + } + + throw new DhcpServerException("No dynamic lease was found for hardware address: " + hardwareAddress); + } + + public void ConvertToDynamicLease(string hardwareAddress) + { + byte[] hardwareAddressBytes = Lease.ParseHardwareAddress(hardwareAddress); + + foreach (Lease lease in _leases.Values) + { + if ((lease.Type == LeaseType.Reserved) && BinaryNumber.Equals(lease.HardwareAddress, hardwareAddressBytes)) + { + //convert reserved to dynamic lease + lease.ConvertToDynamic(); + + //remove reserved lease + Lease reservedLease = new Lease(LeaseType.Reserved, null, DhcpMessageHardwareAddressType.Ethernet, lease.HardwareAddress, lease.Address, null); + _reservedLeases.TryRemove(reservedLease.ClientIdentifier, out _); + + //remove exclusion + if (_exclusions != null) + { + foreach (Exclusion exclusion in _exclusions) + { + if (exclusion.StartingAddress.Equals(lease.Address) && exclusion.EndingAddress.Equals(lease.Address)) + { + //remove single address exclusion entry + if (_exclusions.Count == 1) + { + _exclusions = null; + } + else + { + List exclusions = new List(); + + foreach (Exclusion exc in _exclusions) + { + if (exc.Equals(exclusion)) + continue; + + exclusions.Add(exc); + } + + _exclusions = exclusions; + } + + break; + } + } + } + } + } + } + public void WriteTo(BinaryWriter bW) { bW.Write(Encoding.ASCII.GetBytes("SC")); @@ -1311,7 +1401,7 @@ namespace DnsServerCore.Dhcp } } - public ICollection DnsServers + public IReadOnlyCollection DnsServers { get { return _dnsServers; } set @@ -1323,19 +1413,19 @@ namespace DnsServerCore.Dhcp } } - public ICollection WinsServers + public IReadOnlyCollection WinsServers { get { return _winsServers; } set { _winsServers = value; } } - public ICollection NtpServers + public IReadOnlyCollection NtpServers { get { return _ntpServers; } set { _ntpServers = value; } } - public ICollection StaticRoutes + public IReadOnlyCollection StaticRoutes { get { return _staticRoutes; } set { _staticRoutes = value; } @@ -1347,7 +1437,7 @@ namespace DnsServerCore.Dhcp set { _vendorInfo = value; } } - public ICollection Exclusions + public IReadOnlyCollection Exclusions { get { return _exclusions; } set