/// <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> /// Constructor. /// </summary> /// <param name="flags">Specifies the operation to be performed in addition to operation related options.</param> /// <param name="hostEntry">The host entry information.</param> public DynDnsMessage(DynDnsMessageFlag flags, DynDnsHostEntry hostEntry) { this.TimeStampUtc = DateTime.UtcNow; this.Version = FormatVer; this.Flags = flags; this.HostEntry = hostEntry; }
/// <summary> /// Decrypts and deserializes a message from a byte buffer. /// </summary> /// <param name="buffer">The buffer.</param> /// <param name="sharedKey">The shared encryption key.</param> /// <exception cref="FormatException">Thrown if the buffer does not contain a valid message.</exception> public DynDnsMessage(byte[] buffer, SymmetricKey sharedKey) { try { using (var ms = new EnhancedMemoryStream(Crypto.Decrypt(buffer, sharedKey))) { if (ms.ReadInt32Le() != Magic) { throw new Exception(); } this.Version = ms.ReadByte(); if (this.Version < FormatVer) { throw new FormatException(string.Format("DynDnsMessage version [{0}] is not supported.", this.Version)); } this.TimeStampUtc = new DateTime(ms.ReadInt64Le()); this.Flags = (DynDnsMessageFlag)ms.ReadInt32Le(); this.HostEntry = new DynDnsHostEntry(ms.ReadString16()); } } catch (Exception e) { throw new FormatException("Invalid Dynamic DNS message.", e); } }
/// <summary> /// Registers a <see cref="DynDnsHostEntry" /> with the Dynamic DNS cluster. /// </summary> /// <param name="hostEntry">The host/IP address <see cref="DynDnsHostEntry" /> to be registered.</param> /// <remarks> /// <note> /// This method does not throw an exception if the registration is already registered. /// </note> /// </remarks> /// <exception cref="InvalidOperationException">Thrown if the client has not been started.</exception> public void Register(DynDnsHostEntry hostEntry) { using (TimedLock.Lock(syncLock)) { if (!hosts.ContainsKey(hostEntry)) { hosts[hostEntry] = hostEntry; Register(); } } }
/// <summary> /// Returns a copy of the <see cref="DynDnsHostEntry" /> registrations currently /// exposed to the Dynamic DNS cluster. /// </summary> /// <returns>A <see cref="DynDnsHostEntry" /> array listing the current registrations.</returns> /// <exception cref="InvalidOperationException">Thrown if the client has not been started.</exception> public DynDnsHostEntry[] GetHostRegistrations() { using (TimedLock.Lock(syncLock)) { var list = new DynDnsHostEntry[hosts.Count]; int i; i = 0; foreach (DynDnsHostEntry hostEntry in hosts.Values) { list[i++] = hostEntry; } return(list); } }
/// <summary> /// Loads DNS client settings from a configuration section. /// </summary> /// <param name="keyPrefix">The configuration section key prefix (or <c>null</c>).</param> /// <remarks> /// <para> /// The settings will loaded are: /// </para> /// <div class="tablediv"> /// <table class="dtTABLE" cellspacing="0" ID="Table1"> /// <tr valign="top"> /// <th width="1">Setting</th> /// <th width="1">Default</th> /// <th width="90%">Description</th> /// </tr> /// <tr valign="top"> /// <td>Enabled</td> /// <td>true</td> /// <td> /// Indicates whether the dynamic DNS client should be enabled. /// </td> /// </tr> /// <tr valign="top"> /// <td>NetworkBinding</td> /// <td>ANY</td> /// <td> /// Specifies the <see cref="NetworkBinding" /> the DNS client /// should use for sending UDP host registration messages to the /// DNS servers. /// </td> /// </tr> /// <tr valign="top"> /// <td>Mode</td> /// <td>Cluster</td> /// <td> /// Controls how the client registers hosts with the DNS server. The possible values /// are <see cref="DynDnsMode.Udp" /> or <see cref="DynDnsMode.Cluster"/>. /// <see cref="DynDnsMode.Both" /> is not allowed for DNS clients. /// </td> /// </tr> /// <tr valign="top"> /// <td>SharedKey</td> /// <td>(see note)</td> /// <td> /// Shared symmetric encryption key used to decrypt UDP registration messages /// sent by DNS clients while in <see cref="DynDnsMode.Udp" /> mode. This /// key must match the shared key configured for the client. This defaults /// to a reasonable value. /// </td> /// </tr> /// <tr valign="top"> /// <td>Domain</td> /// <td>(see note)</td> /// <td> /// <para> /// Specifies the name server domain for the name server. If this is /// specified, the DNS client will periodically query DNS for the NS /// records for the domain and then use the IP addresses to send UDP /// host registration messages to the servers. /// </para> /// <para> /// This setting must be formatted as a network binding with a host name /// and port, such as <b>LILLTEK.NET:DYNAMIC-DNS</b>. /// </para> /// <note> /// One of <b>Domain</b> or <b>NameServer</b> must be specified when when <b>Mode=UDP</b>. /// If both settings are present, then <b>Domain</b> will be used. /// </note> /// </td> /// </tr> /// <tr valign="top"> /// <td>NameServer[#]</td> /// <td>(see note)</td> /// <td> /// <para> /// Specifies the network bindings for the DNS servers for the delivery /// of UDP host registration messages. These entries may include /// IP addresses or host names, but note that host name lookups are /// performed only once by the server, when it starts. /// </para> /// <note> /// One of <b>Domain</b> or <b>NameServer</b> must be specified when when <b>Mode=UDP</b>. /// If both settings are present, then <b>Domain</b> will be used. /// </note> /// </td> /// </tr> /// <tr valign="top"> /// <td>BkInterval</td> /// <td>1s</td> /// <td> /// Minimum interval for which background activities will be scheduled. /// </td> /// </tr> /// <tr valign="top"> /// <td>DomainRefreshInterval</td> /// <td>15m</td> /// <td> /// Interval at which DNS NS queries will be performed to refresh the list of /// name servers for the specified <b>Domain</b>. /// </td> /// </tr> /// <tr valign="top"> /// <td>UdpRegisterInterval</td> /// <td>60s</td> /// <td> /// Interval at which UDP host registration messages will be sent to the /// DNS servers when operating in <b>Mode=UDP</b>. /// </td> /// </tr> /// <tr valign="top"> /// <td>Host[#]</td> /// <td>(optional)</td> /// <td> /// <para> /// The set of static host entries to be returned by the DNS server. These /// entries are formatted as: /// </para> /// <code lang="none"> /// <host name> "," <ip or cname> [ "," <TTL> [ "," <host-mode> [ ";" "NAT" ] ] ] /// </code> /// <para> /// where <b>host name</b> is the DNS name being registered, <b>ip</b> or <b>cname</b> /// specifies the IP address or CNAME reference to the host, <b>TTL</b> is the optional /// time-to-live (TTL) to use for the entry in seconds, and <b>host-mode</b> is the optional /// host entry mode, one of <b>ADDRESS</b>, <b>ADDRESSLIST</b>, or <b>CNAME</b>. /// </para> /// <para> /// The <b>TTL</b> value defaults to -1 seconds (indicating that the server's default TTL /// will be used) and the <b>host-mode</b> defaults to <b>ADDRESS</b> for IP addresses or /// <b>CNAME</b> for CNAME references. You can also set <b>TTL=-1</b> to use the DNS server /// default for this. /// </para> /// <note> /// A host mode of <b>ADDRESS</b> or <b>ADDRESSLIST</b> can only be specified for IP /// addresses and <b>CNAME</b> can only be specified for CNAME entries. /// </note> /// </td> /// </tr> /// <tr valign="top"> /// <td>Cluster</td> /// <td>(see note)</td> /// <td> /// <b>Cluster</b> is a subsection in the configuration that /// that specifies the settings required to establish a cooperative /// cluster with the Dynamic DNS instances on the network while operating /// in CLUSTER mode. The client uses the <see cref="ClusterMember" /> class /// to perform the work necessary to join the cluster. The <b>ClusterBaseEP</b> /// setting is required. /// </td> /// </tr> /// </table> /// </div> /// </remarks> public DynDnsClientSettings(string keyPrefix) { Config config = new Config(keyPrefix); string[] list; List <DynDnsHostEntry> registrations; List <NetworkBinding> bindings; list = config.GetArray("Host"); registrations = new List <DynDnsHostEntry>(list.Length); for (int i = 0; i < list.Length; i++) { try { registrations.Add(DynDnsHostEntry.Parse(list[i])); } catch { SysLog.LogWarning("DynamicDnsClient: Error parsing host registration [{0}Host[{1}]={2}].", config.KeyPrefix, i, list[i]); } } this.Hosts = registrations.ToArray(); list = config.GetArray("NameServer"); bindings = new List <NetworkBinding>(list.Length); for (int i = 0; i < list.Length; i++) { try { bindings.Add(new NetworkBinding((list[i]))); } catch { SysLog.LogWarning("DynamicDnsClient: Error parsing name server binding [{0}NameServer[{1}]={2}].", config.KeyPrefix, i, list[i]); } } this.NameServers = bindings.ToArray(); this.Enabled = config.Get("Enabled", this.Enabled); if (this.Enabled) { this.NetworkBinding = config.Get("NetworkBinding", this.NetworkBinding); this.Mode = config.Get <DynDnsMode>("Mode", this.Mode); this.SharedKey = new SymmetricKey(config.Get("SharedKey", "aes:BcskocQ2W4aIGEemkPsy5dhAxuWllweKLVToK1NoYzg=:5UUVxRPml8L4WH82unR74A==")); this.Domain = config.Get("Domain", this.Domain); this.BkInterval = config.Get("BkInterval", this.BkInterval); this.DomainRefreshInterval = config.Get("DomainRefreshInterval", this.DomainRefreshInterval); this.UdpRegisterInterval = config.Get("UdpRegisterInterval", this.UdpRegisterInterval); if (this.Mode == DynDnsMode.Cluster) { this.Cluster = ClusterMemberSettings.LoadConfig(config.KeyPrefix + "Cluster"); } if (this.Mode == DynDnsMode.Both) { throw new FormatException("DynamicDnsClient: [Mode=BOTH] is not supported."); } if (this.Mode == DynDnsMode.Udp && this.Domain.IsAny && this.NameServers.Length == 0) { throw new FormatException("DynDnsClient: One of DOMAIN or NAMESERVER[#] must be specified when [Mode=UDP]."); } } }