private DhcpMessage ProcessDhcpMessage(DhcpMessage request, IPEndPoint remoteEP, IPPacketInformation ipPacketInformation) { if (request.OpCode != DhcpMessageOpCode.BootRequest) { return(null); } switch (request.DhcpMessageType?.Type) { case DhcpMessageType.Discover: { Scope scope = FindScope(request, remoteEP.Address, ipPacketInformation); if (scope == null) { return(null); //no scope available; do nothing } if (scope.OfferDelayTime > 0) { Thread.Sleep(scope.OfferDelayTime); //delay sending offer } Lease offer = scope.GetOffer(request); if (offer == null) { throw new DhcpServerException("DHCP Server failed to offer address: address unavailable due to address pool exhaustion."); } List <DhcpOption> options = scope.GetOptions(request, scope.InterfaceAddress); if (options == null) { return(null); } //log ip offer LogManager log = _log; if (log != null) { log.Write(remoteEP as IPEndPoint, "DHCP Server offered IP address [" + offer.Address.ToString() + "] to " + request.GetClientFullIdentifier() + "."); } return(new DhcpMessage(request, offer.Address, scope.InterfaceAddress, options)); } case DhcpMessageType.Request: { //request ip address lease or extend existing lease Scope scope = FindScope(request, remoteEP.Address, ipPacketInformation); if (scope == null) { return(null); //no scope available; do nothing } Lease leaseOffer; if (request.ServerIdentifier == null) { if (request.RequestedIpAddress == null) { //renewing or rebinding if (request.ClientIpAddress.Equals(IPAddress.Any)) { return(null); //client must set IP address in ciaddr; do nothing } leaseOffer = scope.GetExistingLeaseOrOffer(request); if (leaseOffer == null) { //no existing lease or offer available for client //send nak return(new DhcpMessage(request, IPAddress.Any, scope.InterfaceAddress, new DhcpOption[] { new DhcpMessageTypeOption(DhcpMessageType.Nak), new ServerIdentifierOption(scope.InterfaceAddress), DhcpOption.CreateEndOption() })); } if (!request.ClientIpAddress.Equals(leaseOffer.Address)) { //client ip is incorrect //send nak return(new DhcpMessage(request, IPAddress.Any, scope.InterfaceAddress, new DhcpOption[] { new DhcpMessageTypeOption(DhcpMessageType.Nak), new ServerIdentifierOption(scope.InterfaceAddress), DhcpOption.CreateEndOption() })); } } else { //init-reboot leaseOffer = scope.GetExistingLeaseOrOffer(request); if (leaseOffer == null) { //no existing lease or offer available for client //send nak return(new DhcpMessage(request, IPAddress.Any, scope.InterfaceAddress, new DhcpOption[] { new DhcpMessageTypeOption(DhcpMessageType.Nak), new ServerIdentifierOption(scope.InterfaceAddress), DhcpOption.CreateEndOption() })); } if (!request.RequestedIpAddress.Address.Equals(leaseOffer.Address)) { //the client's notion of its IP address is not correct - RFC 2131 //send nak return(new DhcpMessage(request, IPAddress.Any, scope.InterfaceAddress, new DhcpOption[] { new DhcpMessageTypeOption(DhcpMessageType.Nak), new ServerIdentifierOption(scope.InterfaceAddress), DhcpOption.CreateEndOption() })); } } } else { //selecting offer if (request.RequestedIpAddress == null) { return(null); //client MUST include this option; do nothing } if (!request.ServerIdentifier.Address.Equals(scope.InterfaceAddress)) { return(null); //offer declined by client; do nothing } leaseOffer = scope.GetExistingLeaseOrOffer(request); if (leaseOffer == null) { //no existing lease or offer available for client //send nak return(new DhcpMessage(request, IPAddress.Any, scope.InterfaceAddress, new DhcpOption[] { new DhcpMessageTypeOption(DhcpMessageType.Nak), new ServerIdentifierOption(scope.InterfaceAddress), DhcpOption.CreateEndOption() })); } if (!request.RequestedIpAddress.Address.Equals(leaseOffer.Address)) { //requested ip is incorrect //send nak return(new DhcpMessage(request, IPAddress.Any, scope.InterfaceAddress, new DhcpOption[] { new DhcpMessageTypeOption(DhcpMessageType.Nak), new ServerIdentifierOption(scope.InterfaceAddress), DhcpOption.CreateEndOption() })); } } List <DhcpOption> options = scope.GetOptions(request, scope.InterfaceAddress); if (options == null) { return(null); } scope.CommitLease(leaseOffer); //log ip lease LogManager log = _log; if (log != null) { log.Write(remoteEP as IPEndPoint, "DHCP Server leased IP address [" + leaseOffer.Address.ToString() + "] to " + request.GetClientFullIdentifier() + "."); } if (!string.IsNullOrEmpty(scope.DomainName)) { //update dns string clientDomainName = null; foreach (DhcpOption option in options) { if (option.Code == DhcpOptionCode.ClientFullyQualifiedDomainName) { clientDomainName = (option as ClientFullyQualifiedDomainNameOption).DomainName; break; } } if (clientDomainName == null) { if (request.HostName != null) { clientDomainName = request.HostName.HostName + "." + scope.DomainName; } else if ((leaseOffer.Type == LeaseType.Reserved) && !string.IsNullOrEmpty(leaseOffer.HostName) && !leaseOffer.HostName.EndsWith("." + scope.DomainName, StringComparison.OrdinalIgnoreCase)) { clientDomainName = leaseOffer.HostName + "." + scope.DomainName; //use hostname from reserved lease } } if (clientDomainName != null) { leaseOffer.SetHostName(clientDomainName.ToLower()); UpdateDnsAuthZone(true, scope, leaseOffer); } } return(new DhcpMessage(request, leaseOffer.Address, scope.InterfaceAddress, options)); } case DhcpMessageType.Decline: { //ip address is already in use as detected by client via ARP if ((request.ServerIdentifier == null) || (request.RequestedIpAddress == null)) { return(null); //client MUST include these option; do nothing } Scope scope = FindScope(request, remoteEP.Address, ipPacketInformation); if (scope == null) { return(null); //no scope available; do nothing } if (!request.ServerIdentifier.Address.Equals(scope.InterfaceAddress)) { return(null); //request not for this server; do nothing } Lease lease = scope.GetExistingLeaseOrOffer(request); if (lease == null) { return(null); //no existing lease or offer available for client; do nothing } if (!lease.Address.Equals(request.RequestedIpAddress.Address)) { return(null); //the client's notion of its IP address is not correct; do nothing } //remove lease since the IP address is used by someone else scope.ReleaseLease(lease); //log issue LogManager log = _log; if (log != null) { log.Write(remoteEP as IPEndPoint, "DHCP Server received DECLINE message: " + lease.GetClientFullIdentifier() + " detected that IP address [" + lease.Address + "] is already in use."); } //update dns UpdateDnsAuthZone(false, scope, lease); //do nothing return(null); } case DhcpMessageType.Release: { //cancel ip address lease if (request.ServerIdentifier == null) { return(null); //client MUST include this option; do nothing } Scope scope = FindScope(request, remoteEP.Address, ipPacketInformation); if (scope == null) { return(null); //no scope available; do nothing } if (!request.ServerIdentifier.Address.Equals(scope.InterfaceAddress)) { return(null); //request not for this server; do nothing } Lease lease = scope.GetExistingLeaseOrOffer(request); if (lease == null) { return(null); //no existing lease or offer available for client; do nothing } if (!lease.Address.Equals(request.ClientIpAddress)) { return(null); //the client's notion of its IP address is not correct; do nothing } //release lease scope.ReleaseLease(lease); //log ip lease release LogManager log = _log; if (log != null) { log.Write(remoteEP as IPEndPoint, "DHCP Server released IP address [" + lease.Address.ToString() + "] that was leased to " + lease.GetClientFullIdentifier() + "."); } //update dns UpdateDnsAuthZone(false, scope, lease); //do nothing return(null); } case DhcpMessageType.Inform: { //need only local config; already has ip address assigned externally/manually Scope scope = FindScope(request, remoteEP.Address, ipPacketInformation); if (scope == null) { return(null); //no scope available; do nothing } List <DhcpOption> options = scope.GetOptions(request, scope.InterfaceAddress); if (options == null) { return(null); } //log inform LogManager log = _log; if (log != null) { log.Write(remoteEP as IPEndPoint, "DHCP Server received INFORM message from " + request.GetClientFullIdentifier() + "."); } return(new DhcpMessage(request, IPAddress.Any, scope.InterfaceAddress, options)); } default: return(null); } }
internal List <DhcpOption> GetOptions(DhcpMessage request, IPAddress serverIdentifierAddress) { List <DhcpOption> options = new List <DhcpOption>(); switch (request.DhcpMessageType.Type) { case DhcpMessageType.Discover: options.Add(new DhcpMessageTypeOption(DhcpMessageType.Offer)); break; case DhcpMessageType.Request: case DhcpMessageType.Inform: options.Add(new DhcpMessageTypeOption(DhcpMessageType.Ack)); break; default: return(null); } options.Add(new ServerIdentifierOption(serverIdentifierAddress)); switch (request.DhcpMessageType.Type) { case DhcpMessageType.Discover: case DhcpMessageType.Request: uint leaseTime = GetLeaseTime(); options.Add(new IpAddressLeaseTimeOption(leaseTime)); options.Add(new RenewalTimeValueOption(leaseTime / 2)); options.Add(new RebindingTimeValueOption(Convert.ToUInt32(leaseTime * 0.875))); break; } if (request.ParameterRequestList == null) { options.Add(new SubnetMaskOption(_subnetMask)); options.Add(new BroadcastAddressOption(_broadcastAddress)); if (!string.IsNullOrEmpty(_domainName)) { options.Add(new DomainNameOption(_domainName)); if (request.ClientFullyQualifiedDomainName != null) { options.Add(GetClientFullyQualifiedDomainNameOption(request)); } } if (_routerAddress != null) { options.Add(new RouterOption(new IPAddress[] { _routerAddress })); } if (_dnsServers != null) { options.Add(new DomainNameServerOption(_dnsServers)); } if (_winsServers != null) { options.Add(new NetBiosNameServerOption(_winsServers)); } if (_ntpServers != null) { options.Add(new NetworkTimeProtocolServersOption(_ntpServers)); } if (_staticRoutes != null) { options.Add(new ClasslessStaticRouteOption(_staticRoutes)); } } else { foreach (DhcpOptionCode optionCode in request.ParameterRequestList.OptionCodes) { switch (optionCode) { case DhcpOptionCode.SubnetMask: options.Add(new SubnetMaskOption(_subnetMask)); options.Add(new BroadcastAddressOption(_broadcastAddress)); break; case DhcpOptionCode.DomainName: if (!string.IsNullOrEmpty(_domainName)) { options.Add(new DomainNameOption(_domainName)); if (request.ClientFullyQualifiedDomainName != null) { options.Add(GetClientFullyQualifiedDomainNameOption(request)); } } break; case DhcpOptionCode.Router: if (_routerAddress != null) { options.Add(new RouterOption(new IPAddress[] { _routerAddress })); } break; case DhcpOptionCode.DomainNameServer: if (_dnsServers != null) { options.Add(new DomainNameServerOption(_dnsServers)); } break; case DhcpOptionCode.NetBiosOverTcpIpNameServer: if (_winsServers != null) { options.Add(new NetBiosNameServerOption(_winsServers)); } break; case DhcpOptionCode.NetworkTimeProtocolServers: if (_ntpServers != null) { options.Add(new NetworkTimeProtocolServersOption(_ntpServers)); } break; case DhcpOptionCode.ClasslessStaticRoute: if (_staticRoutes != null) { options.Add(new ClasslessStaticRouteOption(_staticRoutes)); } break; } } } options.Add(DhcpOption.CreateEndOption()); return(options); }