Ejemplo n.º 1
0
        protected override byte[] GetBytes()
        {
            var dnsMessage = new DnsMessage();
            var question   = new DnsQuestion(DomainName.Parse(_domain), RecordType.Txt, RecordClass.INet);

            dnsMessage.Questions.Add(question);
            dnsMessage.IsRecursionDesired = true;

            return(dnsMessage.Encode());
        }
Ejemplo n.º 2
0
        private async Task ForwardMessage(DnsMessage message, UdpReceiveResult originalUdpMessage,
                                          IPEndPoint targetNameServer, int queryTimeout,
                                          bool useCompressionMutation)
        {
            DnsQuestion question = null;

            if (message.Questions.Count > 0)
            {
                question = message.Questions[0];
            }

            byte[] responseBuffer = null;
            try
            {
                if ((Equals(targetNameServer.Address, IPAddress.Loopback) ||
                     Equals(targetNameServer.Address, IPAddress.IPv6Loopback)) &&
                    targetNameServer.Port == ((IPEndPoint)_udpListener.Client.LocalEndPoint).Port)
                {
                    throw new InfiniteForwardingException(question);
                }

                byte[] sendBuffer;
                if (useCompressionMutation)
                {
                    message.Encode(false, out sendBuffer, true);
                }
                else
                {
                    sendBuffer = originalUdpMessage.Buffer;
                }

                _transactionClients[message.TransactionID] = originalUdpMessage.RemoteEndPoint;

                // Send to Forwarder
                await _udpForwarder.SendAsync(sendBuffer, sendBuffer.Length, targetNameServer);

                if (_transactionTimeoutCancellationTokenSources.ContainsKey(message.TransactionID))
                {
                    _transactionTimeoutCancellationTokenSources[message.TransactionID].Cancel();
                }
                var cancellationTokenSource = new CancellationTokenSource();
                _transactionTimeoutCancellationTokenSources[message.TransactionID] = cancellationTokenSource;

                // Timeout task to cancel the request
                try
                {
                    await Task.Delay(queryTimeout, cancellationTokenSource.Token);

                    if (!_transactionClients.ContainsKey(message.TransactionID))
                    {
                        return;
                    }
                    IPEndPoint ignoreEndPoint;
                    CancellationTokenSource ignoreTokenSource;
                    _transactionClients.TryRemove(message.TransactionID, out ignoreEndPoint);
                    _transactionTimeoutCancellationTokenSources.TryRemove(message.TransactionID,
                                                                          out ignoreTokenSource);

                    var warningText = message.Questions.Count > 0
                        ? $"{message.Questions[0].Name} (Type {message.Questions[0].RecordType})"
                        : $"Transaction #{message.TransactionID}";
                    Logger.Warning("Query timeout for: {0}", warningText);
                }
                catch (TaskCanceledException)
                {
                }
            }
            catch (InfiniteForwardingException e)
            {
                Logger.Warning("[Forwarder.Send] Infinite forwarding detected for: {0} (Type {1})", e.Question.Name,
                               e.Question.RecordType);
                Utils.ReturnDnsMessageServerFailure(message, out responseBuffer);
            }
            catch (SocketException e)
            {
                if (e.SocketErrorCode == SocketError.ConnectionReset) // Target name server port unreachable
                {
                    Logger.Warning("[Forwarder.Send] Name server port unreachable: {0}", targetNameServer);
                }
                else
                {
                    Logger.Error("[Forwarder.Send] Unhandled socket error: {0}", e.Message);
                }
                Utils.ReturnDnsMessageServerFailure(message, out responseBuffer);
            }
            catch (Exception e)
            {
                Logger.Error("[Forwarder] Unexpected exception:\n{0}", e);
                Utils.ReturnDnsMessageServerFailure(message, out responseBuffer);
            }

            // If we got some errors
            if (responseBuffer != null)
            {
                await _udpListener.SendAsync(responseBuffer, responseBuffer.Length, originalUdpMessage.RemoteEndPoint);
            }
        }
Ejemplo n.º 3
0
        private async void ProcessMessageAsync(UdpReceiveResult udpMessage)
        {
            await Task.Run(async() =>
            {
                DnsMessage message = new DnsMessage();
                DnsQuestion question;

                try
                {
                    var respondedFromCache = false;

                    try
                    {
                        message  = DnsMessage.Parse(udpMessage.Buffer);
                        question = message.Questions[0];
                    }
                    catch (Exception)
                    {
                        throw new ParsingException();
                    }

                    // Check for authorized subnet access
                    var allowedClient = _options.AllowedClientIPs;
                    var clientIP      = udpMessage.RemoteEndPoint.Address;
                    if ((allowedClient != null) && (allowedClient.Count > 0))
                    {
                        if (allowedClient.All(ipNetwork => !IPNetwork.Contains(ipNetwork, clientIP)))
                        {
                            logger.Warn($"{clientIP} is not authorized.");

                            throw new AuthorizationException();
                        }
                    }
                    logger.Info($"{clientIP} requested {question.Name} (#{message.TransactionID}, {question.RecordType}).");

                    // Query cache
                    if (_options.CacheResponse)
                    {
                        if (Cache.ContainsKey(question.Name) && Cache[question.Name].ContainsKey(question.RecordType))
                        {
                            var entry = Cache[question.Name][question.RecordType];
                            if (!entry.IsExpired)
                            {
                                var cachedMessage = entry.Message;
                                logger.Info($"-> #{message.TransactionID} served from cache.");
                                cachedMessage.TransactionID = message.TransactionID; // Update transaction ID
                                cachedMessage.TSigOptions   = message.TSigOptions;   // Update TSig _options
                                message            = cachedMessage;
                                respondedFromCache = true;
                            }
                        }
                    }

                    var targetNameServer       = _options.LocalNameServer;
                    var useHttpQuery           = _options.UseHttpQuery;
                    var queryTimeout           = _options.QueryTimeout;
                    var useCompressionMutation = _options.CompressionMutation;

                    // Match rules
                    if (message.IsQuery &&
                        (question.RecordType == RecordType.A || question.RecordType == RecordType.Aaaa))
                    {
                        for (var i = Rules.Count - 1; i >= 0; i--)
                        {
                            var match = Regex.Match(question.Name, Rules[i].Pattern);
                            if (!match.Success)
                            {
                                continue;
                            }

                            // Domain name matched

                            var recordType = question.RecordType;
                            if (Rules[i].ForceAAAA != null && Rules[i].ForceAAAA.Value) // RecordType override
                            {
                                recordType = RecordType.Aaaa;
                            }

                            if (Rules[i].NameServer != null) // Name server override
                            {
                                targetNameServer = Rules[i].NameServer;
                            }

                            if (Rules[i].UseHttpQuery != null) // HTTP query override
                            {
                                useHttpQuery = Rules[i].UseHttpQuery.Value;
                            }

                            if (Rules[i].QueryTimeout != null) // Query timeout override
                            {
                                queryTimeout = Rules[i].QueryTimeout.Value;
                            }

                            if (Rules[i].CompressionMutation != null) // Compression pointer mutation override
                            {
                                useCompressionMutation = Rules[i].CompressionMutation.Value;
                            }

                            if (Rules[i].Address != null)
                            {
                                IPAddress ip;
                                IPAddress.TryParse(Rules[i].Address, out ip);
                                if (ip == null) // Invalid IP, may be a domain name
                                {
                                    var address = string.Format(Rules[i].Address, match.Groups.Cast <object>().ToArray());
                                    if (recordType == RecordType.A && useHttpQuery)
                                    {
                                        await ResolveWithHttp(targetNameServer, address, queryTimeout, message);
                                    }
                                    else
                                    {
                                        var serverEndpoint = Utils.CreateIpEndPoint(targetNameServer, 53);
                                        var dnsClient      = new DnsClient(serverEndpoint.Address, queryTimeout,
                                                                           serverEndpoint.Port);
                                        var response =
                                            await
                                            Task <DnsMessage> .Factory.FromAsync(dnsClient.BeginResolve,
                                                                                 dnsClient.EndResolve,
                                                                                 address, recordType, question.RecordClass, null);
                                        if (response == null)
                                        {
                                            logger.Warn($"Remote resolve failed for {address}.");
                                            return;
                                        }
                                        foreach (var answerRecord in response.AnswerRecords)
                                        {
                                            answerRecord.Name = question.Name;
                                            message.AnswerRecords.Add(answerRecord);
                                        }
                                        message.ReturnCode = response.ReturnCode;
                                        message.IsQuery    = false;
                                    }
                                }
                                else
                                {
                                    if (recordType == RecordType.A &&
                                        ip.AddressFamily == AddressFamily.InterNetwork)
                                    {
                                        message.AnswerRecords.Add(new ARecord(question.Name, 600, ip));
                                    }
                                    else if (recordType == RecordType.Aaaa &&
                                             ip.AddressFamily == AddressFamily.InterNetworkV6)
                                    {
                                        message.AnswerRecords.Add(new AaaaRecord(question.Name, 600, ip));
                                    }
                                    else // Type mismatch
                                    {
                                        continue;
                                    }

                                    message.ReturnCode = ReturnCode.NoError;
                                    message.IsQuery    = false;
                                }
                            }

                            break;
                        }
                    }

                    // TODO: Consider how to integrate System.Net.Dns with this project.
                    // Using System.Net.Dns to forward query if compression mutation is disabled
                    //if (message.IsQuery && !useCompressionMutation &&
                    //    (question.RecordType == RecordType.A || question.RecordType == RecordType.Aaaa))
                    //{
                    //    var dnsResponse = await Dns.GetHostAddressesAsync(question.Name);

                    //    if (question.RecordType == RecordType.A)
                    //    {
                    //        message.AnswerRecords.AddRange(dnsResponse.Where(
                    //            ip => ip.AddressFamily == AddressFamily.InterNetwork).Select(
                    //                ip => new ARecord(question.Name, 0, ip)));
                    //    else if (question.RecordType == RecordType.Aaaa)
                    //    {
                    //        message.AnswerRecords.AddRange(dnsResponse.Where(
                    //            ip => ip.AddressFamily == AddressFamily.InterNetworkV6).Select(
                    //                ip => new AaaaRecord(question.Name, 0, ip)));
                    //    }
                    //    message.ReturnCode = ReturnCode.NoError;
                    //    message.IsQuery = false;
                    //}

                    if (message.IsQuery && question.RecordType == RecordType.A && useHttpQuery)
                    {
                        await ResolveWithHttp(targetNameServer, question.Name, queryTimeout, message);
                    }

                    if (message.IsQuery)
                    {
                        // Use internal forwarder to forward query to another name server
                        await ForwardMessage(message, udpMessage, Utils.CreateIpEndPoint(targetNameServer, 53),
                                             queryTimeout, useCompressionMutation);
                    }
                    else
                    {
                        // Already answered, directly return to the client
                        byte[] responseBuffer;
                        message.Encode(false, out responseBuffer);
                        if (responseBuffer != null)
                        {
                            await
                            _udpListener.SendAsync(responseBuffer, responseBuffer.Length, udpMessage.RemoteEndPoint);

                            // Update cache
                            if (_options.CacheResponse && !respondedFromCache)
                            {
                                Cache.Update(question, message, _options.CacheAge);
                            }
                        }
                    }
                }
                catch (ParsingException)
                {
                }
                catch (AuthorizationException)
                {
                    message.ReturnCode = ReturnCode.Refused;
                    message.IsQuery    = false;
                    // Already answered, directly return to the client
                    byte[] responseBuffer;
                    message.Encode(false, out responseBuffer);
                    if (responseBuffer != null)
                    {
                        await
                        _udpListener.SendAsync(responseBuffer, responseBuffer.Length, udpMessage.RemoteEndPoint);
                    }
                }
                catch (SocketException e)
                {
                    logger.Error("[Listener.Send] Unexpected socket error:\n{0}", e);
                }
                catch (Exception e)
                {
                    logger.Error("[Processor] Unexpected exception:\n{0}", e);
                }
            });
        }
Ejemplo n.º 4
0
 public static void ReturnDnsMessageServerFailure(DnsMessage message, out byte[] buffer)
 {
     message.ReturnCode = ReturnCode.ServerFailure;
     message.IsQuery    = false;
     message.Encode(false, out buffer);
 }
Ejemplo n.º 5
0
        private bool ForwardMessage(DnsMessage message, IPEndPoint revicepoint, byte[] buf,
                                    IPEndPoint targetNameServer, int queryTimeout,
                                    bool useCompressionMutation)
        {
            DnsQuestion question = null;

            if (message.Questions.Count > 0)
            {
                question = message.Questions[0];
            }

            byte[] responseBuffer = null;
            try
            {
                if ((Equals(targetNameServer.Address, IPAddress.Loopback) ||
                     Equals(targetNameServer.Address, IPAddress.IPv6Loopback)) &&
                    targetNameServer.Port == ((IPEndPoint)_UdpListener.Client.LocalEndPoint).Port)
                {
                    throw new InfiniteForwardingException(question);
                }

                byte[] sendBuffer;
                if (useCompressionMutation)
                {
                    message.Encode(false, out sendBuffer, true);
                }
                else
                {
                    sendBuffer = buf;
                }

                _transactionClients[message.TransactionID] = revicepoint;


                // Send to Forwarder
                /*await _udpForwarder.SendAsync(sendBuffer, sendBuffer.Length, targetNameServer);*/
                _UdpForwarder.Send(sendBuffer, sendBuffer.Length, targetNameServer);



                if (_transactionTimeoutCancellationTokenSources.ContainsKey(message.TransactionID))
                {
                    _transactionTimeoutCancellationTokenSources[message.TransactionID].Cancel();
                }
                MrTe.Threading.Tasks.CancellationTokenSource cancellationTokenSource = new MrTe.Threading.Tasks.CancellationTokenSource();

                _transactionTimeoutCancellationTokenSources[message.TransactionID] = cancellationTokenSource;


                return(true);

                // Timeout task to cancel the request

                /*try
                 * {*/
                /*await Task.Delay(queryTimeout, cancellationTokenSource.Token);*/

                Task.Delay(queryTimeout, cancellationTokenSource.Token);

                if (!_transactionClients.ContainsKey(message.TransactionID))
                {
                    return(false);
                }
                IPEndPoint ignoreEndPoint;
                MrTe.Threading.Tasks.CancellationTokenSource ignoreTokenSource;

                /*
                 *  _transactionClients.TryRemove(message.TransactionID, out ignoreEndPoint);
                 *  _transactionTimeoutCancellationTokenSources.TryRemove(message.TransactionID,
                 *      out ignoreTokenSource);
                 */
                ignoreEndPoint    = _transactionClients[message.TransactionID];
                ignoreTokenSource = _transactionTimeoutCancellationTokenSources[message.TransactionID];



                string warningText = message.Questions.Count > 0
                        ? message.Questions[0].Name + " (Type " + message.Questions[0].RecordType + ")"
                        : "Transaction #" + message.TransactionID + "";
                Logger.Warning("Query timeout for: {0}", warningText);
                _transactionClients.Remove(message.TransactionID);
                _transactionTimeoutCancellationTokenSources.Remove(message.TransactionID);

                /*
                 * }
                 * catch (TaskCanceledException)
                 * {
                 * }
                 */
            }
            catch (InfiniteForwardingException e)
            {
                Logger.Warning("[Forwarder.Send] Infinite forwarding detected for: {0} (Type {1})", e.Question.Name,
                               e.Question.RecordType);
                Utils.ReturnDnsMessageServerFailure(message, out responseBuffer);
            }
            catch (SocketException e)
            {
                if (e.SocketErrorCode == SocketError.ConnectionReset) // Target name server port unreachable
                {
                    Logger.Warning("[Forwarder.Send] Name server port unreachable: {0}", targetNameServer);
                }
                else
                {
                    Logger.Error("[Forwarder.Send] Unhandled socket error: {0}", e.Message);
                }
                Utils.ReturnDnsMessageServerFailure(message, out responseBuffer);
            }
            catch (Exception e)
            {
                Logger.Error("[Forwarder] Unexpected exception:\n{0}", e);
                Utils.ReturnDnsMessageServerFailure(message, out responseBuffer);
            }

            // If we got some errors

            if (responseBuffer != null)
            {
                /*await _udpListener.SendAsync(responseBuffer, responseBuffer.Length, originalUdpMessage.RemoteEndPoint);*/
                _UdpListener.Send(responseBuffer, responseBuffer.Length, revicepoint);
            }
            return(true);
        }