public void DynDnsHandler_Udp_ADDRESSLIST() { // Start a Dynamic DNS service handler and a client, register two ADDRESSLIST // records for TEST1.COM and confirm that A queries return both entries. // I'm also going to add an ADDRESS record for TEST2.COM and verify that this address // is never returned. DynDnsClientSettings clientSettings; DynDnsHandler handler = null; DynDnsClient client = null; DnsResponse response; try { handler = new DynDnsHandler(); handler.Start(router, null, null, null); clientSettings = new DynDnsClientSettings() { Mode = DynDnsMode.Udp, NameServers = new NetworkBinding[] { new NetworkBinding("127.0.0.1:DYNAMIC-DNS") }, UdpRegisterInterval = TimeSpan.FromSeconds(1) }; client = new DynDnsClient(); client.Register(new DynDnsHostEntry("test1.com,10.0.0.1,1000,ADDRESSLIST")); client.Register(new DynDnsHostEntry("test1.com,10.0.0.2,1000,ADDRESSLIST")); client.Register(new DynDnsHostEntry("test2.com,10.0.0.3,1000,ADDRESSLIST")); client.Open(router, clientSettings); // Wait for everything to spin up. Thread.Sleep(3000); // Perform an A query and verify that we get both addresses in response. response = DnsResolver.Query(IPAddress.Loopback, new DnsRequest(DnsFlag.NONE, "test1.com.", DnsQType.A), TimeSpan.FromSeconds(2)); Assert.AreEqual("test1.com.", response.QName); Assert.AreEqual(DnsQType.A, response.QType); Assert.AreEqual(2, response.Answers.Count); Assert.IsNotNull(response.Answers.SingleOrDefault(r => ((A_RR)r).Address.Equals(IPAddress.Parse("10.0.0.1")))); Assert.IsNotNull(response.Answers.SingleOrDefault(r => ((A_RR)r).Address.Equals(IPAddress.Parse("10.0.0.2")))); } finally { if (client != null) { client.Close(); } if (handler != null) { handler.Stop(); } } }
public void DynDnsClientSettings_LoadCluster() { var cfg = @" §ion DynDnsClient Enabled = true NetworkBinding = ANY Mode = CLUSTER SharedKey = aes:ac2qGMV/VZXXdwdjFvaOBpLjOJgOuG6SbM86w3xk0NM=:B4s0wIHjn+PdRHsIcBgJPQ== // Domain = ANY // NameServer[0] = BkInterval = 3s DomainRefreshInterval = 4m UdpRegisterInterval = 5m §ion Cluster ClusterBaseEP = abstract://LillTek/DataCenter/DynDNS Mode = Normal MasterBroadcastInterval = 1s SlaveUpdateInterval = 1s ElectionInterval = 3s MissingMasterCount = 3 MissingSlaveCount = 3 MasterBkInterval = 1s SlaveBkInterval = 1s BkInterval = 1s &endsection &endsection "; try { DynDnsClientSettings settings; Config.SetConfig(cfg.Replace('&', '#')); settings = new DynDnsClientSettings("DynDnsClient"); Assert.IsTrue(settings.Enabled); Assert.IsTrue(settings.NetworkBinding.IsAny); Assert.AreEqual(DynDnsMode.Cluster, settings.Mode); Assert.AreNotEqual(new DynDnsClientSettings().SharedKey.ToString(), settings.SharedKey.ToString()); Assert.IsTrue(settings.Domain.IsAny); ExtendedAssert.IsEmpty(settings.NameServers); Assert.AreEqual(TimeSpan.FromSeconds(3), settings.BkInterval); Assert.AreEqual(TimeSpan.FromMinutes(4), settings.DomainRefreshInterval); Assert.AreEqual(TimeSpan.FromMinutes(5), settings.UdpRegisterInterval); Assert.IsNotNull(settings.Cluster); } finally { Config.SetConfig(null); } }
public void DynDnsClientSettings_LoadUdpBadServer() { var cfg = @" §ion DynDnsClient Enabled = true NetworkBinding = ANY Mode = BOTH SharedKey = aes:ac2qGMV/VZXXdwdjFvaOBpLjOJgOuG6SbM86w3xk0NM=:B4s0wIHjn+PdRHsIcBgJPQ== // Domain = lilltek.com:DYNAMIC-DNS // NameServer[0] = BkInterval = 3s DomainRefreshInterval = 4m UdpRegisterInterval = 5m §ion Cluster ClusterBaseEP = abstract://LillTek/DataCenter/DynDNS Mode = Normal MasterBroadcastInterval = 1s SlaveUpdateInterval = 1s ElectionInterval = 3s MissingMasterCount = 3 MissingSlaveCount = 3 MasterBkInterval = 1s SlaveBkInterval = 1s BkInterval = 1s &endsection &endsection "; try { DynDnsClientSettings settings; Config.SetConfig(cfg.Replace('&', '#')); try { settings = new DynDnsClientSettings("DynDnsClient"); Assert.Fail("Expected an exception because neither Domain or NameServer[#] were specified."); } catch { // Expected } } finally { Config.SetConfig(null); } }
public void DynDnsHandler_Settings() { DynDnsClientSettings settings; settings = new DynDnsClientSettings("DynDnsClient.Test"); Assert.IsTrue(settings.Enabled); Assert.AreEqual(2, settings.Hosts.Length); Assert.AreEqual("test0.com.", settings.Hosts[0].Host); Assert.AreEqual("10.0.0.1", settings.Hosts[0].Address.ToString()); Assert.AreEqual("test1.com.", settings.Hosts[1].Host); Assert.AreEqual("10.0.0.2", settings.Hosts[1].Address.ToString()); settings = new DynDnsClientSettings("DynDnsClient.Disabled"); Assert.IsFalse(settings.Enabled); }
public void DynDnsClientSettings_Defaults() { DynDnsClientSettings def = new DynDnsClientSettings(); Assert.IsTrue(def.Enabled); Assert.IsTrue(def.NetworkBinding.IsAny); Assert.AreEqual(DynDnsMode.Cluster, def.Mode); Assert.IsNotNull(def.SharedKey); Assert.IsTrue(def.Domain.IsAny); ExtendedAssert.IsEmpty(def.NameServers); ExtendedAssert.IsEmpty(def.Hosts); Assert.AreEqual(TimeSpan.FromSeconds(1), def.BkInterval); Assert.AreEqual(TimeSpan.FromMinutes(15), def.DomainRefreshInterval); Assert.AreEqual(TimeSpan.FromMinutes(1), def.UdpRegisterInterval); Assert.IsNull(def.Cluster); }
public void DynDnsClientSettings_LoadUdpNameServers() { var cfg = @" §ion DynDnsClient Enabled = true NetworkBinding = ANY Mode = UDP SharedKey = aes:ac2qGMV/VZXXdwdjFvaOBpLjOJgOuG6SbM86w3xk0NM=:B4s0wIHjn+PdRHsIcBgJPQ== // Domain = NameServer[0] = 10.0.0.1:10 NameServer[1] = 10.0.0.1:20 BkInterval = 3s DomainRefreshInterval = 4m UdpRegisterInterval = 5m &endsection "; try { DynDnsClientSettings settings; Config.SetConfig(cfg.Replace('&', '#')); settings = new DynDnsClientSettings("DynDnsClient"); Assert.IsTrue(settings.Enabled); Assert.IsTrue(settings.NetworkBinding.IsAny); Assert.AreEqual(DynDnsMode.Udp, settings.Mode); Assert.AreNotEqual(new DynDnsClientSettings().SharedKey.ToString(), settings.SharedKey.ToString()); Assert.IsTrue(settings.Domain.IsAny); CollectionAssert.AreEqual(new NetworkBinding[] { new NetworkBinding("10.0.0.1:10"), new NetworkBinding("10.0.0.1:20") }, settings.NameServers); Assert.AreEqual(TimeSpan.FromSeconds(3), settings.BkInterval); Assert.AreEqual(TimeSpan.FromMinutes(4), settings.DomainRefreshInterval); Assert.AreEqual(TimeSpan.FromMinutes(5), settings.UdpRegisterInterval); Assert.IsNull(settings.Cluster); } finally { Config.SetConfig(null); } }
public void DynDnsClientSettings_LoadUdpDomain() { var cfg = @" §ion DynDnsClient Enabled = true NetworkBinding = ANY Mode = UDP SharedKey = aes:ac2qGMV/VZXXdwdjFvaOBpLjOJgOuG6SbM86w3xk0NM=:B4s0wIHjn+PdRHsIcBgJPQ== Domain = lilltek.net:DYNAMIC-DNS // NameServer[0] = BkInterval = 3s DomainRefreshInterval = 4m UdpRegisterInterval = 5m &endsection "; try { DynDnsClientSettings settings; Config.SetConfig(cfg.Replace('&', '#')); settings = new DynDnsClientSettings("DynDnsClient"); Assert.IsTrue(settings.Enabled); Assert.IsTrue(settings.NetworkBinding.IsAny); Assert.AreEqual(DynDnsMode.Udp, settings.Mode); Assert.AreNotEqual(new DynDnsClientSettings().SharedKey.ToString(), settings.SharedKey.ToString()); Assert.AreEqual(new NetworkBinding("lilltek.net", NetworkPort.DynamicDns), settings.Domain); ExtendedAssert.IsEmpty(settings.NameServers); Assert.AreEqual(TimeSpan.FromSeconds(3), settings.BkInterval); Assert.AreEqual(TimeSpan.FromMinutes(4), settings.DomainRefreshInterval); Assert.AreEqual(TimeSpan.FromMinutes(5), settings.UdpRegisterInterval); Assert.IsNull(settings.Cluster); } finally { Config.SetConfig(null); } }
public void DynDnsService_EndToEnd() { LeafRouter router = null; Process svcProcess = null; Assembly assembly = typeof(LillTek.Datacenter.DynDnsService.Program).Assembly; DynDnsClient client = null; Helper.InitializeApp(assembly); try { Config.SetConfig(@" §ion MsgRouter AppName = LillTek.DynDNS Service AppDescription = Dynamic DNS RouterEP = physical://DETACHED/$(LillTek.DC.DefHubName)/$(Guid) CloudEP = $(LillTek.DC.CloudEP) CloudAdapter = ANY UdpEP = ANY:0 TcpEP = ANY:0 TcpBacklog = 100 TcpDelay = off BkInterval = 1s MaxIdle = 5m EnableP2P = yes AdvertiseTime = 1m DefMsgTTL = 5 SharedKey = PLAINTEXT SessionCacheTime = 2m SessionRetries = 3 SessionTimeout = 10s MaxLogicalAdvertiseEPs = 256 DeadRouterTTL = 2s // This maps the abstract Dynamic DNS endpoints to their default logical endpoints. AbstractMap[abstract://LillTek/DataCenter/DynDNS] = logical://LillTek/DataCenter/DynDNS &endsection §ion MsgRouter AppName = LillTek.DynDNS Service AppDescription = Dynamic DNS RouterEP = physical://DETACHED/$(LillTek.DC.DefHubName)/$(Guid) CloudEP = $(LillTek.DC.CloudEP) CloudAdapter = ANY UdpEP = ANY:0 TcpEP = ANY:0 TcpBacklog = 100 TcpDelay = off BkInterval = 1s MaxIdle = 5m EnableP2P = yes AdvertiseTime = 1m DefMsgTTL = 5 SharedKey = PLAINTEXT SessionCacheTime = 2m SessionRetries = 3 SessionTimeout = 10s MaxLogicalAdvertiseEPs = 256 DeadRouterTTL = 2s // This maps the abstract Dynamic DNS endpoints to their default logical endpoints. AbstractMap[abstract://LillTek/DataCenter/DynDNS] = logical://LillTek/DataCenter/DynDNS &endsection //----------------------------------------------------------------------------- // Dynamic DNS Service Settings §ion LillTek.Datacenter.DynDNS // Specifies the network binding the DNS server should listen on. NetworkBinding = ANY:DNS // Specifies the NetworkBinding the DNS server // should listen on to receive UDP host registration messages // from DynDnsClients. UdpBinding = ANY:DYNAMIC-DNS // Controls how the server is to be configured to obtain host // registrations from dynamic DNS clients. The possible values // are UDP, CLUSTER, or BOTH. Mode = UDP // Shared symmetric encryption key used to decrypt UDP registration messages // sent by DNS clients while in UDP or BOTH mode. This key must match the shared // key configured for the client. This defaults to the same reasonable default // used by the DNS client class. SharedKey = aes:BcskocQ2W4aIGEemkPsy5dhAxuWllweKLVToK1NoYzg=:5UUVxRPml8L4WH82unR74A== // The maximum delta to be allowed between the timestamp of messages received from // UDP broadcast clients and servers and the current system time. // // Messages transmitted between clients and servers in the UDP broadcast cluster are // timestamped with the time they were sent (UTC) to avoid replay attacks. This // setting controls which messages will be discarded for being having a timestamp // too far in the past or too far into the future. // // Ideally, this value would represent the maximum time a message could realistically // remain in transit on the network (a few seconds), but this setting also needs to // account for the possibility that the server system clocks may be out of sync. So, // this value is a tradeoff between security and reliability. MessageTTL = 15m // Specifies the time-to-live setting to use when replying to // DNS queries. This indicates how long the operating system // on the client side should cache the response. ResponseTTL = 5s // Indicates whether DNS host lookup failures should be logged // as warnings. LogFailures = yes §ion Cluster // The cluster's logical base endpoint. Instance endpoints will be constructed // by appending a GUID segment to this and the cluster broadcast endpoint // will be generated by appending '/*'. This setting is required. ClusterBaseEP = abstract://LillTek/DataCenter/DynDNS // Specifies the startup mode for the instance. This can be one of // the following values: // // NORMAL Indicates that the cluster member should go through the normal // master election cycle and eventually enter into the MASTER or SLAVE // state. // // OBSERVER Indicates that the cluster member should immediately enter the // OBSERVER state and remain there. Cluster observer state information // is replicated across the cluster so other instances know // about these instances but observers will never be elected // as the master. // // MONITOR Indicates that the cluster member should immediately enter the // MONITOR state and remain there. Monitors collect and maintain // cluster status but do not actively participate in the cluster. // No member status information about a monitor will be replicated // across the cluster. // // PREFERSLAVE Indicates that the cluster member prefers to be started as a // cluster slave // // PREFERMASTER Indicates that the cluster member prefers to be started as the // cluster master. If a master is already running and it does not // have this preference then a master election will be called. Mode = Normal // The interval at which the cluster master should broadcast cluster update // messages. Default is 1m. MasterBroadcastInterval = 10s // The interval at which slaves send their status updates to the master. // Default is 1m. SlaveUpdateInterval = 10s // The time period cluster members will wait while collecting member status // broadcasts from peers before concluding a master election. Default // is 5s. ElectionInterval = 10s // The number of times a cluster slave member should allow for missed // cluster status messages before calling for a master election. // Default is 3. MissingMasterCount = 2 // The number of times the cluster master should allow for missed // slave status transmissions before removing the slave from the cluster // state. Default is 3. MissingSlaveCount = 2 // The interval at which the cluster master instance should raise its // ClusterMember.MasterTask event so that derived classes can implement // custom background processing behavior. Default is 1s. MasterBkInterval = 1s // The interval at which the cluster slaves should raise their // ClusterMember.SlaveTask event so that derived classes // can implement custom background processing behavior. // Default is 1s. SlaveBkInterval = 1s // The background task polling interval. This value should be less than // or equal to the minimum of MasterBroadcastInterval, MasterBkInterval, // and SlaveBkInterval. Default is 1s. BkInterval = 1s &endsection &endsection ".Replace('&', '#')); router = new LeafRouter(); router.Start();; // Start the Dynamic DNS service svcProcess = Helper.StartProcess(assembly, "-mode:form -start"); Thread.Sleep(10000); // Give the process a chance to spin up // Open a dynamic DNS client and register a host and then // verify that it worked. DynDnsClientSettings clientSettings; clientSettings = new DynDnsClientSettings(); clientSettings.Mode = DynDnsMode.Udp; clientSettings.NameServers = new NetworkBinding[] { new NetworkBinding(NetHelper.GetActiveAdapter(), NetworkPort.DynamicDns) }; clientSettings.UdpRegisterInterval = TimeSpan.FromSeconds(1); client = new DynDnsClient(); client.Register(new DynDnsHostEntry("test.com", IPAddress.Parse("10.1.2.3"))); client.Register(new DynDnsHostEntry("www.lilltek.com", IPAddress.Parse("192.168.1.202"))); client.Open(router, clientSettings); Thread.Sleep(3000); Assert.AreEqual(IPAddress.Parse("10.1.2.3"), DnsLookup("test.com")); // Uncomment this for manual interop testing // Thread.Sleep(10000000); } finally { if (client != null) { client.Close(); } if (svcProcess != null) { svcProcess.Kill(); svcProcess.Close(); } if (router != null) { router.Stop(); } Config.SetConfig(null); } }
public void DynDnsHandler_Udp_CNAME() { // Start a Dynamic DNS service handler and a client, register CNAME // records and confirm that CNAME queries return the proper results. DynDnsClientSettings clientSettings; DynDnsHandler handler = null; DynDnsClient client = null; DnsResponse response; CNAME_RR record; try { handler = new DynDnsHandler(); handler.Start(router, null, null, null); clientSettings = new DynDnsClientSettings() { Mode = DynDnsMode.Udp, NameServers = new NetworkBinding[] { new NetworkBinding("127.0.0.1:DYNAMIC-DNS") }, UdpRegisterInterval = TimeSpan.FromSeconds(1) }; client = new DynDnsClient(); client.Register(new DynDnsHostEntry("test1.com,server.test1.com,1000,CNAME")); client.Register(new DynDnsHostEntry("test2.com,server.test2.com,2000,CNAME")); client.Open(router, clientSettings); // Wait for everything to spin up. Thread.Sleep(3000); // Verify the single result for a CNAME query on test1.com response = DnsResolver.Query(IPAddress.Loopback, new DnsRequest(DnsFlag.NONE, "test1.com.", DnsQType.CNAME), TimeSpan.FromSeconds(2)); Assert.AreEqual("test1.com.", response.QName); Assert.AreEqual(DnsQType.CNAME, response.QType); Assert.AreEqual(1, response.Answers.Count); record = (CNAME_RR)response.Answers[0]; Assert.AreEqual("test1.com.", record.RName); Assert.AreEqual("server.test1.com.", record.CName); Assert.AreEqual(1000, record.TTL); Thread.Sleep(2000); // Verify the single result for a CNAME query on test2.com response = DnsResolver.Query(IPAddress.Loopback, new DnsRequest(DnsFlag.NONE, "test2.com.", DnsQType.CNAME), TimeSpan.FromSeconds(2)); Assert.AreEqual("test2.com.", response.QName); Assert.AreEqual(DnsQType.CNAME, response.QType); Assert.AreEqual(1, response.Answers.Count); record = (CNAME_RR)response.Answers[0]; Assert.AreEqual("test2.com.", record.RName); Assert.AreEqual("server.test2.com.", record.CName); Assert.AreEqual(2000, record.TTL); } finally { if (client != null) { client.Close(); } if (handler != null) { handler.Stop(); } } }
public void DynDnsHandler_Udp_ADDRESS() { // Start a Dynamic DNS service handler and a client, register two ADDRESS // records for TEST1.COM and confirm that A queries load balance across the two entries. // I'm also going to add an ADDRESS record for TEST2.COM and verify that this address // is never returned. DynDnsClientSettings clientSettings; DynDnsHandler handler = null; DynDnsClient client = null; DnsResponse response; A_RR record; bool found1; bool found2; try { handler = new DynDnsHandler(); handler.Start(router, null, null, null); clientSettings = new DynDnsClientSettings() { Mode = DynDnsMode.Udp, NameServers = new NetworkBinding[] { new NetworkBinding("127.0.0.1:DYNAMIC-DNS") }, UdpRegisterInterval = TimeSpan.FromSeconds(1) }; client = new DynDnsClient(); client.Register(new DynDnsHostEntry("test1.com,10.0.0.1,1000,ADDRESS")); client.Register(new DynDnsHostEntry("test1.com,10.0.0.2,1000,ADDRESS")); client.Register(new DynDnsHostEntry("test2.com,10.0.0.3,1000,ADDRESS")); client.Open(router, clientSettings); // Wait for everything to spin up. Thread.Sleep(3000); // Loop 1000 times or until we got responses for both entry IP addresses. Note // that there's a 1000:1 chance that this could be working properly and the test // still fail. found1 = false; found2 = false; for (int i = 0; i < 1000; i++) { response = DnsResolver.Query(IPAddress.Loopback, new DnsRequest(DnsFlag.NONE, "test1.com.", DnsQType.A), TimeSpan.FromSeconds(2)); Assert.AreEqual("test1.com.", response.QName); Assert.AreEqual(DnsQType.A, response.QType); Assert.AreEqual(1, response.Answers.Count); record = (A_RR)response.Answers[0]; Assert.AreNotEqual(IPAddress.Parse("10.0.0.3"), record.Address); if (IPAddress.Parse("10.0.0.1").Equals(record.Address)) { found1 = true; } else if (IPAddress.Parse("10.0.0.2").Equals(record.Address)) { found2 = true; } else { Assert.Fail(); } if (found1 && found2) { break; } } Assert.IsTrue(found1); Assert.IsTrue(found2); } finally { if (client != null) { client.Close(); } if (handler != null) { handler.Stop(); } } }