//Populate v4 options. //@param link the link //@param configObj the config object or null if none protected void PopulateV4Reply(DhcpLink dhcpLink, DhcpV4OptionConfigObject configObj) { string sname = DhcpServerPolicies.EffectivePolicy(_requestMsg, configObj, dhcpLink.GetLink(), Property.V4_HEADER_SNAME); if (!String.IsNullOrEmpty(sname)) { _replyMsg.SetsName(sname); } string filename = DhcpServerPolicies.EffectivePolicy(_requestMsg, configObj, dhcpLink.GetLink(), Property.V4_HEADER_FILENAME); if (!String.IsNullOrEmpty(filename)) { _replyMsg.SetFile(filename); } Dictionary <int, DhcpOption> optionMap = _dhcpServerConfig.EffectiveV4AddrOptions(_requestMsg, dhcpLink, configObj); if (DhcpServerPolicies.EffectivePolicyAsBoolean(configObj, dhcpLink.GetLink(), Property.SEND_REQUESTED_OPTIONS_ONLY)) { optionMap = RequestedOptions(optionMap, _requestMsg); } _replyMsg.PutAllDhcpOptions(optionMap); // copy the relay agent info option from request to reply // in order to echo option back to router as required if (_requestMsg.HasOption(DhcpConstants.V4OPTION_RELAY_INFO)) { _requestMsg.PutDhcpOption(_requestMsg.GetDhcpOption(DhcpConstants.V4OPTION_RELAY_INFO)); } }
/** * Build a BindingAddress for the given InetAddress and DhcpLink. * * @param inetAddr the inet addr * @param clientLink the client link * @param requestMsg the request msg * * @return the binding address */ protected override BindingObject BuildBindingObject(IPAddress inetAddr, DhcpLink clientLink, DhcpMessage requestMsg) { V6AddressBindingPool bp = (V6AddressBindingPool)FindBindingPool(clientLink.GetLink(), inetAddr, requestMsg); if (bp != null) { bp.SetUsed(inetAddr); // TODO check if this is necessary IaAddress iaAddr = new IaAddress(); iaAddr.SetIpAddress(inetAddr); V6BindingAddress bindingAddr = new V6BindingAddress(iaAddr, bp); SetBindingObjectTimes(bindingAddr, bp.GetPreferredLifetimeMs(), bp.GetPreferredLifetimeMs()); // TODO store the configured options in the persisted binding? // bindingAddr.setDhcpOptions(bp.getDhcpOptions()); return(bindingAddr); } else { log.Error("Failed to create BindingAddress: No BindingPool found for IP=" + inetAddr.ToString()); } // MUST have a BindingPool, otherwise something's broke return(null); }
/** * 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); }
/** * 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); }
/// <summary> /// Populate reply msg options. /// </summary> /// <param name="dhcpLink">the link</param> protected void PopulateReplyMsgOptions(DhcpLink dhcpLink) { Dictionary <int, DhcpOption> optionMap = dhcpServerConfig.EffectiveMsgOptions(this.requestMsg, dhcpLink); if (DhcpServerPolicies.EffectivePolicyAsBoolean(dhcpLink.GetLink(), Property.SEND_REQUESTED_OPTIONS_ONLY)) { optionMap = this.RequestedOptions(optionMap, this.requestMsg); } replyMsg.PutAllDhcpOptions(optionMap); }
protected void PopulatePrefixOptions(DhcpV6IaPrefixOption iaPrefixOption, DhcpLink dhcpLink, DhcpV6OptionConfigObject configObj) { Dictionary <int, DhcpOption> optionMap = dhcpServerConfig.EffectivePrefixOptions(this.requestMsg, dhcpLink, configObj); if (DhcpServerPolicies.EffectivePolicyAsBoolean(configObj, dhcpLink.GetLink(), Property.SEND_REQUESTED_OPTIONS_ONLY)) { optionMap = this.RequestedOptions(optionMap, this.requestMsg); } iaPrefixOption.PutAllDhcpOptions(optionMap); }
public Binding CreateSolicitBinding(DhcpLink clientLink, DhcpV6ClientIdOption clientIdOption, DhcpV6IaNaOption iaNaOption, DhcpMessage requestMsg, byte state, IPAddress clientV4IPAddress) { byte[] duid = clientIdOption.GetDuid(); long iaid = iaNaOption.GetIaId(); StaticBinding staticBinding = FindStaticBinding(clientLink.GetLink(), duid, IdentityAssoc.NA_TYPE, iaid, requestMsg); if (staticBinding != null) { return(base.CreateStaticBinding(clientLink, duid, IdentityAssoc.NA_TYPE, iaid, staticBinding, requestMsg)); } else { return(base.CreateBinding(clientLink, duid, IdentityAssoc.NA_TYPE, iaid, GetInetAddrs(iaNaOption), requestMsg, state, clientV4IPAddress)); } }
public Binding UpdateBinding(Binding binding, DhcpLink clientLink, byte[] macAddr, DhcpMessage requestMsg, byte state) { StaticBinding staticBinding = FindStaticBinding(clientLink.GetLink(), macAddr, IdentityAssoc.V4_TYPE, 0, requestMsg); if (staticBinding != null) { return(base.UpdateStaticBinding(binding, clientLink, macAddr, IdentityAssoc.V4_TYPE, 0, staticBinding, requestMsg)); } else { return(base.UpdateBinding(binding, clientLink, macAddr, IdentityAssoc.V4_TYPE, 0, GetInetAddrs(requestMsg), requestMsg, state, null)); } }
/** * Create a V6BindingAddress given an IaAddress loaded from the database. * * @param iaAddr the ia addr * @param clientLink the client link * @param requestMsg the request msg * * @return the binding address */ private V6BindingAddress BuildV6BindingAddressFromIaAddr(IaAddress iaAddr, DhcpLink clientLink, DhcpMessage requestMsg) { IPAddress inetAddr = iaAddr.GetIpAddress(); BindingPool bp = FindBindingPool(clientLink.GetLink(), inetAddr, requestMsg); if (bp != null) { // TODO store the configured options in the persisted binding? // ipAddr.setDhcpOptions(bp.getDhcpOptions()); return(new V6BindingAddress(iaAddr, (V6AddressBindingPool)bp)); } else { log.Error("Failed to create BindingAddress: No BindingPool found for IP=" + inetAddr.ToString()); } // MUST have a BindingPool, otherwise something's broke return(null); }
public Binding CreateDiscoverBinding(DhcpLink clientLink, byte[] macAddr, DhcpMessage requestMsg, byte state) { lock (_lock) { StaticBinding staticBinding = FindStaticBinding(clientLink.GetLink(), macAddr, IdentityAssoc.V4_TYPE, 0, requestMsg); if (staticBinding != null) { return(base.CreateStaticBinding(clientLink, macAddr, IdentityAssoc.V4_TYPE, 0, staticBinding, requestMsg)); } else { return(base.CreateBinding(clientLink, macAddr, IdentityAssoc.V4_TYPE, 0, GetInetAddrs(requestMsg), requestMsg, state, null)); } } }
protected void ProcessDdnsUpdates(bool sendUpdates) { bool doForwardUpdate = true; DhcpV4ClientFqdnOption clientFqdnOption = (DhcpV4ClientFqdnOption)_requestMsg.GetDhcpOption(DhcpConstants.V4OPTION_CLIENT_FQDN); DhcpV4HostnameOption hostnameOption = (DhcpV4HostnameOption)_requestMsg.GetDhcpOption(DhcpConstants.V4OPTION_HOSTNAME); if (clientFqdnOption == null && hostnameOption == null) { //TODO allow name generation? log.Debug("No Client FQDN nor hostname option in request. Skipping DDNS update processing."); return; } string fqdn = ""; string domain = DhcpServerPolicies.DffectivePolicy(_clientLink.GetLink(), Property.DDNS_DOMAIN); DhcpV4ClientFqdnOption replyFqdnOption = null; if (clientFqdnOption != null) { replyFqdnOption = new DhcpV4ClientFqdnOption(); replyFqdnOption.SetDomainName(clientFqdnOption.GetDomainName()); replyFqdnOption.SetUpdateABit(false); replyFqdnOption.SetOverrideBit(false); replyFqdnOption.SetNoUpdateBit(false); replyFqdnOption.SetEncodingBit(clientFqdnOption.GetEncodingBit()); replyFqdnOption.SetRcode1((short)0xff); // RFC 4702 says server should set to 255 replyFqdnOption.SetRcode2((short)0xff); // RFC 4702 says server should set to 255 fqdn = clientFqdnOption.GetDomainName(); if ((fqdn == null) || (fqdn.Length <= 0)) { log.Error("Client FQDN option domain name is null/empty. No DDNS udpates performed."); replyFqdnOption.SetNoUpdateBit(true); // tell client that server did no updates _replyMsg.PutDhcpOption(replyFqdnOption); return; } string policy = DhcpServerPolicies.EffectivePolicy(_requestMsg, _clientLink.GetLink(), Property.DDNS_UPDATE); log.Info("Server configuration for ddns.update policy: " + policy); if ((policy == null) || policy.Contains("none")) { log.Info("Server configuration for ddns.update policy is null or 'none'." + " No DDNS updates performed."); replyFqdnOption.SetNoUpdateBit(true); // tell client that server did no updates _replyMsg.PutDhcpOption(replyFqdnOption); return; } if (clientFqdnOption.GetNoUpdateBit() && policy.Contains("honorNoUpdate")) { log.Info("Client FQDN NoUpdate flag set. Server configured to honor request." + " No DDNS updates performed."); replyFqdnOption.SetNoUpdateBit(true); // tell client that server did no updates _replyMsg.PutDhcpOption(replyFqdnOption); //TODO: RFC 4704 Section 6.1 // ...the server SHOULD delete any RRs that it previously added // via DNS updates for the client. return; } if (!clientFqdnOption.GetUpdateABit() && policy.Contains("honorNoA")) { log.Info("Client FQDN NoA flag set. Server configured to honor request." + " No FORWARD DDNS updates performed."); doForwardUpdate = false; } else { replyFqdnOption.SetUpdateABit(true); // server will do update if (!clientFqdnOption.GetUpdateABit()) { replyFqdnOption.SetOverrideBit(true); // tell client that we overrode request flag } } if (!String.IsNullOrEmpty(domain)) { log.Info("Server configuration for domain policy: " + domain); // if there is a configured domain, then replace the domain provide by the client int dot = fqdn.IndexOf('.'); if (dot > 0) { fqdn = fqdn.Substring(0, dot + 1) + domain; } else { fqdn = fqdn + "." + domain; } replyFqdnOption.SetDomainName(fqdn); } // since the client DID send option 81, return it in the reply _replyMsg.PutDhcpOption(replyFqdnOption); } else { // The client did not send an FQDN option, so we'll try to formulate the FQDN // from the hostname option combined with the DDNS_DOMAIN policy setting. // A replyFqdnOption is fabricated to be stored with the binding for use // with the release/expire binding processing to remove the DDNS entry. replyFqdnOption = new DhcpV4ClientFqdnOption(); fqdn = hostnameOption.GetString(); if (!String.IsNullOrEmpty(domain)) { log.Info("Server configuration for domain policy: " + domain); fqdn = fqdn + "." + domain; // since the client did NOT send option 81, do not put // the fabricated fqdnOption into the reply packet // but set the option so that is can be used below // when storing the fqdnOption to the database, so // that it can be used if/when the lease expires replyFqdnOption.SetDomainName(fqdn); // server will do the A record update, so set the flag // for the option stored in the database, so server will // remove the A record when the lease expires replyFqdnOption.SetUpdateABit(true); } else { log.Error("No DDNS domain configured. No DDNS udpates performed."); replyFqdnOption.SetNoUpdateBit(true); // tell client that server did no updates _replyMsg.PutDhcpOption(replyFqdnOption); return; } } if (sendUpdates) { foreach (Binding binding in _bindings) { if (binding.GetState() == Binding.COMMITTED) { HashSet <BindingObject> bindingObjs = binding.GetBindingObjects(); if (bindingObjs != null) { foreach (var bindingObj in bindingObjs) { V4BindingAddress bindingAddr = (V4BindingAddress)bindingObj; DhcpConfigObject configObj = bindingAddr.GetConfigObj(); DdnsCallback ddnsComplete = new DhcpV4DdnsComplete(bindingAddr, replyFqdnOption); DdnsUpdater ddns = new DdnsUpdater(_requestMsg, _clientLink.GetLink(), configObj, bindingAddr.GetIpAddress(), fqdn, _requestMsg.GetChAddr(), configObj.GetValidLifetime(), doForwardUpdate, false, ddnsComplete); ddns.ProcessUpdates(); } } } } } }
/** * 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> /// 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); }