protected void ProcessDdnsUpdates(bool sendUpdates) { DhcpV6ClientFqdnOption clientFqdnOption = ((DhcpV6ClientFqdnOption)(this.requestMsg.GetDhcpOption(DhcpConstants.V6OPTION_CLIENT_FQDN))); if ((clientFqdnOption == null)) { // TODO allow name generation? log.Debug("No Client FQDN option in request. Skipping DDNS update processing."); return; } bool includeFqdnOptionInReply = false; if (((this.requestMsg.GetRequestedOptionCodes() != null) && this.requestMsg.GetRequestedOptionCodes().Contains(DhcpConstants.V6OPTION_CLIENT_FQDN))) { // RFC 4704 section 6 says: // Servers MUST only include a Client FQDN option in ADVERTISE and REPLY // messages if the client included a Client FQDN option and the Client // FQDN option is requested by the Option Request option in the client's // message to which the server is responding. includeFqdnOptionInReply = true; } DhcpV6ClientFqdnOption replyFqdnOption = new DhcpV6ClientFqdnOption(); replyFqdnOption.SetDomainName(clientFqdnOption.GetDomainName()); replyFqdnOption.SetUpdateAaaaBit(false); replyFqdnOption.SetOverrideBit(false); replyFqdnOption.SetNoUpdateBit(false); string fqdn = clientFqdnOption.GetDomainName(); if (((fqdn == null) || (fqdn.Length <= 0))) { log.Error("Client FQDN option domain name is null/empty. No DDNS udpates performed."); if (includeFqdnOptionInReply) { replyFqdnOption.SetNoUpdateBit(true); // tell client that server did no updates this.replyMsg.PutDhcpOption(replyFqdnOption); } return; } String policy = DhcpServerPolicies.EffectivePolicy(this.requestMsg, this.clientLink.GetLink(), Property.DDNS_UPDATE); log.Info(("Server configuration for ddns.update policy: " + policy)); if (((policy == null) || policy.ToLower() == "none")) { log.Info(("Server configuration for ddns.update policy is null or \'none\'." + " No DDNS updates performed.")); if (includeFqdnOptionInReply) { replyFqdnOption.SetNoUpdateBit(true); // tell client that server did no updates this.replyMsg.PutDhcpOption(replyFqdnOption); } return; } if ((clientFqdnOption.GetNoUpdateBit() && policy.ToLower() == "honorNoUpdate".ToLower())) { log.Info(("Client FQDN NoUpdate flag set. Server configured to honor request." + " No DDNS updates performed.")); if (includeFqdnOptionInReply) { replyFqdnOption.SetNoUpdateBit(true); // tell client that server did no updates this.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; } bool doForwardUpdate = true; if ((!clientFqdnOption.GetUpdateAaaaBit() && policy.ToLower() == "honorNoAAAA".ToLower())) { log.Info(("Client FQDN NoAAAA flag set. Server configured to honor request." + " No FORWARD DDNS updates performed.")); doForwardUpdate = false; } else { replyFqdnOption.SetUpdateAaaaBit(true); // server will do update if (!clientFqdnOption.GetUpdateAaaaBit()) { replyFqdnOption.SetOverrideBit(true); } // tell client that we overrode request flag } string domain = DhcpServerPolicies.EffectivePolicy(this.clientLink.GetLink(), Property.DDNS_DOMAIN); if (((domain != null) && domain.Count() > 0)) { 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); } if (includeFqdnOptionInReply) { this.replyMsg.PutDhcpOption(replyFqdnOption); } if (sendUpdates) { foreach (Binding binding in this.bindings) { if ((binding.GetState() == Binding.COMMITTED)) { HashSet <BindingObject> bindingObjs = binding.GetBindingObjects(); if ((bindingObjs != null)) { foreach (BindingObject bindingObj in bindingObjs) { V6BindingAddress bindingAddr = ((V6BindingAddress)(bindingObj)); DhcpConfigObject configObj = bindingAddr.GetConfigObj(); DdnsCallback ddnsComplete = new DhcpV6DdnsComplete(bindingAddr, replyFqdnOption); DdnsUpdater ddns = new DdnsUpdater(this.requestMsg, this.clientLink.GetLink(), configObj, bindingAddr.GetIpAddress(), fqdn, this.requestMsg.GetDhcpClientIdOption().GetDuid(), configObj.GetValidLifetime(), doForwardUpdate, false, ddnsComplete); ddns.ProcessUpdates(); } } } } } }
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"); } }