/// <summary>Process UDP Request</summary> /// <param name="args"></param> private void ProcessUdpRequest(SocketAsyncEventArgs args) { DnsMessage message; if (!DnsProtocol.TryParse(args.Buffer, out message)) { // TODO log bad message Console.WriteLine("unable to parse message"); return; } Interlocked.Increment(ref _requests); if (message.IsQuery()) { if (message.Questions.Count > 0) { foreach (Question question in message.Questions) { Console.WriteLine("{0} asked for {1} {2} {3}", args.RemoteEndPoint.ToString(), question.Name, question.Class, question.Type); IPHostEntry entry; if (question.Type == ResourceType.PTR) { if (question.Name == "1.0.0.127.in-addr.arpa") // query for PTR record { message.QR = true; message.AA = true; message.RA = false; message.AnswerCount++; message.Answers.Add(new ResourceRecord { Name = question.Name, Class = ResourceClass.IN, Type = ResourceType.PTR, TTL = 3600, DataLength = 0xB, RData = new DomainNamePointRData() { Name = "localhost" } }); } } else if (_resolver.TryGetHostEntry(question.Name, question.Class, question.Type, out entry)) // Right zone, hostname/machine function does exist { message.QR = true; message.AA = true; message.RA = false; message.RCode = (byte)RCode.NOERROR; foreach (IPAddress address in entry.AddressList) { message.AnswerCount++; message.Answers.Add(new ResourceRecord { Name = question.Name, Class = ResourceClass.IN, Type = ResourceType.A, TTL = 10, RData = new ANameRData { Address = address } }); } } else if (question.Name.EndsWith(_resolver.GetZoneName())) // Right zone, but the hostname/machine function doesn't exist { message.QR = true; message.AA = true; message.RA = false; message.RCode = (byte)RCode.NXDOMAIN; message.AnswerCount = 0; message.Answers.Clear(); var soaResourceData = new StatementOfAuthorityRData() { PrimaryNameServer = Environment.MachineName, ResponsibleAuthoritativeMailbox = "stephbu." + Environment.MachineName, Serial = _resolver.GetZoneSerial(), ExpirationLimit = 86400, RetryInterval = 300, RefreshInterval = 300, MinimumTTL = 300 }; var soaResourceRecord = new ResourceRecord { Class = ResourceClass.IN, Type = ResourceType.SOA, TTL = 300, RData = soaResourceData }; message.NameServerCount++; message.Authorities.Add(soaResourceRecord); } // else // Referral to regular DC DNS servers { // store current IP address and Query ID. try { string key = GetKeyName(message); _requestResponseMapLock.EnterWriteLock(); _requestResponseMap.Add(key, args.RemoteEndPoint); } finally { _requestResponseMapLock.ExitWriteLock(); } } using (MemoryStream responseStream = new MemoryStream(512)) { message.WriteToStream(responseStream); if (message.IsQuery()) { // send to upstream DNS servers foreach (IPHostEntry dnsServer in _defaultDns) { SendUdp(responseStream.GetBuffer(), 0, (int)responseStream.Position, new IPEndPoint(dnsServer.AddressList.First(addr => addr.AddressFamily == AddressFamily.InterNetwork), 53)); } } else { Interlocked.Increment(ref _responses); SendUdp(responseStream.GetBuffer(), 0, (int)responseStream.Position, args.RemoteEndPoint); } } } } } else { // message is response to a delegated query string key = GetKeyName(message); try { _requestResponseMapLock.EnterUpgradeableReadLock(); EndPoint ep; if (_requestResponseMap.TryGetValue(key, out ep)) { // first test establishes presence try { _requestResponseMapLock.EnterWriteLock(); // second test within lock means exclusive access if (_requestResponseMap.TryGetValue(key, out ep)) { using (MemoryStream responseStream = new MemoryStream(512)) { message.WriteToStream(responseStream); Interlocked.Increment(ref _responses); Console.WriteLine("{0} answered {1} {2} {3} to {4}", args.RemoteEndPoint.ToString(), message.Questions[0].Name, message.Questions[0].Class, message.Questions[0].Type, ep.ToString()); SendUdp(responseStream.GetBuffer(), 0, (int)responseStream.Position, ep); } _requestResponseMap.Remove(key); } } finally { _requestResponseMapLock.ExitWriteLock(); } } else { Interlocked.Increment(ref _nacks); } } finally { _requestResponseMapLock.ExitUpgradeableReadLock(); } } }
/// <summary>Process UDP Request</summary> /// <param name="args"></param> private void ProcessUdpRequest(SocketAsyncEventArgs args) { DnsMessage message; if (!DnsProtocol.TryParse(args.Buffer, out message)) { // TODO log bad message Logger.Warn("Unable to parse message..."); return; } Interlocked.Increment(ref _requests); if (message.IsQuery()) { if (message.Questions.Count > 0) { foreach (Question question in message.Questions) { Logger.Debug("{0} asked for {1} {2} {3}", args.RemoteEndPoint.ToString(), question.Name, question.Class, question.Type); IPHostEntry entry; if (question.Type == ResourceType.PTR && question.Name == "1.0.0.127.in-addr.arpa") { message.QR = true; message.AA = true; message.RA = false; message.AnswerCount++; message.Answers.Add(new ResourceRecord { Name = question.Name, Class = ResourceClass.IN, Type = ResourceType.PTR, TTL = 3600, DataLength = 0xB, RData = new DomainNamePointRData() { Name = "localhost" } }); } //else if (_resolvers.Any(o => o.TryGetHostEntry(question.Name, question.Class, question.Type, out entry)) // Right zone, hostname/machine function does exist //{ // message.QR = true; // message.AA = true; // message.RA = false; // message.RCode = (byte)RCode.NOERROR; // foreach (IPAddress address in entry.AddressList) // { // message.AnswerCount++; // message.Answers.Add(new ResourceRecord { Name = question.Name, Class = ResourceClass.IN, Type = ResourceType.A, TTL = 10, RData = new ANameRData { Address = address } }); // } //} //else if (question.Name.EndsWith(_resolvers.GetZoneName())) // Right zone, but the hostname/machine function doesn't exist //{ // message.QR = true; // message.AA = true; // message.RA = false; // message.RCode = (byte)RCode.NXDOMAIN; // message.AnswerCount = 0; // message.Answers.Clear(); // var soaResourceData = new StatementOfAuthorityRData() { PrimaryNameServer = Environment.MachineName, ResponsibleAuthoritativeMailbox = "stephbu." + Environment.MachineName, Serial = _resolvers.GetZoneSerial(), ExpirationLimit = 86400, RetryInterval = 300, RefreshInterval = 300, MinimumTTL = 300 }; // var soaResourceRecord = new ResourceRecord { Class = ResourceClass.IN, Type = ResourceType.SOA, TTL = 300, RData = soaResourceData }; // message.NameServerCount++; // message.Authorities.Add(soaResourceRecord); //} // Host Resolution else if (_dnsConfig.HostOverrides.Any(o => String.Equals(question.Name, o.Hostname, StringComparison.InvariantCultureIgnoreCase))) { var address = _dnsConfig.HostOverrides.First(o => String.Equals(question.Name, o.Hostname, StringComparison.InvariantCultureIgnoreCase)); message.QR = true; message.AA = true; message.RA = false; message.RCode = (byte)RCode.NOERROR; message.AnswerCount++; message.Answers.Add(new ResourceRecord { Name = question.Name, Class = ResourceClass.IN, Type = ResourceType.A, TTL = 86400, RData = new ANameRData { Address = address.Address } }); } // Blacklist Resolution else if (DnsBlacklist.Search(question.Name)) { message.QR = true; message.AA = true; message.RA = false; message.RCode = (byte)RCode.NOERROR; message.AnswerCount++; message.Answers.Add(new ResourceRecord { Name = question.Name, Class = ResourceClass.IN, Type = ResourceType.A, TTL = 86400, RData = new ANameRData { Address = new IPAddress(0) } }); } else // Referral to regular DC DNS servers { // store current IP address and Query ID. try { string key = GetKeyName(message); _requestResponseMapLock.EnterWriteLock(); _requestResponseMap.Add(key, args.RemoteEndPoint); } finally { _requestResponseMapLock.ExitWriteLock(); } } using (MemoryStream responseStream = new MemoryStream(512)) { message.WriteToStream(responseStream); if (message.IsQuery()) { // Figure out which server to use, local dns servers or remote dns servers var localZoneServer = _dnsConfig.LocalZones.FirstOrDefault(o => question.Name.EndsWith(o.Zone, StringComparison.InvariantCultureIgnoreCase)); foreach (IPEndPoint dnsServer in localZoneServer != null ? localZoneServer.Servers : _dnsConfig.DnsServers) { SendUdp(responseStream.GetBuffer(), 0, (int)responseStream.Position, dnsServer); } } else { Interlocked.Increment(ref _responses); SendUdp(responseStream.GetBuffer(), 0, (int)responseStream.Position, args.RemoteEndPoint); } } } } } else { // message is response to a delegated query string key = GetKeyName(message); try { _requestResponseMapLock.EnterUpgradeableReadLock(); EndPoint ep; if (_requestResponseMap.TryGetValue(key, out ep)) { // first test establishes presence try { _requestResponseMapLock.EnterWriteLock(); // second test within lock means exclusive access if (_requestResponseMap.TryGetValue(key, out ep)) { using (MemoryStream responseStream = new MemoryStream(512)) { message.WriteToStream(responseStream); Interlocked.Increment(ref _responses); Logger.Debug("{0} answered {1} {2} {3} to {4}", args.RemoteEndPoint.ToString(), message.Questions[0].Name, message.Questions[0].Class, message.Questions[0].Type, ep.ToString()); SendUdp(responseStream.GetBuffer(), 0, (int)responseStream.Position, ep); } _requestResponseMap.Remove(key); } } finally { _requestResponseMapLock.ExitWriteLock(); } } else { Interlocked.Increment(ref _nacks); } } finally { _requestResponseMapLock.ExitUpgradeableReadLock(); } } }