/// <summary> /// Removes a <see cref="DynDnsHostEntry" /> registration from the Dynamic /// DNS cluster. /// </summary> /// <param name="hostEntry">The host/IP address <see cref="DynDnsHostEntry" /> to be unregistered.</param> /// <remarks> /// <note> /// This method does not throw an exception if the registration is not present. /// </note> /// </remarks> /// <exception cref="InvalidOperationException">Thrown if the client has not been started.</exception> public void Unregister(DynDnsHostEntry hostEntry) { using (TimedLock.Lock(syncLock)) { if (hosts.ContainsKey(hostEntry)) { // For UDP mode, we need to send two immediate Unregister message to each DNS // server for the host entry. if (settings.Mode == DynDnsMode.Udp && isOpen) { for (int i = 0; i < 2; i++) { DynDnsMessage message; byte[] packet; message = new DynDnsMessage(DynDnsMessageFlag.OpUnregister, hostEntry); packet = message.ToArray(settings.SharedKey); foreach (var nameServer in settings.NameServers) { socket.SendTo(packet, nameServer); } } } // Remove the host entry from the local table. hosts.Remove(hostEntry); Register(); } } }
/// <summary> /// Handles background tasks when operating in UDP mode. /// </summary> /// <param name="state">Not used.</param> private void OnBkTask(object state) { try { using (TimedLock.Lock(syncLock)) { if (!isOpen || settings.Mode != DynDnsMode.Udp) { return; } if (settings.Domain.IsHost && domainRefreshTimer.HasFired) { // Perform a NS lookup for the domain and populate // settings.NameServer with the results. // $todo(jeff.lill): // // Note that I'm going to ignore any CNAME records returned // for now. It might be important to make sure these are // added to the staticHosts table, but I need to think about // this some more. try { var nameServers = new Dictionary <IPAddress, bool>(); string qname; DnsRequest request; DnsResponse response; qname = settings.Domain.Host; if (!qname.EndsWith(".")) { qname += "."; } request = new DnsRequest(DnsFlag.RD, qname, DnsQType.NS); response = DnsResolver.QueryWithRetry(NetHelper.GetDnsServers(), request, TimeSpan.FromMilliseconds(500), 4); if (response.RCode != DnsFlag.RCODE_OK) { SysLog.LogWarning("DynDnsClient: Domain NS query failed with error [{0}].", response.RCode); } else { // Build the set of name server endpoints by resolving the // name server names returned in the NS response into IP addresses. foreach (var answer in response.Answers) { if (answer.RRType == DnsRRType.NS) { NS_RR nsAnswer = (NS_RR)answer; try { foreach (var address in Dns.GetHostAddresses(nsAnswer.NameServer).IPv4Only()) { if (!nameServers.ContainsKey(address)) { nameServers.Add(address, true); } } } catch { // Ignorning } } } if (nameServers.Count == 0) { // Note that I'm going to keep any name server addresses I already have // in the case where the name server queries above return nothing. This // will give us some resiliency in the face of transient network problems, etc. // I'm going to set the timer to retry in 1 minute in this case. domainRefreshTimer.ResetTemporary(TimeSpan.FromMinutes(1)); } else { var newServers = new List <NetworkBinding>(nameServers.Count); foreach (var address in nameServers.Keys) { newServers.Add(new IPEndPoint(address, settings.Domain.Port)); } settings.NameServers = newServers.ToArray(); } } } catch (Exception e) { domainRefreshTimer.Reset(TimeSpan.FromSeconds(60)); SysLog.LogException(e); } } if (udpRegisterTimer.HasFired) { // It's time to transmit host registrations to the dynamic DNS servers. DynDnsMessage message; byte[] packet; foreach (var entry in hosts.Values) { message = new DynDnsMessage(DynDnsMessageFlag.OpRegister, entry); packet = message.ToArray(settings.SharedKey); foreach (var nameServer in settings.NameServers) { socket.SendTo(packet, nameServer); } } } } } catch (Exception e) { SysLog.LogException(e); } }
/// <summary> /// Releases all resources associated with the instance. /// </summary> public void Close() { using (TimedLock.Lock(syncLock)) { if (!isOpen) { return; } // If we're running in UDP mode, then send a couple deregister messages // for all host entries to each known name server. This will ensure that // the DNS updated quickly when servers are shut down gracefully. Note // that I'm going to send duplicate messages to each server just to be // on the safe side. if (settings.Mode == DynDnsMode.Udp) { for (int i = 0; i < 2; i++) { DynDnsMessage message; byte[] packet; foreach (var entry in hosts.Values) { message = new DynDnsMessage(DynDnsMessageFlag.OpUnregister, entry); packet = message.ToArray(settings.SharedKey); foreach (var nameServer in settings.NameServers) { socket.SendTo(packet, nameServer); } Thread.Sleep(500); } } } // Shut down the client. if (cluster != null) { cluster.Stop(); cluster = null; } if (bkTimer != null) { bkTimer.Dispose(); bkTimer = null; } if (socket != null) { socket.Close(); socket = null; } router = null; isOpen = false; } }