Ejemplo n.º 1
0
        private bool IsAddressAlreadyAllocated(Lease reservedLease)
        {
            foreach (KeyValuePair <ClientIdentifierOption, Lease> lease in _leases)
            {
                if (reservedLease.Address.Equals(lease.Value.Address))
                {
                    return(!lease.Key.Equals(reservedLease.ClientIdentifier));
                }
            }

            foreach (KeyValuePair <ClientIdentifierOption, Lease> offer in _offers)
            {
                if (reservedLease.Address.Equals(offer.Value.Address))
                {
                    return(!offer.Key.Equals(reservedLease.ClientIdentifier));
                }
            }

            return(false);
        }
Ejemplo n.º 2
0
        private void UpdateDnsAuthZone(bool add, Scope scope, Lease lease)
        {
            if (_authZoneManager == null)
            {
                return;
            }

            if (string.IsNullOrWhiteSpace(scope.DomainName))
            {
                return;
            }

            if (string.IsNullOrWhiteSpace(lease.HostName))
            {
                return;
            }

            if (!DnsClient.IsDomainNameValid(lease.HostName))
            {
                return;
            }

            if (add)
            {
                //update forward zone
                _authZoneManager.CreatePrimaryZone(scope.DomainName, _authZoneManager.ServerDomain, false);
                _authZoneManager.SetRecords(lease.HostName, DnsResourceRecordType.A, scope.DnsTtl, new DnsResourceRecordData[] { new DnsARecord(lease.Address) });

                //update reverse zone
                _authZoneManager.CreatePrimaryZone(scope.ReverseZone, _authZoneManager.ServerDomain, false);
                _authZoneManager.SetRecords(Zone.GetReverseZone(lease.Address, 32), DnsResourceRecordType.PTR, scope.DnsTtl, new DnsResourceRecordData[] { new DnsPTRRecord(lease.HostName) });
            }
            else
            {
                //remove from forward zone
                _authZoneManager.DeleteRecords(lease.HostName, DnsResourceRecordType.A);

                //remove from reverse zone
                _authZoneManager.DeleteRecords(Zone.GetReverseZone(lease.Address, 32), DnsResourceRecordType.PTR);
            }
        }
Ejemplo n.º 3
0
        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);
            }
        }
Ejemplo n.º 4
0
        public Scope(BinaryReader bR)
        {
            if (Encoding.ASCII.GetString(bR.ReadBytes(2)) != "SC")
            {
                throw new InvalidDataException("DhcpServer scope file format is invalid.");
            }

            switch (bR.ReadByte())
            {
            case 1:
                _name    = bR.ReadShortString();
                _enabled = bR.ReadBoolean();

                ChangeNetwork(IPAddressExtension.Parse(bR), IPAddressExtension.Parse(bR), IPAddressExtension.Parse(bR));

                _leaseTimeDays    = bR.ReadUInt16();
                _leaseTimeHours   = bR.ReadByte();
                _leaseTimeMinutes = bR.ReadByte();

                _offerDelayTime = bR.ReadUInt16();

                _domainName = bR.ReadShortString();
                if (string.IsNullOrWhiteSpace(_domainName))
                {
                    _domainName = null;
                }

                _dnsTtl = bR.ReadUInt32();

                _routerAddress = IPAddressExtension.Parse(bR);
                if (_routerAddress.Equals(IPAddress.Any))
                {
                    _routerAddress = null;
                }

                {
                    int count = bR.ReadByte();
                    if (count > 0)
                    {
                        if (count == 255)
                        {
                            _useThisDnsServer = true;
                            FindThisDnsServerAddress();
                        }
                        else
                        {
                            _dnsServers = new IPAddress[count];

                            for (int i = 0; i < count; i++)
                            {
                                _dnsServers[i] = IPAddressExtension.Parse(bR);
                            }
                        }
                    }
                }

                {
                    int count = bR.ReadByte();
                    if (count > 0)
                    {
                        _winsServers = new IPAddress[count];

                        for (int i = 0; i < count; i++)
                        {
                            _winsServers[i] = IPAddressExtension.Parse(bR);
                        }
                    }
                }

                {
                    int count = bR.ReadByte();
                    if (count > 0)
                    {
                        _ntpServers = new IPAddress[count];

                        for (int i = 0; i < count; i++)
                        {
                            _ntpServers[i] = IPAddressExtension.Parse(bR);
                        }
                    }
                }

                {
                    int count = bR.ReadByte();
                    if (count > 0)
                    {
                        _staticRoutes = new ClasslessStaticRouteOption.Route[count];

                        for (int i = 0; i < count; i++)
                        {
                            _staticRoutes[i] = new ClasslessStaticRouteOption.Route(bR.BaseStream);
                        }
                    }
                }

                {
                    int count = bR.ReadByte();
                    if (count > 0)
                    {
                        _exclusions = new Exclusion[count];

                        for (int i = 0; i < count; i++)
                        {
                            _exclusions[i] = new Exclusion(IPAddressExtension.Parse(bR), IPAddressExtension.Parse(bR));
                        }
                    }
                }

                {
                    int count = bR.ReadInt32();
                    if (count > 0)
                    {
                        _reservedLeases = new Lease[count];

                        for (int i = 0; i < count; i++)
                        {
                            _reservedLeases[i] = new Lease(bR);
                        }
                    }

                    _allowOnlyReservedLeases = bR.ReadBoolean();
                }

                {
                    int count = bR.ReadInt32();
                    if (count > 0)
                    {
                        for (int i = 0; i < count; i++)
                        {
                            Lease lease = new Lease(bR);

                            _leases.TryAdd(lease.ClientIdentifier, lease);
                        }
                    }
                }

                break;

            default:
                throw new InvalidDataException("Scope data format version not supported.");
            }
        }
Ejemplo n.º 5
0
        internal void ReleaseLease(Lease lease)
        {
            _leases.TryRemove(lease.ClientIdentifier, out _);

            _lastModified = DateTime.UtcNow;
        }
Ejemplo n.º 6
0
        internal Lease GetOffer(DhcpMessage request)
        {
            if (_leases.TryGetValue(request.ClientIdentifier, out Lease existingLease))
            {
                //lease already exists
                return(existingLease);
            }

            if (_reservedLeases != null)
            {
                ClientIdentifierOption clientIdentifierKey = new ClientIdentifierOption(1, request.ClientHardwareAddress);
                foreach (Lease reservedLease in _reservedLeases)
                {
                    if (reservedLease.ClientIdentifier.Equals(clientIdentifierKey))
                    {
                        //reserved address exists
                        IPAddress reservedLeaseAddress = reservedLease.Address;

                        if (!IsAddressAvailable(ref reservedLeaseAddress))
                        {
                            break; //reserved lease address is already allocated so ignore reserved lease
                        }
                        Lease reservedOffer = new Lease(LeaseType.Reserved, request.ClientIdentifier, request.HostName?.HostName, request.ClientHardwareAddress, reservedLease.Address, null, GetLeaseTime());

                        return(_offers.AddOrUpdate(request.ClientIdentifier, reservedOffer, delegate(ClientIdentifierOption key, Lease existingValue)
                        {
                            return reservedOffer;
                        }));
                    }
                }
            }

            if (_allowOnlyReservedLeases)
            {
                throw new DhcpServerException("DHCP Server failed to offer IP address to " + request.GetClientFullIdentifier() + ": scope allows only reserved lease allocations.");
            }

            Lease dummyOffer    = new Lease(LeaseType.None, null, null, null, null, null, 0);
            Lease existingOffer = _offers.GetOrAdd(request.ClientIdentifier, dummyOffer);

            if (dummyOffer != existingOffer)
            {
                if (existingOffer.Type == LeaseType.None)
                {
                    return(null); //dummy offer so another thread is handling offer; do nothing
                }
                //offer already exists
                existingOffer.ExtendLease(GetLeaseTime());

                return(existingOffer);
            }

            //find offer ip address
            IPAddress offerAddress = null;

            if (request.RequestedIpAddress != null)
            {
                //client wish to get this address
                IPAddress requestedAddress = request.RequestedIpAddress.Address;

                if (IsAddressInRange(requestedAddress) && IsAddressAvailable(ref requestedAddress))
                {
                    offerAddress = requestedAddress;
                }
            }

            if (offerAddress == null)
            {
                lock (_lastAddressOfferedLock)
                {
                    //find free address from scope
                    offerAddress = _lastAddressOffered;
                    uint endingAddressNumber         = _endingAddress.ConvertIpToNumber();
                    bool offerAddressWasResetFromEnd = false;

                    while (true)
                    {
                        uint nextOfferAddressNumber = offerAddress.ConvertIpToNumber() + 1u;

                        if (nextOfferAddressNumber > endingAddressNumber)
                        {
                            if (offerAddressWasResetFromEnd)
                            {
                                throw new DhcpServerException("DHCP Server failed to offer IP address to " + request.GetClientFullIdentifier() + ": address unavailable due to address pool exhaustion.");
                            }

                            offerAddress = IPAddressExtension.ConvertNumberToIp(_startingAddress.ConvertIpToNumber() - 1u);
                            offerAddressWasResetFromEnd = true;
                            continue;
                        }

                        offerAddress = IPAddressExtension.ConvertNumberToIp(nextOfferAddressNumber);

                        if (IsAddressAvailable(ref offerAddress))
                        {
                            break;
                        }
                    }

                    _lastAddressOffered = offerAddress;
                }
            }

            Lease offerLease = new Lease(LeaseType.Dynamic, request.ClientIdentifier, request.HostName?.HostName, request.ClientHardwareAddress, offerAddress, null, GetLeaseTime());

            return(_offers.AddOrUpdate(request.ClientIdentifier, offerLease, delegate(ClientIdentifierOption key, Lease existingValue)
            {
                return offerLease;
            }));
        }
Ejemplo n.º 7
0
 private void UpdateDnsAuthZone(bool add, Scope scope, Lease lease)
 {
     UpdateDnsAuthZone(add, scope, lease.HostName, lease.Address);
 }
Ejemplo n.º 8
0
        private void UpdateDnsAuthZone(bool add, Scope scope, Lease lease)
        {
            if (_authoritativeZoneRoot == null)
            {
                return;
            }

            if (string.IsNullOrWhiteSpace(scope.DomainName))
            {
                return;
            }

            if (string.IsNullOrWhiteSpace(lease.HostName))
            {
                return;
            }

            if (!DnsClient.IsDomainNameValid(lease.HostName))
            {
                return;
            }

            if (add)
            {
                //update forward zone
                {
                    if (!_authoritativeZoneRoot.ZoneExists(scope.DomainName))
                    {
                        //create forward zone
                        _authoritativeZoneRoot.SetRecords(scope.DomainName, DnsResourceRecordType.SOA, 14400, new DnsResourceRecordData[] { new DnsSOARecord(_authoritativeZoneRoot.ServerDomain, "hostmaster." + scope.DomainName, 1, 14400, 3600, 604800, 900) });
                        _authoritativeZoneRoot.SetRecords(scope.DomainName, DnsResourceRecordType.NS, 14400, new DnsResourceRecordData[] { new DnsNSRecord(_authoritativeZoneRoot.ServerDomain) });

                        _authoritativeZoneRoot.MakeZoneInternal(scope.DomainName);
                    }

                    _authoritativeZoneRoot.SetRecords(lease.HostName, DnsResourceRecordType.A, scope.DnsTtl, new DnsResourceRecordData[] { new DnsARecord(lease.Address) });
                }

                //update reverse zone
                {
                    if (!_authoritativeZoneRoot.ZoneExists(scope.ReverseZone))
                    {
                        //create reverse zone
                        _authoritativeZoneRoot.SetRecords(scope.ReverseZone, DnsResourceRecordType.SOA, 14400, new DnsResourceRecordData[] { new DnsSOARecord(_authoritativeZoneRoot.ServerDomain, "hostmaster." + scope.ReverseZone, 1, 14400, 3600, 604800, 900) });
                        _authoritativeZoneRoot.SetRecords(scope.ReverseZone, DnsResourceRecordType.NS, 14400, new DnsResourceRecordData[] { new DnsNSRecord(_authoritativeZoneRoot.ServerDomain) });

                        _authoritativeZoneRoot.MakeZoneInternal(scope.ReverseZone);
                    }

                    _authoritativeZoneRoot.SetRecords(Scope.GetReverseZone(lease.Address, 32), DnsResourceRecordType.PTR, scope.DnsTtl, new DnsResourceRecordData[] { new DnsPTRRecord(lease.HostName) });
                }
            }
            else
            {
                //remove from forward zone
                _authoritativeZoneRoot.DeleteRecords(lease.HostName, DnsResourceRecordType.A);

                //remove from reverse zone
                _authoritativeZoneRoot.DeleteRecords(Scope.GetReverseZone(lease.Address, 32), DnsResourceRecordType.PTR);
            }
        }