/// <summary> /// Release an IaAddress. If policy dictates, the address will be deleted, /// otherwise the state will be marked as released instead. In either case, /// a DDNS delete will be issued for the address binding. /// </summary> /// <param name="ia">iaAddr the IaAddress to be released</param> /// <param name="iaAddr">iaAddr the IaAddress to be released</param> public void ReleaseIaAddress(IdentityAssoc ia, IaAddress iaAddr) { try { log.Info("Releasing address: " + iaAddr.GetIpAddress().ToString()); //DdnsDelete(ia, iaAddr); if (DhcpServerPolicies.GlobalPolicyAsBoolean( Property.BINDING_MANAGER_DELETE_OLD_BINDINGS)) { iaMgr.DeleteIaAddr(iaAddr); // free the address only if it is deleted from the db, // otherwise, we will get a unique constraint violation // if another client obtains this released IP address FreeAddress(iaAddr.GetIpAddress()); } else { iaAddr.SetStartTime(DateTime.Now); iaAddr.SetPreferredEndTime(DateTime.Now); iaAddr.SetValidEndTime(DateTime.Now); iaAddr.SetState(IaAddress.RELEASED); iaMgr.UpdateIaAddr(iaAddr); log.Info("Address released: " + iaAddr.ToString()); } } catch (Exception ex) { log.Error("Failed to release address"); } }
/// <summary> /// Find the current binding, if any, for the given client identity association (IA). /// </summary> /// <param name="clientLink">link for the client request message</param> /// <param name="duid">DUID of the client</param> /// <param name="iatype">the IAID of the client request</param> /// <param name="iaid"> IAID of the client request</param> /// <param name="requestMsg">requestMsg the client request message</param> /// <returns>return the existing Binding for this client request</returns> protected Binding FindCurrentBinding(DhcpLink clientLink, byte[] duid, byte iatype, long iaid, DhcpMessage requestMsg) { Binding binding = null; lock (_lock) { try { IdentityAssoc ia = iaMgr.FindIA(duid, iatype, iaid); if (ia != null) { _log.Info("Found current binding for " + IdentityAssoc.KeyToString(duid, iatype, iaid) + " state=" + ia.GetState()); binding = BuildBindingFromIa(ia, clientLink, requestMsg); if (binding != null) { _log.Info("Successfully built Binding object: " + binding); } else { _log.Error("Failed to build Binding object"); } } else { _log.Info("No current binding found for " + IdentityAssoc.KeyToString(duid, iatype, iaid)); } } catch (Exception ex) { _log.Error("Failed to find current binding"); } } return(binding); }
/// <summary> /// Callback from the ReaperTimerTask started when the BindingManager initialized. /// Find any expired addresses as of now, and expire them already. /// </summary> public void ExpireAddresses() { List <IdentityAssoc> expiredIAs = iaMgr.FindExpiredIAs(GetIaType()); if ((expiredIAs != null) && expiredIAs.Count > 0) { log.Info("Found " + expiredIAs.Count + " expired bindings of type: " + IdentityAssoc.IaTypeToString(GetIaType())); foreach (IdentityAssoc ia in expiredIAs) { List <IaAddress> expiredAddrs = ia.GetIaAddresses(); if ((expiredAddrs != null) && expiredAddrs.Count > 0) { // due to the implementation of findExpiredIAs, each IdentityAssoc // SHOULD have only one IaAddress within it to be expired log.Info("Found " + expiredAddrs.Count + " expired bindings for IA: " + "duid=" + Util.ToHexString(ia.GetDuid()) + " iaid=" + ia.GetIaid()); foreach (IaAddress iaAddress in expiredAddrs) { ExpireIaAddress(ia, iaAddress); } } } } }
/// <summary> /// Builds a new Binding.Create a new IdentityAssoc from the given /// tuple and wrap that IdentityAssoc in a Binding. /// </summary> /// <param name="clientLink">client link</param> /// <param name="duid">DUID</param> /// <param name="iatype">IA type</param> /// <param name="iaid">IAID</param> /// <param name="state"></param> /// <returns> binding (a wrapped IdentityAssoc)</returns> private Binding BuildBinding(DhcpLink clientLink, byte[] duid, byte iatype, long iaid, byte state) { IdentityAssoc ia = new IdentityAssoc(); ia.SetDuid(duid); ia.SetIatype(iatype); ia.SetIaid(iaid); ia.SetState(state); return(new Binding(ia, clientLink)); }
public Binding(IdentityAssoc ia, DhcpLink dhcpLink) { this.origIa = ia; // save a reference to the original IA this.SetDhcpOptions(ia.GetDhcpOptions()); this.SetDuid(ia.GetDuid()); this.SetIaAddresses(ia.GetIaAddresses()); this.SetIaid(ia.GetIaid()); this.SetIatype(ia.GetIatype()); this.SetId(ia.GetId()); this.SetState(ia.GetState()); this.dhcpLink = dhcpLink; }
/// <summary> /// Checks if the duid-iatype-iaid tuple matches the given IA. /// </summary> /// <param name="duid">DUID</param> /// <param name="iatype">IA type</param> /// <param name="iaid">IAID</param> /// <param name="ia">IA</param> /// <returns>true, if is my ia</returns> protected bool IsMyIa(byte[] duid, byte iatype, long iaid, IdentityAssoc ia) { bool rc = false; if (duid != null) { if (Array.Equals(ia.GetDuid(), duid) && (ia.GetIatype() == iatype) && (ia.GetIaid() == iaid)) { rc = true; } } return(rc); }
/** * Create a Binding given an IdentityAssoc loaded from the database. * * @param ia the ia * @param clientLink the client link * @param requestMsg the request msg * * @return the binding */ protected override Binding BuildBindingFromIa(IdentityAssoc ia, DhcpLink clientLink, DhcpMessage requestMsg) { Binding binding = new Binding(ia, clientLink); List <IaAddress> iaAddrs = ia.GetIaAddresses(); if ((iaAddrs != null) && iaAddrs.Count > 0) { List <IaAddress> bindingAddrs = new List <IaAddress>(); foreach (IaAddress iaAddr in iaAddrs) { if (!clientLink.GetSubnet().Contains(iaAddr.GetIpAddress())) { log.Info("Ignoring off-link binding address: " + iaAddr.GetIpAddress().ToString()); continue; } V4BindingAddress bindingAddr = null; StaticBinding staticBinding = FindStaticBinding(clientLink.GetLink(), ia.GetDuid(), ia.GetIatype(), ia.GetIaid(), requestMsg); if (staticBinding != null) { bindingAddr = BuildV4StaticBindingFromIaAddr(iaAddr, staticBinding); } else { bindingAddr = BuildV4BindingAddressFromIaAddr(iaAddr, clientLink.GetLink(), requestMsg); } if (bindingAddr != null) { bindingAddrs.Add(bindingAddr); } } // replace the collection of IaAddresses with BindingAddresses binding.SetIaAddresses(bindingAddrs); } else { log.Warn("IA has no addresses, binding is empty."); } return(binding); }
/// <summary> /// Decline an IaAddress. This is done when the client declines an address. /// Perform a DDNS delete just in case it was already registered, then mark /// the address as declined (unavailable). /// </summary> /// <param name="ia">iaAddr the declined IaAddress.</param> /// <param name="iaAddr">iaAddr the declined IaAddress.</param> public void DeclineIaAddress(IdentityAssoc ia, IaAddress iaAddr) { try { log.Info("Declining address: " + iaAddr.GetIpAddress().ToString()); //DdnsDelete(ia, iaAddr); iaAddr.SetStartTime(DateTime.Now); iaAddr.SetPreferredEndTime(DateTime.Now); iaAddr.SetValidEndTime(DateTime.Now); iaAddr.SetState(IaAddress.DECLINED); iaMgr.UpdateIaAddr(iaAddr); log.Info("Address declined: " + iaAddr.ToString()); } catch (Exception ex) { log.Error("Failed to decline address"); } }
/** * Create a Binding given an IdentityAssoc loaded from the database. * * @param ia the ia * @param clientLink the client link * @param requestMsg the request msg * * @return the binding */ protected override Binding BuildBindingFromIa(IdentityAssoc ia, DhcpLink clientLink, DhcpMessage requestMsg) { Binding binding = new Binding(ia, clientLink); List <IaAddress> iaPrefs = ia.GetIaAddresses(); if ((iaPrefs != null) && iaPrefs.Count > 0) { List <IaAddress> bindingPrefixes = new List <IaAddress>(); foreach (IaAddress iaAddr in iaPrefs) { // off-link check needed only for v4? // if (!clientLink.getSubnet().contains(iaAddr.getIpAddress())) { // log.info("Ignoring off-link binding address: " + // iaAddr.getIpAddress().getHostAddress()); // continue; // } V6BindingPrefix bindingPrefix = null; StaticBinding staticBinding = FindStaticBinding(clientLink.GetLink(), ia.GetDuid(), ia.GetIatype(), ia.GetIaid(), requestMsg); if (staticBinding != null) { bindingPrefix = BuildV6BindingPrefixFromIaPrefix((IaPrefix)iaAddr, staticBinding); } else { bindingPrefix = BuildBindingAddrFromIaPrefix((IaPrefix)iaAddr, clientLink.GetLink(), requestMsg); } if (bindingPrefix != null) { bindingPrefixes.Add(bindingPrefix); } } // replace the collection of IaPrefixes with BindingPrefixes binding.SetIaAddresses(bindingPrefixes); } else { log.Warn("IA has no prefixes, binding is empty."); } return(binding); }
/** * Perform the DDNS delete processing when a lease is released or expired. * * @param ia the IdentityAssoc of the client * @param iaAddr the released or expired IaAddress */ protected override void DdnsDelete(IdentityAssoc ia, IaAddress iaAddr) { DhcpV6ClientFqdnOption clientFqdnOption = null; try { if ((ia != null) && (iaAddr != null)) { List <DhcpOption> opts = iaAddr.GetDhcpOptions(); if (opts != null) { foreach (DhcpOption opt in opts) { if (opt.GetCode() == DhcpConstants.V6OPTION_CLIENT_FQDN) { clientFqdnOption = new DhcpV6ClientFqdnOption(); //clientFqdnOption.Decode(ByteBuffer.Wrap(opt.GetValue())); break; } } } if (clientFqdnOption != null) { string fqdn = clientFqdnOption.GetDomainName(); if (!String.IsNullOrEmpty(fqdn)) { DhcpLink link = serverConfig.FindLinkForAddress(iaAddr.GetIpAddress()); if (link != null) { V6BindingAddress bindingAddr = null; StaticBinding staticBinding = FindStaticBinding(link.GetLink(), ia.GetDuid(), ia.GetIatype(), ia.GetIaid(), null); if (staticBinding != null) { bindingAddr = BuildV6StaticBindingFromIaAddr(iaAddr, staticBinding); } else { bindingAddr = BuildV6BindingAddressFromIaAddr(iaAddr, link, null); // safe to send null requestMsg } if (bindingAddr != null) { DdnsCallback ddnsComplete = new DhcpV6DdnsComplete(bindingAddr, clientFqdnOption); DhcpConfigObject configObj = bindingAddr.GetConfigObj(); DdnsUpdater ddns = new DdnsUpdater(link.GetLink(), configObj, bindingAddr.GetIpAddress(), fqdn, ia.GetDuid(), configObj.GetValidLifetime(), clientFqdnOption.GetUpdateAaaaBit(), true, ddnsComplete); ddns.ProcessUpdates(); } else { log.Error("Failed to find binding for address: " + iaAddr.GetIpAddress().ToString()); } } else { log.Error("Failed to find link for binding address: " + iaAddr.GetIpAddress().ToString()); } } else { log.Error("FQDN is null or empty. No DDNS deletes performed."); } } else { log.Warn("No Client FQDN option in current binding. No DDNS deletes performed."); } } } catch (Exception ex) { log.Error("Failed to perform DDNS delete"); } }
/// <summary> /// Create a Binding given an IdentityAssoc loaded from the database. /// </summary> /// <param name="ia">IA</param> /// <param name="clientLink">client link</param> /// <param name="requestMsg">request message</param> /// <returns>binding</returns> protected abstract Binding BuildBindingFromIa(IdentityAssoc ia, DhcpLink clientLink, DhcpMessage requestMsg);
/// <summary> /// Get list of IP addresses for the given client IA request. /// </summary> /// <param name="clientLink">link for the client request message</param> /// <param name="duid">DUID of the client</param> /// <param name="iatype">IA type of the client request</param> /// <param name="iaid">IAID of the client request</param> /// <param name="requestAddrs">list of requested IP addresses, if any</param> /// <param name="requestMsg">client request message</param> /// <returns>list of IPAddress</returns> protected List <IPAddress> GetInetAddrs(DhcpLink clientLink, byte[] duid, byte iatype, long iaid, List <IPAddress> requestAddrs, DhcpMessage requestMsg, IPAddress clientV4IPAddress) { List <IPAddress> inetAddrs = new List <IPAddress>(); if ((requestAddrs != null) && requestAddrs.Count > 0) { foreach (IPAddress reqAddr in requestAddrs) { IPAddress addr = reqAddr; if (!addr.Equals(DhcpConstants.ZEROADDR_V6)) { BindingPool bp = FindBindingPool(clientLink.GetLink(), addr, requestMsg); if (bp.IsFree(new BigInteger(addr.GetAddressBytes())) == false) { continue; } if (bp == null) { _log.Warn("No BindingPool found for requested client address: " + addr.ToString()); if (iatype == IdentityAssoc.PD_TYPE) { // TAHI tests want NoPrefixAvail in this case _log.Warn("Requested prefix is not available, returning"); return(inetAddrs); } // if there is no pool for the requested address, then skip it // because that address is either off-link or no longer valid continue; } _log.Info("Searching existing bindings for requested IP=" + addr.ToString()); IdentityAssoc ia = null; try { ia = iaMgr.FindIA(addr); if (ia != null) { // the address is assigned to an IA, which we // don't expect to be this IA, because we would // have found it using findCurrentBinding... // but, perhaps another thread just created it? if (IsMyIa(duid, iatype, iaid, ia)) { _log.Warn("Requested IP=" + addr.ToString() + " is already held by THIS client " + IdentityAssoc.KeyToString(duid, iatype, iaid) + ". Allowing this requested IP."); } else { _log.Info("Requested IP=" + addr.ToString() + " is held by ANOTHER client " + IdentityAssoc.KeyToString(duid, iatype, iaid)); // the address is held by another IA, so get a new one addr = GetNextFreeAddress(clientLink, requestMsg, clientV4IPAddress); } } if (addr != null) { inetAddrs.Add(addr); } } catch { _log.Error("Failure finding IA for address"); } } } } if (inetAddrs == null || inetAddrs.Count == 0) { // the client did not request any valid addresses, so get the next one IPAddress inetAddr = GetNextFreeAddress(clientLink, requestMsg, clientV4IPAddress); if (inetAddr != null) { inetAddrs.Add(inetAddr); } } return(inetAddrs); }
/// <summary> /// Perform the DDNS delete processing when a lease is released or expired. /// </summary> /// <param name="ia">iaAddr the released or expired IaAddress </param> /// <param name="iaAddr">iaAddr the released or expired IaAddress </param> protected abstract void DdnsDelete(IdentityAssoc ia, IaAddress iaAddr);