internal DHCPv6Packet HandleRelease(DHCPv6Packet packet, IDHCPv6ServerPropertiesResolver properyResolver) { var innerPacket = packet.GetInnerPacket(); DUID clientIdentifier = innerPacket.GetClientIdentifer(); UInt32?identityAssociationId = innerPacket.GetNonTemporaryIdentityAssocationId(); UInt32?prefixIdentityAssociationId = innerPacket.GetPrefixDelegationIdentityAssocationId(); DHCPv6Lease lease = DHCPv6Lease.NotFound; if (identityAssociationId.HasValue == true) { lease = Leases.GetLeaseAssociationIdAndDuid(identityAssociationId.Value, clientIdentifier); } else { var tempLease = Leases.GetLeaseByClientDuid(clientIdentifier); if (tempLease.PrefixDelegation != DHCPv6PrefixDelegation.None && tempLease.PrefixDelegation.IdentityAssociation == prefixIdentityAssociationId.Value ) { lease = tempLease; } } DHCPv6Packet response; var error = DHCPv6ReleaseHandledEvent.ReleaseError.NoError; if (lease == DHCPv6Lease.NotFound) { response = DHCPv6Packet.AsError(packet, DHCPv6StatusCodes.NoBinding, properyResolver.GetServerDuid()); error = DHCPv6ReleaseHandledEvent.ReleaseError.NoLeaseFound; } else { if (lease.IsActive() == false) { response = DHCPv6Packet.AsError(packet, DHCPv6StatusCodes.NoBinding, properyResolver.GetServerDuid()); } else { PrefixBinding prefixBinding = lease.PrefixDelegation != DHCPv6PrefixDelegation.None ? PrefixBinding.FromLease(lease) : null; lease.Release(identityAssociationId.HasValue == false); Leases.Remove(lease); response = DHCPv6Packet.AsReleaseResponse(packet, lease.IdentityAssocicationId, lease.PrefixDelegation.IdentityAssociation, properyResolver.GetServerDuid()); if (prefixBinding != null) { AddNotificationTrigger(PrefixEdgeRouterBindingUpdatedTrigger.WithOldBinding( Id, prefixBinding)); } } } base.Apply(new DHCPv6ReleaseHandledEvent(this.Id, packet, response, error)); return(response); }
internal DHCPv6Packet HandleSolicitWithPrefixDelegation(DHCPv6Packet packet, IDHCPv6ServerPropertiesResolver properyResolver) { DHCPv6Packet innerPacket = packet.GetInnerPacket(); var addressProperties = GetAddressProperties(); Boolean rapitCommit = addressProperties.IsRapitCommitEnabled() && innerPacket.HasRapitCommitOption(); DUID clientDuid = innerPacket.GetClientIdentifer(); DHCPv6Lease currentLease = Leases.GetLeaseByClientDuid(clientDuid); DHCPv6Packet response = null; Boolean responseNeeded = false; Int32 waitingForLease = 15; // In some client implementations like Cisco IOS XE, two solicit packets are sent, one for an address and a second for a prefix, which would be handled without this loop. // Unfortunately, the PD is sent first and as long as the router received an answer for the address the PD packet is not sent again. Hence, progressing is delayed for a small amount of time. while ((currentLease == DHCPv6Lease.NotFound || currentLease.IsActive() == false) && --waitingForLease > 0) { Task.Delay(100).GetAwaiter().GetResult(); currentLease = Leases.GetLeaseByClientDuid(clientDuid); } if (currentLease == DHCPv6Lease.NotFound) { _logger.LogDebug("no lease for client duid {duid} found", clientDuid); base.Apply(new DHCPv6SolicitHandledEvent(this.Id, packet, DHCPv6SolicitHandledEvent.SolicitErros.LeaseNotFound)); } else if (currentLease.IsActive() == false) { _logger.LogDebug("lease with {address} for client duid {duid} found but not active. state is {state}", currentLease.Address, clientDuid, currentLease.State); base.Apply(new DHCPv6SolicitHandledEvent(this.Id, packet, DHCPv6SolicitHandledEvent.SolicitErros.LeaseNotActive)); } else if (addressProperties.PrefixDelgationInfo == null) { _logger.LogDebug("prefix delegation for {name} is not enabled", Name); base.Apply(new DHCPv6SolicitHandledEvent(this.Id, packet, DHCPv6SolicitHandledEvent.SolicitErros.PrefixDelegationNotAvailable)); } else { if (IsFreshPrefix(currentLease) == false) { responseNeeded = true; } else { _logger.LogInformation("a fresh leased prefix found. Skipping creating of a new prefix"); } } if (responseNeeded == true) { UInt32 prefixIdentityAsscocationId = packet.GetInnerPacket().GetPrefixDelegationIdentityAssocationId().Value; var prefix = addressProperties.GetValidPrefix(Leases.GetUsedPrefixes(), prefixIdentityAsscocationId); currentLease.UpdateAddressPrefix(prefix, false); _logger.LogDebug("prefix {prefix}/{lenth} for id {id} is generated", currentLease.PrefixDelegation.NetworkAddress, currentLease.PrefixDelegation.Mask.Identifier.Value, currentLease.PrefixDelegation.IdentityAssociation); if (rapitCommit == true) { _logger.LogDebug("rapit commit is enabled. sending packet as reply"); response = DHCPv6Packet.AsPrefixReplyWithRapitCommit( packet, addressProperties, DHCPv6ScopeProperties.Empty, currentLease, properyResolver.GetServerDuid()); base.AddNotificationTrigger( PrefixEdgeRouterBindingUpdatedTrigger.WithNewBinding(Id, PrefixBinding.FromLease(currentLease) )); } else { _logger.LogDebug("rapit commit is not enabled. sending packet as advertise"); response = DHCPv6Packet.AsPrefixAdvertise( packet, addressProperties, DHCPv6ScopeProperties.Empty, currentLease, properyResolver.GetServerDuid()); } base.Apply(new DHCPv6SolicitHandledEvent(this.Id, packet, response, rapitCommit)); } return(response); }
internal DHCPv6Packet HandleConfirm(DHCPv6Packet packet, IDHCPv6ServerPropertiesResolver properyResolver) { var addressProperties = GetAddressProperties(); var innerPacket = packet.GetInnerPacket(); DUID clientIdentifier = innerPacket.GetClientIdentifer(); UInt32?identityAssociationId = innerPacket.GetNonTemporaryIdentityAssocationId(); UInt32?prefixIdentityAsscocationId = innerPacket.GetPrefixDelegationIdentityAssocationId(); DHCPv6Lease lease; if (identityAssociationId.HasValue == true) { lease = Leases.GetLeaseAssociationIdAndDuid(identityAssociationId.Value, clientIdentifier); } else { lease = Leases.GetLeaseByClientDuid(clientIdentifier); } if (lease == DHCPv6Lease.NotFound) { base.Apply(new DHCPv6ConfirmHandledEvent(this.Id, packet, DHCPv6ConfirmHandledEvent.ConfirmErrors.LeaseNotFound)); return(DHCPv6Packet.Empty); } DHCPv6Packet response; if (lease.IsActive() == false) { response = DHCPv6Packet.AsError(packet, DHCPv6StatusCodes.NotOnLink, properyResolver.GetServerDuid()); base.Apply(new DHCPv6ConfirmHandledEvent(this.Id, packet, response, DHCPv6ConfirmHandledEvent.ConfirmErrors.LeaseNotActive)); } else { Boolean bindingVerified = true; if (identityAssociationId.HasValue == true) { IPv6Address requestedAddress = innerPacket.GetNonTemporaryIdentiyAssocation(identityAssociationId.Value).GetAddress(); if (requestedAddress != lease.Address) { bindingVerified = false; } } if (prefixIdentityAsscocationId.HasValue == true && bindingVerified == true) { if ((prefixIdentityAsscocationId != lease.PrefixDelegation.IdentityAssociation)) { bindingVerified = false; } else { DHCPv6PrefixDelegation requestedPrefix = innerPacket.GetPrefixDelegationIdentiyAssocation(prefixIdentityAsscocationId.Value).GetPrefixDelegation(); bindingVerified = requestedPrefix.AreValuesEqual(lease.PrefixDelegation); } } if (bindingVerified == true) { response = DHCPv6Packet.AsReply(packet, addressProperties, DHCPv6ScopeProperties.Empty, lease, true, properyResolver.GetServerDuid(), false); base.Apply(new DHCPv6ConfirmHandledEvent(this.Id, packet, response)); } else { response = DHCPv6Packet.AsError(packet, DHCPv6StatusCodes.NotOnLink, properyResolver.GetServerDuid()); base.Apply(new DHCPv6ConfirmHandledEvent(this.Id, packet, response, DHCPv6ConfirmHandledEvent.ConfirmErrors.AddressMismtach)); } } return(response); }
private DHCPv6Packet HandleLeaseExtentions(DHCPv6Packet packet, IDHCPv6ServerPropertiesResolver properyResolver, out LeaseExtentionsErros extentionError) { var innerPacket = packet.GetInnerPacket(); var addressProperties = GetAddressProperties(); DUID clientIdentifier = innerPacket.GetClientIdentifer(); UInt32? identityAssociationId = innerPacket.GetNonTemporaryIdentityAssocationId(); UInt32? prefixIdentityAsscocationId = innerPacket.GetPrefixDelegationIdentityAssocationId(); DHCPv6Lease lease; if (identityAssociationId.HasValue == false && prefixIdentityAsscocationId.HasValue == true) { DHCPv6Lease belongingLease = Leases.GetLeaseByClientDuid(clientIdentifier); if (belongingLease == DHCPv6Lease.NotFound) { extentionError = LeaseExtentionsErros.OnlyPrefixIsNotAllowed; return(DHCPv6Packet.AsError(packet, DHCPv6StatusCodes.NoBinding, properyResolver.GetServerDuid())); } // In some client implementations like Cisco IOS XE, two renew packets are sent, one for an address and a second for a prefix. // Unfortunately, if the PD is sent first, the lease is not extented. So... we just wait a second and hopefully than the lease is ready Task.Delay(1000).GetAwaiter().GetResult(); lease = Leases.GetLeaseByClientDuid(clientIdentifier); } else { lease = Leases.GetLeaseAssociationIdAndDuid(identityAssociationId.Value, clientIdentifier); } DHCPv6Packet response = null; extentionError = LeaseExtentionsErros.NoError; if (lease == DHCPv6Lease.NotFound) { response = DHCPv6Packet.AsError(packet, DHCPv6StatusCodes.NoBinding, properyResolver.GetServerDuid()); extentionError = LeaseExtentionsErros.LeaseNotFound; } else { DHCPv6Lease leaseUsedToGenerateResponse = null; if (addressProperties.ReuseAddressIfPossible == true && lease.CanBeExtended() == true) { var tempDelegation = lease.PrefixDelegation; Boolean resetPrefix = false; if (prefixIdentityAsscocationId.HasValue == false && tempDelegation != DHCPv6PrefixDelegation.None) { resetPrefix = true; AddNotificationTrigger( PrefixEdgeRouterBindingUpdatedTrigger.WithOldBinding(Id, PrefixBinding.FromLease(lease))); } else if (tempDelegation == DHCPv6PrefixDelegation.None && prefixIdentityAsscocationId.HasValue == true) { var prefix = addressProperties.GetValidPrefix(Leases.GetUsedPrefixes(), prefixIdentityAsscocationId.Value, lease.PrefixDelegation.NetworkAddress); lease.UpdateAddressPrefix(prefix, false); AddNotificationTrigger( PrefixEdgeRouterBindingUpdatedTrigger.WithNewBinding(Id, PrefixBinding.FromLease(lease))); } if (identityAssociationId.HasValue == true) { var timers = GetLeaseTimers(addressProperties); lease.Renew(timers.Lifespan, timers.RenewTime, timers.ReboundTime, false, resetPrefix); } leaseUsedToGenerateResponse = lease; } else { if ((identityAssociationId.HasValue == true && IsFreshLease(lease) == true) || (prefixIdentityAsscocationId.HasValue == true && IsFreshPrefix(lease) == true)) { leaseUsedToGenerateResponse = lease; } else { PrefixBinding oldBinding = null; PrefixBinding newBinding = null; if (lease.PrefixDelegation != DHCPv6PrefixDelegation.None) { oldBinding = PrefixBinding.FromLease(lease); } if (lease.AddressIsInUse() == true && identityAssociationId.HasValue == true) { Leases.Revoke(lease); } IPv6Address leaseAddress = identityAssociationId.HasValue == true?GetLeasedAddress(addressProperties, lease.Address) : lease.Address; DHCPv6PrefixDelegation leasedPrefix = DHCPv6PrefixDelegation.None; if (prefixIdentityAsscocationId.HasValue == true) { leasedPrefix = addressProperties.GetValidPrefix(Leases.GetUsedPrefixes(), prefixIdentityAsscocationId.Value, lease.PrefixDelegation.NetworkAddress); newBinding = new PrefixBinding(leasedPrefix.NetworkAddress, leasedPrefix.Mask, leaseAddress); if (identityAssociationId.HasValue == false) { lease.UpdateAddressPrefix(leasedPrefix, false); } } if (leaseAddress == IPv6Address.Empty) { base.Apply(new DHCPv6ScopeAddressesAreExhaustedEvent(Id)); AddNotificationTrigger(PrefixEdgeRouterBindingUpdatedTrigger.WithOldBinding(Id, oldBinding)); response = DHCPv6Packet.AsError(packet, DHCPv6StatusCodes.NoAddrsAvail, properyResolver.GetServerDuid()); extentionError = LeaseExtentionsErros.NoAddressAvailaibe; } else { leaseUsedToGenerateResponse = identityAssociationId.HasValue == false ? lease : AddLease(packet, addressProperties, clientIdentifier, identityAssociationId.Value, prefixIdentityAsscocationId, lease, leaseAddress, leasedPrefix); /* * Leases.AddLease( * Guid.NewGuid(), * leaseAddress, * addressProperties.ValidLeaseTime.Value, * addressProperties.T1.Value * addressProperties.ValidLeaseTime.Value, * addressProperties.T2.Value * addressProperties.ValidLeaseTime.Value, * identityAssociationId.Value, * clientIdentifier, * Resolver.HasUniqueIdentifier == true ? Resolver.GetUniqueIdentifier(packet) : null, * prefixIdentityAsscocationId.HasValue == false ? DHCPv6PrefixDelegation.None : leasedPrefix, * lease * ) */ if (identityAssociationId.HasValue == true) { leaseUsedToGenerateResponse.RemovePendingState(); } if (newBinding != null || oldBinding != null && oldBinding != newBinding) { AddNotificationTrigger(new PrefixEdgeRouterBindingUpdatedTrigger(oldBinding, newBinding, Id)); } } } } if (extentionError == LeaseExtentionsErros.NoError) { response = DHCPv6Packet.AsReply(packet, addressProperties, GetScopeProperties(), leaseUsedToGenerateResponse, false, properyResolver.GetServerDuid(), false); } } return(response); }
internal DHCPv6Packet HandleRequestInternal( DHCPv6Packet packet, IDHCPv6ServerPropertiesResolver properyResolver, Boolean isRapitCommit, out DHCPv6RequestHandledEvent.RequestErrors requestError, Boolean onlyGenerateResponse) { var addressProperties = GetAddressProperties(); var innerPacket = packet.GetInnerPacket(); DUID clientIdentifier = innerPacket.GetClientIdentifer(); UInt32?identityAssociationId = innerPacket.GetNonTemporaryIdentityAssocationId(); DHCPv6Lease lease; if (identityAssociationId.HasValue == true) { lease = Leases.GetLeaseAssociationIdAndDuid(identityAssociationId.Value, clientIdentifier); } else { lease = Leases.GetLeaseByClientDuid(clientIdentifier); } requestError = DHCPv6RequestHandledEvent.RequestErrors.NoError; DHCPv6Packet response; if (lease == DHCPv6Lease.Empty) { response = DHCPv6Packet.AsError(packet, DHCPv6StatusCodes.NoAddrsAvail, properyResolver.GetServerDuid()); requestError = DHCPv6RequestHandledEvent.RequestErrors.LeaseNotFound; } else { if (onlyGenerateResponse == true) { return(DHCPv6Packet.AsReply(packet, addressProperties, GetScopeProperties(), lease, true, properyResolver.GetServerDuid(), isRapitCommit)); } var ancsestorLease = lease.HasAncestor() == true?Leases.GetAncestor(lease) : null; if (lease.IsPending() == true) { if (identityAssociationId.HasValue == true) { lease.RemovePendingState(); if (ancsestorLease != null) { Leases.Revoke(ancsestorLease); } response = DHCPv6Packet.AsReply(packet, addressProperties, GetScopeProperties(), lease, false, properyResolver.GetServerDuid(), isRapitCommit); } else { response = DHCPv6Packet.AsError(packet, DHCPv6StatusCodes.NoAddrsAvail, properyResolver.GetServerDuid()); requestError = DHCPv6RequestHandledEvent.RequestErrors.LeasePendingButOnlyPrefixRequested; } } else if (lease.IsActive() == true) { if (identityAssociationId.HasValue == false) { lease.ActivateAddressPrefix(); } response = DHCPv6Packet.AsReply(packet, addressProperties, GetScopeProperties(), lease, true, properyResolver.GetServerDuid(), isRapitCommit); } else { response = DHCPv6Packet.AsError(packet, DHCPv6StatusCodes.NoAddrsAvail, properyResolver.GetServerDuid()); requestError = DHCPv6RequestHandledEvent.RequestErrors.LeaseNotInCorrectState; } if (requestError == DHCPv6RequestHandledEvent.RequestErrors.NoError) { PrefixBinding oldBinding = null; PrefixBinding newBinding = null; if ((ancsestorLease?.PrefixDelegation ?? DHCPv6PrefixDelegation.None) != DHCPv6PrefixDelegation.None) { oldBinding = PrefixBinding.FromLease(ancsestorLease, false); } if (lease.PrefixDelegation != DHCPv6PrefixDelegation.None) { newBinding = PrefixBinding.FromLease(lease, false); } if ((oldBinding != newBinding) && (oldBinding != null || newBinding != null)) { base.AddNotificationTrigger(new PrefixEdgeRouterBindingUpdatedTrigger(oldBinding, newBinding, Id)); } } } return(response); }