示例#1
0
        /// <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();
                }
            }
        }